示例#1
0
 def test_contains_point(self):
     """Test contain_point method"""
     area = Area(v_id=1, c_mapinfo=self.c_mapinfo)
     p = Point(0.5, 0.5)
     bbox = Bbox(4.0, 0.0, 4.0, 0.0)
     self.assertTrue(area.contains_point(p, bbox))
     self.assertTrue(area.contains_point(p))
示例#2
0
文件: split.py 项目: mlennert/grass
def get_bbox(reg, row, col, width, height, overlap):
    """Return a Bbox

    :param reg: a Region object to split
    :type reg: Region object
    :param row: the number of row
    :type row: int
    :param col: the number of row
    :type col: int
    :param width: the width of tiles
    :type width: int
    :param height: the width of tiles
    :type height: int
    :param overlap: the value of overlap between tiles
    :type overlap: int
    """
    north = reg.north - (row * height - overlap) * reg.nsres
    south = reg.north - ((row + 1) * height + overlap) * reg.nsres
    east = reg.west + ((col + 1) * width + overlap) * reg.ewres
    west = reg.west + (col * width - overlap) * reg.ewres
    return Bbox(
        north=north if north <= reg.north else reg.north,
        south=south if south >= reg.south else reg.south,
        east=east if east <= reg.east else reg.east,
        west=west if west >= reg.west else reg.west,
    )
示例#3
0
 def bbox(self):
     """Return the BBox of the vecor map
     """
     bbox = Bbox()
     if libvect.Vect_get_map_box(self.c_mapinfo, bbox.c_bbox) == 0:
         raise GrassError("I can not find the Bbox.")
     return bbox
示例#4
0
 def __init__(self, points_xy=None, align_to_region=True, xmin=None, 
              xmax=None, ymin=None, ymax=None):
     if points_xy is not None:
         points = np.array(points_xy)
         self.xmin = np.min(points[:,0])
         self.xmax = np.max(points[:,0])
         self.ymin = np.min(points[:,1])
         self.ymax = np.max(points[:,1])
     else:
         self.xmin = xmin
         self.ymin = ymin
         self.xmax = xmax
         self.ymax = ymax
     if align_to_region is not None:
         reg = region.Region()
         self.xmin = np.floor( (self.xmin - reg.get_bbox().west) / 
                                reg.ewres ) * \
                                reg.ewres + reg.get_bbox().west
         self.ymin = np.floor( (self.ymin - reg.get_bbox().south ) / 
                                reg.nsres ) * \
                                reg.nsres + reg.get_bbox().south
         self.xmax = np.ceil( (self.xmax - reg.get_bbox().east ) / 
                               reg.ewres ) * \
                               reg.ewres + reg.get_bbox().east
         self.ymax = np.ceil( (self.ymax - reg.get_bbox().north ) / 
                               reg.nsres ) * \
                               reg.nsres + reg.get_bbox().north
     self.bbox = Bbox()
     self.bbox.north = self.ymax
     self.bbox.south = self.ymin
     self.bbox.west = self.xmin
     self.bbox.east = self.xmax
示例#5
0
 def select_by_bbox(self, bbox):
     """Return the BBox of the vector map
     """
     # TODO replace with bbox if bbox else Bbox() ??
     bbox = Bbox()
     if libvect.Vect_get_map_box(self.c_mapinfo, bbox.c_bbox) == 0:
         raise GrassError("I can not find the Bbox.")
     return bbox
def update_lines(line, alist, cur=None, sql=None):
    """Update lines using only the boundary"""
    to_up = []
    bbox = Bbox()
    aline = Line()
    for area in alist:
        bbox = area.bbox(bbox)
        if (intersects(area.get_points(aline), line)) or (area.contain_pnt(
                line[0], bbox)):
            to_up.append((line.cat, area.cat))
    if (cur is not None) and (sql is not None):
        cur.executemany(sql, to_up)
    return to_up
示例#7
0
    def get_bbox(self):
        """Return a Bbox object with the extension of the region. ::

            >>> reg = Region()
            >>> reg.get_bbox()
            Bbox(228500.0, 215000.0, 645000.0, 630000.0)

        ..
        """
        from grass.pygrass.vector.basic import Bbox
        return Bbox(north=self.north, south=self.south,
                    east=self.east, west=self.west,
                    top=self.top, bottom=self.bottom)
