Beispiel #1
0
def test_buf_dst_crs(tmpdir):
    outfile = str(tmpdir.mkdir('out').join("buffered.geojson"))
    result = CliRunner().invoke(fio_buffer.core.buffer, [
        'tests/data/points.geojson',
        outfile,
        '--distance', '100',
        '--driver', 'GeoJSON',
        '--buf-crs', 'EPSG:3857',
        '--dst-crs', 'EPSG:900913'
    ])
    assert result.exit_code == 0
    with fio.open('tests/data/points.geojson') as points, fio.open(outfile) as actual:
        for pnt, buf in zip(points, actual):

            # Reproject, buffer, reroject to create an expected geometry
            geom = transform_geom('EPSG:4326', 'EPSG:3857', pnt['geometry'])
            buf_geom = mapping(shape(geom).buffer(100))
            e_coords = transform_geom('EPSG:3857', 'EPSG:900913', buf_geom)['coordinates'][0]

            a_coords = buf['geometry']['coordinates'][0]
            for e_pair, a_pair in zip(e_coords, a_coords):
                # Multipolygons can creep in and mess up the test so just skip them
                if buf['geometry']['type'] == 'Polygon':
                    e_x, e_y = e_pair
                    a_x, a_y = a_pair
                    assert round(e_x, 3) == round(a_x, 3)
                    assert round(e_y, 3) == round(a_y, 3)
Beispiel #2
0
def _processor(args):

    """
    Process a single feature

    Parameters
    ----------
    args : dict
        feat - A GeoJSON feature to process.
        src_crs - The geometry's CRS.
        buf_crs - Apply buffer after reprojecting to this CRS.
        dst_crs - Reproject buffered geometry to this CRS before returning.
        skip_failures - If True then Exceptions don't stop processing.
        buf_args - Keyword arguments for the buffer operation.

    Returns
    -------
    dict
        GeoJSON feature with updated geometry.
    """

    feat = args['feat']
    src_crs = args['src_crs']
    buf_crs = args['buf_crs']
    dst_crs = args['dst_crs']
    skip_failures = args['skip_failures']
    buf_args = args['buf_args']

    try:
        # src_crs -> buf_crs
        reprojected = transform_geom(
            src_crs, buf_crs, feat['geometry'],
            antimeridian_cutting=True
        )

        # buffering operation
        buffered = asShape(reprojected).buffer(**buf_args)

        # buf_crs -> dst_crs
        feat['geometry'] = transform_geom(
            buf_crs, dst_crs, mapping(buffered),
            antimeridian_cutting=True
        )

        return feat

    except Exception:
        log.exception("Feature with ID %s failed" % feat.get('id'))
        if not skip_failures:
            raise
Beispiel #3
0
def bbox_copy(in_file, out_file, bbox, in_layer=0, out_layer=None, dst_crs=None):
    """Dump all features within the provided WGS84 bbox to a new file
    """
    with fiona.drivers():
        with fiona.open(in_file, layer=in_layer) as source:
            output_schema = source.schema.copy()
            # transform the provided bbox to the crs of source data
            bbox_proj = transform_bbox(bbox, from_epsg(4326),
                                       out_crs=source.meta['crs'])
            # use source crs if no reprojection specified
            if dst_crs:
                out_crs = dst_crs
            else:
                out_crs = source.crs
            with fiona.open(out_file, 'w',
                            crs=out_crs, driver="ESRI Shapefile",
                            schema=output_schema) as sink:
                for f in source.filter(bbox=bbox_proj):
                    # transform only if dst_crs specified
                    if dst_crs:
                        g = transform_geom(
                                    source.crs, dst_crs, f['geometry'],
                                    antimeridian_cutting=True)
                        f['geometry'] = g
                    sink.write(f)
def build_mask(raster_path, shp_path, dest_path):
    # Read the GeoTIFF with rasterio
    with rasterio.open(raster_path) as src:
        profile = src.profile
        crs = profile["crs"].to_string()

        # Read the shapefile with fiona
        with fiona.open(shp_path, "r") as shapefile:
            shp_crs = shapefile.crs
            geoms = [
                transform_geom(shapefile.crs, crs, feature["geometry"])
                for feature in shapefile
            ]

        # Mask with the list of geometries; crop to the geoms extent
        dest_image, dest_transform = mask(src, geoms, crop=True)

    # Update the profile
    profile["height"] = dest_image.shape[1]
    profile["width"] = dest_image.shape[2]
    profile["transform"] = dest_transform

    # Write the masked data in the destination raster
    with rasterio.open(dest_path, "w", **profile) as dest:
        dest.write(dest_image)
Beispiel #5
0
def transform_shape_vector(infile):
    """Reads vector AOI bounds and reprojects to EPSG:4326. Returns bounds as shapely polygon.

    Parameters
    ----------
    infile : str
        Path to vector AOI.

    Returns
    -------
    shp : shapely object
        Infile AOI bounds as a shapely polygon object.

    Raises
    -------
    ValueError
        If the input vector file is not a polygon.

    """
    import fiona
    from fiona.transform import transform_geom

    with fiona.open(infile, encoding='utf-8') as c:
        shp_geom = c.schema['geometry']

        if shp_geom != 'Polygon':
            raise ValueError(
                'Shapefile not accepted. Only polygons may be used as input.')

        infile_4326 = transform_geom(c.crs.get("init"), 'epsg:4326',
                                     c[0]['geometry'])
        shp = shape(infile_4326)
        shp = shp.buffer(0.125)

        return shp
