Example #1
0
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
    }
Example #2
0
    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))
Example #3
0
    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))
Example #4
0
    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))
Example #5
0
    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))
Example #6
0
 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)])
Example #7
0
 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)])
Example #8
0
 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)
Example #9
0
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
    }
Example #10
0
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
Example #11
0
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
Example #12
0
    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"]