Пример #1
0
def _combine_envelopes(geometries, use_bb=True, use_distance=False):
    """Inner support function for combine_envelopes."""
    import ambry.geo as dg
    reductions = 0
    new_geometries = []

    accum = None
    reduced = set()

    for i1 in range(len(geometries)):
        if i1 in reduced:
            continue
        g1 = geometries[i1]
        for i2 in range(i1 + 1, len(geometries)):
            if i2 in reduced:
                continue

            g2 = geometries[i2]

            intersects = False

            if (g1.Intersects(g2) or g1.Contains(g2) or g2.Contains(g1)
                    or g1.Touches(g2)):
                intersects = True

            # If the final output is to onvert the reduced geometries to bounding boxes, it
            # can have BBs that intersect that were not reduced, because the underlying geometries
            # didn't intersect
            if use_bb and not intersects:
                bb1 = dg.create_bb(g1.GetEnvelope(), g1.GetSpatialReference())
                bb2 = dg.create_bb(g2.GetEnvelope(), g2.GetSpatialReference())
                if bb1.Intersects(bb2):
                    intersects = True

            if use_distance and not intersects:
                if use_bb:
                    if bb1.Distance(bb2) < use_distance:
                        intersects = True
                else:
                    if g1.Distance(g2) < use_distance:
                        intersects = True

            if intersects:
                reductions += 1
                reduced.add(i2)
                if not accum:
                    accum = g1.Union(g2)
                else:
                    accum = accum.Union(g2)

        if accum is not None:
            new_geometries.append(accum.Clone())
            accum = None
        else:
            new_geometries.append(g1.Clone())

    return reductions, new_geometries
Пример #2
0
def _combine_envelopes(geometries, use_bb = True, use_distance=False):
    """Inner support function for combine_envelopes"""
    import ambry.geo as dg
    reductions = 0
    new_geometries = []
    
    accum = None
    reduced = set()

    for i1 in range(len(geometries)):
        if i1 in reduced:
            continue
        g1 = geometries[i1]
        for i2 in range(i1+1, len(geometries)):
            if i2 in reduced:
                continue

            g2 = geometries[i2]


            intersects = False
            
            if (g1.Intersects(g2) or  g1.Contains(g2) or g2.Contains(g1) or g1.Touches(g2)):
                intersects = True
      
            # If the final output is to onvert the reduced geometries to bounding boxes, it
            # can have BBs that intersect that were not reduced, because the underlying geometries
            # didn't intersect
            if use_bb and not intersects:
                bb1 =  dg.create_bb(g1.GetEnvelope(), g1.GetSpatialReference())
                bb2 =  dg.create_bb(g2.GetEnvelope(), g2.GetSpatialReference())
                if bb1.Intersects(bb2):  
                    intersects = True
                    
            if use_distance and not intersects:
                if use_bb:
                    if bb1.Distance(bb2) < use_distance:
                        intersects = True                        
                else:
                    if g1.Distance(g2) < use_distance:
                        intersects = True         

            if intersects:
                reductions += 1
                reduced.add(i2)
                if not accum:
                    accum = g1.Union(g2)
                else:
                    accum = accum.Union(g2)
        
        if accum is not None:
            new_geometries.append(accum.Clone())
            accum = None
        else:
            new_geometries.append(g1.Clone())

    return reductions, new_geometries