def rasterio_get_data(filepath, geojson):
    """
    Returns the data rectangle surrounding the geometry over several channels from a raster.

    :param filepath: the path to the raster file
    :param geojson: the GeoJSON feature
    :return: the extracted data
    :rtype: np.ndarray
    """
    try:
        crs_obj = geojson["properties"]["crs"]
    except KeyError:
        # Default coordinates reference system is WGS84
        crs = "EPSG:4326"
    else:
        crs = CRS.from_user_input(crs_obj["properties"]["name"]).to_string()
    logging.info(f"GeoJSON CRS: {crs}")

    with rasterio.open(filepath) as img:
        img_crs = img.profile["crs"].to_string()
        logging.info(f"Raster CRS: {img_crs}")

        if crs != img_crs:
            geometry = transform_geom(crs, img_crs, geojson["geometry"])
        else:
            geometry = geojson["geometry"]
        logging.info(f"GeoJSON geometry: {geometry}")

        array, _ = rasterio.mask.mask(img,
                                      shapes=[geometry],
                                      crop=True,
                                      filled=False)
        logging.info(f"Array extracted from raster. Shape={array.shape}")

        return array.data
Beispiel #7
0
    def from_shapefile(self, zipped_shapefile_file, id_field=None):
        """ Load ShapeFile content provided into a zipped archive.

        zipped_shapefile_file -- a file-like object on the zipped content
        id_field -- the field name used a identifier
        """
        with fiona.BytesCollection(zipped_shapefile_file.read()) as shape:
            # Extract source projection and compute if reprojection is required
            projection = self._fiona_shape_projection(shape)
            reproject = projection and not self.is_projection_allowed(
                projection.upper())

            for feature in shape:
                properties = {}
                for prop, value in feature.get('properties', {}).items():
                    try:
                        properties[prop] = json.loads(value)
                    except (json.JSONDecodeError, TypeError):
                        properties[prop] = value

                geometry = feature.get('geometry')

                if reproject:
                    geometry = transform_geom(
                        shape.crs,
                        f'EPSG:{app_settings.INTERNAL_GEOMETRY_SRID}',
                        geometry)
                identifier = properties.get(id_field, uuid.uuid4())

                self.features.create(
                    layer=self,
                    identifier=identifier,
                    properties=properties,
                    geom=GEOSGeometry(json.dumps(geometry)),
                )
Beispiel #8
0
def cat(ctx, input, precision, indent, compact, ignore_errors, dst_crs,
        x_json_seq_rs):
    """Concatenate and print the features of input datasets as a
    sequence of GeoJSON features."""
    verbosity = ctx.obj['verbosity']
    logger = logging.getLogger('fio')
    sink = click.get_text_stream('stdout')

    dump_kwds = {'sort_keys': True}
    if indent:
        dump_kwds['indent'] = indent
    if compact:
        dump_kwds['separators'] = (',', ':')
    item_sep = compact and ',' or ', '

    try:
        with fiona.drivers(CPL_DEBUG=verbosity>2):
            for path in input:
                with fiona.open(path) as src:
                    for feat in src:
                        if dst_crs or precision > 0:
                            g = transform_geom(
                                    src.crs, dst_crs, feat['geometry'],
                                    antimeridian_cutting=True,
                                    precision=precision)
                            feat['geometry'] = g
                        if x_json_seq_rs:
                            sink.write(u'\u001e')
                        json.dump(feat, sink, **dump_kwds)
                        sink.write("\n")
        sys.exit(0)
    except Exception:
        logger.exception("Failed. Exception caught")
        sys.exit(1)
Beispiel #9
0
def test_transform_geom_null_dest():
    failed_geom = {
        'type': 'Polygon',
        'coordinates': ((
            (81.2180196471443, 6.197141424988303),
            (80.34835696810447, 5.968369859232141),
            (79.87246870312859, 6.763463446474915),
            (79.69516686393516, 8.200843410673372),
            (80.14780073437967, 9.824077663609557),
            (80.83881798698664, 9.268426825391174),
            (81.3043192890718, 8.564206244333675),
            (81.78795901889143, 7.523055324733178),
            (81.63732221876066, 6.481775214051936),
            (81.2180196471443, 6.197141424988303)
        ),)
    }
    with pytest.warns(UserWarning):
        transformed_geom = transform.transform_geom(
            src_crs="epsg:4326",
            dst_crs="epsg:32628",
            geom=failed_geom,
            antimeridian_cutting=True,
            precision=2,
        )
        assert transformed_geom is None
Beispiel #10
0
def reproject(f, srs_crs, dest_crs):
    f['geometry'] = transform_geom(srs_crs,
                                   dest_crs,
                                   f['geometry'],
                                   antimeridian_cutting=True,
                                   precision=-1)
    return f
Beispiel #11
0
def test_axis_ordering(crs):
    """ Test if transform uses traditional_axis_mapping """

    expected = (-8427998.647958742, 4587905.27136252)
    t1 = transform.transform(crs, "epsg:3857", [-75.71], [38.06])
    assert (t1[0][0], t1[1][0]) == pytest.approx(expected)
    geom = {"type": "Point", "coordinates": [-75.71, 38.06]}
    g1 = transform.transform_geom(crs, "epsg:3857", geom, precision=3)
    assert g1["coordinates"] == pytest.approx(expected)

    rev_expected = (-75.71, 38.06)
    t2 = transform.transform("epsg:3857", crs, [-8427998.647958742], [4587905.27136252])
    assert (t2[0][0], t2[1][0]) == pytest.approx(rev_expected)
    geom = {"type": "Point", "coordinates": [-8427998.647958742, 4587905.27136252]}
    g2 = transform.transform_geom("epsg:3857", crs, geom, precision=3)
    assert g2["coordinates"] == pytest.approx(rev_expected)