示例#8
0
def _get_vector_features_as_wkb_list(lock, conn, data):
    """Return vector layer features as wkb list

    supported feature types:
    point, centroid, line, boundary, area

    :param lock: A multiprocessing.Lock instance
    :param conn: A multiprocessing.Pipe instance used to send True or False
    :param data: The list of data entries [function_id,name,mapset,extent,
                                           feature_type, field]

    """
    wkb_list = None
    try:
        name = data[1]
        mapset = data[2]
        extent = data[3]
        feature_type = data[4]
        field = data[5]
        bbox = None

        mapset = utils.get_mapset_vector(name, mapset)

        if not mapset:
            raise ValueError("Unable to find vector map <%s>" % (name))

        layer = VectorTopo(name, mapset)

        if layer.exist() is True:
            if extent is not None:
                bbox = Bbox(
                    north=extent["north"],
                    south=extent["south"],
                    east=extent["east"],
                    west=extent["west"],
                )

            layer.open("r")
            if feature_type.lower() == "area":
                wkb_list = layer.areas_to_wkb_list(bbox=bbox, field=field)
            else:
                wkb_list = layer.features_to_wkb_list(
                    bbox=bbox, feature_type=feature_type, field=field)
            layer.close()
    finally:
        # Send even if an exception was raised.
        conn.send(wkb_list)
