def get_label_points(geojson, use_polylabel=True): """ Generate label points for polygon features :param geojson: A GeoJSON feature collection contain Polygons or MultiPolygons :returns: A new GeoJSON Feature collection containing Point features """ if use_polylabel: try: from shapely.algorithms.polylabel import polylabel except: logging.error("Polylabel not available, using centroid for label points") polylabel = None else: logging.error("using centroid for label points, Polylabel disabled") polylabel = None label_features = [] for feature in geojson['features']: if feature['geometry']['type'] not in ['Polygon', 'MultiPolygon']: continue feature_geometry = shape(feature['geometry']) if type(feature_geometry) == MultiPolygon: geometries = feature_geometry.geoms else: geometries = [feature_geometry] for geometry in geometries: if polylabel and geometry.is_valid: #polylabel doesnt work on invalid geometries, centroid does try: project = partial( pyproj.transform, pyproj.Proj(init='epsg:4326'), pyproj.Proj(init='epsg:3857')) geometry_3857 = transform(project, geometry) label_geometry_3857 = polylabel(geometry_3857) project = partial( pyproj.transform, pyproj.Proj(init='epsg:3857'), pyproj.Proj(init='epsg:4326')) label_geometry = transform(project, label_geometry_3857) # apply projection except Exception as e: logger.error("Error getting polylabel point for feature: " + str(feature['properties']), exc_info=e) label_geometry = geometry.centroid else: label_geometry = geometry.centroid if label_geometry: f = { 'type': 'Feature', 'geometry': mapping(label_geometry), 'properties': feature['properties'] } label_features.append(f) return { "type": "FeatureCollection", "features": label_features }
def test_polylabel(self): """ Finds pole of inaccessibility for a polygon with a tolerance of 10 """ polygon = LineString([(0, 0), (50, 200), (100, 100), (20, 50), (-100, -20), (-150, -200)]).buffer(100) label = polylabel(polygon, tolerance=10) expected = Point(59.35615556364569, 121.8391962974644) self.assertTrue(expected.almost_equals(label))
def test_concave_polygon(self): """ Finds pole of inaccessibility for a concave polygon and ensures that the point is inside. """ concave_polygon = LineString([(500, 0), (0, 0), (0, 500), (500, 500)]).buffer(100) label = polylabel(concave_polygon) self.assertTrue(concave_polygon.contains(label))
def test_rectangle_special_case(self): """ The centroid algorithm used is vulnerable to floating point errors and can give unexpected results for rectangular polygons. Test that this special case is handled correctly. https://github.com/mapbox/polylabel/issues/3 """ polygon = Polygon([(32.71997,-117.19310), (32.71997,-117.21065), (32.72408,-117.21065), (32.72408,-117.19310)]) label = polylabel(polygon) self.assertEqual(label.coords[:], [(32.722025, -117.201875)])
def test_rectangle_special_case(self): """ The centroid algorithm used is vulnerable to floating point errors and can give unexpected results for rectangular polygons. Test that this special case is handled correctly. https://github.com/mapbox/polylabel/issues/3 """ polygon = Polygon([(32.71997, -117.19310), (32.71997, -117.21065), (32.72408, -117.21065), (32.72408, -117.19310)]) label = polylabel(polygon) self.assertEqual(label.coords[:], [(32.722025, -117.201875)])
def test_polygon_with_hole(self): """ Finds pole of inaccessibility for a polygon with a hole https://github.com/Toblerity/Shapely/issues/817 """ polygon = Polygon( shell=[(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)], holes=[[(2, 2), (6, 2), (6, 6), (2, 6), (2, 2)]], ) label = polylabel(polygon, 0.05) self.assertAlmostEqual(label.x, 7.65625) self.assertAlmostEqual(label.y, 7.65625)
def get_label_points(geojson): """ Generate label points for polygon features :param geojson: A GeoJSON feature collection contain Polygons or MultiPolygons :returns: A new GeoJSON Feature collection containing Point features """ try: from shapely.algorithms.polylabel import polylabel except: utils.error("Polylabel not available, using centroid for label points") polylabel = None label_features = [] for feature in geojson['features']: if feature['geometry']['type'] not in ['Polygon', 'MultiPolygon']: continue feature_geometry = shape(feature['geometry']) if type(feature_geometry) == MultiPolygon: geometries = feature_geometry.geoms else: geometries = [feature_geometry] for geometry in geometries: if polylabel and geometry.is_valid: #polylabel doesnt work on invalid geometries, centroid does label_geometry = polylabel(geometry) else: label_geometry = geometry.centroid if label_geometry: f = { 'type': 'Feature', 'geometry': mapping(label_geometry), 'properties': feature['properties'] } label_features.append(f) return { "type": "FeatureCollection", "features": label_features }
def poi_polygon(fn_shp, fn_poi_shp, tolerance): ds_shp = ogr.Open(fn_shp) layer = ds_shp.GetLayer(0) proj_wkt = layer.GetSpatialRef().ExportToWkt() feature = layer.GetFeature(0) export = feature.GetGeometryRef().ExportToJson() export_valid = json.loads(export) geom = geometry.shape(export_valid) srs = osr.SpatialReference() srs.ImportFromWkt(proj_wkt) poi = polylabel.polylabel(geom, tolerance) write_poly_to_shp(poi.wkt, fn_poi_shp, srs=srs, layer_type=ogr.wkbPoint, export_wkt=False) ds_shp = None
def load(chip_file): ''' Parameters ---------- chip_file : str Path to chip design file. Returns ------- dict .. versionchanged:: 0.3.0 Read design ID and test routes from ``<dmf:ChipDesign>`` tag. See https://github.com/sci-bots/dmf-chip/issues/1 for more information. ''' info = {'__metadata__': {}} if isinstance(chip_file, six.string_types): with open(chip_file, 'rb') as input_: info['__metadata__']['sha256'] = sha256(input_.read()).hexdigest() else: info['__metadata__']['sha256'] = sha256(chip_file.read()).hexdigest() chip_file.seek(0) root = lxml.etree.parse(chip_file).getroot() NSMAP = {k: v for k, v in root.nsmap.items() if k} # Short-hand to xpath using namespaces referenced in file. _xpath = ft.wraps(root.xpath)(ft.partial(root.xpath, namespaces=NSMAP)) try: inkscape_version = _xpath('/svg:svg/@inkscape:version')[0] semantic_version = sv.Version(re.split('\s+', inkscape_version)[0], partial=True) if semantic_version >= sv.Version('0.92.0'): logger.info('Detected Inkscape 0.92+; using 96 pixels per inch') info['__metadata__']['ppi'] = 96 else: logger.info('Detected Inkscape <0.92; using 90 pixels per inch') info['__metadata__']['ppi'] = 90 except Exception: logger.exception('') if 'ppi' not in info['__metadata__']: logger.info('Using 96 pixels per inch') info['__metadata__']['ppi'] = 96 if all(k in root.attrib for k in ('width', 'height')): ppi = info['__metadata__']['ppi'] * ureg.pixel / ureg.inch shape = { k: ureg.parse_expression(root.attrib[k]) for k in ('width', 'height') } for k, v in shape.items(): if isinstance(v, ureg.Quantity): shape[k] = (v * ppi).to('pixel').magnitude info['__metadata__'].update(shape) # Read design-id from `<dmf:ChipDesign><dmf:DesignID>` tag. ids = _xpath('//dmf:ChipDesign/dmf:DesignId') if ids: info['__metadata__']['design-id'] = ids[0].text # Read test routes. test_route_elements = \ _xpath('//dmf:ChipDesign/dmf:TestRoutes/dmf:TestRoute[@id!=""]') test_routes = [] for route in test_route_elements: xpath_ = ft.wraps(route.xpath)(ft.partial(route.xpath, namespaces=NSMAP)) route_ = dict(route.attrib.items()) route_['waypoints'] = [w.text for w in xpath_('dmf:Waypoint')] test_routes.append(route_) info['__metadata__']['test-routes'] = test_routes # Extract electrode information. device_layer = _xpath('//svg:g[@inkscape:label="Device"]')[0] _device_xpath = ft.partial(device_layer.xpath, namespaces=NSMAP) electrode_elements = _device_xpath('.//svg:path | .//svg:polygon') electrodes = [] for p in electrode_elements: electrode_info = { 'points': shape_points(p), '__tag__': p.tag, '__sourceline__': p.sourceline } if 'data-channels' in p.attrib and p.attrib['data-channels']: electrode_info['channels'] = \ list(map(int, re.split(r'\s*,\s*', p.attrib['data-channels']))) electrode_info.update(p.attrib) electrodes.append(electrode_info) info['electrodes'] = electrodes # Extract electrode connections information. # # Create `Polygon` instances to allow fast collision detection between # end-points of each connection line and electrodes (if any). electrode_polygons = {} for electrode_i in info['electrodes']: try: polygon_i = Polygon(electrode_i['points']) # Compute electrode ["pole of accessibility"][1]; similar to # centroid, but _guaranteed to be within shape_. # # [1]: https://github.com/mapbox/polylabel pole_i = polylabel(polygon_i) electrode_i['pole_of_accessibility'] = { 'x': pole_i.x, 'y': pole_i.y } electrode_polygons[electrode_i['id']] = polygon_i except: logger.exception('Error: `%s`' % electrode_i) def find_shape(x, y): point = Point(x, y) for id_, polygon_i in electrode_polygons.items(): if polygon_i.contains(point): return id_ else: return None connections_layer = _xpath('//svg:g[@inkscape:label="Connections"]')[0] _connections_xpath = ft.partial(connections_layer.xpath, namespaces=NSMAP) connection_elements = _connections_xpath('.//svg:line | .//svg:path') connections = [] for element_i in connection_elements: info_i = dict(element_i.attrib) info_i['__tag__'] = element_i.tag info_i['__sourceline__'] = element_i.sourceline info_i['points'] = shape_points(element_i) for point, name in ((info_i['points'][0], 'source'), (info_i['points'][-1], 'target')): id_ = find_shape(*point) if id_ is None: continue info_i[name] = {'id': id_, 'x': point[0], 'y': point[1]} connections.append(info_i) info['connections'] = connections # Compute electrode areas using vectorized form of [Shoelace formula][1]. # # [1]: http://en.wikipedia.org/wiki/Shoelace_formula electrodes_by_id = {e['id']: e for e in info['electrodes']} df = pd.concat([ pd.DataFrame(e['points'], columns=['x', 'y']) for e in info['electrodes'] ], keys=[e['id'] for e in info['electrodes']]) df.index.names = 'id', 'vertex_i' # "rank" denotes the number of vertices in the respective electrode SVG shape. df['rank'] = df.groupby(level='id')['x'].transform('count').astype(int) area_a = df.x.copy() area_b = df.y.copy() vertex = df.index.get_level_values('vertex_i') area_a[vertex == df['rank'] - 1] *= df.loc[vertex == 0, 'y'].values area_a[vertex < df['rank'] - 1] *= df.loc[vertex > 0, 'y'].values area_b[vertex == df['rank'] - 1] *= df.loc[vertex == 0, 'x'].values area_b[vertex < df['rank'] - 1] *= df.loc[vertex > 0, 'x'].values df['area_a'] = area_a df['area_b'] = area_b area_components = df.groupby(level='id')[['area_a', 'area_b']].sum() shape_areas = .5 * (area_components['area_b'] - area_components['area_a']) for id_i, area_i in six.iteritems(shape_areas): electrodes_by_id[id_i]['area'] = abs(area_i) electrodes_by_id[id_i]['direction'] = ('clockwise' if area_i >= 0 else 'counter-clockwise') return info
with open('response.geo.json', 'w') as outfile: json.dump(data, outfile, indent=4, sort_keys=True) else: with open('response.geo.json') as inputfile: data = json.load(inputfile) for feature in data["features"]: if feature["geometry"]["type"] == "LineString": if len(feature["geometry"]["coordinates"]) == 2: print("Line") line = LineString(feature["geometry"]["coordinates"]) labelpoint = list(line.representative_point().coords)[0] else: poly = Polygon(feature["geometry"]["coordinates"]) labelpoint = list(polylabel(poly).coords)[0] feature["geometry"]["coordinates"] = labelpoint feature["geometry"]["type"] = "Point" searchKeys = list(set(keys).intersection(feature["properties"])) i = 0 searchValue = feature["properties"][searchKeys[i]] while searchValue not in keys[searchKeys[i]]: i += 1 searchValue = feature["properties"][searchKeys[i]] own = keys[searchKeys[i]][searchValue] feature["properties"]["own"] = own with open('additionalPois.json') as inputfile: additional = json.load(inputfile) data["features"] += additional["features"]