def record_converter(record, desired_output, admin_level_info, country_info,
                     available_fields, src_crs):
    name_field = findNameField(record, admin_level_info, available_fields)
    id_field = getIdField(admin_level_info, available_fields)
    feature_name = None
    if name_field != None:
        feature_name = record['properties'][name_field]
        if feature_name.isupper() or feature_name.islower():
            feature_name = feature_name.title()
    else:
        print(
            f"Could not find name field: {country_info['countryIsoAlpha3Code']}, {admin_level_info['localName']}"
        )

    return {
        'geometry':
        transform_geom(src_crs, "EPSG:3832", record['geometry']),
        'properties':
        OrderedDict([
            (f"{desired_output['shortName']}_NAME", feature_name),
            (f"{desired_output['shortName']}_CODE",
             f"{country_info['countryIsoAlpha3Code']}-{int(record['properties'][id_field])}"
             ), ('CNTRY_ISO3', country_info['countryIsoAlpha3Code']),
            ('LC_AD_TYPE', admin_level_info['localName']), ('SRC_DS', 'popgis')
        ])
    }
Beispiel #13
0
def shapefile_generator(filename):
    """
    A generator that iterates over records in a shapefile
    """
    with fiona.open(filename) as collection:
        for item in collection:
            item['geometry'] = transform_geom(collection.meta['crs'],
                                              'epsg:4326', item['geometry'])
            yield item
Beispiel #14
0
def _reproject_geom(geometry, src_crs, dst_crs, validity_check=True):
    if geometry.is_empty or src_crs == dst_crs:
        return geometry.buffer(0)
    out_geom = to_shape(
        transform_geom(src_crs.to_dict(), dst_crs.to_dict(),
                       mapping(geometry))).buffer(0)
    if validity_check and not out_geom.is_valid or out_geom.is_empty:
        raise TopologicalError("invalid geometry after reprojection")
    return out_geom
Beispiel #15
0
 def _reproject_geom(geometry, src_crs, dst_crs):
     if geometry.is_empty or src_crs == dst_crs:
         return _repair(geometry)
     out_geom = _repair(
         to_shape(
             transform_geom(src_crs.to_dict(), dst_crs.to_dict(),
                            mapping(geometry))))
     if validity_check and (not out_geom.is_valid or out_geom.is_empty):
         raise TopologicalError("invalid geometry after reprojection")
     return out_geom
Beispiel #16
0
def __(geom: Dict[str, Any],
       src_srid: int,
       dst_srid: int,
       antimeridian_cutting: bool = False,
       antimeridian_offset: float = 10.0,
       precision: int = -1) -> Dict[str, Any]:
    """
  """
    return transform_geom(f"EPSG:{src_srid}", f"EPSG:{dst_srid}", geom,
                          antimeridian_cutting, antimeridian_offset, precision)
Beispiel #17
0
def test_transform_issue971():
    """ See https://github.com/Toblerity/Fiona/issues/971 """
    source_crs = "epsg:25832"
    dest_src = "epsg:4326"
    geom = {'type': 'GeometryCollection', 'geometries': [{'type': 'LineString',
                                                          'coordinates': [(512381.8870945257, 5866313.311218272),
                                                                          (512371.23869999964, 5866322.282500001),
                                                                          (512364.6014999999, 5866328.260199999)]}]}
    geom_transformed = transform.transform_geom(source_crs, dest_src, geom, precision=3)
    assert geom_transformed['geometries'][0]['coordinates'][0] == pytest.approx((9.184, 52.946))
Beispiel #18
0
def test_transform_geom_array_z(geom):
    """Transforming a geom array with Z succeeds"""
    g2 = transform.transform_geom(
        "epsg:4326",
        "epsg:3857",
        [geom for _ in range(5)],
        precision=3,
    )
    assert isinstance(g2, list)
    assert len(g2) == 5
 def _reproject_geom(geometry, src_crs, dst_crs):
     if geometry.is_empty:
         return geometry
     else:
         out_geom = to_shape(
             transform_geom(src_crs.to_dict(),
                            dst_crs.to_dict(),
                            mapping(geometry),
                            antimeridian_cutting=antimeridian_cutting))
         return _repair(out_geom) if validity_check else out_geom
Beispiel #20
0
def main():
    logging.basicConfig(
        stream=sys.stdout,
        level=logging.INFO,
        format='%(asctime)-15s %(name)s %(levelname)-8s %(message)s')

    parser = argparse.ArgumentParser(
        description='Import regions from shapefile')
    parser.add_argument('filename',
                        type=str,
                        help='Shapefile containing regions')
    args = parser.parse_args()

    session = get_session()

    session.execute("DELETE FROM t1_survey_region")

    with fiona.open(args.filename, encoding='Windows-1252') as shp:
        for index, feature in enumerate(tqdm(shp)):
            props = feature['properties']

            geometry = shape(
                transform_geom(shp.crs, 'EPSG:4326', feature['geometry']))
            geometry = geometry.buffer(0)

            session.execute(
                """INSERT INTO region (id, name, geometry, state, positional_accuracy_in_m)
					VALUES (:id, :name, ST_GeomFromWKB(_BINARY :geometry_wkb), :state, :positional_accuracy_in_m)""",
                {
                    'id': index,
                    'name': props['RegName'],
                    'geometry_wkb': shapely.wkb.dumps(
                        to_multipolygon(geometry)),
                    'state': props['StateName'],
                    'positional_accuracy_in_m': int(props['Accuracy'])
                })

            for geometry in subdivide_geometry(geometry):

                session.execute(
                    """INSERT INTO region_subdiv (id, name, geometry)
					VALUES (:id, :name, ST_GeomFromWKB(_BINARY :geometry_wkb))""", {
                        'id':
                        index,
                        'name':
                        props['RegName'],
                        'geometry_wkb':
                        shapely.wkb.dumps(to_multipolygon(geometry))
                    })

    log.info("Updating t1_survey_region (this may take a while)")
    session.execute("CALL update_t1_survey_region(NULL)")

    session.commit()