def main():
    """Do the main processing
    """

    # Parse input options:
    patch_map = options['input']
    patches = patch_map.split('@')[0]
    patches_mapset = patch_map.split('@')[1] if len(
        patch_map.split('@')) > 1 else None
    pop_proxy = options['pop_proxy']
    layer = options['layer']
    costs = options['costs']
    cutoff = float(options['cutoff'])
    border_dist = int(options['border_dist'])
    conefor_dir = options['conefor_dir']
    memory = int(options['memory'])

    # Parse output options:
    prefix = options['prefix']
    edge_map = '{}_edges'.format(prefix)
    vertex_map = '{}_vertices'.format(prefix)
    shortest_paths = '{}_shortest_paths'.format(prefix)

    # Parse flags:
    p_flag = flags['p']
    t_flag = flags['t']
    r_flag = flags['r']

    dist_flags = 'kn' if flags['k'] else 'n'

    lin_cat = 1
    zero_dist = None

    folder = grass.tempdir()
    if not os.path.exists(folder):
        os.makedirs(folder)

    # Setup counter for progress message
    counter = 0

    # Check if location is lat/lon (only in lat/lon geodesic distance
    # measuring is supported)
    if grass.locn_is_latlong():
        grass.verbose("Location is lat/lon: Geodesic distance \
                      measure is used")

    # Check if prefix is legal GRASS name
    if not grass.legal_name(prefix):
        grass.fatal('{} is not a legal name for GRASS \
                    maps.'.format(prefix))

    if prefix[0].isdigit():
        grass.fatal('Tables names starting with a digit are not SQL \
                    compliant.'.format(prefix))

    # Check if output maps not already exists or could be overwritten
    for output in [edge_map, vertex_map, shortest_paths]:
        if grass.db.db_table_exist(output) and not grass.overwrite():
            grass.fatal('Vector map <{}> already exists'.format(output))

    # Check if input has required attributes
    in_db_connection = grass.vector.vector_db(patch_map)
    if not int(layer) in in_db_connection.keys():
        grass.fatal('No attribute table connected vector map {} at \
                    layer {}.'.format(patches, layer))

    #Check if cat column exists
    pcols = grass.vector.vector_columns(patch_map, layer=layer)

    #Check if cat column exists
    if not 'cat' in pcols.keys():
        grass.fatal('Cannot find the reqired column cat in vector map \
                    {}.'.format(patches))

    #Check if pop_proxy column exists
    if not pop_proxy in pcols.keys():
        grass.fatal('Cannot find column {} in vector map \
                    {}'.format(pop_proxy, patches))

    #Check if pop_proxy column is numeric type
    if not pcols[pop_proxy]['type'] in ['INTEGER', 'REAL', 'DOUBLE PRECISION']:
        grass.fatal('Column {} is of type {}. Only numeric types \
                    (integer or double precision) \
                    allowed!'.format(pop_proxy, pcols[pop_proxy]['type']))

    #Check if pop_proxy column does not contain values <= 0
    pop_vals = np.fromstring(grass.read_command('v.db.select',
                                                flags='c',
                                                map=patches,
                                                columns=pop_proxy,
                                                nv=-9999).rstrip('\n'),
                             dtype=float,
                             sep='\n')

    if np.min(pop_vals) <= 0:
        grass.fatal('Column {} contains values <= 0 or NULL. Neither \
                    values <= 0 nor NULL allowed!}'.format(pop_proxy))

    ##############################################
    # Use pygrass region instead of grass.parse_command !?!
    start_reg = grass.parse_command('g.region', flags='ugp')

    max_n = start_reg['n']
    min_s = start_reg['s']
    max_e = start_reg['e']
    min_w = start_reg['w']
    # cost_nsres = reg['nsres']
    # cost_ewres = reg['ewres']

    # Rasterize patches
    # http://www.gdal.org/gdal_tutorial.html
    # http://geoinformaticstutorial.blogspot.no/2012/11/convert-
    # shapefile-to-raster-with-gdal.html
    if t_flag:
        # Rasterize patches with "all-touched" mode using GDAL
        # Read region-settings (not needed canuse max_n, min_s, max_e,
        # min_w nsres, ewres...
        prast = os.path.join(folder, 'patches_rast.tif')

        # Check if GDAL-GRASS plugin is installed
        if ogr.GetDriverByName('GRASS'):
            #With GDAL-GRASS plugin
            #Locate file for patch vector map
            pfile = grass.parse_command('g.findfile',
                                        element='vector',
                                        file=patches,
                                        mapset=patches_mapset)['file']
            pfile = os.path.join(pfile, 'head')

        else:
            # Without GDAL-GRASS-plugin
            grass.warning("Cannot find GDAL-GRASS plugin. Consider \
                          installing it in order to save time for \
                          all-touched rasterisation")
            pfile = os.path.join(folder, 'patches_vect.gpkg')
            # Export patch vector map to temp-file in a GDAL-readable
            # format (shp)
            grass.run_command('v.out.ogr',
                              flags='m',
                              quiet=True,
                              input=patch_map,
                              type='area',
                              layer=layer,
                              output=pfile,
                              lco='GEOMETRY_NAME=geom')

        # Rasterize vector map with all-touched option
        os.system('gdal_rasterize -l {} -at -tr {} {} \
                  -te {} {} {} {} -ot Uint32 -a cat \
                  {} {} -q'.format(patches, start_reg['ewres'],
                                   start_reg['nsres'], start_reg['w'],
                                   start_reg['s'], start_reg['e'],
                                   start_reg['n'], pfile, prast))

        if not ogr.GetDriverByName('GRASS'):
            # Remove vector temp-file
            os.remove(os.path.join(folder, 'patches_vect.gpkg'))

        # Import rasterized patches
        grass.run_command('r.external',
                          flags='o',
                          quiet=True,
                          input=prast,
                          output='{}_patches_pol'.format(TMP_PREFIX))

    else:
        # Simple rasterisation (only area)
        # in G 7.6 also with support for 'centroid'
        if float(grass.version()['version'][:3]) >= 7.6:
            conv_types = ['area', 'centroid']
        else:
            conv_types = ['area']
        grass.run_command('v.to.rast',
                          quiet=True,
                          input=patches,
                          use='cat',
                          type=conv_types,
                          output='{}_patches_pol'.format(TMP_PREFIX))

    # Extract boundaries from patch raster map
    grass.run_command('r.mapcalc',
                      expression='{p}_patches_boundary=if(\
    {p}_patches_pol,\
    if((\
    (isnull({p}_patches_pol[-1,0])||| \
    {p}_patches_pol[-1,0]!={p}_patches_pol)||| \
    (isnull({p}_patches_pol[0,1])||| \
    {p}_patches_pol[0,1]!={p}_patches_pol)||| \
    (isnull({p}_patches_pol[1,0])||| \
    {p}_patches_pol[1,0]!={p}_patches_pol)||| \
    (isnull({p}_patches_pol[0,-1])||| \
    {p}_patches_pol[0,-1]!={p}_patches_pol)), \
    {p}_patches_pol,null()), null())'.format(p=TMP_PREFIX),
                      quiet=True)

    rasterized_cats = grass.read_command(
        'r.category',
        separator='newline',
        map='{p}_patches_boundary'.format(p=TMP_PREFIX)).replace(
            '\t', '').strip('\n')
    rasterized_cats = list(
        map(int, set([x for x in rasterized_cats.split('\n') if x != ''])))

    #Init output vector maps if they are requested by user
    network = VectorTopo(edge_map)
    network_columns = [(u'cat', 'INTEGER PRIMARY KEY'), (u'from_p', 'INTEGER'),
                       (u'to_p', 'INTEGER'), (u'min_dist', 'DOUBLE PRECISION'),
                       (u'dist', 'DOUBLE PRECISION'),
                       (u'max_dist', 'DOUBLE PRECISION')]
    network.open('w', tab_name=edge_map, tab_cols=network_columns)

    vertex = VectorTopo(vertex_map)
    vertex_columns = [
        (u'cat', 'INTEGER PRIMARY KEY'),
        (pop_proxy, 'DOUBLE PRECISION'),
    ]
    vertex.open('w', tab_name=vertex_map, tab_cols=vertex_columns)

    if p_flag:
        # Init cost paths file for start-patch
        grass.run_command('v.edit',
                          quiet=True,
                          map=shortest_paths,
                          tool='create')
        grass.run_command('v.db.addtable',
                          quiet=True,
                          map=shortest_paths,
                          columns="cat integer,\
                                   from_p integer,\
                                   to_p integer,\
                                   dist_min double precision,\
                                   dist double precision,\
                                   dist_max double precision")

    start_region_bbox = Bbox(north=float(max_n),
                             south=float(min_s),
                             east=float(max_e),
                             west=float(min_w))
    vpatches = VectorTopo(patches, mapset=patches_mapset)
    vpatches.open('r', layer=int(layer))

    ###Loop through patches
    vpatch_ids = np.array(vpatches.features_to_wkb_list(
        feature_type="centroid", bbox=start_region_bbox),
                          dtype=[('vid', 'uint32'), ('cat', 'uint32'),
                                 ('geom', '|S10')])
    cats = set(vpatch_ids['cat'])
    n_cats = len(cats)
    if n_cats < len(vpatch_ids['cat']):
        grass.verbose('At least one MultiPolygon found in patch map.\n \
                      Using average coordinates of the centroids for \
                      visual representation of the patch.')

    for cat in cats:
        if cat not in rasterized_cats:
            grass.warning('Patch {} has not been rasterized and will \
                          therefore not be treated as part of the \
                          network. Consider using t-flag or change \
                          resolution.'.format(cat))

            continue
        grass.verbose("Calculating connectivity-distances for patch \
                      number {}".format(cat))

        # Filter
        from_vpatch = vpatch_ids[vpatch_ids['cat'] == cat]

        # Get patch ID
        if from_vpatch['vid'].size == 1:
            from_centroid = Centroid(v_id=int(from_vpatch['vid']),
                                     c_mapinfo=vpatches.c_mapinfo)
            from_x = from_centroid.x
            from_y = from_centroid.y

            # Get centroid
            if not from_centroid:
                continue
        else:
            xcoords = []
            ycoords = []
            for f_p in from_vpatch['vid']:
                from_centroid = Centroid(v_id=int(f_p),
                                         c_mapinfo=vpatches.c_mapinfo)
                xcoords.append(from_centroid.x)
                ycoords.append(from_centroid.y)

                # Get centroid
                if not from_centroid:
                    continue
            from_x = np.average(xcoords)
            from_y = np.average(ycoords)

        # Get BoundingBox
        from_bbox = grass.parse_command('v.db.select',
                                        map=patch_map,
                                        flags='r',
                                        where='cat={}'.format(cat))

        attr_filter = vpatches.table.filters.select(pop_proxy)
        attr_filter = attr_filter.where("cat={}".format(cat))
        proxy_val = vpatches.table.execute().fetchone()

        # Prepare start patch
        start_patch = '{}_patch_{}'.format(TMP_PREFIX, cat)
        reclass_rule = grass.encode('{} = 1\n* = NULL'.format(cat))
        recl = grass.feed_command(
            'r.reclass',
            quiet=True,
            input='{}_patches_boundary'.format(TMP_PREFIX),
            output=start_patch,
            rules='-')
        recl.stdin.write(reclass_rule)
        recl.stdin.close()
        recl.wait()

        # Check if patch was rasterised (patches smaller raster resolution and close to larger patches may not be rasterised)
        #start_check = grass.parse_command('r.info', flags='r', map=start_patch)
        #start_check = grass.parse_command('r.univar', flags='g', map=start_patch)
        #print(start_check)
        """if start_check['min'] != '1':
            grass.warning('Patch {} has not been rasterized and will \
                          therefore not be treated as part of the \
                          network. Consider using t-flag or change \
                          resolution.'.format(cat))

            grass.run_command('g.remove', flags='f', vector=start_patch,
                              raster=start_patch, quiet=True)
            grass.del_temp_region()
            continue"""

        # Prepare stop patches
        ############################################
        reg = grass.parse_command('g.region',
                                  flags='ug',
                                  quiet=True,
                                  raster=start_patch,
                                  n=float(from_bbox['n']) + float(cutoff),
                                  s=float(from_bbox['s']) - float(cutoff),
                                  e=float(from_bbox['e']) + float(cutoff),
                                  w=float(from_bbox['w']) - float(cutoff),
                                  align='{}_patches_pol'.format(TMP_PREFIX))

        north = reg['n'] if max_n > reg['n'] else max_n
        south = reg['s'] if min_s < reg['s'] else min_s
        east = reg['e'] if max_e < reg['e'] else max_e
        west = reg['w'] if min_w > reg['w'] else min_w

        # Set region to patch search radius
        grass.use_temp_region()
        grass.run_command('g.region',
                          quiet=True,
                          n=north,
                          s=south,
                          e=east,
                          w=west,
                          align='{}_patches_pol'.format(TMP_PREFIX))

        # Create buffer around start-patch as a mask
        # for cost distance analysis
        grass.run_command('r.buffer',
                          quiet=True,
                          input=start_patch,
                          output='MASK',
                          distances=cutoff)
        grass.run_command('r.mapcalc',
                          quiet=True,
                          expression='{pf}_patch_{p}_neighbours_contur=\
                                     if({pf}_patches_boundary=={p},\
                                     null(),\
                                     {pf}_patches_boundary)'.format(
                              pf=TMP_PREFIX, p=cat))
        grass.run_command('r.mask', flags='r', quiet=True)

        # Calculate cost distance
        cost_distance_map = '{}_patch_{}_cost_dist'.format(prefix, cat)
        grass.run_command('r.cost',
                          flags=dist_flags,
                          quiet=True,
                          overwrite=True,
                          input=costs,
                          output=cost_distance_map,
                          start_rast=start_patch,
                          memory=memory)

        #grass.run_command('g.region', flags='up')
        # grass.raster.raster_history(cost_distance_map)
        cdhist = History(cost_distance_map)
        cdhist.clear()
        cdhist.creator = os.environ['USER']
        cdhist.write()
        # History object cannot modify description
        grass.run_command('r.support',
                          map=cost_distance_map,
                          description='Generated by r.connectivity.distance',
                          history=os.environ['CMDLINE'])

        # Export distance at boundaries
        maps = '{0}_patch_{1}_neighbours_contur,{2}_patch_{1}_cost_dist'
        maps = maps.format(TMP_PREFIX, cat, prefix),

        connections = grass.encode(
            grass.read_command('r.stats',
                               flags='1ng',
                               quiet=True,
                               input=maps,
                               separator=';').rstrip('\n'))
        if connections:
            con_array = np.genfromtxt(BytesIO(connections),
                                      delimiter=';',
                                      dtype=None,
                                      names=['x', 'y', 'cat', 'dist'])
        else:
            grass.warning('No connections for patch {}'.format(cat))

            # Write centroid to vertex map
            vertex.write(Point(from_x, from_y), cat=int(cat), attrs=proxy_val)
            vertex.table.conn.commit()

            # Remove temporary map data
            grass.run_command('g.remove',
                              quiet=True,
                              flags='f',
                              type=['raster', 'vector'],
                              pattern="{}*{}*".format(TMP_PREFIX, cat))
            grass.del_temp_region()
            continue

        #Find closest points on neigbour patches
        to_cats = set(np.atleast_1d(con_array['cat']))
        to_coords = []
        for to_cat in to_cats:
            connection = con_array[con_array['cat'] == to_cat]
            connection.sort(order=['dist'])
            pixel = border_dist if len(
                connection) > border_dist else len(connection) - 1
            # closest_points_x = connection['x'][pixel]
            # closest_points_y = connection['y'][pixel]
            closest_points_to_cat = to_cat
            closest_points_min_dist = connection['dist'][0]
            closest_points_dist = connection['dist'][pixel]
            closest_points_max_dist = connection['dist'][-1]
            to_patch_ids = vpatch_ids[vpatch_ids['cat'] == int(to_cat)]['vid']

            if len(to_patch_ids) == 1:
                to_centroid = Centroid(v_id=to_patch_ids,
                                       c_mapinfo=vpatches.c_mapinfo)
                to_x = to_centroid.x
                to_y = to_centroid.y
            elif len(to_patch_ids) >= 1:
                xcoords = []
                ycoords = []
                for t_p in to_patch_ids:
                    to_centroid = Centroid(v_id=int(t_p),
                                           c_mapinfo=vpatches.c_mapinfo)
                    xcoords.append(to_centroid.x)
                    ycoords.append(to_centroid.y)

                    # Get centroid
                    if not to_centroid:
                        continue
                to_x = np.average(xcoords)
                to_y = np.average(ycoords)

            to_coords.append('{},{},{},{},{},{}'.format(
                connection['x'][0], connection['y'][0], to_cat,
                closest_points_min_dist, closest_points_dist,
                closest_points_max_dist))

            #Save edges to network dataset
            if closest_points_dist <= 0:
                zero_dist = 1

            # Write data to network
            network.write(Line([(from_x, from_y), (to_x, to_y)]),
                          cat=lin_cat,
                          attrs=(
                              cat,
                              int(closest_points_to_cat),
                              closest_points_min_dist,
                              closest_points_dist,
                              closest_points_max_dist,
                          ))
            network.table.conn.commit()

            lin_cat = lin_cat + 1

        # Save closest points and shortest paths through cost raster as
        # vector map (r.drain limited to 1024 points) if requested
        if p_flag:
            grass.verbose('Extracting shortest paths for patch number \
                          {}...'.format(cat))

            points_n = len(to_cats)

            tiles = int(points_n / 1024.0)
            rest = points_n % 1024
            if not rest == 0:
                tiles = tiles + 1

            tile_n = 0
            while tile_n < tiles:
                tile_n = tile_n + 1
                #Import closest points for start-patch in 1000er blocks
                sp = grass.feed_command('v.in.ascii',
                                        flags='nr',
                                        overwrite=True,
                                        quiet=True,
                                        input='-',
                                        stderr=subprocess.PIPE,
                                        output="{}_{}_cp".format(
                                            TMP_PREFIX, cat),
                                        separator=",",
                                        columns="x double precision,\
                                           y double precision,\
                                           to_p integer,\
                                           dist_min double precision,\
                                           dist double precision,\
                                           dist_max double precision")
                sp.stdin.write(grass.encode("\n".join(to_coords)))
                sp.stdin.close()
                sp.wait()

                # Extract shortest paths for start-patch in chunks of
                # 1024 points
                cost_paths = "{}_{}_cost_paths".format(TMP_PREFIX, cat)
                start_points = "{}_{}_cp".format(TMP_PREFIX, cat)
                grass.run_command('r.drain',
                                  overwrite=True,
                                  quiet=True,
                                  input=cost_distance_map,
                                  output=cost_paths,
                                  drain=cost_paths,
                                  start_points=start_points)

                grass.run_command('v.db.addtable',
                                  map=cost_paths,
                                  quiet=True,
                                  columns="cat integer,\
                                   from_p integer,\
                                   to_p integer,\
                                   dist_min double precision,\
                                   dist double precision,\
                                   dist_max double precision")
                grass.run_command('v.db.update',
                                  map=cost_paths,
                                  column='from_p',
                                  value=cat,
                                  quiet=True)
                grass.run_command('v.distance',
                                  quiet=True,
                                  from_=cost_paths,
                                  to=start_points,
                                  upload='to_attr',
                                  column='to_p',
                                  to_column='to_p')
                grass.run_command('v.db.join',
                                  quiet=True,
                                  map=cost_paths,
                                  column='to_p',
                                  other_column='to_p',
                                  other_table=start_points,
                                  subset_columns='dist_min,dist,dist_max')

                #grass.run_command('v.info', flags='c',
                #                  map=cost_paths)
                grass.run_command('v.patch',
                                  flags='ae',
                                  overwrite=True,
                                  quiet=True,
                                  input=cost_paths,
                                  output=shortest_paths)

                # Remove temporary map data
                grass.run_command('g.remove',
                                  quiet=True,
                                  flags='f',
                                  type=['raster', 'vector'],
                                  pattern="{}*{}*".format(TMP_PREFIX, cat))

        # Remove temporary map data for patch
        if r_flag:
            grass.run_command('g.remove',
                              flags='f',
                              type='raster',
                              name=cost_distance_map,
                              quiet=True)

        vertex.write(Point(from_x, from_y), cat=int(cat), attrs=proxy_val)

        vertex.table.conn.commit()

        # Print progress message
        grass.percent(i=int((float(counter) / n_cats) * 100), n=100, s=3)

        # Update counter for progress message
        counter = counter + 1

    if zero_dist:
        grass.warning('Some patches are directly adjacent to others. \
                       Minimum distance set to 0.0000000001')

    # Close vector maps and build topology
    network.close()
    vertex.close()

    # Add vertex attributes
    # grass.run_command('v.db.addtable', map=vertex_map)
    # grass.run_command('v.db.join', map=vertex_map, column='cat',
    #                   other_table=in_db_connection[int(layer)]['table'],
    #                   other_column='cat', subset_columns=pop_proxy,
    #                   quiet=True)

    # Add history and meta data to produced maps
    grass.run_command('v.support',
                      flags='h',
                      map=edge_map,
                      person=os.environ['USER'],
                      cmdhist=os.environ['CMDLINE'])

    grass.run_command('v.support',
                      flags='h',
                      map=vertex_map,
                      person=os.environ['USER'],
                      cmdhist=os.environ['CMDLINE'])

    if p_flag:
        grass.run_command('v.support',
                          flags='h',
                          map=shortest_paths,
                          person=os.environ['USER'],
                          cmdhist=os.environ['CMDLINE'])

    # Output also Conefor files if requested
    if conefor_dir:
        query = """SELECT p_from, p_to, avg(dist) FROM
                 (SELECT
                 CASE
                 WHEN from_p > to_p THEN to_p
                 ELSE from_p END AS p_from,
                    CASE
                 WHEN from_p > to_p THEN from_p
                 ELSE to_p END AS p_to,
                 dist
                 FROM {}) AS x
                 GROUP BY p_from, p_to""".format(edge_map)
        with open(os.path.join(conefor_dir, 'undirected_connection_file'),
                  'w') as edges:
            edges.write(
                grass.read_command('db.select', sql=query, separator=' '))
        with open(os.path.join(conefor_dir, 'directed_connection_file'),
                  'w') as edges:
            edges.write(
                grass.read_command('v.db.select',
                                   map=edge_map,
                                   separator=' ',
                                   flags='c'))
        with open(os.path.join(conefor_dir, 'node_file'), 'w') as nodes:
            nodes.write(
                grass.read_command('v.db.select',
                                   map=vertex_map,
                                   separator=' ',
                                   flags='c'))
