Exemplo n.º 1
0
def get_electro_length(opts):
    # open vector plant
    pname = opts["struct"]
    pname, vmapset = pname.split("@") if "@" in pname else (pname, "")
    with VectorTopo(pname,
                    mapset=vmapset,
                    layer=int(opts["struct_layer"]),
                    mode="r") as vect:
        kcol = opts["struct_column_kind"]
        ktype = opts["struct_kind_turbine"]
        # check if electro_length it is alredy in the table
        if "electro_length" not in vect.table.columns:
            vect.table.columns.add("electro_length", "double precision")
        # open vector map with the existing electroline
        ename = opts["electro"]
        ename, emapset = ename.split("@") if "@" in ename else (ename, "")
        ltemp = []
        with VectorTopo(ename,
                        mapset=emapset,
                        layer=int(opts["electro_layer"]),
                        mode="r") as electro:
            pid = os.getpid()
            elines = opts["elines"] if opts["elines"] else (
                "tmprgreen_%i_elines" % pid)
            for cat, line in enumerate(vect):
                if line.attrs[kcol] == ktype:
                    # the turbine is the last point of the penstock
                    turbine = line[-1]
                    # find the closest electro line
                    eline = electro.find["by_point"].geo(turbine, maxdist=1e6)
                    dist = eline.distance(turbine)
                    line.attrs["electro_length"] = dist.dist
                    if line.attrs["side"] == "option1":
                        ltemp.append([
                            geo.Line([turbine, dist.point]),
                            (line.attrs["plant_id"], line.attrs["side"]),
                        ])
                else:
                    line.attrs["electro_length"] = 0.0
            vect.table.conn.commit()
        new = VectorTopo(elines)  # new vec with elines
        new.layer = 1
        cols = [
            (u"cat", "INTEGER PRIMARY KEY"),
            (u"plant_id", "VARCHAR(10)"),
            (u"side", "VARCHAR(10)"),
        ]
        new.open("w", tab_cols=cols)
        reg = Region()
        for cat, line in enumerate(ltemp):
            if version == 70:
                new.write(line[0], line[1])
            else:
                new.write(line[0], cat=cat, attrs=line[1])
        new.table.conn.commit()
        new.comment = " ".join(sys.argv)
        new.close()
Exemplo n.º 2
0
def get_electro_length(opts):
    # open vector plant
    pname = opts['struct']
    pname, vmapset = pname.split('@') if '@' in pname else (pname, '')
    with VectorTopo(pname,
                    mapset=vmapset,
                    layer=int(opts['struct_layer']),
                    mode='r') as vect:
        kcol = opts['struct_column_kind']
        ktype = opts['struct_kind_turbine']
        # check if electro_length it is alredy in the table
        if 'electro_length' not in vect.table.columns:
            vect.table.columns.add('electro_length', 'double precision')
        # open vector map with the existing electroline
        ename = opts['electro']
        ename, emapset = ename.split('@') if '@' in ename else (ename, '')
        ltemp = []
        with VectorTopo(ename,
                        mapset=emapset,
                        layer=int(opts['electro_layer']),
                        mode='r') as electro:
            pid = os.getpid()
            elines = (opts['elines'] if opts['elines'] else
                      ('tmprgreen_%i_elines' % pid))
            for cat, line in enumerate(vect):
                if line.attrs[kcol] == ktype:
                    # the turbine is the last point of the penstock
                    turbine = line[-1]
                    # find the closest electro line
                    eline = electro.find['by_point'].geo(turbine, maxdist=1e6)
                    dist = eline.distance(turbine)
                    line.attrs['electro_length'] = dist.dist
                    if line.attrs['side'] == 'option1':
                        ltemp.append([
                            geo.Line([turbine, dist.point]),
                            (line.attrs['plant_id'], line.attrs['side'])
                        ])
                else:
                    line.attrs['electro_length'] = 0.
            vect.table.conn.commit()
        new = VectorTopo(elines)  # new vec with elines
        new.layer = 1
        cols = [
            (u'cat', 'INTEGER PRIMARY KEY'),
            (u'plant_id', 'VARCHAR(10)'),
            (u'side', 'VARCHAR(10)'),
        ]
        new.open('w', tab_cols=cols)
        reg = Region()
        for cat, line in enumerate(ltemp):
            if version == 70:
                new.write(line[0], line[1])
            else:
                new.write(line[0], cat=cat, attrs=line[1])
        new.table.conn.commit()
        new.comment = (' '.join(sys.argv))
        new.close()