Пример #3
0
def bound_clusters_in_raster(a,
                             aa,
                             shape_file_dir,
                             contour_interval,
                             contour_value,
                             use_bb=True,
                             use_distance=False):
    """Create a shapefile that contains contours and bounding boxes for
    clusters of contours.

    :param a: A numpy array that contains the data inwhich to find clusters
    :type a: Numpy array

    :param aa: The analysis object that sets the coordinate system for the area that contains the array
    :type aa: ambry.geo.AnalysisArea

    :param shape_file_dir: The path to a directory where generated files will be stored.
    :type shape_file_dir: string

    :param contour_interval: The difference between successive contour intervals.
    :type contour_interval: float

    :param contour_value:
    :type contour_value: float

    :param use_bb: If True, compute nearness and intersection using the contours bounding boxes, not the geometry
    :type use_bb: bool

    :param use_distance: If not False, consider contours that are closer than this value to be overlapping.
    :type : number

    :rtype: Returns a list of dictionaries, one for each of the combined bounding boxes

    This method will store, in the `shape_file_dir` directory:

    * a GeoTIFF representation of the array `a`
    * An ERSI shapefile layer  named `countours`, holding all of the countours.
    * A layer named `contour_bounds` with the bounding boxes for all of the contours with value `contour_value`
    * A layer named `combined_bounds` with bounding boxes of intersecting and nearby boxes rom `contour_bounds`

    The routine will iteratively combine contours that overlap.

    If `use_distance` is set to a number, and contours that are closer than this value will be joined.

    If `use_bb` is set, the intersection and distance computations use the bounding boxes of the contours,
    not the contours themselves.

    """

    import ambry.geo as dg
    from osgeo.gdalconst import GDT_Float32
    import ambry.util as util

    from osgeo import gdal
    import ogr
    import os
    import numpy as np

    if os.path.exists(shape_file_dir):
        util.rm_rf(shape_file_dir)
        os.makedirs(shape_file_dir)

    rasterf = os.path.join(shape_file_dir, 'contour.tiff')

    ogr_ds = ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(
        shape_file_dir)

    # Setup the countour layer.
    ogr_lyr = ogr_ds.CreateLayer('contours', aa.srs)
    ogr_lyr.CreateField(ogr.FieldDefn('id', ogr.OFTInteger))
    ogr_lyr.CreateField(ogr.FieldDefn('value', ogr.OFTReal))

    # Create the contours from the GeoTIFF file.
    ds = aa.get_geotiff(rasterf, data_type=GDT_Float32)
    ds.GetRasterBand(1).SetNoDataValue(0)
    ds.GetRasterBand(1).WriteArray(np.flipud(a))

    gdal.ContourGenerate(
        ds.GetRasterBand(1),
        contour_interval,  # contourInterval
        0,  # contourBase
        [],  # fixedLevelCount
        0,  # useNoData
        0,  # noDataValue
        ogr_lyr,  # destination layer
        0,  # idField
        1  # elevation field
    )

    # Get buffered bounding boxes around each of the hotspots,
    # and put them into a new layer.

    bound_lyr = ogr_ds.CreateLayer('contour_bounds', aa.srs)
    for i in range(ogr_lyr.GetFeatureCount()):
        f1 = ogr_lyr.GetFeature(i)
        if f1.GetFieldAsDouble('value') != contour_value:
            continue
        g1 = f1.GetGeometryRef()
        bb = dg.create_bb(g1.GetEnvelope(), g1.GetSpatialReference())
        f = ogr.Feature(bound_lyr.GetLayerDefn())
        f.SetGeometry(bb)
        bound_lyr.CreateFeature(f)

    # Doing a full loop instead of a list comprehension b/c the way that comprehensions
    # compose arrays results in segfaults, probably because a copied geometry
    # object is being released before being used.
    geos = []
    for i in range(bound_lyr.GetFeatureCount()):
        f = bound_lyr.GetFeature(i)
        g = f.geometry()
        geos.append(g.Clone())

    # Combine hot spots that have intersecting bounding boxes, to get larger
    # areas that cover all of the adjacent intersecting smaller areas.
    geos = dg.combine_envelopes(geos, use_bb=use_bb, use_distance=use_distance)

    # Write out the combined bounds areas.
    lyr = ogr_ds.CreateLayer('combined_bounds', aa.srs)
    lyr.CreateField(ogr.FieldDefn('id', ogr.OFTInteger))
    lyr.CreateField(ogr.FieldDefn('area', ogr.OFTReal))
    lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString))
    lyr.CreateField(ogr.FieldDefn('code', ogr.OFTString))

    envelopes = []
    id = 1
    for env in geos:
        f = ogr.Feature(lyr.GetLayerDefn())
        bb = dg.create_bb(env.GetEnvelope(), env.GetSpatialReference())
        f.SetGeometry(bb)
        f.SetField(0, id)
        f.SetField(1, bb.Area())
        f.SetField(2, None)
        f.SetField(3, None)
        id += 1
        lyr.CreateFeature(f)
        envelopes.append({
            'id': id,
            'env': bb.GetEnvelope(),
            'area': bb.Area()
        })

    return envelopes
