예제 #1
0
    def test_point_snapping_break_ties(self):
        """DelineateIt: distance ties are broken using flow accumulation."""
        from natcap.invest.delineateit import delineateit

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(32731)  # WGS84/UTM zone 31s
        wkt = srs.ExportToWkt()

        # need stream layer, points
        stream_matrix = numpy.array(
            [[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0]],
            dtype=numpy.int8)
        stream_raster_path = os.path.join(self.workspace_dir, 'streams.tif')
        flow_accum_array = numpy.array(
            [[1, 5, 1, 1, 1, 1], [1, 5, 1, 1, 1, 1], [1, 5, 1, 1, 1, 1],
             [1, 5, 1, 1, 1, 1], [1, 5, 9, 9, 9, 9], [1, 4, 1, 1, 1, 1],
             [1, 4, 1, 1, 1, 1]],
            dtype=numpy.int8)
        flow_accum_path = os.path.join(self.workspace_dir, 'flow_accum.tif')
        pygeoprocessing.numpy_array_to_raster(stream_matrix, 255, (2, -2),
                                              (2, -2), wkt, stream_raster_path)
        pygeoprocessing.numpy_array_to_raster(flow_accum_array, -1, (2, -2),
                                              (2, -2), wkt, flow_accum_path)

        source_points_path = os.path.join(self.workspace_dir,
                                          'source_features.geojson')
        source_features = [Point(9, -7)]  # equidistant from two streams
        pygeoprocessing.shapely_geometry_to_vector(
            source_features,
            source_points_path,
            wkt,
            'GeoJSON',
            ogr_geom_type=ogr.wkbUnknown)

        snapped_points_path = os.path.join(self.workspace_dir,
                                           'snapped_points.gpkg')

        snap_distance = 10  # large enough to get multiple streams per point.
        delineateit.snap_points_to_nearest_stream(source_points_path,
                                                  stream_raster_path,
                                                  flow_accum_path,
                                                  snap_distance,
                                                  snapped_points_path)

        snapped_points_vector = gdal.OpenEx(snapped_points_path,
                                            gdal.OF_VECTOR)
        snapped_points_layer = snapped_points_vector.GetLayer()

        # should snap to stream point [4, 3] in the array above
        # if not considering flow accumulation, it would snap to the
        # nearest stream point found first in the array, at [2, 1]
        points = [
            shapely.wkb.loads(bytes(feature.GetGeometryRef().ExportToWkb()))
            for feature in snapped_points_layer
        ]
        self.assertEqual(len(points), 1)
        self.assertEqual((points[0].x, points[0].y), (9, -11))
예제 #2
0
    def test_point_snapping_multipoint(self):
        """DelineateIt: test multi-point snapping."""
        from natcap.invest.delineateit import delineateit

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(32731)  # WGS84/UTM zone 31s
        wkt = srs.ExportToWkt()

        # need stream layer, points
        stream_matrix = numpy.array(
            [[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0]],
            dtype=numpy.int8)
        stream_raster_path = os.path.join(self.workspace_dir, 'streams.tif')
        # byte datatype
        pygeoprocessing.numpy_array_to_raster(stream_matrix, 255, (2, -2),
                                              (2, -2), wkt, stream_raster_path)

        source_points_path = os.path.join(self.workspace_dir,
                                          'source_features.gpkg')
        gpkg_driver = gdal.GetDriverByName('GPKG')
        points_vector = gpkg_driver.Create(source_points_path, 0, 0, 0,
                                           gdal.GDT_Unknown)
        layer_name = os.path.splitext(os.path.basename(source_points_path))[0]
        points_layer = points_vector.CreateLayer(layer_name,
                                                 points_vector.GetSpatialRef(),
                                                 ogr.wkbUnknown)
        # Create a bunch of points for the various OGR multipoint types and
        # make sure that they are all snapped to exactly the same place.
        points_layer.StartTransaction()
        for multipoint_type in (ogr.wkbMultiPoint, ogr.wkbMultiPointM,
                                ogr.wkbMultiPointZM, ogr.wkbMultiPoint25D):
            new_feature = ogr.Feature(points_layer.GetLayerDefn())
            new_geom = ogr.Geometry(multipoint_type)
            component_point = ogr.Geometry(ogr.wkbPoint)
            component_point.AddPoint(3, -5)
            new_geom.AddGeometry(component_point)
            new_feature.SetGeometry(new_geom)
            points_layer.CreateFeature(new_feature)

        # Verify point snapping will run if we give it empty multipoints.
        for point_type in (ogr.wkbPoint, ogr.wkbMultiPoint):
            new_feature = ogr.Feature(points_layer.GetLayerDefn())
            new_geom = ogr.Geometry(point_type)
            new_feature.SetGeometry(new_geom)
            points_layer.CreateFeature(new_feature)

        points_layer.CommitTransaction()

        snapped_points_path = os.path.join(self.workspace_dir,
                                           'snapped_points.gpkg')
        snap_distance = 10  # large enough to get multiple streams per point.
        delineateit.snap_points_to_nearest_stream(source_points_path,
                                                  (stream_raster_path, 1),
                                                  snap_distance,
                                                  snapped_points_path)

        try:
            snapped_points_vector = gdal.OpenEx(snapped_points_path,
                                                gdal.OF_VECTOR)
            snapped_points_layer = snapped_points_vector.GetLayer()

            # All 4 multipoints should have been snapped to the same place and
            # should all be Point geometries.
            self.assertEqual(4, snapped_points_layer.GetFeatureCount())
            expected_feature = shapely.geometry.Point(5, -5)
            for feature in snapped_points_layer:
                shapely_feature = shapely.wkb.loads(
                    bytes(feature.GetGeometryRef().ExportToWkb()))
                self.assertTrue(shapely_feature.equals(expected_feature))
        finally:
            snapped_points_layer = None
            snapped_points_vector = None