示例#10
0
def do_it_all(global_vars, target_pts_np):
    """Conduct weighted and parametrised partial viewshed and cummulate it with
    the previous partial viewsheds
    :param target_pts_np: Array of target points in global coordinate system
    :type target_pts_np: ndarray
    :return: 2D array of weighted parametrised cummulative viewshed
    :rtype: ndarray
    """
    # Set counter
    counter = 1

    # Get variables out of global_vars dictionary
    reg = global_vars["region"]
    exp_range = global_vars["range"]
    flagstring = global_vars["flagstring"]
    r_dsm = global_vars["r_dsm"]
    v_elevation = global_vars["observer_elevation"]
    refr_coeff = global_vars["refr_coeff"]
    memory = global_vars["memory"]
    parametrise_viewshed = global_vars["param_viewshed"]
    dsm_type = global_vars["dsm_type"]
    b_1 = global_vars["b_1"]
    cores = global_vars["cores"]
    tempname = global_vars["tempname"]

    # Create empty viewshed
    np_cum = np.empty((reg.rows, reg.cols), dtype=np.single)
    np_cum[:] = np.nan
    tmp_vs = "{}_{}".format(tempname, os.getpid())

    for target_pnt in target_pts_np:

        # Display a progress info message
        grass.percent(counter, len(target_pts_np), 1)
        grass.verbose("Processing point {i} ({p:.1%})".format(
            i=int(target_pnt[0]), p=counter / len(target_pts_np)))

        # Global coordinates and attributes of target point T
        t_glob = target_pnt[1:]

        # ======================================================================
        # 1. Set local computational region: +/- exp_range from target point
        # ======================================================================
        # compute position of target point within a pixel
        delta_n = math.ceil(
            (t_glob[1] - reg.south) / reg.nsres) * reg.nsres - (t_glob[1] -
                                                                reg.south)
        delta_s = (t_glob[1] - reg.south) - math.floor(
            (t_glob[1] - reg.south) / reg.nsres) * reg.nsres
        delta_e = math.ceil(
            (t_glob[0] - reg.west) / reg.ewres) * reg.ewres - (t_glob[0] -
                                                               reg.west)
        delta_w = (t_glob[0] - reg.west) - math.floor(
            (t_glob[0] - reg.west) / reg.ewres) * reg.ewres

        # ensure that local region doesn't exceed global region
        loc_reg_n = min(t_glob[1] + exp_range + delta_n, reg.north)
        loc_reg_s = max(t_glob[1] - exp_range - delta_s, reg.south)
        loc_reg_e = min(t_glob[0] + exp_range + delta_e, reg.east)
        loc_reg_w = max(t_glob[0] - exp_range - delta_w, reg.west)

        # pygrass sets region for pygrass tasks
        lreg = deepcopy(reg)
        lreg.set_bbox(Bbox(loc_reg_n, loc_reg_s, loc_reg_e, loc_reg_w))
        lreg.set_raster_region()

        # Create processing environment with region information
        c_env = os.environ.copy()
        c_env["GRASS_REGION"] = grass.region_env(n=loc_reg_n,
                                                 s=loc_reg_s,
                                                 e=loc_reg_e,
                                                 w=loc_reg_w)

        lreg_shape = [lreg.rows, lreg.cols]

        # ======================================================================
        # 2. Calculate binary viewshed and convert to numpy
        # ======================================================================
        vs = grass.pipe_command(
            "r.viewshed",
            flags="b" + flagstring,
            input=r_dsm,
            output=tmp_vs,
            coordinates="{},{}".format(t_glob[0], t_glob[1]),
            observer_elevation=0.0,
            target_elevation=v_elevation,
            max_distance=exp_range,
            refraction_coeff=refr_coeff,
            memory=int(round(memory / cores)),
            quiet=True,
            overwrite=True,
            env=c_env,
        )
        vs.communicate()
        # Workaround for https://github.com/OSGeo/grass/issues/1436
        clean_temp(vs.pid)

        # Read viewshed into numpy with single precision and replace NoData
        np_viewshed = raster2numpy(tmp_vs).astype(np.single)
        np_viewshed[np_viewshed == -2147483648] = np.nan

        # ======================================================================
        # 3. Prepare local coordinates and attributes of target point T
        # ======================================================================
        # Calculate how much of rows/cols of local region lies
        # outside global region
        o_1 = [
            max(t_glob[1] + exp_range + reg.nsres / 2 - reg.north, 0),
            max(reg.west - (t_glob[0] - exp_range - reg.ewres / 2), 0),
        ]

        t_loc = np.append(
            np.array([
                exp_range / reg.nsres + 0.5 - o_1[0] / reg.nsres,
                exp_range / reg.ewres + 0.5 - o_1[1] / reg.ewres,
            ]),
            t_glob[2:],
        )

        # ======================================================================
        # 4. Parametrise viewshed
        # ======================================================================
        np_viewshed = parametrise_viewshed(
            lreg_shape,
            t_loc,
            np_viewshed,
            reg,
            exp_range,
            r_dsm,
            dsm_type,
            v_elevation,
            b_1,
        ).astype(np.single)

        # ======================================================================
        # 5. Cummulate viewsheds
        # ======================================================================
        # Determine position of local parametrised viewshed within
        # global cummulative viewshed
        o_2 = [
            int(round((reg.north - loc_reg_n) / reg.nsres)),  # NS (rows)
            int(round((loc_reg_w - reg.west) / reg.ewres)),  # EW (cols)
        ]

        # Add local parametrised viewshed to global cummulative viewshed
        # replace nans with 0 in processed regions, keep nan where both are nan
        all_nan = np.all(
            np.isnan([
                np_cum[o_2[0]:o_2[0] + lreg_shape[0],
                       o_2[1]:o_2[1] + lreg_shape[1]],
                np_viewshed,
            ]),
            axis=0,
        )

        np_cum[o_2[0]:o_2[0] + lreg_shape[0],
               o_2[1]:o_2[1] + lreg_shape[1]] = np.nansum(
                   [
                       np_cum[o_2[0]:o_2[0] + lreg_shape[0],
                              o_2[1]:o_2[1] + lreg_shape[1]],
                       np_viewshed,
                   ],
                   axis=0,
               )

        np_cum[o_2[0]:o_2[0] + lreg_shape[0],
               o_2[1]:o_2[1] + lreg_shape[1]][all_nan] = np.nan

        counter += 1

    return np_cum