Пример #4
0
def bound_clusters_in_raster( a, aa, shape_file_dir, 
                                 contour_interval,contour_value, use_bb=True, use_distance=False):
        """Create a shapefile that contains contours and bounding boxes for clusters
        of contours.
        
        :param a: A numpy array that contains the data inwhich to find clusters
        :type a: Numpy array
        
        :param aa: The analysis object that sets the coordinate system for the area that contains the array
        :type aa: ambry.geo.AnalysisArea
        
        :param shape_file_dir: The path to a directory where generated files will be stored. 
        :type shape_file_dir: string
        
        :param contour_interval: The difference between successive contour intervals. 
        :type contour_interval: float

        :param contour_value: 
        :type contour_value: float
  
        :param use_bb: If True, compute nearness and intersection using the contours bounding boxes, not the geometry
        :type use_bb: bool
        
        :param use_distance: If not False, consider contours that are closer than this value to be overlapping. 
        :type : number
        
        :rtype: Returns a list of dictionaries, one for each of the combined bounding boxes
        
        This method will store, in the `shape_file_dir` directory:
        
        * a GeoTIFF representation of the array `a`
        * An ERSI shapefile layer  named `countours`, holding all of the countours. 
        * A layer named `contour_bounds` with the bounding boxes for all of the contours with value `contour_value`
        * A layer named `combined_bounds` with bounding boxes of intersecting and nearby boxes rom `contour_bounds`
        
        The routine will iteratively combine contours that overlap. 
        
        If `use_distance` is set to a number, and contours that are closer than this value will be joined. 
        
        If `use_bb` is set, the intersection and distance computations use the bounding boxes of the contours, 
        not the contours themselves. 
        
     
        """
        
        import ambry.geo as dg
        from osgeo.gdalconst import GDT_Float32
        import ambry.util as util
        
        from osgeo import gdal
        import ogr, os
        import numpy as np
       
        if os.path.exists(shape_file_dir):
            util.rm_rf(shape_file_dir)
            os.makedirs(shape_file_dir)
        
        rasterf = os.path.join(shape_file_dir,'contour.tiff')

        ogr_ds = ogr.GetDriverByName('ESRI Shapefile').CreateDataSource(shape_file_dir)
        
        # Setup the countour layer. 
        ogr_lyr = ogr_ds.CreateLayer('contours', aa.srs)
        ogr_lyr.CreateField(ogr.FieldDefn('id', ogr.OFTInteger))
        ogr_lyr.CreateField(ogr.FieldDefn('value', ogr.OFTReal))
        
        # Create the contours from the GeoTIFF file. 
        ds = aa.get_geotiff(rasterf, data_type=GDT_Float32)
        ds.GetRasterBand(1).SetNoDataValue(0)
        ds.GetRasterBand(1).WriteArray(np.flipud(a))
        
        gdal.ContourGenerate(ds.GetRasterBand(1), 
                             contour_interval,  # contourInterval
                             0,   # contourBase
                             [],  # fixedLevelCount
                             0, # useNoData
                             0, # noDataValue
                             ogr_lyr, #destination layer
                             0,  #idField
                             1 # elevation field
                             )

 
        # Get buffered bounding boxes around each of the hotspots, 
        # and put them into a new layer. 
 
        bound_lyr = ogr_ds.CreateLayer('contour_bounds', aa.srs)
        for i in range(ogr_lyr.GetFeatureCount()):
            f1 = ogr_lyr.GetFeature(i)
            if f1.GetFieldAsDouble('value') != contour_value:
                continue
            g1 = f1.GetGeometryRef()
            bb = dg.create_bb(g1.GetEnvelope(), g1.GetSpatialReference())
            f = ogr.Feature(bound_lyr.GetLayerDefn())
            f.SetGeometry(bb)
            bound_lyr.CreateFeature(f)
            
    
        # Doing a full loop instead of a list comprehension b/c the way that comprehensions
        # compose arrays results in segfaults, probably because a copied geometry
        # object is being released before being used. 
        geos = []
        for i in range(bound_lyr.GetFeatureCount()):
            f = bound_lyr.GetFeature(i)
            g = f.geometry()
            geos.append(g.Clone())
    
        # Combine hot spots that have intersecting bounding boxes, to get larger
        # areas that cover all of the adjacent intersecting smaller areas. 
        geos = dg.combine_envelopes(geos, use_bb=use_bb, use_distance = use_distance) 

        # Write out the combined bounds areas. 
        lyr = ogr_ds.CreateLayer('combined_bounds', aa.srs)
        lyr.CreateField(ogr.FieldDefn('id', ogr.OFTInteger))
        lyr.CreateField(ogr.FieldDefn('area', ogr.OFTReal))
        lyr.CreateField(ogr.FieldDefn('name', ogr.OFTString))
        lyr.CreateField(ogr.FieldDefn('code', ogr.OFTString))
        
        envelopes = []
        id = 1
        for env in geos:
            f = ogr.Feature(lyr.GetLayerDefn())
            bb = dg.create_bb(env.GetEnvelope(), env.GetSpatialReference())
            f.SetGeometry(bb)
            f.SetField(0, id)
            f.SetField(1, bb.Area())
            f.SetField(2, None)
            f.SetField(3, None)   
            id += 1         
            lyr.CreateFeature(f)
            envelopes.append({'id':id, 'env':bb.GetEnvelope(), 'area':bb.Area()})
            

        return envelopes