Beispiel #21
0
def cat(ctx, files, precision, indent, compact, ignore_errors, dst_crs,
        use_rs, bbox, layer):

    """
    Concatenate and print the features of input datasets as a sequence of
    GeoJSON features.

    When working with a multi-layer dataset the first layer is used by default.
    Use the '--layer' option to select a different layer.
    """

    verbosity = (ctx.obj and ctx.obj['verbosity']) or 2
    logger = logging.getLogger('fio')

    dump_kwds = {'sort_keys': True}
    if indent:
        dump_kwds['indent'] = indent
    if compact:
        dump_kwds['separators'] = (',', ':')

    # Validate file idexes provided in --layer option
    # (can't pass the files to option callback)
    if layer:
        options.validate_multilayer_file_index(files, layer)

    # first layer is the default
    for i in range(1, len(files) + 1):
        if str(i) not in layer.keys():
            layer[str(i)] = [0]
    try:
        with fiona.drivers(CPL_DEBUG=verbosity > 2):
            for i, path in enumerate(files, 1):
                for lyr in layer[str(i)]:
                    with fiona.open(path, layer=lyr) as src:
                        if bbox:
                            try:
                                bbox = tuple(map(float, bbox.split(',')))
                            except ValueError:
                                bbox = json.loads(bbox)
                        for i, feat in src.items(bbox=bbox):
                            if dst_crs or precision >= 0:
                                g = transform_geom(
                                    src.crs, dst_crs, feat['geometry'],
                                    antimeridian_cutting=True,
                                    precision=precision)
                                feat['geometry'] = g
                                feat['bbox'] = fiona.bounds(g)
                            if use_rs:
                                click.echo(u'\u001e', nl=False)
                            click.echo(json.dumps(feat, **dump_kwds))

    except Exception:
        logger.exception("Exception caught during processing")
        raise click.Abort()
Beispiel #22
0
def cat(ctx, files, precision, indent, compact, ignore_errors, dst_crs,
        use_rs, bbox, layer):

    """
    Concatenate and print the features of input datasets as a sequence of
    GeoJSON features.

    When working with a multi-layer dataset the first layer is used by default.
    Use the '--layer' option to select a different layer.
    """

    verbosity = (ctx.obj and ctx.obj['verbosity']) or 2
    logger = logging.getLogger('fio')

    dump_kwds = {'sort_keys': True}
    if indent:
        dump_kwds['indent'] = indent
    if compact:
        dump_kwds['separators'] = (',', ':')
    item_sep = compact and ',' or ', '
    # Validate file idexes provided in --layer option
    # (can't pass the files to option callback)
    if layer:
        options.validate_multilayer_file_index(files, layer)
    # first layer is the default
    for i in range(1, len(files) + 1):
        if str(i) not in layer.keys():
            layer[str(i)] = [0]
    try:
        with fiona.drivers(CPL_DEBUG=verbosity > 2):
            for i, path in enumerate(files, 1):
                for lyr in layer[str(i)]:
                    with fiona.open(path, layer=lyr) as src:
                        if bbox:
                            try:
                                bbox = tuple(map(float, bbox.split(',')))
                            except ValueError:
                                bbox = json.loads(bbox)
                        for i, feat in src.items(bbox=bbox):
                            if dst_crs or precision >= 0:
                                g = transform_geom(
                                        src.crs, dst_crs, feat['geometry'],
                                        antimeridian_cutting=True,
                                        precision=precision)
                                feat['geometry'] = g
                                feat['bbox'] = fiona.bounds(g)
                            if use_rs:
                                click.echo(u'\u001e', nl=False)
                            click.echo(json.dumps(feat, **dump_kwds))

    except Exception:
        logger.exception("Exception caught during processing")
        raise click.Abort()
Beispiel #23
0
    def extract_pixels(self, raster_fn, ranch=None, pasture=None):

        if ranch is not None:
            ranch = ranch.replace(' ', '_')

        if pasture is not None:
            pasture = pasture.replace(' ', '_')

        if pasture is None:
            raise NotImplementedError("Cannot process request")

        ds = rasterio.open(raster_fn)
        ds_proj4 = ds.crs.to_proj4()

        loc_path = self.loc_path
        _d = self._d

        sf_fn = _join(loc_path, _d['sf_fn'])
        sf_feature_properties_key = _d['sf_feature_properties_key']
        sf_fn = os.path.abspath(sf_fn)
        sf = fiona.open(sf_fn, 'r')

        features = []
        for feature in sf:
            properties = feature['properties']
            key = properties[sf_feature_properties_key].replace(' ', '_')

            _pasture, _ranch = key.split(self.key_delimiter)
            if self.reverse_key:
                _ranch, _pasture = _pasture, _ranch

            if ranch is not None:
                if _ranch.lower() != ranch.lower():
                    continue

            _features = transform_geom(sf.crs_wkt, ds_proj4,
                                       feature['geometry'])

            if pasture is None:
                features.append(_features)
            elif _pasture.lower() == pasture.lower():
                features.append(_features)

        data = ds.read(1, masked=True)

        if 'biomass' in raster_fn:
            data = np.ma.masked_values(data, 0)

        pasture_mask, _, _ = raster_geometry_mask(ds, features)

        x = np.ma.MaskedArray(data, mask=pasture_mask)
        return x.compressed().tolist(), int(x.count())