예제 #3
0
    def test_point_snapping(self):
        """DelineateIt: test point snapping."""
        from natcap.invest.delineateit import delineateit

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(32731)  # WGS84/UTM zone 31s
        wkt = srs.ExportToWkt()

        # need stream layer, points
        stream_matrix = numpy.array(
            [[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0]],
            dtype=numpy.int8)
        stream_raster_path = os.path.join(self.workspace_dir, 'streams.tif')
        # byte datatype
        pygeoprocessing.numpy_array_to_raster(stream_matrix, 255, (2, -2),
                                              (2, -2), wkt, stream_raster_path)

        source_points_path = os.path.join(self.workspace_dir,
                                          'source_features.geojson')
        source_features = [
            Point(-1, -1),  # off the edge of the stream raster.
            Point(3, -5),
            Point(7, -9),
            Point(13, -5),
            MultiPoint([(13, -5)]),
            box(-2, -2, -1, -1),  # Off the edge
        ]
        fields = {'foo': ogr.OFTInteger, 'bar': ogr.OFTString}
        attributes = [
            {
                'foo': 0,
                'bar': '0.1'
            },
            {
                'foo': 1,
                'bar': '1.1'
            },
            {
                'foo': 2,
                'bar': '2.1'
            },
            {
                'foo': 3,
                'bar': '3.1'
            },
            {
                'foo': 3,
                'bar': '3.1'
            },  # intentional duplicate fields
            {
                'foo': 4,
                'bar': '4.1'
            }
        ]
        pygeoprocessing.shapely_geometry_to_vector(
            source_features,
            source_points_path,
            wkt,
            'GeoJSON',
            fields=fields,
            attribute_list=attributes,
            ogr_geom_type=ogr.wkbUnknown)

        snapped_points_path = os.path.join(self.workspace_dir,
                                           'snapped_points.gpkg')

        snap_distance = -1
        with self.assertRaises(ValueError) as cm:
            delineateit.snap_points_to_nearest_stream(source_points_path,
                                                      (stream_raster_path, 1),
                                                      snap_distance,
                                                      snapped_points_path)
        self.assertTrue('must be >= 0' in str(cm.exception))

        snap_distance = 10  # large enough to get multiple streams per point.
        delineateit.snap_points_to_nearest_stream(source_points_path,
                                                  (stream_raster_path, 1),
                                                  snap_distance,
                                                  snapped_points_path)

        snapped_points_vector = gdal.OpenEx(snapped_points_path,
                                            gdal.OF_VECTOR)
        snapped_points_layer = snapped_points_vector.GetLayer()

        # snapped layer will include 4 valid points and 1 polygon.
        self.assertEqual(5, snapped_points_layer.GetFeatureCount())

        expected_geometries_and_fields = [
            (Point(5, -5), {
                'foo': 1,
                'bar': '1.1'
            }),
            (Point(5, -9), {
                'foo': 2,
                'bar': '2.1'
            }),
            (Point(13, -11), {
                'foo': 3,
                'bar': '3.1'
            }),
            (Point(13, -11), {
                'foo': 3,
                'bar': '3.1'
            }),  # Multipoint now point
            (box(-2, -2, -1, -1), {
                'foo': 4,
                'bar': '4.1'
            }),  # unchanged
        ]
        for feature, (expected_geom,
                      expected_fields) in zip(snapped_points_layer,
                                              expected_geometries_and_fields):
            shapely_feature = shapely.wkb.loads(
                bytes(feature.GetGeometryRef().ExportToWkb()))

            self.assertTrue(shapely_feature.equals(expected_geom))
            self.assertEqual(expected_fields, feature.items())