def make_tiles(self): #==================== log('Tiling {}...'.format(self.__id)) source_kind = self.__raster_layer.source_kind if source_kind == 'image': tile_extractor = ImageTiler(self.__raster_layer, self.__tile_set) elif source_kind == 'pdf': tile_extractor = PDFTiler(self.__raster_layer, self.__tile_set) elif source_kind == 'svg': if self.__raster_layer.local_world_to_base is None: tile_extractor = SVGTiler(self.__raster_layer, self.__tile_set) else: tile_extractor = SVGImageTiler(self.__raster_layer, self.__tile_set) else: raise TypeError('Unsupported kind of background tile source: {}'.format(source_kind)) return self.__make_zoomed_tiles(tile_extractor)
def __finish_make(self): #======================= # We are finished with the knowledge base settings['KNOWLEDGE_STORE'].close() # Show what the map is about if self.__flatmap.models is not None: log('Generated map: {} for {}'.format(self.id, self.__flatmap.models)) else: log('Generated map: {}'.format(self.id)) ## FIX v's errorCheck for filename in self.__geojson_files: if settings.get('saveGeoJSON', False): print(filename) else: os.remove(filename)
def process(self): #================= for n in range(len(self.__slides)): slide = self.__slides[n] slide_number = n + 1 slide_layer = PowerpointSlide(self, slide, slide_number) log('Slide {}, {}'.format(slide_number, slide_layer.id)) if settings.get('saveDrawML'): xml = open(os.path.join(self.flatmap.map_directory, '{}.xml'.format(slide_layer.id)), 'w') xml.write(slide.element.xml) xml.close() slide_layer.process() for error in self.errors: log.warn(error) else: self.add_layer(slide_layer)
def __make_zoomed_tiles(self, tile_extractor): #============================================= mbtiles = MBTiles(self.__database_path, True, True) mbtiles.add_metadata(id=self.__id) zoom = self.__max_zoom log('Tiling zoom level {} for {}'.format(zoom, self.__id)) progress_bar = ProgressBar(total=len(self.__tile_set), unit='tiles', ncols=40, bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt}') for tile in self.__tile_set: tile_image = tile_extractor.get_tile(tile) alpha_image = add_alpha(tile_image) if not_empty(alpha_image): mbtiles.save_tile_as_png(zoom, tile.x, tile.y, alpha_image) progress_bar.update(1) progress_bar.close() self.__make_overview_tiles(mbtiles, zoom, self.__tile_set.start_coords, self.__tile_set.end_coords) mbtiles.close(compress=True)
def __output_geojson(self): #========================== log('Outputting GeoJson features...') for layer in self.__flatmap.layers: if layer.exported: log('Layer: {}'.format(layer.id)) geojson_output = GeoJSONOutput(layer, self.__flatmap.area, self.__map_dir) saved_layer = geojson_output.save( layer.features, settings.get('saveGeoJSON', False)) for (layer_name, filename) in saved_layer.items(): self.__geojson_files.append(filename) self.__tippe_inputs.append({ 'file': filename, 'layer': layer_name, 'description': '{} -- {}'.format(layer.description, layer_name) }) self.__flatmap.update_annotations(layer.annotations)
def __make_vector_tiles(self, compressed=True): #============================================== # Generate Mapbox vector tiles if len(self.__tippe_inputs) == 0: raise ValueError('No selectable layers found...') log('Running tippecanoe...') tippe_command = [ 'tippecanoe', '--force', '--projection=EPSG:4326', '--buffer=100', '--minimum-zoom={}'.format(self.__zoom[0]), '--maximum-zoom={}'.format(self.__zoom[1]), '--no-tile-size-limit', '--output={}'.format(self.__mbtiles_file), ] if not compressed: tippe_command.append('--no-tile-compression') if settings.get('quiet', False): tippe_command.append('--quiet') tippe_command += list([ "-L{}".format(json.dumps(input)) for input in self.__tippe_inputs ]) if settings.get('showTippe', False): print(' \\\n '.join(tippe_command)) subprocess.run(tippe_command) # `tippecanoe` uses the bounding box containing all features as the # map bounds, which is not the same as the extracted bounds, so update # the map's metadata tile_db = MBTiles(self.__mbtiles_file) tile_db.add_metadata(compressed=compressed) tile_db.update_metadata( center=','.join([str(x) for x in self.__centre]), bounds=','.join([str(x) for x in self.__extent])) tile_db.execute("COMMIT") tile_db.close() self.__upload_files.append('index.mbtiles')
def __init__(self, options): # ``silent`` implies not ``verbose`` if options.get('silent', False): options['verbose'] = False # Setup logging log_file = options.get('logFile') if log_file is None: log_path = options.get('logPath') if log_path is not None: log_file = os.path.join(log_path, '{}.log'.format(os.getpid())) configure_logging(log_file, verbose=options.get('verbose', False), silent=options.get('silent', False), debug=options.get('debug', False)) log('Mapmaker {}'.format(__version__)) # Default base output directory to ``./flatmaps``. if 'output' not in options: options['output'] = './flatmaps' # Check zoom settings are valid min_zoom = options.get('minZoom', 2) max_zoom = options.get('maxZoom', 10) initial_zoom = options.get('initialZoom', 4) if min_zoom < 0 or min_zoom > max_zoom: raise ValueError( 'Min zoom must be between 0 and {}'.format(max_zoom)) if max_zoom < min_zoom or max_zoom > 15: raise ValueError( 'Max zoom must be between {} and 15'.format(min_zoom)) if initial_zoom < min_zoom or initial_zoom > max_zoom: raise ValueError('Initial zoom must be between {} and {}'.format( min_zoom, max_zoom)) self.__zoom = (min_zoom, max_zoom, initial_zoom) # Save options into global ``settings`` dict settings.update(options) # Check we have been given a map source and get our manifest if 'source' in options: self.__manifest = Manifest(options['source'], options.get('singleSvg', False)) else: raise ValueError('No source manifest specified') self.__id = options.get('id', self.__manifest.id) if self.__id is None: raise ValueError('No id given for map') log('Making map: {}'.format(self.__id)) # Make sure our output directories exist map_base = options.get('output') if not os.path.exists(map_base): os.makedirs(map_base) self.__map_dir = os.path.join(map_base, self.__id) if options.get('clean', False): shutil.rmtree(self.__map_dir, True) if not os.path.exists(self.__map_dir): os.makedirs(self.__map_dir) # The vector tiles' database that is created by `tippecanoe` self.__mbtiles_file = os.path.join(self.__map_dir, 'index.mbtiles') self.__geojson_files = [] self.__tippe_inputs = [] # Raster tile layers self.__raster_layers = [] # Our source of knowledge, updated with information # about maps we've made, held in a global place settings['KNOWLEDGE_STORE'] = KnowledgeStore(map_base) # The map we are making self.__flatmap = FlatMap(self.__manifest, self)
def geometry(self) -> [GeometricShape]: """ Returns: A list of geometric objects. This are LineStrings describing paths between nodes and possibly additional features (e.g. way markers) of the paths. """ display_bezier_points = True #False ### To come from settings... if self.__path_layout == 'automatic': log("Automated pathway layout. Path ID: ", self.__path_id) evaluate_settings = self.__sheath.settings() # TODO: use evenly-distributed offsets for the final product. number_of_neurons = len(evaluate_settings['derivatives']) # locations = [0.01 + x*(0.99-0.01)/number_of_neurons for x in range(number_of_neurons)] location = 0.5 geometry = [] for scaffold, path_id, derivative in zip( evaluate_settings['scaffolds'], evaluate_settings['path_ids'], evaluate_settings['derivatives']): scaffold.generate() connectivity = Connectivity(path_id, scaffold, derivative, location) auto_beziers = connectivity.get_neuron_line_beziers() path = BezierPath.fromSegments(auto_beziers) geometry.append( GeometricShape( shapely.geometry.LineString(bezier_sample(path)))) end_nodes = set(self.__source_nodes) end_nodes.update(self.__target_nodes) for node in end_nodes: for edge in self.__graph.edges(node, data=True): if edge[2].get('type') == 'terminal': line = self.__line_from_edge(edge) if line is not None: geometry.append(GeometricShape(line)) if display_bezier_points: for beziers in self.__sheath.path_beziers.values(): for bezier in beziers: bz_pts = tuple([p.x, p.y] for p in bezier.points) for pt in [bz_pts[0], bz_pts[3]]: geometry.append( GeometricShape(GeometricShape.circle(pt), { 'type': 'bezier', 'kind': 'bezier-end' })) for pt in bz_pts[1:3]: geometry.append( GeometricShape(GeometricShape.circle(pt), { 'type': 'bezier', 'kind': 'bezier-control' })) geometry.append( GeometricShape(GeometricShape.line(*bz_pts[0:2]), {'type': 'bezier'})) geometry.append( GeometricShape(GeometricShape.line(*bz_pts[2:4]), {'type': 'bezier'})) return geometry # Fallback is centreline layout geometry = [] for edge in self.__graph.edges.data(): nerve = edge[2].get('nerve') properties = {'nerve': nerve} if nerve is not None else None bezier = edge[2].get('geometry') if self.__path_layout != 'linear' and bezier is not None: geometry.append( GeometricShape( shapely.geometry.LineString(bezier_sample(bezier)), properties)) else: line = self.__line_from_edge(edge) if line is not None: geometry.append(GeometricShape(line, properties)) return geometry
def __save_metadata(self): #========================= log('Creating index and style files...') tile_db = MBTiles(self.__mbtiles_file) # Save the URL of the map's manifest tile_db.add_metadata(source=self.__manifest.url) # What the map models if self.__models is not None: tile_db.add_metadata(describes=self.__models) # Save layer details in metadata tile_db.add_metadata(layers=json.dumps(self.__layer_metadata())) # Save pathway details in metadata tile_db.add_metadata( pathways=json.dumps(self.__map_properties.resolved_pathways)) # Save annotations in metadata tile_db.add_metadata(annotations=json.dumps(self.__annotations)) # Save command used to run mapmaker tile_db.add_metadata(created_by=self.__creator) # Save the maps creation time tile_db.add_metadata(created=datetime.datetime.utcnow().isoformat()) # Commit updates to the database tile_db.execute("COMMIT") #* ## TODO: set ``layer.properties`` for annotations... #* ##update_RDF(options['map_base'], options['map_id'], source, annotations) # Get list of all image sources from all layers raster_layers = [] for layer in self.__layer_dict.values(): raster_layers.extend(layer.raster_layers) map_index = { 'id': self.__id, 'source': self.__manifest.url, 'min-zoom': self.__zoom[0], 'max-zoom': self.__zoom[1], 'bounds': self.__extent, 'version': FLATMAP_VERSION, 'image_layer': len(raster_layers) > 0 ## For compatibility } if self.__models is not None: map_index['describes'] = self.__models # Create `index.json` for building a map in the viewer with open(os.path.join(self.__map_dir, 'index.json'), 'w') as output_file: json.dump(map_index, output_file) # Create style file metadata = tile_db.metadata() style_dict = MapStyle.style(raster_layers, metadata, self.__zoom) with open(os.path.join(self.__map_dir, 'style.json'), 'w') as output_file: json.dump(style_dict, output_file) # Create TileJSON file json_source = tile_json(self.__id, self.__zoom, self.__extent) with open(os.path.join(self.__map_dir, 'tilejson.json'), 'w') as output_file: json.dump(json_source, output_file) tile_db.close() self.__upload_files.extend( ['index.json', 'style.json', 'tilejson.json'])
def __init__(self, options): # ``silent`` implies ``quiet`` if options.get('silent', False): options['quiet'] = True # Setup logging configure_logging(options.get('logFile'), quiet=options.get('quiet', False), silent=options.get('silent', False)) # Check we have been given a map source if 'source' in options: self.__manifest = Manifest(options['source']) else: raise ValueError('No map source specified') # Default base output directory to ``./flatmaps``. if 'output' not in options: options['output'] = './flatmaps' # Check zoom settings are valid min_zoom = options.get('minZoom', 2) max_zoom = options.get('maxZoom', 10) initial_zoom = options.get('initialZoom', 4) if min_zoom < 0 or min_zoom > max_zoom: raise ValueError( 'Min zoom must be between 0 and {}'.format(max_zoom)) if max_zoom < min_zoom or max_zoom > 15: raise ValueError( 'Max zoom must be between {} and 15'.format(min_zoom)) if initial_zoom < min_zoom or initial_zoom > max_zoom: raise ValueError('Initial zoom must be between {} and {}'.format( min_zoom, max_zoom)) self.__zoom = (min_zoom, max_zoom, initial_zoom) # Save options into global ``settings`` dict settings.update(options) log('Mapmaker {}'.format(__version__)) self.__id = options.get('id', self.__manifest.id) if self.__id is None: raise ValueError('No `id` given for map') log('Making map: {}'.format(self.id)) self.__models = self.__manifest.models # Make sure our output directories exist map_base = options.get('output') if not os.path.exists(map_base): os.makedirs(map_base) self.__map_dir = os.path.join(map_base, self.__id) if options.get('clean', False): shutil.rmtree(self.__map_dir, True) if not os.path.exists(self.__map_dir): os.makedirs(self.__map_dir) # The vector tiles' database that is created by `tippecanoe` self.__mbtiles_file = os.path.join(self.__map_dir, 'index.mbtiles') self.__geojson_files = [] self.__tippe_inputs = [] self.__upload_files = [] # Properties about map features self.__map_properties = JsonProperties(self.__manifest) self.__layer_dict = OrderedDict() self.__visible_layer_count = 0 self.__annotations = {} self.__creator = 'mapmaker' ## FIX, add version info creator self.__map_area = None self.__extent = None self.__centre = None self.__last_feature_id = 0 self.__class_to_feature = defaultdict(list) self.__id_to_feature = {}