Beispiel #24
0
    def read_records(self, file_name, range_tracker):
        from fiona import BytesCollection
        from fiona.transform import transform_geom
        import json

        total_bytes = self.estimate_size()
        next_pos = range_tracker.start_position()

        def split_points_unclaimed(stop_pos):
            return 0 if stop_pos <= next_pos else iobase.RangeTracker.SPLIT_POINTS_UNKNOWN

        range_tracker.set_split_points_unclaimed_callback(
            split_points_unclaimed)

        with self.open_file(file_name) as f:
            if self.layer_name:
                collection = BytesCollection(f.read(), layer=self.layer_name)
            else:
                collection = BytesCollection(f.read())

            src_crs = _GeoSourceUtils.validate_crs(collection.crs,
                                                   self.in_epsg)

            num_features = len(collection)
            feature_bytes = math.floor(total_bytes / num_features)
            i = 0

            logging.info(
                json.dumps({
                    'msg': 'read_records',
                    'file_name': file_name,
                    'profile': collection.profile,
                    'num_features': num_features,
                    'total_bytes': total_bytes
                }))

            while range_tracker.try_claim(next_pos):
                i = math.ceil(next_pos / feature_bytes)
                if i >= num_features:
                    break

                cur_feature = collection[i]
                geom = cur_feature['geometry']
                props = cur_feature['properties']

                if not self.skip_reproject:
                    geom = transform_geom(src_crs, 'epsg:4326', geom)

                yield (props, geom)

                next_pos = next_pos + feature_bytes
    def process(self, element: bytes):
        import json
        from fiona.transform import transform_geom

        parsed = json.loads(element.decode('utf-8'))
        geom = {"type": "Point", "coordinates": [parsed['x'], parsed['y']]}

        # reproject from the given proj str to 4326, aka WGS 84 used by BQ
        geom = transform_geom(self.in_crs, 'epsg:4326', geom)

        # ready to be inserted into BQ
        record = {**parsed, 'geom': json.dumps(geom)}
        logging.info(record)
        yield record
Beispiel #26
0
def output_poly_to_file(dst_file, polygons, src_crs, dst_crs):
    print('Writing polygon file...')

    with fiona.open(dst_file,
                    'w',
                    crs=dst_crs,
                    driver='ESRI Shapefile',
                    schema={'geometry': 'Polygon',
                            'properties': {'id': 'int'}}) as dst:
        for counter, polygon in enumerate(polygons):
            # reproject if necessary
            new_polygon = transform.transform_geom(src_crs, dst_crs, mapping(polygon))
            new_polygon = shape(new_polygon)

            prop = {'id': counter}
            dst.write({'geometry': mapping(new_polygon), 'properties': prop})
Beispiel #27
0
    def read_records(self, file_name, range_tracker):
        from fiona import transform
        from fiona.io import ZipMemoryFile
        import json

        total_bytes = self.estimate_size()
        next_pos = range_tracker.start_position()

        def split_points_unclaimed(stop_pos):
            return 0 if stop_pos <= next_pos else iobase.RangeTracker.SPLIT_POINTS_UNKNOWN

        with self.open_file(file_name) as f, ZipMemoryFile(f.read()) as mem:
            collection = mem.open(self.gdb_name, layer=self.layer_name)
            src_crs = _GeoSourceUtils.validate_crs(collection.crs,
                                                   self.in_epsg)

            num_features = len(collection)
            feature_bytes = math.floor(total_bytes / num_features)
            i = 0

            # XXX workaround due to https://github.com/Toblerity/Fiona/issues/996
            features = list(collection)

            logging.info(
                json.dumps({
                    'msg': 'read_records',
                    'file_name': file_name,
                    'profile': collection.profile,
                    'num_features': num_features,
                    'total_bytes': total_bytes
                }))

            while range_tracker.try_claim(next_pos):
                i = math.ceil(next_pos / feature_bytes)
                if i >= num_features:
                    break

                cur_feature = features[i]
                geom = cur_feature['geometry']
                props = cur_feature['properties']

                if not self.skip_reproject:
                    geom = transform.transform_geom(src_crs, 'epsg:4326', geom)

                yield (props, geom)

                next_pos = next_pos + feature_bytes
    def __antiMeridianCut(self, geom):
        """
        Solving antimeridian problem.

        """

        src_crs = '+proj=longlat +datum=WGS84 +no_defs'
        dst_crs = '+proj=longlat +datum=WGS84 +no_defs'

        am_offset = 360.0

        line_t = transform_geom(src_crs, dst_crs, geom,
                                antimeridian_cutting=self.__antimeridian,
                                antimeridian_offset=am_offset,
                                precision=-1)

        return line_t