Exemplo n.º 3
0
def extendLine(map, map_out, maxlen=200, scale=0.5, debug=False, verbose=1):
    #
    # map=Input map name
    # map_out=Output map with extensions
    # maxlen=Max length in map units that line can be extended (def=200)
    # scale=Maximum length of extension as proportion of original line, disabled if 0 (def=0.5)
    # vlen=number of verticies to look back in calculating line end direction (def=1)
    # Not sure if it is worth putting this in as parameter.
    #
    allowOverwrite = os.getenv('GRASS_OVERWRITE', '0') == '1'
    grass.info("map={}, map_out={}, maxlen={}, scale={}, debug={}".format(
        map, map_out, maxlen, scale, debug))
    vlen = 1  # not sure if this is worth putting in as parameter
    cols = [(u'cat', 'INTEGER PRIMARY KEY'), (u'parent', 'INTEGER'),
            (u'dend', 'TEXT'), (u'orgx', 'DOUBLE PRECISION'),
            (u'orgy', 'DOUBLE PRECISION'), (u'search_len', 'DOUBLE PRECISION'),
            (u'search_az', 'DOUBLE PRECISION'), (u'best_xid', 'INTEGER'),
            (u'near_x', 'DOUBLE PRECISION'), (u'near_y', 'DOUBLE PRECISION'),
            (u'other_cat', 'INTEGER'), (u'xtype', 'TEXT'),
            (u'x_len', 'DOUBLE PRECISION')]
    extend = VectorTopo('extend')
    if extend.exist():
        extend.remove()
    extend.open('w', tab_name='extend', tab_cols=cols)
    #
    # Go through input map, looking at each line and it's two nodes to find nodes
    # with only a single line starting/ending there - i.e. a dangle.
    # For each found, generate an extension line in the new map "extend"
    #
    inMap = VectorTopo(map)
    inMap.open('r')
    dangleCnt = 0
    tickLen = len(inMap)
    grass.info("Searching {} features for dangles".format(tickLen))
    ticker = 0
    grass.message("Percent complete...")
    for ln in inMap:
        ticker = (ticker + 1)
        grass.percent(ticker, tickLen, 5)
        if ln.gtype == 2:  # Only process lines
            for nd in ln.nodes():
                if nd.nlines == 1:  # We have a dangle
                    dangleCnt = dangleCnt + 1
                    vtx = min(len(ln) - 1, vlen)
                    if len([1 for _ in nd.lines(only_out=True)
                            ]) == 1:  # Dangle starting at node
                        dend = "head"
                        sx = ln[0].x
                        sy = ln[0].y
                        dx = sx - ln[vtx].x
                        dy = sy - ln[vtx].y
                    else:  # Dangle ending at node
                        dend = "tail"
                        sx = ln[-1].x
                        sy = ln[-1].y
                        dx = sx - ln[-(vtx + 1)].x
                        dy = sy - ln[-(vtx + 1)].y
                    endaz = math.atan2(dy, dx)
                    if scale > 0:
                        extLen = min(ln.length() * scale, maxlen)
                    else:
                        extLen = maxlen
                    ex = extLen * math.cos(endaz) + sx
                    ey = extLen * math.sin(endaz) + sy
                    extLine = geo.Line([(sx, sy), (ex, ey)])
                    quiet = extend.write(extLine,
                                         (ln.cat, dend, sx, sy, extLen, endaz,
                                          0, 0, 0, 0, 'null', extLen))

    grass.info(
        "{} dangle nodes found, committing table extend".format(dangleCnt))
    extend.table.conn.commit()
    extend.close(build=True, release=True)
    inMap.close()

    #
    # Create two tables where extensions intersect;
    # 1. intersect with original lines
    # 2. intersect with self - to extract intersects between extensions
    #
    # First the intersects with original lines
    grass.info(
        "Searching for intersects between potential extensions and original lines"
    )
    table_isectIn = Table('isectIn',
                          connection=sqlite3.connect(get_path(path)))
    if table_isectIn.exist():
        table_isectIn.drop(force=True)
    run_command("v.distance",
                flags='a',
                overwrite=True,
                quiet=True,
                from_="extend",
                from_type="line",
                to=map,
                to_type="line",
                dmax="0",
                upload="cat,dist,to_x,to_y",
                column="near_cat,dist,nx,ny",
                table="isectIn")
    # Will have touched the dangle it comes from, so remove those touches
    run_command(
        "db.execute",
        sql=
        "DELETE FROM isectIn WHERE rowid IN (SELECT isectIn.rowid FROM isectIn INNER JOIN extend ON from_cat=cat WHERE near_cat=parent)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    run_command("db.execute",
                sql="ALTER TABLE isectIn ADD ntype VARCHAR",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    run_command("db.execute",
                sql="UPDATE isectIn SET ntype = 'orig' ",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    #
    # Now second self intersect table
    #
    grass.info("Searching for intersects of potential extensions")
    table_isectX = Table('isectX', connection=sqlite3.connect(get_path(path)))
    if table_isectX.exist():
        table_isectX.drop(force=True)
    run_command("v.distance",
                flags='a',
                overwrite=True,
                quiet=True,
                from_="extend",
                from_type="line",
                to="extend",
                to_type="line",
                dmax="0",
                upload="cat,dist,to_x,to_y",
                column="near_cat,dist,nx,ny",
                table="isectX")
    # Obviously all extensions will intersect with themself, so remove those "intersects"
    run_command("db.execute",
                sql="DELETE FROM isectX WHERE from_cat = near_cat",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    run_command("db.execute",
                sql="ALTER TABLE isectX ADD ntype VARCHAR",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    run_command("db.execute",
                sql="UPDATE isectX SET ntype = 'ext' ",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    #
    # Combine the two tables and add a few more attributes
    #
    run_command("db.execute",
                sql="INSERT INTO isectIn SELECT * FROM isectX",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    cols_isectIn = Columns('isectIn',
                           connection=sqlite3.connect(get_path(path)))
    cols_isectIn.add(['from_x'], ['DOUBLE PRECISION'])
    cols_isectIn.add(['from_y'], ['DOUBLE PRECISION'])
    cols_isectIn.add(['ext_len'], ['DOUBLE PRECISION'])
    # Get starting coordinate at the end of the dangle
    run_command(
        "db.execute",
        sql=
        "UPDATE isectIn SET from_x = (SELECT extend.orgx FROM extend WHERE from_cat=extend.cat)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    run_command(
        "db.execute",
        sql=
        "UPDATE isectIn SET from_y = (SELECT extend.orgy FROM extend WHERE from_cat=extend.cat)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    table_isectIn.conn.commit()
    # For each intersect point, calculate the distance along extension line from end of dangle
    # Would be nicer to do this in the database but SQLite dosen't support sqrt or exponents
    grass.info(
        "Calculating distances of intersects along potential extensions")
    cur = table_isectIn.execute(
        sql_code="SELECT rowid, from_x, from_y, nx, ny FROM isectIn")
    for row in cur.fetchall():
        rowid, fx, fy, nx, ny = row
        x_len = math.sqrt((fx - nx)**2 + (fy - ny)**2)
        sqlStr = "UPDATE isectIn SET ext_len={:.8f} WHERE rowid={:d}".format(
            x_len, rowid)
        table_isectIn.execute(sql_code=sqlStr)
    grass.verbose("Ready to commit isectIn changes")
    table_isectIn.conn.commit()
    # Remove any zero distance from end of their dangle.
    # This happens when another extension intersects exactly at that point
    run_command("db.execute",
                sql="DELETE FROM isectIn WHERE ext_len = 0.0",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    table_isectIn.conn.commit()

    # Go through the extensions and find the intersect closest to each origin.
    grass.info("Searching for closest intersect for each potential extension")

    # db.execute sql="ALTER TABLE extend_t1 ADD COLUMN bst INTEGER"
    # db.execute sql="ALTER TABLE extend_t1 ADD COLUMN nrx DOUBLE PRECISION"
    # db.execute sql="ALTER TABLE extend_t1 ADD COLUMN nry DOUBLE PRECISION"
    # db.execute sql="ALTER TABLE extend_t1 ADD COLUMN ocat TEXT"
    #    run_command("db.execute",
    #                sql = "INSERT OR REPLACE INTO extend_t1 (bst, nrx, nry, ocat) VALUES ((SELECT isectIn.rowid, ext_len, nx, ny, near_cat, ntype FROM isectIn WHERE from_cat=extend_t1.cat ORDER BY ext_len ASC LIMIT 1))",
    #               driver = "sqlite",
    #               database = "$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")

    grass.verbose("CREATE index")
    run_command("db.execute",
                sql="CREATE INDEX idx_from_cat ON isectIn (from_cat)",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    grass.verbose("UPDATE best_xid")
    run_command(
        "db.execute",
        sql=
        "UPDATE extend SET best_xid = (SELECT isectIn.rowid FROM isectIn WHERE from_cat=extend.cat ORDER BY ext_len ASC LIMIT 1)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    grass.verbose("UPDATE x_len")
    run_command(
        "db.execute",
        sql=
        "UPDATE extend SET x_len = (SELECT ext_len FROM isectIn WHERE from_cat=extend.cat ORDER BY ext_len ASC LIMIT 1)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    grass.verbose("UPDATE near_x")
    run_command(
        "db.execute",
        sql=
        "UPDATE extend SET near_x = (SELECT nx FROM isectIn WHERE from_cat=extend.cat ORDER BY ext_len ASC LIMIT 1)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    grass.verbose("UPDATE near_y")
    run_command(
        "db.execute",
        sql=
        "UPDATE extend SET near_y = (SELECT ny FROM isectIn WHERE from_cat=extend.cat ORDER BY ext_len ASC LIMIT 1)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    grass.verbose("UPDATE other_cat")
    run_command(
        "db.execute",
        sql=
        "UPDATE extend SET other_cat = (SELECT near_cat FROM isectIn WHERE from_cat=extend.cat ORDER BY ext_len ASC LIMIT 1)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    grass.verbose("UPDATE xtype")
    run_command(
        "db.execute",
        sql=
        "UPDATE extend SET xtype = (SELECT ntype FROM isectIn WHERE from_cat=extend.cat ORDER BY ext_len ASC LIMIT 1)",
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    grass.verbose("DROP index")
    run_command("db.execute",
                sql="DROP INDEX idx_from_cat",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    grass.verbose("CREATE index on near_cat")
    run_command("db.execute",
                sql="CREATE INDEX idx_near_cat ON isectIn (near_cat)",
                driver="sqlite",
                database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")

    quiet = table_isectIn.filters.select('rowid', 'ext_len', 'nx', 'ny',
                                         'near_cat', 'ntype')
    #    quiet=table_isectIn.filters.order_by(['ext_len ASC'])
    quiet = table_isectIn.filters.order_by('ext_len ASC')
    quiet = table_isectIn.filters.limit(1)
    table_extend = Table('extend', connection=sqlite3.connect(get_path(path)))

    # Code below was relplaced by commands above untill memory problem can be sorted
    #    table_extend.filters.select('cat')
    #    cur=table_extend.execute()
    #    updateCnt = 0
    #    for row in cur.fetchall():
    #        cat, = row
    #        quiet=table_isectIn.filters.where('from_cat={:d}'.format(cat))

    ##SELECT rowid, ext_len, nx, ny, near_cat, ntype FROM isectIn WHERE from_cat=32734 ORDER BY ext_len ASC LIMIT 1

    #        x_sect=table_isectIn.execute().fetchone()
    #        if x_sect is not None:
    #            x_rowid, ext_len, nx, ny, other_cat, ntype = x_sect
    #            sqlStr="UPDATE extend SET best_xid={:d}, x_len={:.8f}, near_x={:.8f}, near_y={:.8f}, other_cat={:d}, xtype='{}' WHERE cat={:d}".format(x_rowid, ext_len, nx, ny, other_cat, ntype, cat)
    #            table_extend.execute(sql_code=sqlStr)
    ## Try periodic commit to avoide crash!
    #            updateCnt = (updateCnt + 1) % 10000
    #            if updateCnt == 0:
    #              table_extend.conn.commit()
    grass.verbose("Ready to commit extend changes")
    table_extend.conn.commit()
    #
    # There may be extensions that crossed, and that intersection chosen by one but
    # not "recripricated" by the other.
    # Need to remove those possibilities and allow the jilted extension to re-search.
    #
    grass.verbose("Deleting intersects already resolved")
    run_command(
        "db.execute",
        sql=
        "DELETE FROM isectIn WHERE rowid IN (SELECT isectIn.rowid FROM isectIn JOIN extend ON near_cat=cat WHERE ntype='ext' AND xtype!='null')",  #"AND from_cat!=other_cat" no second chance!
        driver="sqlite",
        database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db")
    table_isectIn.conn.commit()
    grass.verbose("Deleting complete")

    # To find the jilted - need a copy of extensions that have found an
    # intersection (won't overwrite so drop first)
    grass.verbose(
        "Re-searching for mis-matched intersects between potential extensions")
    table_imatch = Table('imatch', connection=sqlite3.connect(get_path(path)))
    if table_imatch.exist():
        table_imatch.drop(force=True)
    wvar = "xtype!='null'"
    run_command(
        "db.copy",
        overwrite=True,
        quiet=True,
        from_driver="sqlite",
        from_database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db",
        from_table="extend",
        to_driver="sqlite",
        to_database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db",
        to_table="imatch",
        where=wvar)
    # Memory problems?
    if gc.isenabled():
        grass.verbose("Garbage collection enabled - forcing gc cycle")
        gc.collect()
    else:
        grass.verbose("Garbage collection not enabled")
# Ensure tables are commited
    table_extend.conn.commit()
    table_imatch.conn.commit()
    table_isectIn.conn.commit()
    # Identify the jilted
    sqlStr = "SELECT extend.cat FROM extend JOIN imatch ON extend.other_cat=imatch.cat WHERE extend.xtype='ext' and extend.cat!=imatch.other_cat"
    cur = table_extend.execute(sql_code=sqlStr)
    updateCnt = 0
    for row in cur.fetchall():
        cat, = row
        grass.verbose("Reworking extend.cat={}".format(cat))
        quiet = table_isectIn.filters.where('from_cat={:d}'.format(cat))
        #print("SQL: {}".format(table_isectIn.filters.get_sql()))
        x_sect = table_isectIn.execute().fetchone(
        )  ## Problem here under modules
        if x_sect is None:
            sqlStr = "UPDATE extend SET best_xid=0, x_len=search_len, near_x=0, near_y=0, other_cat=0, xtype='null' WHERE cat={:d}".format(
                cat)
        else:
            x_rowid, ext_len, nx, ny, other_cat, ntype = x_sect
            sqlStr = "UPDATE extend SET best_xid={:d}, x_len={:.8f}, near_x={:.8f}, near_y={:.8f}, other_cat={:d}, xtype='{}' WHERE cat={:d}".format(
                x_rowid, ext_len, nx, ny, other_cat, ntype, cat)
        table_extend.execute(sql_code=sqlStr)
        ## Try periodic commit to avoide crash!
        updateCnt = (updateCnt + 1) % 100
        if (updateCnt == 0):  # or (cat == 750483):
            grass.verbose(
                "XXXXXXXXXXX Committing table_extend XXXXXXXXXXXXXXXXXXXXXX")
            table_extend.conn.commit()

    grass.verbose("Committing adjustments to table extend")
    table_extend.conn.commit()
    #
    # For debugging, create a map with the chosen intersect points
    #
    if debug:
        wvar = "xtype!='null' AND x_len!=0"
        #        print(wvar)
        run_command(
            "v.in.db",
            overwrite=True,
            quiet=True,
            table="extend",
            driver="sqlite",
            database="$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db",
            x="near_x",
            y="near_y",
            key="cat",
            where=wvar,
            output="chosen")
#
# Finally adjust the dangle lines in input map - use a copy (map_out) if requested
#
    if map_out:
        run_command("g.copy",
                    overwrite=allowOverwrite,
                    quiet=True,
                    vector=map + "," + map_out)
    else:  # Otherwise just modify the original dataset (map)
        if allowOverwrite:
            grass.warning("Modifying vector map ({})".format(map))
            map_out = map
        else:
            grass.error(
                "Use switch --o to modifying input vector map ({})".format(
                    map))
            return 1
#
# Get info for lines that need extending
    table_extend.filters.select(
        'parent, dend, near_x, near_y, search_az, xtype')
    table_extend.filters.where("xtype!='null'")
    extLines = table_extend.execute().fetchall()
    cat_mods = [ext[0] for ext in extLines]
    tickLen = len(cat_mods)
    grass.info("Extending {} dangles".format(tickLen))
    ticker = 0
    grass.message("Percent complete...")

    # Open up the map_out copy (or the original) and work through looking for lines that need modifying
    inMap = VectorTopo(map_out)
    inMap.open('rw', tab_name=map_out)

    for ln_idx in range(len(inMap)):
        ln = inMap.read(ln_idx + 1)
        if ln.gtype == 2:  # Only process lines
            while ln.cat in cat_mods:  # Note: could be 'head' and 'tail'
                ticker = (ticker + 1)
                grass.percent(ticker, tickLen, 5)
                cat_idx = cat_mods.index(ln.cat)
                cat, dend, nx, ny, endaz, xtype = extLines.pop(cat_idx)
                dump = cat_mods.pop(cat_idx)
                if xtype == 'orig':  # Overshoot by 0.1 as break lines is unreliable
                    nx = nx + 0.1 * math.cos(endaz)
                    ny = ny + 0.1 * math.sin(endaz)
                newEnd = geo.Point(x=nx, y=ny, z=None)
                if dend == 'head':
                    ln.insert(0, newEnd)
                else:  # 'tail'
                    ln.append(newEnd)
                quiet = inMap.rewrite(ln_idx + 1, ln)
        else:
            quite = inMap.delete(ln_idx + 1)


## Try periodic commit and garbage collection to avoide crash!
        if (ln_idx % 1000) == 0:
            #           inMap.table.conn.commit()  - no such thing - Why??
            if gc.isenabled():
                quiet = gc.collect()

    inMap.close(build=True, release=True)
    grass.message("v.extendlines completing")
    #
    # Clean up temporary tables and maps
    #
    if not debug:
        table_isectIn.drop(force=True)
        table_isectX.drop(force=True)
        table_imatch.drop(force=True)
        extend.remove()
        chosen = VectorTopo('chosen')
        if chosen.exist():
            chosen.remove()
    return 0
Exemplo n.º 4
0
def main():
    inputraster = options['input']
    number_lines = int(options['number_lines'])
    edge_detection_algorithm = options['edge_detection']
    no_edge_friction = int(options['no_edge_friction'])
    lane_border_multiplier = int(options['lane_border_multiplier'])
    min_tile_size = None
    if options['min_tile_size']:
        min_tile_size = float(options['min_tile_size'])
    existing_cutlines = None
    if options['existing_cutlines']:
        existing_cutlines = options['existing_cutlines'].split(',')
    tiles = options['output']
    memory = int(options['memory'])
    tiled = False

    if options['tile_width']:
        tiled = True
        gscript.message(_("Using tiles processing for edge detection"))
        width = int(options['tile_width'])
        height = int(options['tile_height'])
        overlap = int(options['overlap'])

    processes = int(options['processes'])

    global temp_maps
    temp_maps = []
    r = 'raster'
    v = 'vector'

    if existing_cutlines:
        existingcutlinesmap = 'temp_icutlines_existingcutlinesmap_%i' % os.getpid(
        )
        if len(existing_cutlines) > 1:
            gscript.run_command('v.patch',
                                input_=existing_cutlines,
                                output=existingcutlinesmap,
                                quiet=True,
                                overwrite=True)
            existing_cutlines = existingcutlinesmap

        gscript.run_command('v.to.rast',
                            input_=existing_cutlines,
                            output=existingcutlinesmap,
                            use='val',
                            type_='line,boundary',
                            overwrite=True,
                            quiet=True)

        temp_maps.append([existingcutlinesmap, r])

    temp_edge_map = "temp_icutlines_edgemap_%d" % os.getpid()
    temp_maps.append([temp_edge_map, r])

    gscript.message(
        _("Creating edge map using <%s> edgedetection algorithm") %
        edge_detection_algorithm)
    if edge_detection_algorithm == 'zc':
        kwargs = {
            'input': inputraster,
            'output': temp_edge_map,
            'width_': int(options['zc_width']),
            'threshold': float(options['zc_threshold']),
            'quiet': True
        }

        if tiled:
            grd = GridModule('i.zc',
                             width=width,
                             height=height,
                             overlap=overlap,
                             processes=processes,
                             split=False,
                             **kwargs)
            grd.run()
        else:
            gscript.run_command('i.zc', **kwargs)

    elif edge_detection_algorithm == 'canny':
        if not gscript.find_program('i.edge', '--help'):
            message = _("You need to install the addon i.edge to use ")
            message += _("the Canny edge detector.\n")
            message += _(
                " You can install the addon with 'g.extension i.edge'")
            gscript.fatal(message)

        kwargs = {
            'input': inputraster,
            'output': temp_edge_map,
            'low_threshold': float(options['canny_low_threshold']),
            'high_threshold': float(options['canny_high_threshold']),
            'sigma': float(options['canny_sigma']),
            'quiet': True
        }

        if tiled:
            grd = GridModule('i.edge',
                             width=width,
                             height=height,
                             overlap=overlap,
                             processes=processes,
                             split=False,
                             flags='n',
                             **kwargs)
            grd.run()
        else:
            gscript.run_command('i.edge', flags='n', **kwargs)

    else:
        gscript.fatal(
            "Only zero-crossing and Canny available as edge detection algorithms."
        )

    region = gscript.region()
    gscript.message(_("Finding cutlines in both directions"))

    nsrange = float(region.n - region.s - region.nsres)
    ewrange = float(region.e - region.w - region.ewres)

    if nsrange > ewrange:
        hnumber_lines = number_lines
        vnumber_lines = max(int(number_lines * (ewrange / nsrange)), 1)
    else:
        vnumber_lines = number_lines
        hnumber_lines = max(int(number_lines * (nsrange / ewrange)), 1)

    # Create the lines in horizonal direction
    nsstep = float(region.n - region.s - region.nsres) / hnumber_lines
    hpointsy = [((region.n - i * nsstep) - region.nsres / 2.0)
                for i in range(0, hnumber_lines + 1)]
    hlanepointsy = [y - nsstep / 2.0 for y in hpointsy]
    hstartpoints = listzip([region.w + 0.2 * region.ewres] * len(hpointsy),
                           hpointsy)
    hstoppoints = listzip([region.e - 0.2 * region.ewres] * len(hpointsy),
                          hpointsy)
    hlanestartpoints = listzip([region.w + 0.2 * region.ewres] *
                               len(hlanepointsy), hlanepointsy)
    hlanestoppoints = listzip([region.e - 0.2 * region.ewres] *
                              len(hlanepointsy), hlanepointsy)

    hlanemap = 'temp_icutlines_hlanemap_%i' % os.getpid()
    temp_maps.append([hlanemap, v])
    temp_maps.append([hlanemap, r])

    os.environ['GRASS_VERBOSE'] = '0'
    new = VectorTopo(hlanemap)
    new.open('w')
    for line in listzip(hlanestartpoints, hlanestoppoints):
        new.write(geom.Line(line), cat=1)
    new.close()
    del os.environ['GRASS_VERBOSE']

    gscript.run_command('v.to.rast',
                        input_=hlanemap,
                        output=hlanemap,
                        use='val',
                        type_='line',
                        overwrite=True,
                        quiet=True)

    hbasemap = 'temp_icutlines_hbasemap_%i' % os.getpid()
    temp_maps.append([hbasemap, r])

    # Building the cost maps using the following logic
    # - Any pixel not on an edge, nor on an existing cutline gets a
    # no_edge_friction cost, or no_edge_friction_cost x 10  if there are
    # existing cutlines
    # - Any pixel on an edge gets a cost of 1 if there are no existing cutlines,
    # and a cost of no_edge_friction if there are
    # - A lane line gets a very high cost (lane_border_multiplier x cost of no
    # edge pixel - the latter depending on the existence of cutlines).

    mapcalc_expression = "%s = " % hbasemap
    mapcalc_expression += "if(isnull(%s), " % hlanemap
    if existing_cutlines:
        mapcalc_expression += "if(%s == 0 && isnull(%s), " % (
            temp_edge_map, existingcutlinesmap)
        mapcalc_expression += "%i, " % (no_edge_friction * 10)
        mapcalc_expression += "if(isnull(%s), %s, 1))," % (existingcutlinesmap,
                                                           no_edge_friction)
        mapcalc_expression += "%i)" % (lane_border_multiplier *
                                       no_edge_friction * 10)
    else:
        mapcalc_expression += "if(%s == 0, " % temp_edge_map
        mapcalc_expression += "%i, " % no_edge_friction
        mapcalc_expression += "1), "
        mapcalc_expression += "%i)" % (lane_border_multiplier *
                                       no_edge_friction)
    gscript.run_command('r.mapcalc',
                        expression=mapcalc_expression,
                        quiet=True,
                        overwrite=True)

    hcumcost = 'temp_icutlines_hcumcost_%i' % os.getpid()
    temp_maps.append([hcumcost, r])
    hdir = 'temp_icutlines_hdir_%i' % os.getpid()
    temp_maps.append([hdir, r])

    # Create the lines in vertical direction
    ewstep = float(region.e - region.w - region.ewres) / vnumber_lines
    vpointsx = [((region.e - i * ewstep) - region.ewres / 2.0)
                for i in range(0, vnumber_lines + 1)]
    vlanepointsx = [x + ewstep / 2.0 for x in vpointsx]
    vstartpoints = listzip(vpointsx,
                           [region.n - 0.2 * region.nsres] * len(vpointsx))
    vstoppoints = listzip(vpointsx,
                          [region.s + 0.2 * region.nsres] * len(vpointsx))
    vlanestartpoints = listzip(vlanepointsx, [region.n - 0.2 * region.nsres] *
                               len(vlanepointsx))
    vlanestoppoints = listzip(vlanepointsx, [region.s + 0.2 * region.nsres] *
                              len(vlanepointsx))

    vlanemap = 'temp_icutlines_vlanemap_%i' % os.getpid()
    temp_maps.append([vlanemap, v])
    temp_maps.append([vlanemap, r])

    os.environ['GRASS_VERBOSE'] = '0'
    new = VectorTopo(vlanemap)
    new.open('w')
    for line in listzip(vlanestartpoints, vlanestoppoints):
        new.write(geom.Line(line), cat=1)
    new.close()
    del os.environ['GRASS_VERBOSE']

    gscript.run_command('v.to.rast',
                        input_=vlanemap,
                        output=vlanemap,
                        use='val',
                        type_='line',
                        overwrite=True,
                        quiet=True)

    vbasemap = 'temp_icutlines_vbasemap_%i' % os.getpid()
    temp_maps.append([vbasemap, r])
    mapcalc_expression = "%s = " % vbasemap
    mapcalc_expression += "if(isnull(%s), " % vlanemap
    if existing_cutlines:
        mapcalc_expression += "if(%s == 0 && isnull(%s), " % (
            temp_edge_map, existingcutlinesmap)
        mapcalc_expression += "%i, " % (no_edge_friction * 10)
        mapcalc_expression += "if(isnull(%s), %s, 1))," % (existingcutlinesmap,
                                                           no_edge_friction)
        mapcalc_expression += "%i)" % (lane_border_multiplier *
                                       no_edge_friction * 10)
    else:
        mapcalc_expression += "if(%s == 0, " % temp_edge_map
        mapcalc_expression += "%i, " % no_edge_friction
        mapcalc_expression += "1), "
        mapcalc_expression += "%i)" % (lane_border_multiplier *
                                       no_edge_friction)
    gscript.run_command('r.mapcalc',
                        expression=mapcalc_expression,
                        quiet=True,
                        overwrite=True)

    vcumcost = 'temp_icutlines_vcumcost_%i' % os.getpid()
    temp_maps.append([vcumcost, r])
    vdir = 'temp_icutlines_vdir_%i' % os.getpid()
    temp_maps.append([vdir, r])

    if processes > 1:
        pmemory = memory / 2.0
        rcv = gscript.start_command('r.cost',
                                    input_=vbasemap,
                                    startcoordinates=vstartpoints,
                                    stopcoordinates=vstoppoints,
                                    output=vcumcost,
                                    outdir=vdir,
                                    memory=pmemory,
                                    quiet=True,
                                    overwrite=True)

        rch = gscript.start_command('r.cost',
                                    input_=hbasemap,
                                    startcoordinates=hstartpoints,
                                    stopcoordinates=hstoppoints,
                                    output=hcumcost,
                                    outdir=hdir,
                                    memory=pmemory,
                                    quiet=True,
                                    overwrite=True)
        rcv.wait()
        rch.wait()

    else:
        gscript.run_command('r.cost',
                            input_=vbasemap,
                            startcoordinates=vstartpoints,
                            stopcoordinates=vstoppoints,
                            output=vcumcost,
                            outdir=vdir,
                            memory=memory,
                            quiet=True,
                            overwrite=True)

        gscript.run_command('r.cost',
                            input_=hbasemap,
                            startcoordinates=hstartpoints,
                            stopcoordinates=hstoppoints,
                            output=hcumcost,
                            outdir=hdir,
                            memory=memory,
                            quiet=True,
                            overwrite=True)

    hlines = 'temp_icutlines_hlines_%i' % os.getpid()
    temp_maps.append([hlines, r])
    vlines = 'temp_icutlines_vlines_%i' % os.getpid()
    temp_maps.append([vlines, r])

    if processes > 1:
        rdh = gscript.start_command('r.drain',
                                    input_=hcumcost,
                                    direction=hdir,
                                    startcoordinates=hstoppoints,
                                    output=hlines,
                                    flags='d',
                                    quiet=True,
                                    overwrite=True)

        rdv = gscript.start_command('r.drain',
                                    input_=vcumcost,
                                    direction=vdir,
                                    startcoordinates=vstoppoints,
                                    output=vlines,
                                    flags='d',
                                    quiet=True,
                                    overwrite=True)

        rdh.wait()
        rdv.wait()

    else:
        gscript.run_command('r.drain',
                            input_=hcumcost,
                            direction=hdir,
                            startcoordinates=hstoppoints,
                            output=hlines,
                            flags='d',
                            quiet=True,
                            overwrite=True)

        gscript.run_command('r.drain',
                            input_=vcumcost,
                            direction=vdir,
                            startcoordinates=vstoppoints,
                            output=vlines,
                            flags='d',
                            quiet=True,
                            overwrite=True)

    # Combine horizonal and vertical lines
    temp_raster_tile_borders = 'temp_icutlines_raster_tile_borders_%i' % os.getpid(
    )
    temp_maps.append([temp_raster_tile_borders, r])
    gscript.run_command('r.patch',
                        input_=[hlines, vlines],
                        output=temp_raster_tile_borders,
                        quiet=True,
                        overwrite=True)

    gscript.message(_("Creating vector polygons"))

    # Create vector polygons

    # First we need to shrink the region a bit to make sure that all vector
    # points / lines fall within the raster
    gscript.use_temp_region()
    gscript.run_command('g.region',
                        s=region.s + region.nsres,
                        e=region.e - region.ewres,
                        quiet=True)

    region_map = 'temp_icutlines_region_map_%i' % os.getpid()
    temp_maps.append([region_map, v])
    temp_maps.append([region_map, r])
    gscript.run_command('v.in.region',
                        output=region_map,
                        type_='line',
                        quiet=True,
                        overwrite=True)

    gscript.del_temp_region()

    gscript.run_command('v.to.rast',
                        input_=region_map,
                        output=region_map,
                        use='val',
                        type_='line',
                        quiet=True,
                        overwrite=True)

    temp_raster_polygons = 'temp_icutlines_raster_polygons_%i' % os.getpid()
    temp_maps.append([temp_raster_polygons, r])
    gscript.run_command('r.patch',
                        input_=[temp_raster_tile_borders, region_map],
                        output=temp_raster_polygons,
                        quiet=True,
                        overwrite=True)

    temp_raster_polygons_thin = 'temp_icutlines_raster_polygons_thin_%i' % os.getpid(
    )
    temp_maps.append([temp_raster_polygons_thin, r])
    gscript.run_command('r.thin',
                        input_=temp_raster_polygons,
                        output=temp_raster_polygons_thin,
                        quiet=True,
                        overwrite=True)

    # Create a series of temporary map names as we have to go
    # through several steps until we reach the final map.
    temp_vector_polygons1 = 'temp_icutlines_vector_polygons1_%i' % os.getpid()
    temp_maps.append([temp_vector_polygons1, v])
    temp_vector_polygons2 = 'temp_icutlines_vector_polygons2_%i' % os.getpid()
    temp_maps.append([temp_vector_polygons2, v])
    temp_vector_polygons3 = 'temp_icutlines_vector_polygons3_%i' % os.getpid()
    temp_maps.append([temp_vector_polygons3, v])
    temp_vector_polygons4 = 'temp_icutlines_vector_polygons4_%i' % os.getpid()
    temp_maps.append([temp_vector_polygons4, v])

    gscript.run_command('r.to.vect',
                        input_=temp_raster_polygons_thin,
                        output=temp_vector_polygons1,
                        type_='line',
                        flags='t',
                        quiet=True,
                        overwrite=True)

    # Erase all category values from the lines
    gscript.run_command('v.category',
                        input_=temp_vector_polygons1,
                        op='del',
                        cat='-1',
                        output=temp_vector_polygons2,
                        quiet=True,
                        overwrite=True)

    # Transform lines to boundaries
    gscript.run_command('v.type',
                        input_=temp_vector_polygons2,
                        from_type='line',
                        to_type='boundary',
                        output=temp_vector_polygons3,
                        quiet=True,
                        overwrite=True)

    # Add centroids
    gscript.run_command('v.centroids',
                        input_=temp_vector_polygons3,
                        output=temp_vector_polygons4,
                        quiet=True,
                        overwrite=True)

    # If a threshold is given erase polygons that are too small
    if min_tile_size:
        gscript.run_command('v.clean',
                            input_=temp_vector_polygons4,
                            tool=['rmdangle', 'rmarea'],
                            threshold=[-1, min_tile_size],
                            output=tiles,
                            quiet=True,
                            overwrite=True)
    else:
        gscript.run_command('g.copy',
                            vect=[temp_vector_polygons4, tiles],
                            quiet=True,
                            overwrite=True)

    gscript.vector_history(tiles)
Exemplo n.º 5
0
def main():

    input = options["input"]
    if options["refline"]:
        refline_cat = int(options["refline"])
    else:
        refline_cat = None
    nb_vertices = int(options["vertices"])
    if options["range"]:
        search_range = float(options["range"])
    else:
        search_range = None
    output = options["output"]
    transversals = flags["t"]
    median = flags["m"]

    global tmp_points_map
    global tmp_centerpoints_map
    global tmp_line_map
    global tmp_cleaned_map
    global tmp_map
    tmp_points_map = "points_map_tmp_%d" % os.getpid()
    tmp_centerpoints_map = "centerpoints_map_tmp_%d" % os.getpid()
    tmp_line_map = "line_map_tmp_%d" % os.getpid()
    tmp_cleaned_map = "cleaned_map_tmp_%d" % os.getpid()
    tmp_map = "generaluse_map_tmp_%d" % os.getpid()

    nb_lines = grass.vector_info_topo(input)["lines"]

    # Find best reference line and max distance between centerpoints of lines
    segment_input = ""
    categories = grass.read_command("v.category",
                                    input=input,
                                    option="print",
                                    quiet=True).splitlines()
    for category in categories:
        segment_input += "P {}".format(category.strip())
        segment_input += " {} {}".format(category.strip(), " 50%")
        segment_input += os.linesep

    grass.write_command(
        "v.segment",
        input=input,
        output=tmp_centerpoints_map,
        rules="-",
        stdin=segment_input,
        quiet=True,
    )

    center_distances = grass.read_command(
        "v.distance",
        from_=tmp_centerpoints_map,
        to=tmp_centerpoints_map,
        upload="dist",
        flags="pa",
        quiet=True,
    ).splitlines()

    cats = []
    mean_dists = []
    count = 0
    distmax = 0
    for center in center_distances:
        if count < 2:
            count += 1
            continue
        cat = center.strip().split("|")[0]
        distsum = 0
        for x in center.strip().split("|")[1:]:
            distsum += float(x)
        mean_dist = distsum / len(center.strip().split("|")[1:])
        cats.append(cat)
        mean_dists.append(mean_dist)

    if transversals and not search_range:
        search_range = sum(mean_dists) / len(mean_dists)
        grass.message(_("Calculated search range:  %.5f." % search_range))

    if not refline_cat:
        refline_cat = sorted(zip(cats, mean_dists),
                             key=lambda tup: tup[1])[0][0]

        grass.message(
            _("Category number of chosen reference line: %s." % refline_cat))

    # Use transversals algorithm
    if transversals:

        # Break any intersections in the original lines so that
        # they do not interfere further on
        grass.run_command("v.clean",
                          input=input,
                          output=tmp_cleaned_map,
                          tool="break",
                          quiet=True)

        xmean = []
        ymean = []
        xmedian = []
        ymedian = []
        step = 100.0 / nb_vertices

        os.environ["GRASS_VERBOSE"] = "-1"

        for vertice in range(0, nb_vertices + 1):
            # v.segment sometimes cannot find points when
            # using 0% or 100% offset
            length_offset = step * vertice
            if length_offset < 0.00001:
                length_offset = 0.00001
            if length_offset > 99.99999:
                length_offset = 99.9999
            # Create endpoints of transversal
            segment_input = "P 1 %s %.5f%% %f\n" % (
                refline_cat,
                length_offset,
                search_range,
            )
            segment_input += "P 2 %s %.5f%% %f\n" % (
                refline_cat,
                length_offset,
                -search_range,
            )
            grass.write_command(
                "v.segment",
                input=input,
                output=tmp_points_map,
                stdin=segment_input,
                overwrite=True,
            )

            # Create transversal
            grass.write_command(
                "v.net",
                points=tmp_points_map,
                output=tmp_line_map,
                operation="arcs",
                file="-",
                stdin="99999 1 2",
                overwrite=True,
            )

            # Patch transversal onto cleaned input lines
            maps = tmp_cleaned_map + "," + tmp_line_map
            grass.run_command("v.patch",
                              input=maps,
                              out=tmp_map,
                              overwrite=True)

            # Find intersections
            grass.run_command(
                "v.clean",
                input=tmp_map,
                out=tmp_line_map,
                tool="break",
                error=tmp_points_map,
                overwrite=True,
            )

            # Add categories to intersection points
            grass.run_command(
                "v.category",
                input=tmp_points_map,
                out=tmp_map,
                op="add",
                overwrite=True,
            )

            # Get coordinates of points
            coords = grass.read_command("v.to.db",
                                        map=tmp_map,
                                        op="coor",
                                        flags="p").splitlines()

            count = 0
            x = []
            y = []
            for coord in coords:
                x.append(float(coord.strip().split("|")[1]))
                y.append(float(coord.strip().split("|")[2]))

            # Calculate mean and median for this transversal
            if len(x) > 0:
                xmean.append(sum(x) / len(x))
                ymean.append(sum(y) / len(y))

                x.sort()
                y.sort()

                xmedian.append((x[(len(x) - 1) // 2] + x[(len(x)) // 2]) / 2)
                ymedian.append((y[(len(y) - 1) // 2] + y[(len(y)) // 2]) / 2)

        del os.environ["GRASS_VERBOSE"]

    # Use closest point algorithm
    else:

        # Get reference line calculate its length
        grass.run_command("v.extract",
                          input=input,
                          output=tmp_line_map,
                          cats=refline_cat,
                          quiet=True)

        os.environ["GRASS_VERBOSE"] = "0"
        lpipe = grass.read_command("v.to.db",
                                   map=tmp_line_map,
                                   op="length",
                                   flags="p").splitlines()
        del os.environ["GRASS_VERBOSE"]

        for l in lpipe:
            linelength = float(l.strip().split("|")[1])

        step = linelength / nb_vertices

        # Create reference points for vertice calculation
        grass.run_command(
            "v.to.points",
            input=tmp_line_map,
            output=tmp_points_map,
            dmax=step,
            quiet=True,
        )

        nb_points = grass.vector_info_topo(tmp_points_map)["points"]

        cat = []
        x = []
        y = []

        # Get coordinates of closest points on all input lines
        if search_range:
            points = grass.read_command(
                "v.distance",
                from_=tmp_points_map,
                from_layer=2,
                to=input,
                upload="to_x,to_y",
                dmax=search_range,
                flags="pa",
                quiet=True,
            ).splitlines()
        else:
            points = grass.read_command(
                "v.distance",
                from_=tmp_points_map,
                from_layer=2,
                to=input,
                upload="to_x,to_y",
                flags="pa",
                quiet=True,
            ).splitlines()

        firstline = True
        for point in points:
            if firstline:
                firstline = False
                continue
            cat.append((int(point.strip().split("|")[0])))
            x.append(float(point.strip().split("|")[2]))
            y.append(float(point.strip().split("|")[3]))

        # Calculate mean coordinates
        xsum = [0] * nb_points
        ysum = [0] * nb_points
        linecount = [0] * nb_points

        for i in range(len(cat)):
            index = cat[i] - 1
            linecount[index] += 1
            xsum[index] = xsum[index] + x[i]
            ysum[index] = ysum[index] + y[i]

        xmean = [0] * nb_points
        ymean = [0] * nb_points

        for c in range(0, nb_points):
            xmean[c] = xsum[c] / linecount[c]
            ymean[c] = ysum[c] / linecount[c]

        # Calculate the median

        xmedian = [0] * nb_points
        ymedian = [0] * nb_points

        for c in range(0, nb_points):
            xtemp = []
            ytemp = []
            for i in range(len(cat)):
                if cat[i] == c + 1:
                    xtemp.append(x[i])
                    ytemp.append(y[i])
            xtemp.sort()
            ytemp.sort()
            xmedian[c] = (xtemp[(len(xtemp) - 1) // 2] +
                          xtemp[(len(xtemp)) // 2]) / 2
            ymedian[c] = (ytemp[(len(ytemp) - 1) // 2] +
                          ytemp[(len(ytemp)) // 2]) / 2

    # Create new line and write to file
    if median and nb_lines > 2:
        line = geo.Line(list(zip(xmedian, ymedian)))
    else:
        if median and nb_lines <= 2:
            grass.message(
                _("More than 2 lines necesary for median, using mean."))
        line = geo.Line(list(zip(xmean, ymean)))

    new = VectorTopo(output)
    new.open("w")

    new.write(line)
    new.close()
Exemplo n.º 6
0
def main():

    input = options['input']
    if options['refline']:
        refline_cat = int(options['refline'])
    else:
        refline_cat = None
    nb_vertices = int(options['vertices'])
    if options['range']:
        search_range = float(options['range'])
    else:
        search_range = None
    output = options['output']
    transversals = flags['t']
    median = flags['m']

    global tmp_points_map
    global tmp_centerpoints_map
    global tmp_line_map
    global tmp_cleaned_map
    global tmp_map
    tmp_points_map = 'points_map_tmp_%d' % os.getpid()
    tmp_centerpoints_map = 'centerpoints_map_tmp_%d' % os.getpid()
    tmp_line_map = 'line_map_tmp_%d' % os.getpid()
    tmp_cleaned_map = 'cleaned_map_tmp_%d' % os.getpid()
    tmp_map = 'generaluse_map_tmp_%d' % os.getpid()

    nb_lines = grass.vector_info_topo(input)['lines']

    # Find best reference line and max distance between centerpoints of lines
    segment_input = ''
    categories = grass.pipe_command('v.category',
                                    input=input,
                                    option='print',
                                    quiet=True)
    for category in categories.stdout:
        segment_input += 'P ' + category.strip()
        segment_input += ' ' + category.strip() + ' 50%\n'

    grass.write_command('v.segment',
                        input=input,
                        output=tmp_centerpoints_map,
                        rules='-',
                        stdin=segment_input,
                        quiet=True)

    center_distances = grass.pipe_command('v.distance',
                                          from_=tmp_centerpoints_map,
                                          to=tmp_centerpoints_map,
                                          upload='dist',
                                          flags='pa',
                                          quiet=True)

    cats = []
    mean_dists = []
    count = 0
    distmax = 0
    for center in center_distances.stdout:
        if count < 2:
            count += 1
            continue
        cat = center.strip().split('|')[0]
        distsum = 0
        for x in center.strip().split('|')[1:]:
            distsum += float(x)
        mean_dist = distsum / len(center.strip().split('|')[1:])
        cats.append(cat)
        mean_dists.append(mean_dist)

    if transversals and not search_range:
        search_range = sum(mean_dists) / len(mean_dists)
        grass.message(_("Calculated search range:  %.5f." % search_range))

    if not refline_cat:
        refline_cat = sorted(zip(cats, mean_dists),
                             key=lambda tup: tup[1])[0][0]

        grass.message(
            _("Category number of chosen reference line: %s." % refline_cat))

    # Use transversals algorithm
    if transversals:

        # Break any intersections in the original lines so that
        # they do not interfere further on
        grass.run_command('v.clean',
                          input=input,
                          output=tmp_cleaned_map,
                          tool='break',
                          quiet=True)

        xmean = []
        ymean = []
        xmedian = []
        ymedian = []
        step = 100.0 / nb_vertices

        os.environ['GRASS_VERBOSE'] = '-1'

        for vertice in range(0, nb_vertices + 1):
            # v.segment sometimes cannot find points when
            # using 0% or 100% offset
            length_offset = step * vertice
            if length_offset < 0.00001:
                length_offset = 0.00001
            if length_offset > 99.99999:
                length_offset = 99.9999
            # Create endpoints of transversal
            segment_input = 'P 1 %s %.5f%% %f\n' % (refline_cat, length_offset,
                                                    search_range)
            segment_input += 'P 2 %s %.5f%% %f\n' % (
                refline_cat, length_offset, -search_range)
            grass.write_command('v.segment',
                                input=input,
                                output=tmp_points_map,
                                stdin=segment_input,
                                overwrite=True)

            # Create transversal
            grass.write_command('v.net',
                                points=tmp_points_map,
                                output=tmp_line_map,
                                operation='arcs',
                                file='-',
                                stdin='99999 1 2',
                                overwrite=True)

            # Patch transversal onto cleaned input lines
            maps = tmp_cleaned_map + ',' + tmp_line_map
            grass.run_command('v.patch',
                              input=maps,
                              out=tmp_map,
                              overwrite=True)

            # Find intersections
            grass.run_command('v.clean',
                              input=tmp_map,
                              out=tmp_line_map,
                              tool='break',
                              error=tmp_points_map,
                              overwrite=True)

            # Add categories to intersection points
            grass.run_command('v.category',
                              input=tmp_points_map,
                              out=tmp_map,
                              op='add',
                              overwrite=True)

            # Get coordinates of points
            coords = grass.pipe_command('v.to.db',
                                        map=tmp_map,
                                        op='coor',
                                        flags='p')

            count = 0
            x = []
            y = []
            for coord in coords.stdout:
                x.append(float(coord.strip().split('|')[1]))
                y.append(float(coord.strip().split('|')[2]))

            # Calculate mean and median for this transversal
            if len(x) > 0:
                xmean.append(sum(x) / len(x))
                ymean.append(sum(y) / len(y))

                x.sort()
                y.sort()

                xmedian.append((x[(len(x) - 1) / 2] + x[(len(x)) / 2]) / 2)
                ymedian.append((y[(len(y) - 1) / 2] + y[(len(y)) / 2]) / 2)

        del os.environ['GRASS_VERBOSE']

    # Use closest point algorithm
    else:

        # Get reference line calculate its length
        grass.run_command('v.extract',
                          input=input,
                          output=tmp_line_map,
                          cats=refline_cat,
                          quiet=True)

        os.environ['GRASS_VERBOSE'] = '0'
        lpipe = grass.pipe_command('v.to.db',
                                   map=tmp_line_map,
                                   op='length',
                                   flags='p')
        del os.environ['GRASS_VERBOSE']

        for l in lpipe.stdout:
            linelength = float(l.strip().split('|')[1])

        step = linelength / nb_vertices

        # Create reference points for vertice calculation
        grass.run_command('v.to.points',
                          input=tmp_line_map,
                          output=tmp_points_map,
                          dmax=step,
                          quiet=True)

        nb_points = grass.vector_info_topo(tmp_points_map)['points']

        cat = []
        x = []
        y = []

        # Get coordinates of closest points on all input lines
        if search_range:
            points = grass.pipe_command('v.distance',
                                        from_=tmp_points_map,
                                        from_layer=2,
                                        to=input,
                                        upload='to_x,to_y',
                                        dmax=search_range,
                                        flags='pa',
                                        quiet=True)
        else:
            points = grass.pipe_command('v.distance',
                                        from_=tmp_points_map,
                                        from_layer=2,
                                        to=input,
                                        upload='to_x,to_y',
                                        flags='pa',
                                        quiet=True)

        firstline = True
        for point in points.stdout:
            if firstline:
                firstline = False
                continue
            cat.append((int(point.strip().split('|')[0])))
            x.append(float(point.strip().split('|')[2]))
            y.append(float(point.strip().split('|')[3]))

        # Calculate mean coordinates
        xsum = [0] * nb_points
        ysum = [0] * nb_points
        linecount = [0] * nb_points

        for i in range(len(cat)):
            index = cat[i] - 1
            linecount[index] += 1
            xsum[index] = xsum[index] + x[i]
            ysum[index] = ysum[index] + y[i]

        xmean = [0] * nb_points
        ymean = [0] * nb_points

        for c in range(0, nb_points):
            xmean[c] = xsum[c] / linecount[c]
            ymean[c] = ysum[c] / linecount[c]

        # Calculate the median

        xmedian = [0] * nb_points
        ymedian = [0] * nb_points

        for c in range(0, nb_points):
            xtemp = []
            ytemp = []
            for i in range(len(cat)):
                if cat[i] == c + 1:
                    xtemp.append(x[i])
                    ytemp.append(y[i])
            xtemp.sort()
            ytemp.sort()
            xmedian[c] = (xtemp[(len(xtemp) - 1) / 2] +
                          xtemp[(len(xtemp)) / 2]) / 2
            ymedian[c] = (ytemp[(len(ytemp) - 1) / 2] +
                          ytemp[(len(ytemp)) / 2]) / 2

    # Create new line and write to file
    if median and nb_lines > 2:
        line = geo.Line(zip(xmedian, ymedian))
    else:
        if median and nb_lines <= 2:
            grass.message(
                _("More than 2 lines necesary for median, using mean."))
        line = geo.Line(zip(xmean, ymean))

    new = VectorTopo(output)
    new.open('w')

    new.write(line)
    new.close()