diff options
author | Marvin Borner | 2018-07-13 19:06:45 +0200 |
---|---|---|
committer | Marvin Borner | 2018-07-13 19:06:45 +0200 |
commit | 6fcfb7c04d32e1c8b26a312295bf7ac3ec2d2ad7 (patch) | |
tree | dbc87ef16fa01d5d99116de283592b8fe5e02944 /public/bower_components/jvectormap/converter | |
parent | dfd839f27146df0ad0494e11734fc7d310c70ebf (diff) |
Fixed many permissions and began admin interface
Diffstat (limited to 'public/bower_components/jvectormap/converter')
3 files changed, 1077 insertions, 0 deletions
diff --git a/public/bower_components/jvectormap/converter/converter.py b/public/bower_components/jvectormap/converter/converter.py new file mode 100644 index 0000000..93be1de --- /dev/null +++ b/public/bower_components/jvectormap/converter/converter.py @@ -0,0 +1,299 @@ +# +# jVectorMap version 2.0.4 +# +# Copyright 2011-2013, Kirill Lebedev +# + +import sys +import shapely.geometry +import shapely.wkb +import shapely.affinity +from osgeo import ogr +from osgeo import osr +import json +import codecs +import copy + +class Map: + def __init__(self, name, language): + self.paths = {} + self.name = name + self.language = language + self.width = 0 + self.height = 0 + self.bbox = [] + + def addPath(self, path, code, name): + self.paths[code] = {"path": path, "name": name} + + def getJSCode(self): + map = {"paths": self.paths, "width": self.width, "height": self.height, "insets": self.insets, "projection": self.projection} + return "jQuery.fn.vectorMap('addMap', '"+self.name+"_"+self.projection['type']+"_"+self.language+"',"+json.dumps(map)+');' + + +class Converter: + def __init__(self, config): + args = { + 'buffer_distance': -0.4, + 'simplify_tolerance': 0.2, + 'longitude0': 0, + 'projection': 'mill', + 'name': 'world', + 'width': 900, + 'language': 'en', + 'precision': 2, + 'insets': [] + } + args.update(config) + + self.map = Map(args['name'], args.get('language')) + + if args.get('sources'): + self.sources = args['sources'] + else: + self.sources = [{ + 'input_file': args.get('input_file'), + 'where': args.get('where'), + 'name_field': args.get('name_field'), + 'code_field': args.get('code_field'), + 'input_file_encoding': args.get('input_file_encoding') + }] + + default_source = { + 'where': '', + 'name_field': 0, + 'code_field': 1, + 'input_file_encoding': 'iso-8859-1' + } + + for index in range(len(self.sources)): + for key in default_source: + if self.sources[index].get(key) is None: + self.sources[index][key] = default_source[key] + + self.features = {} + self.width = args.get('width') + self.minimal_area = args.get('minimal_area') + self.longitude0 = float(args.get('longitude0')) + self.projection = args.get('projection') + self.precision = args.get('precision') + self.buffer_distance = args.get('buffer_distance') + self.simplify_tolerance = args.get('simplify_tolerance') + self.for_each = args.get('for_each') + self.emulate_longitude0 = args.get('emulate_longitude0') + if args.get('emulate_longitude0') is None and (self.projection == 'merc' or self.projection =='mill') and self.longitude0 != 0: + self.emulate_longitude0 = True + + if args.get('viewport'): + self.viewport = map(lambda s: float(s), args.get('viewport').split(' ')) + else: + self.viewport = False + + # spatial reference to convert to + self.spatialRef = osr.SpatialReference() + projString = '+proj='+str(self.projection)+' +a=6381372 +b=6381372 +lat_0=0' + if not self.emulate_longitude0: + projString += ' +lon_0='+str(self.longitude0) + self.spatialRef.ImportFromProj4(projString) + + # handle map insets + if args.get('insets'): + self.insets = args.get('insets') + else: + self.insets = [] + + def loadData(self): + for sourceConfig in self.sources: + self.loadDataSource( sourceConfig ) + + def loadDataSource(self, sourceConfig): + source = ogr.Open( sourceConfig['input_file'] ) + layer = source.GetLayer(0) + layer.SetAttributeFilter( sourceConfig['where'].encode('ascii') ) + self.viewportRect = False + + transformation = osr.CoordinateTransformation( layer.GetSpatialRef(), self.spatialRef ) + if self.viewport: + layer.SetSpatialFilterRect( *self.viewport ) + point1 = transformation.TransformPoint(self.viewport[0], self.viewport[1]) + point2 = transformation.TransformPoint(self.viewport[2], self.viewport[3]) + self.viewportRect = shapely.geometry.box(point1[0], point1[1], point2[0], point2[1]) + + layer.ResetReading() + + codes = {} + + if self.emulate_longitude0: + meridian = -180 + self.longitude0 + p1 = transformation.TransformPoint(-180, 89) + p2 = transformation.TransformPoint(meridian, -89) + left = shapely.geometry.box(p1[0], p1[1], p2[0], p2[1]) + p3 = transformation.TransformPoint(meridian, 89) + p4 = transformation.TransformPoint(180, -89) + right = shapely.geometry.box(p3[0], p3[1], p4[0], p4[1]) + + # load features + nextCode = 0 + for feature in layer: + geometry = feature.GetGeometryRef() + geometryType = geometry.GetGeometryType() + + if geometryType == ogr.wkbPolygon or geometryType == ogr.wkbMultiPolygon: + geometry.TransformTo( self.spatialRef ) + shapelyGeometry = shapely.wkb.loads( geometry.ExportToWkb() ) + if not shapelyGeometry.is_valid: + shapelyGeometry = shapelyGeometry.buffer(0, 1) + + if self.emulate_longitude0: + leftPart = shapely.affinity.translate(shapelyGeometry.intersection(left), p4[0] - p3[0]) + rightPart = shapely.affinity.translate(shapelyGeometry.intersection(right), p1[0] - p2[0]) + shapelyGeometry = leftPart.buffer(0.1, 1).union(rightPart.buffer(0.1, 1)).buffer(-0.1, 1) + + if not shapelyGeometry.is_valid: + shapelyGeometry = shapelyGeometry.buffer(0, 1) + shapelyGeometry = self.applyFilters(shapelyGeometry) + if shapelyGeometry: + name = feature.GetFieldAsString(str(sourceConfig.get('name_field'))).decode(sourceConfig.get('input_file_encoding')) + code = feature.GetFieldAsString(str(sourceConfig.get('code_field'))).decode(sourceConfig.get('input_file_encoding')) + if code in codes: + code = '_' + str(nextCode) + nextCode += 1 + codes[code] = name + self.features[code] = {"geometry": shapelyGeometry, "name": name, "code": code} + else: + raise Exception, "Wrong geometry type: "+geometryType + + + def convert(self, outputFile): + print 'Generating '+outputFile + + self.loadData() + + codes = self.features.keys() + main_codes = copy.copy(codes) + self.map.insets = [] + envelope = [] + for inset in self.insets: + insetBbox = self.renderMapInset(inset['codes'], inset['left'], inset['top'], inset['width']) + insetHeight = (insetBbox[3] - insetBbox[1]) * (inset['width'] / (insetBbox[2] - insetBbox[0])) + self.map.insets.append({ + "bbox": [{"x": insetBbox[0], "y": -insetBbox[3]}, {"x": insetBbox[2], "y": -insetBbox[1]}], + "left": inset['left'], + "top": inset['top'], + "width": inset['width'], + "height": insetHeight + }) + envelope.append( + shapely.geometry.box( + inset['left'], inset['top'], inset['left'] + inset['width'], inset['top'] + insetHeight + ) + ) + for code in inset['codes']: + main_codes.remove(code) + + insetBbox = self.renderMapInset(main_codes, 0, 0, self.width) + insetHeight = (insetBbox[3] - insetBbox[1]) * (self.width / (insetBbox[2] - insetBbox[0])) + + envelope.append( shapely.geometry.box( 0, 0, self.width, insetHeight ) ) + mapBbox = shapely.geometry.MultiPolygon( envelope ).bounds + + self.map.width = mapBbox[2] - mapBbox[0] + self.map.height = mapBbox[3] - mapBbox[1] + self.map.insets.append({ + "bbox": [{"x": insetBbox[0], "y": -insetBbox[3]}, {"x": insetBbox[2], "y": -insetBbox[1]}], + "left": 0, + "top": 0, + "width": self.width, + "height": insetHeight + }) + self.map.projection = {"type": self.projection, "centralMeridian": float(self.longitude0)} + + open(outputFile, 'w').write( self.map.getJSCode() ) + + if self.for_each is not None: + for code in codes: + childConfig = copy.deepcopy(self.for_each) + for param in ('input_file', 'output_file', 'where', 'name'): + childConfig[param] = childConfig[param].replace('{{code}}', code.lower()) + converter = Converter(childConfig) + converter.convert(childConfig['output_file']) + + def renderMapInset(self, codes, left, top, width): + envelope = [] + for code in codes: + envelope.append( self.features[code]['geometry'].envelope ) + + bbox = shapely.geometry.MultiPolygon( envelope ).bounds + + scale = (bbox[2]-bbox[0]) / width + + # generate SVG paths + for code in codes: + feature = self.features[code] + geometry = feature['geometry'] + if self.buffer_distance: + geometry = geometry.buffer(self.buffer_distance*scale, 1) + if geometry.is_empty: + continue + if self.simplify_tolerance: + geometry = geometry.simplify(self.simplify_tolerance*scale, preserve_topology=True) + if isinstance(geometry, shapely.geometry.multipolygon.MultiPolygon): + polygons = geometry.geoms + else: + polygons = [geometry] + path = '' + for polygon in polygons: + rings = [] + rings.append(polygon.exterior) + rings.extend(polygon.interiors) + for ring in rings: + for pointIndex in range( len(ring.coords) ): + point = ring.coords[pointIndex] + if pointIndex == 0: + path += 'M'+str( round( (point[0]-bbox[0]) / scale + left, self.precision) ) + path += ','+str( round( (bbox[3] - point[1]) / scale + top, self.precision) ) + else: + path += 'l' + str( round(point[0]/scale - ring.coords[pointIndex-1][0]/scale, self.precision) ) + path += ',' + str( round(ring.coords[pointIndex-1][1]/scale - point[1]/scale, self.precision) ) + path += 'Z' + self.map.addPath(path, feature['code'], feature['name']) + return bbox + + + def applyFilters(self, geometry): + if self.viewportRect: + geometry = self.filterByViewport(geometry) + if not geometry: + return False + if self.minimal_area: + geometry = self.filterByMinimalArea(geometry) + if not geometry: + return False + return geometry + + + def filterByViewport(self, geometry): + try: + return geometry.intersection(self.viewportRect) + except shapely.geos.TopologicalError: + return False + + + def filterByMinimalArea(self, geometry): + if isinstance(geometry, shapely.geometry.multipolygon.MultiPolygon): + polygons = geometry.geoms + else: + polygons = [geometry] + polygons = filter(lambda p: p.area > self.minimal_area, polygons) + return shapely.geometry.multipolygon.MultiPolygon(polygons) + + +args = {} +if len(sys.argv) > 1: + paramsJson = open(sys.argv[1], 'r').read() +else: + paramsJson = sys.stdin.read() +paramsJson = json.loads(paramsJson) + +converter = Converter(paramsJson) +converter.convert(paramsJson['output_file']) diff --git a/public/bower_components/jvectormap/converter/processor.py b/public/bower_components/jvectormap/converter/processor.py new file mode 100644 index 0000000..a583798 --- /dev/null +++ b/public/bower_components/jvectormap/converter/processor.py @@ -0,0 +1,573 @@ +import sys +import json +import csv +import shapely.wkb +import shapely.geometry +import shapely.ops +import codecs +import os +import inspect +import copy +from osgeo import ogr +from osgeo import osr +from booleano.parser import Grammar, EvaluableParseManager, SymbolTable, Bind +from booleano.operations import Variable + + +class Map: + def __init__(self, name, language): + self.paths = {} + self.name = name + self.language = language + self.width = 0 + self.height = 0 + self.bbox = [] + + def addPath(self, path, code, name): + self.paths[code] = {"path": path, "name": name} + + def getJSCode(self): + map = {"paths": self.paths, "width": self.width, "height": self.height, "insets": self.insets, "projection": self.projection} + return "jQuery.fn.vectorMap('addMap', '"+self.name+"_"+self.projection['type']+"',"+json.dumps(map)+');' + + +class Converter: + def __init__(self, config): + args = { + 'buffer_distance': -0.4, + 'simplify_tolerance': 0.2, + 'longitude0': 0, + 'projection': 'mill', + 'name': 'world', + 'width': 900, + 'left': 0, + 'top': 0, + 'language': 'en', + 'precision': 2, + 'insets': [] + } + args.update(config) + + self.config = args + + self.map = Map(args['name'], args.get('language')) + + if args.get('sources'): + self.sources = args['sources'] + else: + self.sources = [{ + 'input_file': args.get('input_file'), + 'where': args.get('where'), + 'name_field': args.get('name_field'), + 'code_field': args.get('code_field'), + 'input_file_encoding': args.get('input_file_encoding') + }] + + default_source = { + 'where': '', + 'name_field': 0, + 'code_field': 1, + 'input_file_encoding': 'iso-8859-1' + } + + for index in range(len(self.sources)): + for key in default_source: + if self.sources[index].get(key) is None: + self.sources[index][key] = default_source[key] + + self.features = {} + self.width = args.get('width') + self.left = args.get('left') + self.top = args.get('top') + self.minimal_area = args.get('minimal_area') + self.longitude0 = float(args.get('longitude0')) + self.projection = args.get('projection') + self.precision = args.get('precision') + self.buffer_distance = args.get('buffer_distance') + self.simplify_tolerance = args.get('simplify_tolerance') + self.for_each = args.get('for_each') + self.emulate_longitude0 = args.get('emulate_longitude0') + if args.get('emulate_longitude0') is None and (self.projection == 'merc' or self.projection =='mill') and self.longitude0 != 0: + self.emulate_longitude0 = True + + if args.get('viewport'): + self.viewport = map(lambda s: float(s), args.get('viewport').split(' ')) + else: + self.viewport = False + + # spatial reference to convert to + self.spatialRef = osr.SpatialReference() + projString = '+proj='+str(self.projection)+' +a=6381372 +b=6381372 +lat_0=0' + if not self.emulate_longitude0: + projString += ' +lon_0='+str(self.longitude0) + self.spatialRef.ImportFromProj4(projString) + + # handle map insets + if args.get('insets'): + self.insets = args.get('insets') + else: + self.insets = [] + + + def convert(self, data_source, output_file): + codes = map(lambda g: g.properties[self.config['code_field']], data_source.geometries) + main_codes = copy.copy(codes) + self.map.insets = [] + envelope = [] + for inset in self.insets: + insetBbox = self.renderMapInset(data_source, inset['codes'], inset['left'], inset['top'], inset['width']) + insetHeight = (insetBbox[3] - insetBbox[1]) * (inset['width'] / (insetBbox[2] - insetBbox[0])) + self.map.insets.append({ + "bbox": [{"x": insetBbox[0], "y": -insetBbox[3]}, {"x": insetBbox[2], "y": -insetBbox[1]}], + "left": inset['left'], + "top": inset['top'], + "width": inset['width'], + "height": insetHeight + }) + envelope.append( + shapely.geometry.box( + inset['left'], inset['top'], inset['left'] + inset['width'], inset['top'] + insetHeight + ) + ) + for code in inset['codes']: + main_codes.remove(code) + + insetBbox = self.renderMapInset(data_source, main_codes, self.left, self.top, self.width) + insetHeight = (insetBbox[3] - insetBbox[1]) * (self.width / (insetBbox[2] - insetBbox[0])) + envelope.append( shapely.geometry.box( self.left, self.top, self.left + self.width, self.top + insetHeight ) ) + mapBbox = shapely.geometry.MultiPolygon( envelope ).bounds + + self.map.width = mapBbox[2] + mapBbox[0] + self.map.height = mapBbox[3] + mapBbox[1] + self.map.insets.append({ + "bbox": [{"x": insetBbox[0], "y": -insetBbox[3]}, {"x": insetBbox[2], "y": -insetBbox[1]}], + "left": self.left, + "top": self.top, + "width": self.width, + "height": insetHeight + }) + self.map.projection = {"type": self.projection, "centralMeridian": float(self.longitude0)} + + open(output_file, 'w').write( self.map.getJSCode() ) + + if self.for_each is not None: + for code in codes: + childConfig = copy.deepcopy(self.for_each) + for param in ('input_file', 'output_file', 'where', 'name'): + childConfig[param] = childConfig[param].replace('{{code}}', code.lower()) + converter = Converter(childConfig) + converter.convert(childConfig['output_file']) + + def renderMapInset(self, data_source, codes, left, top, width): + envelope = [] + geometries = filter(lambda g: g.properties[self.config['code_field']] in codes, data_source.geometries) + for geometry in geometries: + envelope.append( geometry.geom.envelope ) + + bbox = shapely.geometry.MultiPolygon( envelope ).bounds + + scale = (bbox[2]-bbox[0]) / width + + # generate SVG paths + for geometry in geometries: + geom = geometry.geom + if self.buffer_distance: + geom = geom.buffer(self.buffer_distance*scale, 1) + if geom.is_empty: + continue + if self.simplify_tolerance: + geom = geom.simplify(self.simplify_tolerance*scale, preserve_topology=True) + if isinstance(geom, shapely.geometry.multipolygon.MultiPolygon): + polygons = geom.geoms + else: + polygons = [geom] + path = '' + for polygon in polygons: + rings = [] + rings.append(polygon.exterior) + rings.extend(polygon.interiors) + for ring in rings: + for pointIndex in range( len(ring.coords) ): + point = ring.coords[pointIndex] + if pointIndex == 0: + path += 'M'+str( round( (point[0]-bbox[0]) / scale + left, self.precision) ) + path += ','+str( round( (bbox[3] - point[1]) / scale + top, self.precision) ) + else: + path += 'l' + str( round(point[0]/scale - ring.coords[pointIndex-1][0]/scale, self.precision) ) + path += ',' + str( round(ring.coords[pointIndex-1][1]/scale - point[1]/scale, self.precision) ) + path += 'Z' + self.map.addPath(path, geometry.properties[self.config['code_field']], geometry.properties[self.config['name_field']]) + return bbox + + +class Geometry: + def __init__(self, geometry, properties): + self.geom = geometry + self.properties = properties + + +class GeometryProperty(Variable): + operations = set(["equality", "membership"]) + + def __init__(self, name): + self.name = name + + def equals(self, value, context): + return context[self.name] == value + + def belongs_to(self, value, context): + return value in context[self.name] + + def is_subset(self, value, context): + return set(value).issubset(set(context[self.name])) + + def to_python(self, value): + return unicode(value[self.name]) + + +class DataSource: + def __init__(self, config): + default_config = { + "projection": "merc", + "longitude0": 0 + } + default_config.update(config) + self.config = default_config + + self.spatialRef = osr.SpatialReference() + projString = '+proj='+str(self.config['projection'])+' +a=6381372 +b=6381372 +lat_0=0' + #if 'emulate_longitude0' in self.config and not self.config['emulate_longitude0']: + projString += ' +lon_0='+str(self.config['longitude0']) + self.spatialRef.ImportFromProj4(projString) + + def load_data(self): + self.source = ogr.Open( self.config['file_name'], update = 0 ) + self.layer = self.source.GetLayer(0) + if 'filter' in self.config and self.config['filter'] is not None: + self.layer.SetAttributeFilter( self.config['filter'].encode('ascii') ) + self.layer_dfn = self.layer.GetLayerDefn() + + self.fields = [] + field_count = self.layer_dfn.GetFieldCount() + for field_index in range(field_count): + field = self.layer_dfn.GetFieldDefn( field_index ) + self.fields.append({ + 'name': field.GetName(), + 'type': field.GetType(), + 'width': field.GetWidth(), + 'precision': field.GetPrecision() + }) + + self.geometries = [] + + for feature in self.layer: + geometry = feature.GetGeometryRef() + geometry.TransformTo( self.spatialRef ) + geometry = shapely.wkb.loads( geometry.ExportToWkb() ) + if not geometry.is_valid: + geometry = geometry.buffer(0) + properties = {} + for field in self.fields: + properties[field['name']] = feature.GetFieldAsString(field['name']).decode('utf-8') + self.geometries.append( Geometry(geometry, properties) ) + + self.layer.ResetReading() + + self.create_grammar() + + def create_grammar(self): + root_table = SymbolTable("root", + map( lambda f: Bind(f['name'], GeometryProperty(f['name'])), self.fields ) + ) + + tokens = { + 'not': 'not', + 'eq': '==', + 'ne': '!=', + 'belongs_to': 'in', + 'is_subset': 'are included in', + 'or': "or", + 'and': 'and' + } + grammar = Grammar(**tokens) + self.parse_manager = EvaluableParseManager(root_table, grammar) + + def output(self, output): + if output.get('format') == 'jvectormap': + self.output_jvm(output) + else: + self.output_ogr(output) + + def output_ogr(self, output): + driver = ogr.GetDriverByName( 'ESRI Shapefile' ) + if os.path.exists( output['file_name'] ): + driver.DeleteDataSource( output['file_name'] ) + source = driver.CreateDataSource( output['file_name'] ) + layer = source.CreateLayer( self.layer_dfn.GetName(), + geom_type = self.layer_dfn.GetGeomType(), + srs = self.layer.GetSpatialRef() ) + + for field in self.fields: + fd = ogr.FieldDefn( str(field['name']), field['type'] ) + fd.SetWidth( field['width'] ) + if 'precision' in field: + fd.SetPrecision( field['precision'] ) + layer.CreateField( fd ) + + for geometry in self.geometries: + if geometry.geom is not None: + feature = ogr.Feature( feature_def = layer.GetLayerDefn() ) + for index, field in enumerate(self.fields): + if field['name'] in geometry.properties: + feature.SetField( index, geometry.properties[field['name']].encode('utf-8') ) + else: + feature.SetField( index, '' ) + feature.SetGeometryDirectly( + ogr.CreateGeometryFromWkb( + shapely.wkb.dumps( + geometry.geom + ) + ) + ) + layer.CreateFeature( feature ) + feature.Destroy() + + source.Destroy() + + def output_jvm(self, output): + params = copy.deepcopy(output['params']) + params.update({ + "projection": self.config["projection"], + "longitude0": self.config["longitude0"] + }) + converter = Converter(params) + converter.convert(self, output['file_name']) + +class PolygonSimplifier: + def __init__(self, geometries): + self.format = '%.8f %.8f' + self.tolerance = 0.05 + self.geometries = geometries + + connections = {} + counter = 0 + for geom in geometries: + counter += 1 + polygons = [] + + if isinstance(geom, shapely.geometry.Polygon): + polygons.append(geom) + else: + for polygon in geom: + polygons.append(polygon) + + for polygon in polygons: + if polygon.area > 0: + lines = [] + lines.append(polygon.exterior) + for line in polygon.interiors: + lines.append(line) + + for line in lines: + for i in range(len(line.coords)-1): + indexFrom = i + indexTo = i+1 + pointFrom = self.format % line.coords[indexFrom] + pointTo = self.format % line.coords[indexTo] + if pointFrom == pointTo: + continue + if not (pointFrom in connections): + connections[pointFrom] = {} + connections[pointFrom][pointTo] = 1 + if not (pointTo in connections): + connections[pointTo] = {} + connections[pointTo][pointFrom] = 1 + self.connections = connections + self.simplifiedLines = {} + self.pivotPoints = {} + + def simplifyRing(self, ring): + coords = list(ring.coords)[0:-1] + simpleCoords = [] + + isPivot = False + pointIndex = 0 + while not isPivot and pointIndex < len(coords): + pointStr = self.format % coords[pointIndex] + pointIndex += 1 + isPivot = ((len(self.connections[pointStr]) > 2) or (pointStr in self.pivotPoints)) + pointIndex = pointIndex - 1 + + if not isPivot: + simpleRing = shapely.geometry.LineString(coords).simplify(self.tolerance) + if len(simpleRing.coords) <= 2: + return None + else: + self.pivotPoints[self.format % coords[0]] = True + self.pivotPoints[self.format % coords[-1]] = True + simpleLineKey = self.format % coords[0]+':'+self.format % coords[1]+':'+self.format % coords[-1] + self.simplifiedLines[simpleLineKey] = simpleRing.coords + return simpleRing + else: + points = coords[pointIndex:len(coords)] + points.extend(coords[0:pointIndex+1]) + iFrom = 0 + for i in range(1, len(points)): + pointStr = self.format % points[i] + if ((len(self.connections[pointStr]) > 2) or (pointStr in self.pivotPoints)): + line = points[iFrom:i+1] + lineKey = self.format % line[-1]+':'+self.format % line[-2]+':'+self.format % line[0] + if lineKey in self.simplifiedLines: + simpleLine = self.simplifiedLines[lineKey] + simpleLine = list(reversed(simpleLine)) + else: + simpleLine = shapely.geometry.LineString(line).simplify(self.tolerance).coords + lineKey = self.format % line[0]+':'+self.format % line[1]+':'+self.format % line[-1] + self.simplifiedLines[lineKey] = simpleLine + simpleCoords.extend( simpleLine[0:-1] ) + iFrom = i + if len(simpleCoords) <= 2: + return None + else: + return shapely.geometry.LineString(simpleCoords) + + def simplifyPolygon(self, polygon): + simpleExtRing = self.simplifyRing(polygon.exterior) + if simpleExtRing is None: + return None + simpleIntRings = [] + for ring in polygon.interiors: + simpleIntRing = self.simplifyRing(ring) + if simpleIntRing is not None: + simpleIntRings.append(simpleIntRing) + return shapely.geometry.Polygon(simpleExtRing, simpleIntRings) + + def simplify(self): + results = [] + for geom in self.geometries: + polygons = [] + simplePolygons = [] + + if isinstance(geom, shapely.geometry.Polygon): + polygons.append(geom) + else: + for polygon in geom: + polygons.append(polygon) + + for polygon in polygons: + simplePolygon = self.simplifyPolygon(polygon) + if not (simplePolygon is None or simplePolygon._geom is None): + simplePolygons.append(simplePolygon) + + if len(simplePolygons) > 0: + results.append(shapely.geometry.MultiPolygon(simplePolygons)) + else: + results.append(None) + return results + + +class Processor: + def __init__(self, config): + self.config = config + + def process(self): + self.data_sources = {} + for action in self.config: + getattr(self, action['name'])( action, self.data_sources.get(".") ) + + def read_data(self, config, data_source): + self.data_sources["."] = DataSource( config ) + self.data_sources["."].load_data() + + def write_data(self, config, data_source): + data_source.output( config ) + + def union(self, config, data_source): + groups = {} + geometries = [] + for geometry in data_source.geometries: + if geometry.properties[config['by']] in groups: + groups[geometry.properties[config['by']]]['geoms'].append(geometry.geom) + else: + groups[geometry.properties[config['by']]] = { + 'geoms': [geometry.geom], + 'properties': geometry.properties + } + for key in groups: + geometries.append( Geometry(shapely.ops.cascaded_union( groups[key]['geoms'] ), groups[key]['properties']) ) + data_source.geometries = geometries + + def merge(self, config, data_source): + new_geometries = [] + for rule in config['rules']: + expression = data_source.parse_manager.parse( rule['where'] ) + geometries = filter(lambda g: expression(g.properties), data_source.geometries) + geometries = map(lambda g: g.geom, geometries) + new_geometries.append( Geometry(shapely.ops.cascaded_union( geometries ), rule['fields']) ) + data_source.fields = config['fields'] + data_source.geometries = new_geometries + + def join_data(self, config, data_source): + field_names = [f['name'] for f in config['fields']] + if 'data' in config: + data_col = config['data'] + else: + data_file = open(config['file_name'], 'rb') + data_col = csv.reader(data_file, delimiter='\t', quotechar='"') + data = {} + for row in data_col: + row_dict = dict(zip(field_names, row)) + data[row_dict.pop(config['on'])] = row_dict + for geometry in data_source.geometries: + if geometry.properties[config['on']] in data: + geometry.properties.update( data[geometry.properties[config['on']]] ) + field_names = map(lambda f: f['name'], data_source.fields) + data_source.fields = data_source.fields + filter(lambda f: f['name'] not in field_names, config['fields']) + + def remove(self, config, data_source): + expression = data_source.parse_manager.parse( config['where'] ) + data_source.geometries = filter(lambda g: not expression(g.properties), data_source.geometries) + + def remove_fields(self, config, data_source): + data_source.fields = filter(lambda f: f.name not in config['fields'], data_source.fields) + + def remove_other_fields(self, config, data_source): + data_source.fields = filter(lambda f: f['name'] in config['fields'], data_source.fields) + + def buffer(self, config, data_source): + for geometry in data_source.geometries: + geometry.geom = geometry.geom.buffer(config['distance'], config['resolution']) + + def simplify_adjancent_polygons(self, config, data_source): + simple_geometries = PolygonSimplifier( map( lambda g: g.geom, data_source.geometries ) ).simplify() + for i in range(len(data_source.geometries)): + data_source.geometries[i].geom = simple_geometries[i] + + def intersect_rect(self, config, data_source): + transform = osr.CoordinateTransformation( data_source.layer.GetSpatialRef(), data_source.spatialRef ) + point1 = transform.TransformPoint(config['rect'][0], config['rect'][1]) + point2 = transform.TransformPoint(config['rect'][2], config['rect'][3]) + rect = shapely.geometry.box(point1[0], point1[1], point2[0], point2[1]) + for geometry in data_source.geometries: + geometry.geom = geometry.geom.intersection(rect) + + def remove_small_polygons(self, config, data_source): + for geometry in data_source.geometries: + if isinstance(geometry.geom, shapely.geometry.multipolygon.MultiPolygon): + polygons = geometry.geom.geoms + else: + polygons = [geometry.geom] + polygons = filter(lambda p: p.area > config['minimal_area'], polygons) + if len(polygons) > 0: + geometry.geom = shapely.geometry.multipolygon.MultiPolygon(polygons) + + +args = {} +if len(sys.argv) > 1: + paramsJson = open(sys.argv[1], 'r').read() +else: + paramsJson = sys.stdin.read() +paramsJson = json.loads(paramsJson) + +processor = Processor(paramsJson) +processor.process() diff --git a/public/bower_components/jvectormap/converter/simplifier.py b/public/bower_components/jvectormap/converter/simplifier.py new file mode 100644 index 0000000..18ad9da --- /dev/null +++ b/public/bower_components/jvectormap/converter/simplifier.py @@ -0,0 +1,205 @@ +import argparse +import sys +import os +from osgeo import ogr +from osgeo import osr +import anyjson +import shapely.geometry +import shapely.ops +import codecs +import time + + +format = '%.8f %.8f' +tolerance = 0.01 +infile = '/Users/kirilllebedev/Maps/50m-admin-0-countries/ne_50m_admin_0_countries.shp' +outfile = 'map.shp' + +# Open the datasource to operate on. +in_ds = ogr.Open( infile, update = 0 ) +in_layer = in_ds.GetLayer( 0 ) +in_defn = in_layer.GetLayerDefn() + + +# Create output file with similar information. +shp_driver = ogr.GetDriverByName( 'ESRI Shapefile' ) +if os.path.exists('map.shp'): + shp_driver.DeleteDataSource( outfile ) +shp_ds = shp_driver.CreateDataSource( outfile ) +shp_layer = shp_ds.CreateLayer( in_defn.GetName(), + geom_type = in_defn.GetGeomType(), + srs = in_layer.GetSpatialRef() ) + +in_field_count = in_defn.GetFieldCount() +for fld_index in range(in_field_count): + src_fd = in_defn.GetFieldDefn( fld_index ) + fd = ogr.FieldDefn( src_fd.GetName(), src_fd.GetType() ) + fd.SetWidth( src_fd.GetWidth() ) + fd.SetPrecision( src_fd.GetPrecision() ) + shp_layer.CreateField( fd ) + + +# Load geometries +geometries = [] +for feature in in_layer: + geometry = feature.GetGeometryRef() + geometryType = geometry.GetGeometryType() + + if geometryType == ogr.wkbPolygon or geometryType == ogr.wkbMultiPolygon: + shapelyGeometry = shapely.wkb.loads( geometry.ExportToWkb() ) + #if not shapelyGeometry.is_valid: + #buffer to fix selfcrosses + #shapelyGeometry = shapelyGeometry.buffer(0) + if shapelyGeometry: + geometries.append(shapelyGeometry) +in_layer.ResetReading() + +start = int(round(time.time() * 1000)) +# Simplification +points = [] +connections = {} +counter = 0 +for geom in geometries: + counter += 1 + polygons = [] + + if isinstance(geom, shapely.geometry.Polygon): + polygons.append(geom) + else: + for polygon in geom: + polygons.append(polygon) + + for polygon in polygons: + if polygon.area > 0: + lines = [] + lines.append(polygon.exterior) + for line in polygon.interiors: + lines.append(line) + + for line in lines: + for i in range(len(line.coords)-1): + indexFrom = i + indexTo = i+1 + pointFrom = format % line.coords[indexFrom] + pointTo = format % line.coords[indexTo] + if pointFrom == pointTo: + continue + if not (pointFrom in connections): + connections[pointFrom] = {} + connections[pointFrom][pointTo] = 1 + if not (pointTo in connections): + connections[pointTo] = {} + connections[pointTo][pointFrom] = 1 +print int(round(time.time() * 1000)) - start + +simplifiedLines = {} +pivotPoints = {} +def simplifyRing(ring): + coords = list(ring.coords)[0:-1] + simpleCoords = [] + + isPivot = False + pointIndex = 0 + while not isPivot and pointIndex < len(coords): + pointStr = format % coords[pointIndex] + pointIndex += 1 + isPivot = ((len(connections[pointStr]) > 2) or (pointStr in pivotPoints)) + pointIndex = pointIndex - 1 + + if not isPivot: + simpleRing = shapely.geometry.LineString(coords).simplify(tolerance) + if len(simpleRing.coords) <= 2: + return None + else: + pivotPoints[format % coords[0]] = True + pivotPoints[format % coords[-1]] = True + simpleLineKey = format % coords[0]+':'+format % coords[1]+':'+format % coords[-1] + simplifiedLines[simpleLineKey] = simpleRing.coords + return simpleRing + else: + points = coords[pointIndex:len(coords)] + points.extend(coords[0:pointIndex+1]) + iFrom = 0 + for i in range(1, len(points)): + pointStr = format % points[i] + if ((len(connections[pointStr]) > 2) or (pointStr in pivotPoints)): + line = points[iFrom:i+1] + lineKey = format % line[-1]+':'+format % line[-2]+':'+format % line[0] + if lineKey in simplifiedLines: + simpleLine = simplifiedLines[lineKey] + simpleLine = list(reversed(simpleLine)) + else: + simpleLine = shapely.geometry.LineString(line).simplify(tolerance).coords + lineKey = format % line[0]+':'+format % line[1]+':'+format % line[-1] + simplifiedLines[lineKey] = simpleLine + simpleCoords.extend( simpleLine[0:-1] ) + iFrom = i + if len(simpleCoords) <= 2: + return None + else: + return shapely.geometry.LineString(simpleCoords) + + +def simplifyPolygon(polygon): + simpleExtRing = simplifyRing(polygon.exterior) + if simpleExtRing is None: + return None + simpleIntRings = [] + for ring in polygon.interiors: + simpleIntRing = simplifyRing(ring) + if simpleIntRing is not None: + simpleIntRings.append(simpleIntRing) + return shapely.geometry.Polygon(simpleExtRing, simpleIntRings) + + +results = [] +for geom in geometries: + polygons = [] + simplePolygons = [] + + if isinstance(geom, shapely.geometry.Polygon): + polygons.append(geom) + else: + for polygon in geom: + polygons.append(polygon) + + for polygon in polygons: + simplePolygon = simplifyPolygon(polygon) + if not (simplePolygon is None or simplePolygon._geom is None): + simplePolygons.append(simplePolygon) + + if len(simplePolygons) > 0: + results.append(shapely.geometry.MultiPolygon(simplePolygons)) + else: + results.append(None) + + +# Process all features in input layer. +in_feat = in_layer.GetNextFeature() +counter = 0 +while in_feat is not None: + if results[counter] is not None: + out_feat = ogr.Feature( feature_def = shp_layer.GetLayerDefn() ) + out_feat.SetFrom( in_feat ) + out_feat.SetGeometryDirectly( + ogr.CreateGeometryFromWkb( + shapely.wkb.dumps( + results[counter] + ) + ) + ) + shp_layer.CreateFeature( out_feat ) + out_feat.Destroy() + else: + print 'geometry is too small: '+in_feat.GetField(16) + + in_feat.Destroy() + in_feat = in_layer.GetNextFeature() + counter += 1 + + +# Cleanup +shp_ds.Destroy() +in_ds.Destroy() + +print int(round(time.time() * 1000)) - start
\ No newline at end of file |