Beispiel #29
0
def debug_dumpPoligons(polygons, inputfn, source_epsg):
    """Créé dans un nouveau dossier du même nom que le SHP d'entrée
       un nouveau SHP résultat de la découpe et autant de GeoJSON
       en EPSG:4326 que d'entitées créés
    """
    schema = {
        'geometry': 'Polygon',
        'properties': {
            'polygoneid': 'int',
        }
    }

    output_dir = './SPLITTED_' + os.path.splitext(inputfn)[0]
    if not os.path.exists(output_dir):
        os.mkdir(output_dir)

    print("Ecriture des fichiers dans", output_dir)

    i = 0
    with fiona.collection(output_dir + '/SPLITTED_' + inputfn, 'w',
                          'ESRI Shapefile', schema) as output:
        for polygon in polygons:
            output.write({
                'properties': {
                    'polygoneid': i
                },
                'geometry': mapping(polygon)
            })
            i += 1

    i = 0
    for polygon in polygons:
        geom_transform = transform_geom(source_epsg, "EPSG:4326",
                                        mapping(polygon))
        with fiona.collection(output_dir + '/' + str(i) + '.geojson', 'w',
                              'GeoJSON', schema) as output:
            output.write({
                'properties': {
                    'polygoneid': i
                },
                'geometry': geom_transform
            })
            i += 1

    print(i, "fichiers GeoJSON créés")
Beispiel #30
0
def record_converter(record, desired_output, admin_level_info, country_info,
                     available_fields, src_crs):
    id = convertGdamId(
        record['properties'][f"GID_{desired_output['levelCode']}"],
        desired_output['levelCode'])
    return {
        'geometry':
        transform_geom(src_crs, "EPSG:3832", record['geometry']),
        'properties':
        OrderedDict([
            (f"{desired_output['shortName']}_NAME",
             record['properties'][f"NAME_{desired_output['levelCode']}"]),
            (f"{desired_output['shortName']}_CODE",
             f"{country_info['countryIsoAlpha3Code']}-{id}"),
            ('CNTRY_ISO3', country_info['countryIsoAlpha3Code']),
            ('LC_AD_TYPE', admin_level_info['localName']), ('SRC_DS', 'GADM')
        ])
    }
Beispiel #31
0
    def __antiMeridianCut(self, geom):
        """
        Solving antimeridian problem.
        """

        src_crs = '+proj=longlat +datum=WGS84 +no_defs'
        dst_crs = '+proj=longlat +datum=WGS84 +no_defs'

        am_offset = 360.0

        line_t = transform_geom(src_crs,
                                dst_crs,
                                geom,
                                antimeridian_cutting=self.__antimeridian,
                                antimeridian_offset=am_offset,
                                precision=-1)

        return line_t
Beispiel #32
0
def output_to_file(dst_file, geoms, src_crs, dst_crs):
    print('Writing point file...')

    with fiona.open(dst_file,
                    'w',
                    crs=dst_crs,
                    driver='ESRI Shapefile',
                    schema={'geometry': 'Point',
                            'properties': {'POINT_NUM': 'int',
                                           'X': 'float',
                                           'Y': 'float'}}) as dst:
        for counter, point in enumerate(geoms):
            # reproject if necessary
            new_point = shape(transform.transform_geom(src_crs, dst_crs, mapping(point)))

            prop = {'POINT_NUM': counter + 1,
                    'X': new_point.x,
                    'Y': new_point.y}
            dst.write({'geometry': mapping(new_point), 'properties': prop})
Beispiel #33
0
    def get_pasture_indx(self, raster_fn, pasture, ranch):

        if ranch is not None:
            ranch = ranch.replace(' ', '_')

        if pasture is not None:
            pasture = pasture.replace(' ', '_')

        ds = rasterio.open(raster_fn)
        ds_proj4 = ds.crs.to_proj4()

        target_ranch = ranch.replace(' ', '_').lower().strip()
        target_pasture = pasture.replace(' ', '_').lower().strip()

        loc_path = self.loc_path
        _d = self._d

        sf_fn = _join(loc_path, _d['sf_fn'])
        sf_feature_properties_key = _d['sf_feature_properties_key']
        sf_fn = os.path.abspath(sf_fn)
        sf = fiona.open(sf_fn, 'r')

        features = []
        for feature in sf:
            properties = feature['properties']
            _key = properties[sf_feature_properties_key].replace(' ', '_')

            _pasture, _ranch = _key.split(self.key_delimiter)
            if self.reverse_key:
                _ranch, _pasture = _pasture, _ranch

            if _ranch.lower() == target_ranch and _pasture.lower(
            ) == target_pasture:
                _features = transform_geom(sf.crs_wkt, ds_proj4,
                                           feature['geometry'])
                features.append(_features)

        if len(features) == 0:
            raise KeyError((ranch, pasture))

        pasture_mask, _, _ = raster_geometry_mask(ds, features)
        indx = np.where(pasture_mask == False)
        return indx
Beispiel #34
0
    def extract_pixels_by_pasture(self, raster_fn, ranch=None):

        if ranch is not None:
            ranch = ranch.replace(' ', '_')

        ds = rasterio.open(raster_fn)
        ds_proj4 = ds.crs.to_proj4()

        loc_path = self.loc_path
        _d = self._d

        sf_fn = _join(loc_path, _d['sf_fn'])
        sf_feature_properties_key = _d['sf_feature_properties_key']
        sf_fn = os.path.abspath(sf_fn)
        sf = fiona.open(sf_fn, 'r')

        data = ds.read(1, masked=True)

        #        if 'biomass' in raster_fn:
        #            data = np.ma.masked_values(data, 0)

        _data = {}
        for feature in sf:
            properties = feature['properties']
            key = properties[sf_feature_properties_key].replace(' ', '_')

            _pasture, _ranch = key.split(self.key_delimiter)
            if self.reverse_key:
                _ranch, _pasture = _pasture, _ranch

            if ranch is not None:
                if _ranch.lower() != ranch.lower():
                    continue

            _features = transform_geom(sf.crs_wkt, ds_proj4,
                                       feature['geometry'])
            pasture_mask, _, _ = raster_geometry_mask(ds, [_features])

            x = np.ma.MaskedArray(data, mask=pasture_mask)
            _data[(_ranch, _pasture)] = x.compressed().tolist(), int(x.count())

        return _data
Beispiel #35
0
def transform_vector(shapefile, crs):
    """Reads vector AOI bounds and reprojects to desired crs. Returns bounds as shapely polygon.

    Parameters
    ----------
    shapefile : Path
        Path to vector AOI.
    crs : rasterio CRS string
        CRS to transform to.

    Returns
    -------
    shp : shapely object
        Infile AOI bounds as a shapely polygon object.

    Raises
    -------
    ValueError
        If the input shapefile contains more than one geometry.
    ValueError
        If the input file is not of an accepted file format.

    """

    vector_exts = ['.shp', '.geojson', '.json']
    ext = pathlib.Path(shapefile).suffix

    if ext not in vector_exts:
        raise ValueError(f'File not accepted. Acceptable vector formats are {vector_exts}')

    with fiona.open(shapefile) as c:
        if len(c) > 1:
            raise ValueError('File contains multiple features. '
                             'Only single feature files may be used as input.')

        transformed = transform_geom(c.crs.get("init"), str(crs), c[0]['geometry'])

    shp = shape(transformed)
    geom = [mapping(shp)]

    return geom
def main(infile, outfile):

    """
    Reproject a layer to web mercator.
    """

    # Cache stuff we need later
    bbox = Polygon([[-180, -85], [-180, 85], [180, 85], [180, -85]])
    with fio.open(infile) as src:
        meta = src.meta.copy()
        meta['crs'] = 'EPSG:3857'
        meta['driver'] = 'GeoJSON'

    with fio.open(infile) as src, fio.open(outfile, 'w', **meta) as dst, click.progressbar(src) as features:

        for feat in features:

            geom = shape(feat['geometry'].copy()).intersection(bbox)

            feat['geometry'] = transform_geom(src.crs, dst.crs, mapping(geom))
            dst.write(feat)
Beispiel #37
0
def cat(ctx, files, precision, indent, compact, ignore_errors, dst_crs,
        use_rs, bbox):
    """Concatenate and print the features of input datasets as a
    sequence of GeoJSON features."""
    verbosity = (ctx.obj and ctx.obj['verbosity']) or 2
    logger = logging.getLogger('fio')

    dump_kwds = {'sort_keys': True}
    if indent:
        dump_kwds['indent'] = indent
    if compact:
        dump_kwds['separators'] = (',', ':')
    item_sep = compact and ',' or ', '

    try:
        with fiona.drivers(CPL_DEBUG=verbosity > 2):
            for path in files:
                with fiona.open(path) as src:
                    if bbox:
                        try:
                            bbox = tuple(map(float, bbox.split(',')))
                        except ValueError:
                            bbox = json.loads(bbox)
                    for i, feat in src.items(bbox=bbox):
                        if dst_crs or precision > 0:
                            g = transform_geom(
                                    src.crs, dst_crs, feat['geometry'],
                                    antimeridian_cutting=True,
                                    precision=precision)
                            feat['geometry'] = g
                            feat['bbox'] = fiona.bounds(g)
                        if use_rs:
                            click.echo(u'\u001e', nl=False)
                        click.echo(json.dumps(feat, **dump_kwds))

    except Exception:
        logger.exception("Exception caught during processing")
        raise click.Abort()
def _processor(args):

    """
    Reproject a single feature's geometry.

    Parameters
    ----------
    args : dict
        feat : dict
            A GeoJSON feature to process.
        src_crs : str
            The geometry's CRS.
        dst_crs : str
            Reproject buffered geometry to this CRS before returning.
        skip_failures : bool
            If True then Exceptions don't stop processing.

    Returns
    -------
    dict
        GeoJSON feature with updated geometry.
    """

    feat = args['feat']
    src_crs = args['src_crs']
    dst_crs = args['dst_crs']
    skip_failures = args['skip_failures']

    try:
        feat['geometry'] = transform_geom(src_crs, dst_crs, feat['geometry'])
        return feat

    except Exception:
        log.exception("Feature with ID %s failed" % feat.get('id'))
        if not skip_failures:
            raise
Beispiel #39
0
def test_transform_geom_with_z(geom):
    """Transforming a geom with Z succeeds"""
    g2 = transform.transform_geom("epsg:4326", "epsg:3857", geom, precision=3)
Beispiel #40
0
def rasterise_vector(vector_filename, shape=None, transform=None, crs=None,
                     raster_filename=None, dtype='uint32'):
    """
    Given a full file pathname to a vector file, rasterise the
    vectors geometry by either provding the raster shape and
    transform, or a raster file on disk.

    :param vector_filename:
        A full file pathname to an OGR compliant vector file.

    :param shape:
        Optional. If provided, then shape is a tuple containing the
        (height, width) of an array. If omitted, then `shape` will
        be retrieved via the raster provided in `raster_filename`.

    :param transform:
        Optional. If provided, then an `Affine` containing the
        transformation matrix parameters. If omitted, then `transform`
        will be retrieved via the `raster_filename`.

    :param crs:
        Optional. If provided, then WKT should be provided. If
        omitted, then `crs` will be retreived via the
        `raster_filename`.

    :param raster_filename:
        A full file pathname to a GDAL compliant raster file.

    :return:
        A `NumPy` array of the same dimensions provided by either the
        `shape` or `raster_filename`.

    :notes:
        The vector file will be re-projected as required in order
        to match the same crs as provided by `crs` or by
        `raster_filename`.
    """
    with fiona.open(vector_filename, 'r') as v_src:
        if raster_filename is not None:
            with rasterio.open(raster_filename, 'r') as r_src:
                transform = r_src.affine
                shape = r_src.shape
                crs = r_src.crs
                r_bounds = tuple(r_src.bounds)
        else:
            ul = (0, 0) * transform
            lr = (shape[1], shape[0]) * transform
            min_x, max_x = min(ul[0], lr[0]), max(ul[0], lr[0])
            min_y, max_y = min(ul[1], lr[1]), max(ul[1], lr[1])
            r_bounds = (min_x, min_y, max_x, max_y)

            # convert the crs_wkt to a dict styled proj4
            sr = osr.SpatialReference()
            sr.ImportFromWkt(crs)
            if CRS_CLASS:
                crs = CRS.from_string(sr.ExportToProj4())
            else:
                crs = from_string(sr.ExportToProj4())

        # rasterio has a CRS class that makes for easier crs comparison
        if CRS_CLASS:
            v_crs = CRS(v_src.crs)
            same_crs = v_crs == crs
            # fiona may update to the class crs in future, but for now...
            crs = crs.to_dict()
        else:
            same_crs = is_same_crs(v_src.crs, crs)

        # use rtree where possible for speedy shape reduction
        if RTREE:
            shapes = {}
            index = rtree.index.Index()

            # get crs, check if the same as the image and project as needed
            if not same_crs:
                for feat in v_src:
                    new_geom = transform_geom(v_src.crs, crs, feat['geometry'])
                    fid = int(feat['id'])
                    shapes[fid] = (new_geom, fid + 1)
                    index.insert(fid, shp(new_geom).bounds)
            else:
                for feat in v_src:
                    fid = int(feat['id'])
                    shapes[fid] = (feat['geometry'], fid + 1)
                    index.insert(fid, shp(feat['geometry']).bounds)

            # we check the bounding box of each geometry object against
            # the image bounding box. Basic pre-selection to filter which
            # vectors are to be rasterised
            # bounding box intersection
            fids = index.intersection(r_bounds)
            selected_shapes = [shapes[fid] for fid in fids]
        else:
            selected_shapes = []
            r_poly = box(*r_bounds)
            if not same_crs:
                for feat in v_src:
                    new_geom = transform_geom(v_src.crs, crs, feat['geometry'])
                    fid = int(feat['id'])
                    geom = shp(new_geom)
                    if geom.intersects(r_poly):
                        selected_shapes.append((new_geom, fid + 1))
            else:
                for feat in v_src:
                    fid = int(feat['id'])
                    geom = shp(feat['geometry'])
                    if geom.intersects(r_poly):
                        selected_shapes.append((feat['geometry'], fid + 1))


    rasterised = rasterize(selected_shapes, out_shape=shape, fill=0,
                           transform=transform, dtype=dtype)

    return rasterised
from shapely import speedups

speedups.enable()

with fiona.open("data/chko.shp", "r") as pas:
    with fiona.open("data/highways.geojson", "r") as hws:

        buffered_highways = []

        wgs84 = "EPSG:4326"
        jtsk = pas.crs

        d8 = list(filter(lambda hw: hw["properties"]["ref"] == "D8", hws))

        for hw in d8:
            geom_transformed = transform_geom(wgs84, jtsk, hw["geometry"])

            g = shape(geom_transformed)
            buffered_highways.append(g.buffer(100))

        intersections = []

        for hw in buffered_highways:

            for pa in pas:

                pa_geom = shape(pa["geometry"])
                if hw.intersects(pa_geom):
                    out_geom = hw.intersection(pa_geom)
                    intersections.append(out_geom)
Beispiel #42
0
def _processor(args):

    """
    Process a single feature.

    Parameters
    ----------
    args : dict
        feat : dict
            A GeoJSON feature to process.
        src_crs : str or dict
            The geometry's CRS.
        buf_crs : str or dict
            Apply buffer after reprojecting to this CRS.
        dst_crs : str or dict
            Reproject buffered geometry to this CRS before returning.
        skip_failures : bool
            If True then Exceptions don't stop processing.
        buf_args : dict
            Keyword arguments for the buffer operation.

    Returns
    -------
    dict
        GeoJSON feature with updated geometry.
    """

    feat = args['feat']
    src_crs = args['src_crs']
    buf_crs = args['buf_crs']
    dst_crs = args['dst_crs']
    skip_failures = args['skip_failures']
    buf_args = args['buf_args']

    # Support buffering by a field's value
    if not isinstance(buf_args['distance'], (float, int)):
        field_val = feat['properties'][buf_args['distance']]

        # Buffering according to a field but field is None so just return the feature
        if field_val is None:
            return feat
        else:
            buf_args['distance'] = field_val

    try:
        # src_crs -> buf_crs
        reprojected = transform_geom(
            src_crs, buf_crs, feat['geometry'],
            antimeridian_cutting=True
        )

        # buffering operation
        buffered = shape(reprojected).buffer(**buf_args)

        # buf_crs -> dst_crs
        feat['geometry'] = transform_geom(
            buf_crs, dst_crs, mapping(buffered),
            antimeridian_cutting=True
        )

        return feat

    except Exception:
        logger.exception("Feature with ID %s failed during buffering", feat.get('id'))
        if not skip_failures:
            raise