Esempio n. 1
0
def main():

    # Parse command line arguments
    parser = argparse.ArgumentParser(description=__doc__)

    utils.add_standard_command_options(parser)

    parser.add_argument(
        "-f", "--format", action="store", dest="format", default="ESRI Shapefile", help="Format of road network"
    )

    parser.add_argument("--inRoads", required=True, action="store", dest="inRoads", help="Input road network")

    parser.add_argument("--outRoads", required=True, action="store", dest="outRoads", help="Output road network")

    parser.add_argument(
        "--buildings", required=True, action="store", dest="buildings", help="Input building roof contours (3D)"
    )

    parser.add_argument("--topo", required=True, action="store", dest="topo", help="Input raster DEM")

    parser.add_argument(
        "--split",
        type=int,
        action="store",
        dest="split",
        help="Threshold in changed road direction (degrees)" + " for when to split road",
    )

    args = parser.parse_args()

    if not path.exists(args.topo):
        log.error("Input raster does not exist")
        sys.exit(1)

    if not path.exists(args.buildings):
        log.error("Input building contours does not exist")
        sys.exit(1)
        return 1

    log.info("Reading DEM")
    topo = readGDAL(args.topo, bandIndex=1)[0]

    # Opening driver for road networks
    try:
        driver = ogr.GetDriverByName(args.format)
    except:
        log.error("Invalid format for road networks, check ogr documentation")
        sys.exit(1)

    if args.split is None:
        log.info("Do not split roads")
        splitLimit = None
    else:
        splitLimit = float(args.split)
        log.info("Split roads that change direction" + " more than %f" % splitLimit)

    # extract extent from topo raster
    xmin = topo.xll
    ymin = topo.yll
    xmax = topo.xur()
    ymax = topo.yur()

    # Calculate dimensions of spatial index
    ncols = int((xmax - xmin) / CELLSIZE)
    nrows = int((ymax - ymin) / CELLSIZE)

    # Init spatial index of building contours
    spatInd = SpatialIndex(xmin, ymin, nrows, ncols, CELLSIZE)

    log.info("Reading and indexing building contours")
    # Read buildings and store using spatial indices
    spatInd.indexBuildingContours(args.buildings)

    # open road network shape-file
    log.info("Reading road network")
    inRoadFile = driver.Open(args.inRoads, update=0)

    if path.exists(args.outRoads):
        driver.DeleteDataSource(args.outRoads)

    outRoadFile = driver.CreateDataSource(args.outRoads)
    if inRoadFile is None:
        log.error("Could not open file with input road network")
        sys.exit(1)

    if outRoadFile is None:
        log.error("Could not open file with output road network")
        sys.exit(1)

    # Get layer definition and first feature of input road network
    inRoadLayer = inRoadFile.GetLayer()
    inRoadLayerDefn = inRoadLayer.GetLayerDefn()

    outRoadLayer = outRoadFile.CreateLayer("first_layer", geom_type=inRoadLayer.GetGeomType())

    # create fields on output road file
    for fieldInd in range(inRoadLayerDefn.GetFieldCount()):
        fieldDefn = inRoadLayerDefn.GetFieldDefn(fieldInd)
        outRoadLayer.CreateField(fieldDefn)

    outRoadLayerDefn = outRoadLayer.GetLayerDefn()
    fieldNames = [outRoadLayerDefn.GetFieldDefn(i).GetName() for i in range(outRoadLayerDefn.GetFieldCount())]

    log.info("Adding attributes to road feature (if missing)")
    # Add attributes for street canyon geometry
    if "BHGT1" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BHGT1", ogr.OFTInteger))
    if "BHGT2" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BHGT2", ogr.OFTInteger))
    if "BHGT1W" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BHGT1W", ogr.OFTInteger))
    if "BHGT2W" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BHGT2W", ogr.OFTInteger))
    if "BANG1" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BANG1", ogr.OFTInteger))
    if "BANG2" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BANG2", ogr.OFTInteger))
    if "BDIST" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BDIST", ogr.OFTInteger))
    if "BSECT" not in fieldNames:
        fieldDefn = ogr.FieldDefn("BSECT", ogr.OFTString)
        fieldDefn.SetWidth(40)
        outRoadLayer.CreateField(fieldDefn)
    if "BSECTW" not in fieldNames:
        fieldDefn = ogr.FieldDefn("BSECTW", ogr.OFTString)
        fieldDefn.SetWidth(40)
        outRoadLayer.CreateField(fieldDefn)

    fig1 = plt.figure(1)
    ax1 = plt.subplot(111)
    ax1.axis("equal")
    if PLOTIND > 0:
        spatInd.plot(ax1)

    roadInd = 0
    noGeom = 0
    nsplit = 0
    # get first road feature
    inRoadFeature = inRoadLayer.GetNextFeature()
    # Loop over all roads
    log.info("Finding nearest facades, setting heights...")
    pg = ProgressBar(inRoadLayer.GetFeatureCount(), sys.stdout)
    while inRoadFeature:
        pg.update(roadInd)
        outRoadFeatures = splitRoad(inRoadFeature, splitLimit, outRoadLayer.GetLayerDefn())
        if len(outRoadFeatures) > 1:
            log.debug("Raod split into %s parts" % len(outRoadFeatures))
        nsplit += len(outRoadFeatures) - 1
        for outRoadFeature in outRoadFeatures:
            intersections = []
            outRoadGeom = outRoadFeature.GetGeometryRef()
            road = Road(outRoadGeom)
            if outRoadGeom is None or outRoadGeom.GetPointCount() == 0 or not spatInd.inside(road):
                noGeom += 1
                maxHeight1 = None
                maxHeight2 = None
                avgDist = None
                bAngle1 = None
                bAngle2 = None
                avgHeight1 = None
                avgHeight2 = None
            else:
                sumHeight1 = 0
                sumHeight2 = 0
                maxHeight1 = 0
                maxHeight2 = 0
                sumDist = 0
                # Define crossections along the road,
                # Defined by start and endpoints at both side of the road
                cs1List, cs2List = road.defineCrossSections()
                nCS = len(cs1List)
                log.debug("Defined %i cross sections" % nCS)
                # Check intersections with building contours for all cross-sections
                for csInd in range(nCS):
                    cs1 = cs1List[csInd]
                    cs2 = cs2List[csInd]
                    cs1MidPoint = cs1.P0 + 0.5 * (cs1.P1 - cs1.P0)
                    buildingSegments = spatInd.getBuildingSegments(cs1MidPoint[0], cs1MidPoint[1])

                    log.debug("Calculating intersection")
                    if PLOTIND == roadInd and CSIND == csInd:
                        dist1, Pint1 = getIntersectingFacade(ax1, cs1, buildingSegments, True)
                    else:
                        dist1, Pint1 = getIntersectingFacade(ax1, cs1, buildingSegments, False)
                    if Pint1 is None:
                        log.debug("No intersection on side 1")
                        height1 = 0
                        dist1 = MAXDIST
                    else:
                        log.debug("Intersection1 in (%f, %f, %f)" % (Pint1[0], Pint1[1], Pint1[2]))
                        height1 = spatInd.getBuildingHeight(Pint1[0], Pint1[1], Pint1[2], topo) + HEIGHTCORR
                        intersections.append(Pint1[:2])

                    if PLOTIND == roadInd and csInd == CSIND:
                        plotSegments(ax1, buildingSegments, color="red", width=2.0)
                        row, col = spatInd.getInd(cs1MidPoint[0], cs1MidPoint[1])
                        spatInd.plotCell(ax1, row, col, color="purple", width=2.0)
                        plotSegments(ax1, [cs1List[csInd]], color="pink", style="-", width=1.0)
                        plt.draw()

                    cs2MidPoint = cs2.P0 + 0.5 * (cs2.P1 - cs2.P0)
                    buildingSegments = spatInd.getBuildingSegments(cs2MidPoint[0], cs2MidPoint[1])

                    if PLOTIND == roadInd and csInd == CSIND:
                        plotSegments(ax1, buildingSegments, color="red", width=2.0)
                        row, col = spatInd.getInd(cs2MidPoint[0], cs2MidPoint[1])
                        spatInd.plotCell(ax1, row, col, color="brown", width=2.0)
                        plotSegments(ax1, [cs2List[csInd]], color="red", style="-", width=1.0)
                        plt.draw()

                    log.debug("Calculating intersection")
                    if PLOTIND == roadInd and CSIND == csInd:
                        dist2, Pint2 = getIntersectingFacade(ax1, cs2, buildingSegments, True)
                    else:
                        dist2, Pint2 = getIntersectingFacade(ax1, cs2, buildingSegments, False)

                    if Pint2 is None:
                        log.debug("No intersection on side 2")
                        height2 = 0
                    else:
                        log.debug("Intersection2 in (%f, %f, %f)" % (Pint2[0], Pint2[1], Pint2[2]))
                        height2 = spatInd.getBuildingHeight(Pint2[0], Pint2[1], Pint2[2], topo) + HEIGHTCORR
                        intersections.append(Pint2[:2])

                    sumHeight1 += height1
                    sumHeight2 += height2
                    sumDist += dist1 + dist2
                    maxHeight1 = int(max(height1, maxHeight1))
                    maxHeight2 = int(max(height2, maxHeight2))
                    if PLOTIND == roadInd and CSIND == csInd:
                        if Pint1 is not None:
                            ax1.text(Pint1[0], Pint1[1], "Distance=%f" % dist1)
                        if Pint2 is not None:
                            ax1.text(Pint2[0], Pint2[1], "Distance=%f" % dist2)

                avgHeight1 = int(sumHeight1 / float(nCS))
                avgHeight2 = int(sumHeight2 / float(nCS))
                # averaging over both sides of street
                # distance refers to between facades on opposite sides
                avgDist = int(round(sumDist / float(nCS)))
                bAngle1, bAngle2 = road.normalAngles()
                if PLOTIND > 0:
                    plotSegments(ax1, road.getSegments(), color="grey", width=0.3)
                if PLOTIND == roadInd:
                    plotSegments(ax1, road.getSegments(), color="black", width=2.0)
                    plotSegments(ax1, cs1List, color="green", style="--", width=0.5)
                    plotSegments(ax1, cs2List, color="green", style="--", width=0.5)

                    X = [intersect[0] for intersect in intersections]
                    Y = [intersect[1] for intersect in intersections]
                    if len(X) > 0:
                        ax1.plot(X, Y, "*")
                    plt.title("Road %i, cross-section %i" % (PLOTIND, CSIND))
                    plt.draw()

            # building height as list of sectors
            bsect = bheight2sect(avgHeight1, avgHeight2, bAngle1)
            bsectw = bheight2sect(maxHeight1, maxHeight2, bAngle1)

            outRoadFeature.SetField("BSECT", bsect)
            outRoadFeature.SetField("BSECTW", bsectw)
            outRoadFeature.SetField("BHGT1", avgHeight1)
            outRoadFeature.SetField("BHGT2", avgHeight2)
            outRoadFeature.SetField("BHGT1W", maxHeight1)
            outRoadFeature.SetField("BHGT2W", maxHeight2)
            outRoadFeature.SetField("BANG1", bAngle1)
            outRoadFeature.SetField("BANG2", bAngle2)
            outRoadFeature.SetField("BDIST", avgDist)

            outRoadLayer.CreateFeature(outRoadFeature)
            outRoadFeature.Destroy()
        inRoadFeature.Destroy()
        inRoadFeature = inRoadLayer.GetNextFeature()
        roadInd += 1

    inRoads = inRoadLayer.GetFeatureCount()
    outRoads = outRoadLayer.GetFeatureCount()
    # close datasource for building contours
    inRoadFile.Destroy()
    outRoadFile.Destroy()
    pg.finished()
    if PLOTIND > 0:
        plt.show()

    log.info("Read %i roads, wrote %i roads (created %i by splitting)" % (inRoads, outRoads, nsplit))

    if noGeom > 0:
        log.warning("Found %i roads without geometry" % noGeom)

    log.info("Finished")
Esempio n. 2
0
def main():
    # -----------Setting up and unsing option parser----------------
    parser = OptionParser(usage=usage, version=version)

    parser.add_option("-d",
                      "--doc",
                      action="store_true",
                      dest="doc",
                      help="Prints more detailed documentation and exit")

    parser.add_option("-v",
                      "--verbose",
                      action="store_const",
                      const=logging.INFO,
                      dest="loglevel",
                      default=logging.WARNING,
                      help="Produce verbose output")

    parser.add_option("--no-progress",
                      action="store_const",
                      dest="progressStream",
                      const=None,
                      default=sys.stdout,
                      help="turn off the progress bar")

    parser.add_option("-i",
                      "--input",
                      action="store",
                      dest="infileName",
                      help="Input raster")

    parser.add_option("--bandIndex",
                      action="store",
                      dest="bandIndex",
                      help="Band index to read from",
                      default=1)

    parser.add_option("-o",
                      "--output",
                      action="store",
                      dest="output",
                      default=None,
                      help="Output file")

    parser.add_option("--solidName",
                      default="TOPO",
                      action="store",
                      dest="solidName",
                      help="Name of solid in STL-output")

    parser.add_option("--precision",
                      default=6,
                      action="store",
                      dest="precision",
                      help="Precision of coordinates in STL-output")

    parser.add_option("--buffer",
                      action="store",
                      dest="buffer",
                      help="Add buffer distance to topo, " +
                      "damping out differences in elevation")

    (options, args) = parser.parse_args()

    # configuring logging
    FORMAT = '%(levelname)s %(message)s'
    logging.basicConfig(format=FORMAT)

    # ------------Process and validate options---------------
    if options.doc:
        print __doc__
        sys.exit()

    if len(args) > 0:
        parser.error("Incorrect number of arguments")

    # validate infile path
    if options.infileName is not None:
        inFilePath = options.infileName
        if not path.exists(inFilePath):
            log.error("Input raster does not exist")
            sys.exit(1)
    else:
        log.error("No input file specified")
        sys.exit(1)

    # validate outfile path
    if options.output is None:
        log.error("No output file specified")
        sys.exit(1)

    if options.buffer is not None:
        bufferDist = float(options.buffer)

    # Assure that gdal is present
    if not __gdal_loaded__:
        raise OSError("Function readGDAL needs GDAL with python bindings")

    # register all of the raster drivers
    gdal.AllRegister()
    ds = gdal.Open(inFilePath, GA_ReadOnly)
    if ds is None:
        log.error('Could not open ' + inFilePath)
        sys.exit(1)

    ncols = ds.RasterXSize
    nrows = ds.RasterYSize
    # nbands = ds.RasterCount

    # Info used for georeferencing
    geoTransform = ds.GetGeoTransform()
    xul = geoTransform[0]  # top left x
    cellsizeX = geoTransform[1]  # w-e pixel resolution
    rot1 = geoTransform[2]  # rotation, 0 if image is "north up"
    yul = geoTransform[3]  # top left y
    rot2 = geoTransform[4]  # rotation, 0 if image is "north up"
    cellsizeY = geoTransform[5]  # n-s pixel resolution
    # proj = ds.GetProjection()

    # Calculate lower left corner
    xll = xul
    yll = yul + nrows * cellsizeY  # cellsizeY should be a negative value

    # Rotated rasters not handled...yet
    if rot1 != 0 or rot2 != 0:
        log.error('Handling of rotated rasters are not implemented yet')
        sys.exit(1)

    bandIndex = int(options.bandIndex)
    band = ds.GetRasterBand(bandIndex)

    nodata = band.GetNoDataValue()
    # If no nodata value is present in raster, set to -9999 for completeness
    if nodata is None:
        nodata = -9999

    # Processing of data is made for blocks of the following size
    # two rows are processed at a time since triangles
    # are created between cell centres.
    procXBlockSize = ncols
    procYBlockSize = 2

    with open(options.output, 'w') as stlFile:
        pg = ProgressBar(nrows, options.progressStream)

        stlFile.write("solid " + options.solidName + "\n")

        #        avgHeight = 0
        # write original cells to STL
        # Loop over blocks of raster

        for i in range(0, nrows - 1, 1):
            pg.update(i)
            data = band.ReadAsArray(xoff=0,
                                    yoff=i,
                                    win_xsize=procXBlockSize,
                                    win_ysize=procYBlockSize)
            if nodata in data:
                log.error("Nodata value found in raster," +
                          " this should be interpolated before" +
                          " converting to STL")
                sys.exit(1)

            # newCellsizeY is negative
            blockYll = yul + (procYBlockSize + i) * cellsizeY
            blockXll = xll

            block2STL(data, stlFile, blockXll, blockYll, cellsizeX, cellsizeY,
                      nodata, int(options.precision))


#            avgHeight += np.mean(data)

#        avgHeight /= (nrows - 1)

# write buffer cells to STL
        leftBoundary = band.ReadAsArray(xoff=0,
                                        yoff=0,
                                        win_xsize=1,
                                        win_ysize=nrows)

        rightBoundary = band.ReadAsArray(xoff=ncols - 1,
                                         yoff=0,
                                         win_xsize=1,
                                         win_ysize=nrows)

        topBoundary = band.ReadAsArray(xoff=0,
                                       yoff=0,
                                       win_xsize=procXBlockSize,
                                       win_ysize=1)

        bottomBoundary = band.ReadAsArray(xoff=0,
                                          yoff=nrows - 1,
                                          win_xsize=procXBlockSize,
                                          win_ysize=1)

        avgHeight = 0.25 * (leftBoundary.mean() + rightBoundary.mean() +
                            topBoundary.mean() + bottomBoundary.mean())

        if options.buffer is not None:
            # overlap of one cell since triangles are created between
            # cell centres
            bufferCells = int(bufferDist / cellsizeX) + 1

            leftBuffer = leftBoundary[:]

            for i in range(1, bufferCells):
                dist = i * cellsizeX
                leftBuffer = np.hstack((damp(leftBoundary, avgHeight, dist,
                                             bufferDist), leftBuffer))

            block2STL(leftBuffer, stlFile, xll - (bufferCells - 1) * cellsizeX,
                      yll, cellsizeX, cellsizeY, nodata,
                      int(options.precision))

            rightBuffer = rightBoundary[:]
            for i in range(1, bufferCells):
                dist = i * cellsizeX
                rightBuffer = np.hstack((rightBuffer,
                                         damp(rightBoundary, avgHeight, dist,
                                              bufferDist)))

            block2STL(rightBuffer, stlFile, xll + (ncols - 1) * cellsizeX, yll,
                      cellsizeX, cellsizeY, nodata, int(options.precision))

            topBuffer = topBoundary[:]
            for i in range(1, bufferCells):
                dist = abs(i * cellsizeY)
                topBuffer = np.vstack((damp(topBoundary, avgHeight, dist,
                                            bufferDist), topBuffer))

            block2STL(topBuffer, stlFile, xll, yul + cellsizeY, cellsizeX,
                      cellsizeY, nodata, int(options.precision))

            bottomBuffer = bottomBoundary[:]
            for i in range(1, bufferCells):
                dist = abs(i * cellsizeY)
                bottomBuffer = np.vstack((bottomBuffer,
                                          damp(bottomBoundary, avgHeight, dist,
                                               bufferDist)))

            block2STL(bottomBuffer, stlFile, xll,
                      yll + (bufferCells - 1) * cellsizeY, cellsizeX,
                      cellsizeY, nodata, int(options.precision))

            # Add corner buffers
            cornerBlock = np.ones((bufferCells, bufferCells))

            # upper right
            blockXll = xll + (ncols - 1) * cellsizeX
            blockYll = yul + cellsizeY
            startHeight = rightBoundary[0, 0]
            cornerPoint = (xll + (ncols - 0.5) * cellsizeX,
                           yul + 0.5 * cellsizeY)

            for col in range(bufferCells):
                for row in range(bufferCells):
                    centre = getCentreCoords(row, col, blockXll, blockYll,
                                             cellsizeX, cellsizeY, bufferCells,
                                             bufferCells)

                    dist = (np.sqrt(
                        pow(centre[0] - cornerPoint[0], 2) +
                        pow(centre[1] - cornerPoint[1], 2)))

                    # dist = min(row, col) * cellsizeX
                    cornerBlock[row, col] = damp(startHeight, avgHeight, dist,
                                                 bufferDist)

            cornerBlock[:, 0] = topBuffer[:, -1]
            cornerBlock[-1, :] = rightBuffer[0, :]

            block2STL(cornerBlock, stlFile, blockXll, blockYll, cellsizeX,
                      cellsizeY, nodata, int(options.precision))

            # lower left
            blockXll = xll - (bufferCells - 1) * cellsizeX
            blockYll = yll + (bufferCells - 1) * cellsizeY
            startHeight = leftBoundary[-1, 0]
            cornerPoint = (xll + 0.5 * cellsizeX, yll - 0.5 * cellsizeY)
            for col in range(bufferCells):
                for row in range(bufferCells):
                    centre = getCentreCoords(row, col, blockXll, blockYll,
                                             cellsizeX, cellsizeY, bufferCells,
                                             bufferCells)

                    dist = (np.sqrt(
                        pow(centre[0] - cornerPoint[0], 2) +
                        pow(centre[1] - cornerPoint[1], 2)))

                    cornerBlock[row, col] = damp(startHeight, avgHeight, dist,
                                                 bufferDist)
            cornerBlock[:, -1] = bottomBuffer[:, 0]
            cornerBlock[0, :] = leftBuffer[-1, :]
            block2STL(cornerBlock, stlFile, blockXll, blockYll, cellsizeX,
                      cellsizeY, nodata, int(options.precision))

            # upper left
            blockXll = xll - (bufferCells - 1) * cellsizeX
            blockYll = yul + cellsizeY
            startHeight = leftBoundary[0, 0]
            cornerPoint = (xll + 0.5 * cellsizeX, yul + 0.5 * cellsizeY)
            for col in range(bufferCells):
                for row in range(bufferCells):
                    centre = getCentreCoords(row, col, blockXll, blockYll,
                                             cellsizeX, cellsizeY, bufferCells,
                                             bufferCells)

                    dist = (np.sqrt(
                        pow(centre[0] - cornerPoint[0], 2) +
                        pow(centre[1] - cornerPoint[1], 2)))

                    cornerBlock[row, col] = damp(startHeight, avgHeight, dist,
                                                 bufferDist)
            cornerBlock[:, -1] = topBuffer[:, 0]
            cornerBlock[-1, :] = leftBuffer[0, :]
            block2STL(cornerBlock, stlFile, blockXll, blockYll, cellsizeX,
                      cellsizeY, nodata, int(options.precision))

            # lower right
            blockXll = xll + (ncols - 1) * cellsizeX
            blockYll = yll + (bufferCells - 1) * cellsizeY
            startHeight = rightBoundary[-1, 0]
            cornerPoint = (xll + (ncols - 0.5) * cellsizeX,
                           yll - 0.5 * cellsizeY)
            for col in range(bufferCells):
                for row in range(bufferCells):
                    centre = getCentreCoords(row, col, blockXll, blockYll,
                                             cellsizeX, cellsizeY, bufferCells,
                                             bufferCells)

                    dist = (np.sqrt(
                        pow(centre[0] - cornerPoint[0], 2) +
                        pow(centre[1] - cornerPoint[1], 2)))

                    cornerBlock[row, col] = damp(startHeight, avgHeight, dist,
                                                 bufferDist)

            cornerBlock[:, 0] = bottomBuffer[:, -1]
            cornerBlock[0, :] = rightBuffer[-1, :]
            block2STL(cornerBlock, stlFile, blockXll, blockYll, cellsizeX,
                      cellsizeY, nodata, int(options.precision))

        stlFile.write("endsolid %s\n" % options.solidName)

    pg.finished()
Esempio n. 3
0
    def indexBuildingContours(self, buildingFile):
        """
        Read building contours from shape file and create a spatial indexing.
        The indexing is implemented as a nested dict
        cols={row1,row2,row3}, where row1..n = {cell1,cell2,...,celln},
        and cell1...n = [contour_1,contour_2,...,contour_n]
        Extent of index is set to extent of the used DEM (topo)
        @param buildingFile: shapefile with 3D building contours
        """
        # open building contours shape-file
        log.info("Reading building contours")
        # Init reading of shape-files using OGR
        shapeDriver = ogr.GetDriverByName("ESRI Shapefile")
        buildings = shapeDriver.Open(buildingFile, update=0)
        if buildings is None:
            log.error("Could not open file with building contours")
            return 1
        buildingsLayer = buildings.GetLayer()

        self.ind = {}

        # set up progress indicator
        pg = ProgressBar(buildingsLayer.GetFeatureCount(), sys.stdout)

        contourInd = 0  # Counter for building contour
        buildHeights = []  # List to store building height for plotting
        noGeom = 0  # Counter for invalid features without geometry reference

        # Read and process building contours
        contour = buildingsLayer.GetNextFeature()  # get first feature
        while contour:
            if log.level == 0:
                pg.update(contourInd)
            log.debug("Contour %i" % contourInd)

            contourGeom = contour.GetGeometryRef()

            if contourGeom is None or contourGeom.GetPointCount() == 0:
                noGeom += 1
            else:
                for i in range(1, contourGeom.GetPointCount()):
                    x1 = contourGeom.GetX(i - 1)
                    y1 = contourGeom.GetY(i - 1)
                    z1 = contourGeom.GetZ(i - 1)

                    x2 = contourGeom.GetX(i)
                    y2 = contourGeom.GetY(i)
                    z2 = contourGeom.GetZ(i)

                    P1 = np.array([x1, y1, z1])
                    P2 = np.array([x2, y2, z2])
                    try:
                        row, col = self.getInd((x2 + x1) / 2.0, (y1 + y2) / 2.0)
                    except ValueError:  # outside extent
                        row = col = None
                    if row is not None and col is not None:
                        if row not in self.ind:
                            self.ind[row] = {}
                            self.ind[row][col] = []
                        elif col not in self.ind[row]:
                            self.ind[row][col] = []

                        self.ind[row][col].append(Segment(P1, P2))

            contour.Destroy()
            contour = buildingsLayer.GetNextFeature()
            contourInd += 1
        # close datasource for building contours
        buildings.Destroy()
        pg.finished()
        if noGeom > 0:
            log.warning("Found %i building contours without geometry" % noGeom)
Esempio n. 4
0
def main():
    # -----------Setting up and unsing option parser-----------------------
    parser = OptionParser(usage=usage, version=version)

    parser.add_option("-d", "--doc",
                      action="store_true", dest="doc",
                      help="Prints more detailed documentation and exit")

    parser.add_option("-v",
                      action="store_const", const=logging.DEBUG,
                      dest="loglevel", default=get_loglevel(),
                      help="Produce verbose output")

    parser.add_option("--no-progress",
                      action="store_const", dest="progressStream",
                      const=None, default=sys.stdout,
                      help="turn off the progress bar")

    parser.add_option("-o", "--output",
                      action="store", dest="outfileName", default=None,
                      help="Output file")

    parser.add_option("-i", "--input",
                      action="store", dest="infileName",
                      help="Input raster")

    parser.add_option("--bbox",
                      action="store", dest="bbox",
                      help="Only read data within bbox," +
                      " --box <\"x1,y1,x2,y2\"")

    parser.add_option("--reclassify",
                      action="store", dest="classTable",
                      help="Tab-separated table with code " +
                      "and z0 value for each landuse class")

    parser.add_option("--reclassFromColumn",
                      action="store", dest="reclassFromColumn",
                      help="Header of reclass table column " +
                      "containing values to " +
                      "reclass (default is to use first column of classTable)")

    parser.add_option("--reclassToColumn",
                      action="store", dest="reclassToColumn",
                      help="Header of reclass table column containing codes," +
                      " default is to use first column (default is to use " +
                      "second column of classTable)")

    parser.add_option("--resample",
                      action="store", dest="cellFactor",
                      help="Resample grid by dividing cellsize with a" +
                      " factor. Factor <1 results in refinement." +
                      " Reprojection uses temporary refinement")

    parser.add_option("--resamplingMethod",
                      action="store", dest="resamplingMethod",
                      help="For cellFactor > 1: " +
                      "Choose between 'mean', 'sum', 'majority' or" +
                      " 'count', default is sum,"
                      "For cellFactor < 1, choose between: " +
                      "'keepTotal' and 'keepValue', default is 'keepTotal'")

    parser.add_option("--summarize",
                      action="store_true", dest="summarize",
                      help="Print a summary of the input grid properties")

    parser.add_option("--bandIndex",
                      action="store", dest="bandIndex",
                      help="Band index to read from",
                      default=1)

    parser.add_option("--dataType",
                      action="store", dest="dataType",
                      help="Output raster/shape data type",
                      default=None)

    parser.add_option("--toShape",
                      action="store_true", dest="toShape",
                      help="output as shape file",
                      default=None)

    parser.add_option("--fieldName", metavar='FIELD',
                      action="store", dest="fieldName",
                      help="write data in shape file to FIELD," +
                      " default is 'value'",
                      default=None)

    parser.add_option("--filter",
                      action="store", dest="filter",
                      help="Filter out data equal or below" +
                      " limit in shape output",
                      default=None)

    parser.add_option("-t", "--template",
                      action="store", dest="template",
                      help="Header for output raster when reprojecting")

    parser.add_option("--fromProj", dest="fromProj",
                      help="Input raster proj4 definition string")

    parser.add_option("--toProj", dest="toProj",
                      help="Output raster proj4 definition string")

    (options, args) = parser.parse_args()

    #------------Setting up logging capabilities -----------
    # Setup logging
    logging.basicConfig(
        format='%(levelname)s:%(name)s: %(message)s',
        level=options.loglevel,
    )
    log = logging.getLogger(__name__)

    #------------Process and validate options---------------
    if options.doc:
        print doc
        sys.exit()

    if len(args) > 0:
        parser.error("Incorrect number of arguments")

    #validate infile path
    if options.infileName is not None:
        inFilePath = path.abspath(options.infileName)
        if not path.exists(inFilePath):
            log.error("Input raster %s does not exist" % options.infileName)
            sys.exit(1)
    else:
        parser.error("No input data specified")

    #validate outfile path
    if options.outfileName is not None:
        outFilePath = path.abspath(options.outfileName)
        if options.toShape and ".shp" not in outFilePath:
            parser.error("Output shape has to to be specified with" +
                         " .shp extension")

    else:
        outFilePath = None

    #Validate fieldName option
    if options.toShape:
        if options.fieldName == "":
            parser.error("fieldName can't be an empty string")
        fieldName = options.fieldName or "value"
    elif options.fieldName is not None:
        parser.error("fieldName option only allowed together" +
                     " with shape output")

    # Validate filter option and convert filter to numeric value if present
    if not options.toShape and options.filter is not None:
        parser.error("Filter option only allowed together with shape output")
    elif options.toShape:
        if options.filter is not None:
            filter = float(options.filter)
        else:
            filter = None

    # read and process reclass table file
    if options.classTable is not None:
        reclassFromColumn = options.reclassFromColumn
        reclassToColumn = options.reclassToColumn

        if reclassFromColumn is not None and reclassToColumn is not None:

            desc = [{"id": reclassFromColumn, "type": float},
                    {"id": reclassToColumn, "type": float}]

            classTable = datatable.DataTable(desc=desc)
            classTable.read(options.classTable)
        else:
            classTable = datatable.DataTable()
            classTable.read(options.classTable)
            reclassFromColumn = classTable.desc[0]["id"]
            reclassToColumn = classTable.desc[1]["id"]
            classTable.convertCol(reclassFromColumn, float)
            classTable.convertCol(reclassToColumn, float)

        classTable.setKeys([reclassFromColumn])

        log.debug("Successfully read landuse class table")

        classDict = {}
        for row in classTable.data:
            classDict[row[classTable.colIndex[reclassFromColumn]]
                      ] = row[classTable.colIndex[reclassToColumn]]

    if options.cellFactor is not None:
        cellFactor = float(options.cellFactor)
        if cellFactor > 1 and \
                options.resamplingMethod not in ('sum',
                                                 'mean',
                                                 'majority',
                                                 'count',
                                                 None):

                log.error(
                    "Invalid resampling method, valid options for grid " +
                    "coarsening are 'sum' " +
                    "and 'mean' and 'majority', " +
                    "specified %s" % options.resamplingMethod
                )
                sys.exit(1)

        elif cellFactor < 1 and \
                options.resamplingMethod not in ('keepTotal',
                                                 'keepValue',
                                                 None):
                log.error(
                    "Invalid resampling method, valid options for grid " +
                    "coarsening are 'keepTotal' and 'keepValue'" +
                    ", specified %s" % resamplingMethod)
                sys.exit(1)

        # setting default resampling methods
        if cellFactor > 1 and \
                options.resamplingMethod is None:
            resamplingMethod = 'sum'

        elif options.resamplingMethod is None:
            resamplingMethod = 'keepTotal'
        else:
            resamplingMethod = options.resamplingMethod

        if options.resamplingMethod == 'majority' or \
                options.resamplingMethod == 'count' and \
                options.toProj is not None:
            log.error(
                "Resampling method " +
                "%s not possible to " % options.resamplingMethod +
                "combine with reprojection")
            sys.exit(1)

    # Assure that gdal is present
    if not __gdal_loaded__:
        raise OSError("Function readGDAL needs GDAL with python bindings")

    # register all of the raster drivers
    gdal.AllRegister()
    ds = gdal.Open(inFilePath, GA_ReadOnly)
    if ds is None:
        print 'Could not open ' + filename
        sys.exit(1)

    ncols = ds.RasterXSize
    nrows = ds.RasterYSize
    nbands = ds.RasterCount

    # Info used for georeferencing
    geoTransform = ds.GetGeoTransform()
    xul = geoTransform[0]  # top left x
    cellsizeX = geoTransform[1]  # w-e pixel resolution
    rot1 = geoTransform[2]  # rotation, 0 if image is "north up"
    yul = geoTransform[3]  # top left y
    rot2 = geoTransform[4]  # rotation, 0 if image is "north up"
    cellsizeY = geoTransform[5]  # n-s pixel resolution
    proj = osr.SpatialReference(ds.GetProjection())

    # Calculate lower left corner
    xll = xul
    yll = yul + nrows * cellsizeY  # cellsizeY should be a negative value

    # Rotated rasters not handled...yet
    if rot1 != 0 or rot2 != 0:
        print 'Rotated rasters are not supported by pyAirviro.geo.raster'
        sys.exit(1)

    if abs(cellsizeX) != abs(cellsizeY):
        print('Non-homogenous cellsizes are not' +
              ' supported by pyAirviro.geo.raster')
        sys.exit(1)

    bandIndex = int(options.bandIndex)

    band = ds.GetRasterBand(bandIndex)
    nodata = band.GetNoDataValue()

    # If no nodata value is present in raster, set to -9999 for completeness
    if nodata is None:
        nodata = -9999
    # Read data from a window defined by option --bbox <"x1,y1,x2,y2">
    if options.bbox is not None:
        xur = xll + ncols * cellsizeX
        try:
            x1, y1, x2, y2 = map(float, options.bbox.split(","))
        except:
            log.error("Invalid value for option --bbox <\"x1,y1,x2,y2\">")
            sys.exit(1)

        # Check if totally outside raster extent
        if x2 < xll or y2 < yll  or x1 > xur or y1 > yul:
            log.error("Trying to extract outside grid boundaries")
            sys.exit(1)

        # Limit bbox to raster extent
        if x1 < xll:
            x1 = xll
        if x2 > xur:
            x2 = xur
        if y1 < yll:
            y1 = yll
        if y2 > yul:
            y2 = yul

        # estimate min and max of rows and cols
        colmin = int((x1 - xll) / cellsizeX)
        colmaxdec = (x2 - xll) / float(cellsizeX)
        rowmin = int((yul - y2) / abs(cellsizeY))
        rowmaxdec = (yul - y1) / float(abs(cellsizeY))

        if (colmaxdec - int(colmaxdec)) > 0:
            colmax = int(colmaxdec)
        else:
            colmax = int(colmaxdec - 1)

        if (rowmaxdec - int(rowmaxdec)) > 0:
            rowmax = int(rowmaxdec)
        else:
            rowmax = int(rowmaxdec - 1)

        nrows = rowmax - rowmin + 1
        ncols = colmax - colmin + 1
        xll = xll + colmin * cellsizeX
        yll = yul + (rowmax + 1) * cellsizeY  # cellsizeY is negative
        yul = yll - nrows * cellsizeY
    else:
        rowmin = 0
        colmin = 0

    # process option for resampling
    if options.cellFactor is not None:
        cellFactor = float(cellFactor)
    else:
        cellFactor = 1

    if cellFactor >= 1:
        procYBlockSize = int(cellFactor)

    else:
        procYBlockSize = 1

    if options.toProj is None:
        # Set output raster dimensions and cellsize
        newNcols = int(ncols / cellFactor)
        newNrows = int(nrows / cellFactor)
        newCellsizeX = cellsizeX * cellFactor
        newCellsizeY = cellsizeY * cellFactor  # is a negative value as before
        newXll = xll
        newYll = yll
        newYul = yul
        newNodata = nodata

    else:
        # Create coordinate transform
        if options.fromProj is None:
            src_srs = proj
        else:
            src_srs = osr.SpatialReference()
            src_srs.ImportFromProj4(options.fromProj)
        tgt_srs = osr.SpatialReference()
        tgt_srs.ImportFromProj4(options.toProj)
        import pdb;pdb.set_trace()
        coordTrans = osr.CoordinateTransformation(src_srs, tgt_srs)

        if options.template is None:
            # estimate extent from input
            newNcols = ncols
            newNrows = nrows
            newCellsizeX = cellsizeX
            newCellsizeY = cellsizeY
            newNodata = nodata
            newXll, newYll, z = coordTrans.TransformPoint(xll, yll)
            newXll = int(newXll)
            newYll = int(newYll)
            newYul = newYll - newNrows * newCellsizeY
        else:
            header = open(options.template, "r").read()
            newNcols = int(
                re.compile("ncols\s*([0-9]*)").search(header).group(1))
            newNrows = int(
                re.compile("nrows\s*([0-9]*)").search(header).group(1))
            newCellsizeX = float(
                re.compile("cellsize\s*([0-9]*)").search(header).group(1))
            newCellsizeY = -1 * newCellsizeX
            try:
                newNodata = float(
                    re.compile(
                        "NODATA_value\s*(.*?)\n"
                    ).search(header).group(1)
                )
            except AttributeError:
                newNodata = float(
                    re.compile(
                        "nodata_value\s*(.*?)\n"
                    ).search(header).group(1)
                )
            newXll = float(
                re.compile("xllcorner\s*(.*?)\n").search(header).group(1))
            newYll = float(
                re.compile("yllcorner\s*(.*?)\n").search(header).group(1))
            newYul = newYll - newNrows * newCellsizeY

    # Processing of data is made for blocks of the following size
    # Important - blocks are set to cover all columns for simpler processing
    # This might not always be optimal for read/write speed
    procXBlockSize = ncols

    # process option for dataType
    if options.toShape:
        dataTypes, defaultDataType = ogrDataTypes, 'Real'
    else:
        dataTypes, defaultDataType = gdalDataTypes, 'Float32'
    try:
        dataType = dataTypes[options.dataType or defaultDataType]
    except KeyError:
        log.error(
            "Unknown datatype choose between: %s" % ",".join(dataTypes.keys()))
        sys.exit(1)

    # Create and configure output raster data source
    if not options.toShape and outFilePath is not None:
        # Creates a raster dataset with 1 band

        mem_ds = gdal.GetDriverByName('MEM').Create(outFilePath,
                                                    newNcols,
                                                    newNrows,
                                                    1,
                                                    dataType)

        if mem_ds is None:
            print "Error: could not create output raster"
            sys.exit(1)

        outGeotransform = [newXll, newCellsizeX, 0, newYul, 0, newCellsizeY]
        mem_ds.SetGeoTransform(outGeotransform)
        if options.toProj is not None:
            mem_ds.SetProjection(tgt_srs.ExportToWkt())
        else:
            mem_ds.SetProjection(proj)
        outBand = mem_ds.GetRasterBand(1)
        outBand.SetNoDataValue(newNodata)  # Set nodata-value

    if options.toProj is not None:
        outArray = np.zeros((newNrows, newNcols))
        nvals = np.zeros((newNrows, newNcols))
        outDef = {"ncols": newNcols,
                  "nrows": newNrows,
                  "xll": newXll,
                  "yll": newYll,
                  "yul": newYll - newNrows * newCellsizeY,
                  "xur": newXll + newNcols * newCellsizeX,
                  "cellsize": newCellsizeX
                  }

    # Create and inititialize output vector data source
    if options.toShape:
        shapeDriver = ogr.GetDriverByName('ESRI Shapefile')
        if path.exists(outFilePath):
            shapeDriver.DeleteDataSource(outFilePath)
        shapeFile = shapeDriver.CreateDataSource(outFilePath)
        if shapeFile is None:
            log.error("Could not open output shapefile %s" % outFilePath)
            sys.exit(1)
        layer = shapeFile.CreateLayer(outFilePath, geom_type=ogr.wkbPolygon)
        fieldDefn = ogr.FieldDefn(fieldName, dataType)
        layer.CreateField(fieldDefn)

    # inititialize input grid summary
    inputGridSummary = {"sum": 0,
                        "mean": 0,
                        "nnodata": 0,
                        "nnegative": 0,
                        "xll": xll,
                        "yll": yll,
                        "ncols": ncols,
                        "nrows": nrows,
                        "cellsizeX": cellsizeX,
                        "cellsizeY": cellsizeY,
                        "nodatavalue": nodata}

    outputGridSummary = {"sum": 0,
                         "mean": 0,
                         "nnodata": 0,
                         "nnegative": 0,
                         "xll": newXll,
                         "yll": newYll,
                         "ncols": newNcols,
                         "nrows": newNrows,
                         "cellsizeX": newCellsizeX,
                         "cellsizeY": newCellsizeY,
                         "nodatavalue": newNodata}

    # Loop over block of raster (at least one row in each block)
    rowsOffset = 0
    errDict = {}
    pg = ProgressBar(nrows, options.progressStream)

    for i in range(0, nrows, int(procYBlockSize)):
        pg.update(i)
        data = band.ReadAsArray(xoff=colmin, yoff=rowmin + i,
                                win_xsize=procXBlockSize,
                                win_ysize=procYBlockSize)

        if options.summarize:
            inputGridSummary = updateGridSummary(data,
                                                 inputGridSummary, nodata)

        if options.classTable is not None:
            try:
                data = reclassBlock(data, classDict, errDict)
            except IOError as e:
                log.error(str(e))
                sys.exit(1)

        if options.cellFactor is not None:
            try:
                data = resampleBlock(data[:, :],
                                     cellFactor,
                                     resamplingMethod,
                                     nodata)

            except ValueError as err:
                log.error(err.message)
                sys.exit(1)
            except IOError as err:
                log.error(err.message)
                sys.exit(1)

        if options.toProj is not None:
            blockDef = {"nrows": int(procYBlockSize / cellFactor),
                        "ncols": int(procXBlockSize / cellFactor),
                        "xll": xll + (colmin) * cellsizeX,
                        "yul": yll - (nrows - rowmin - i) * cellsizeY,
                        "cellsize": cellsizeX * cellFactor,
                        "nodata": nodata}

            reprojectBlock(outArray,
                           data,
                           cellFactor,
                           blockDef,
                           outDef,
                           coordTrans,
                           nvals)

        if outFilePath is not None:
            if options.toShape:
                blockYll = yul + i * newCellsizeY  # newCellsizeY is negative
                blockXll = xll
                block2vector(data, layer, blockXll, blockYll, newCellsizeX,
                             newCellsizeY, nodata, fieldName, filter)
            elif options.toProj is None:
                outBand.WriteArray(data, 0,
                                   rowsOffset)  # Write block to raster
                outBand.FlushCache()  # Write data to disk

        if options.summarize:
            outputGridSummary = updateGridSummary(data,
                                                  outputGridSummary,
                                                  nodata)

        rowsOffset += int(procYBlockSize / cellFactor)  # Update offset

    if options.toShape:
        shapeFile.Destroy()

    if not options.toShape and options.toProj is not None:
        if options.resamplingMethod is not None and resamplingMethod == "mean":
            outArray = np.where(nvals > 0, outArray / nvals, outArray)

        outBand.WriteArray(outArray, 0, 0)
        outBand.FlushCache()  # Write data to disk

    if options.outfileName is not None and not options.toShape:
        outputDriver = ds.GetDriver()
        output_ds = outputDriver.CreateCopy(options.outfileName, mem_ds, 0)
        output_ds = None
        mem_ds = None

    pg.finished()

    if options.summarize:
        print "\nInput raster summary"
        printGridSummary(inputGridSummary, prefix="input")
        print "\nOutput raster summary"
        printGridSummary(outputGridSummary, prefix="output")

    if errDict != {}:
        print "Errors/warnings during processing:"

    for err, nerr in errDict.items():
        print "%s err in %i cells" % (err, nerr)
Esempio n. 5
0
def main():
    #-----------Setting up and unsing option parser-----------------------
    parser = OptionParser(usage=usage, version=version)

    parser.add_option("-d", "--doc",
                      action="store_true", dest="doc",
                      help="Prints more detailed documentation and exit")

    parser.add_option("-l", "--loglevel",
                      action="store", dest="loglevel", default=2,
                      help="Sets the loglevel (0-3 where 3=full logging)")

    parser.add_option("--no-progress",
                      action="store_const", dest="progressStream",
                      const=None, default=sys.stdout,
                      help="turn off the progress bar")

    parser.add_option("-o", "--output",
                      action="store", dest="outfileName", default=None,
                      help="Output file")

    parser.add_option("-i", "--input",
                      action="store", dest="infileName",
                      help="Input raster")

    parser.add_option("--bandIndex",
                      action="store", dest="bandIndex",
                      help="Band index to read from",
                      default=1)

    parser.add_option("--dataType",
                      action="store", dest="dataType",
                      help="Output data type",
                      default=None)

    parser.add_option("--featureType",
                      action="store", dest="featureType",
                      help="Type of feature ('poly' or 'point')," +
                      " default='point'",
                      default='point')

    parser.add_option("--fieldName", metavar='FIELD',
                      action="store", dest="fieldName",
                      help="write data in shape file to FIELD," +
                      " default='value'",
                      default='value')

    parser.add_option("--filter",
                      action="store", dest="filter",
                      help="Filter out data equal or below" +
                      " limit in shape output",
                      default=None)

    (options, args) = parser.parse_args()

    #------------Setting up logging capabilities -----------
    rootLogger = logger.RootLogger(int(options.loglevel))
    global log
    log = rootLogger.getLogger(sys.argv[0])

    #------------Process and validate options---------------
    if options.doc:
        print __doc__
        sys.exit()

    if len(args) > 0:
        parser.error("Incorrect number of arguments")

    #validate infile path
    if options.infileName is not None:
        inFilePath = options.infileName
        if not path.exists(inFilePath):
            log.error("Input raster does not exist")
            sys.exit(1)
    else:
        log.error("No input file specified")
        sys.exit(1)

    #validate outfile path
    if options.outfileName is not None:
        outFilePath = path.abspath(options.outfileName)
        if ".shp" not in outFilePath:
            log.error("Output shape must have .shp extension")
            sys.exit(1)
    else:
        log.error("No output file specified")
        sys.exit(1)

    #Validate fieldName option
    fieldName = options.fieldName
    if fieldName == "":
        parser.error("fieldName can't be an empty string")

    #Validate filter option and convert filter to numeric value if present
    if options.filter is not None:
        filter = float(options.filter)
    else:
        filter = None

    #validate featureType
    if options.featureType not in ('point', 'poly'):
        log.error("Invalid feature type, must be either 'point' or 'poly'")
        sys.exit(1)

    #Assure that gdal is present
    if not __gdal_loaded__:
        raise OSError("Function readGDAL needs GDAL with python bindings")

    # register all of the raster drivers
    gdal.AllRegister()
    ds = gdal.Open(inFilePath, GA_ReadOnly)
    if ds is None:
        log.error('Could not open ' + inFilePath)
        sys.exit(1)

    ncols = ds.RasterXSize
    nrows = ds.RasterYSize
    nbands = ds.RasterCount

    #Info used for georeferencing
    geoTransform = ds.GetGeoTransform()
    xul = geoTransform[0]  # top left x
    cellsizeX = geoTransform[1]  # w-e pixel resolution
    rot1 = geoTransform[2]  # rotation, 0 if image is "north up"
    yul = geoTransform[3]  # top left y
    rot2 = geoTransform[4]  # rotation, 0 if image is "north up"
    cellsizeY = geoTransform[5]  # n-s pixel resolution
    proj = ds.GetProjection()

    #Calculate lower left corner
    xll = xul
    yll = yul + nrows * cellsizeY  # cellsizeY should be a negative value

    #Rotated rasters not handled...yet
    if rot1 != 0 or rot2 != 0:
        log.error('Handling of rotated rasters are not implemented yet')
        sys.exit(1)

    bandIndex = int(options.bandIndex)
    band = ds.GetRasterBand(bandIndex)

    nodata = band.GetNoDataValue()
    #If no nodata value is present in raster, set to -9999 for completeness
    if nodata is None:
        nodata = -9999

    rowmin = 0
    colmin = 0

    #Processing of data is made for blocks of the following size
    #Important - blocks are set to cover all columns for simpler processing
    #This might not always be optimal for read/write speed
    procXBlockSize = ncols
    procYBlockSize = 1

    #process option for dataType
    dataTypes, defaultDataType = ogrDataTypes, 'Real'

    try:
        dataType = dataTypes[options.dataType or defaultDataType]
    except KeyError:
        log.error(
            "Unknown datatype choose between: %s" % ",".join(dataTypes.keys()))
        sys.exit(1)

    #Create and inititialize output vector data source
    shapeDriver = ogr.GetDriverByName('ESRI Shapefile')
    if path.exists(outFilePath):
        shapeDriver.DeleteDataSource(outFilePath)
    shapeFile = shapeDriver.CreateDataSource(outFilePath)
    if shapeFile is None:
        log.error("Could not open output shapefile %s" % outFilePath)
        sys.exit(1)
    if options.featureType == "point":
        layer = shapeFile.CreateLayer(outFilePath, geom_type=ogr.wkbPoint)
    else:
        layer = shapeFile.CreateLayer(outFilePath, geom_type=ogr.wkbPolygon)

    fieldDefn = ogr.FieldDefn(fieldName, dataType)
    layer.CreateField(fieldDefn)

    #Loop over block of raster (at least one row in each block)
    rowsOffset = 0
    pg = ProgressBar(nrows, options.progressStream)

    for i in range(0, nrows, procYBlockSize):
        pg.update(i)
        data = band.ReadAsArray(xoff=colmin, yoff=rowmin + i,
                                win_xsize=procXBlockSize,
                                win_ysize=procYBlockSize)

        blockYll = yul + i * cellsizeY  # newCellsizeY is negative
        blockXll = xll
        if options.featureType == 'point':
            block2point(data, layer, blockXll, blockYll, cellsizeX,
                        cellsizeY, nodata, fieldName, filter)
        else:
            block2poly(data, layer, blockXll, blockYll, cellsizeX,
                       cellsizeY, nodata, fieldName, filter)

        rowsOffset += procYBlockSize  # Update offset

    shapeFile.Destroy()
    pg.finished()
Esempio n. 6
0
def main():
    # -----------Setting up and unsing option parser----------------
    parser = OptionParser(usage=usage, version=version)

    parser.add_option("-d", "--doc",
                      action="store_true", dest="doc",
                      help="Prints more detailed documentation and exit")

    parser.add_option("-v", "--verbose",
                      action="store_const", const=logging.INFO,
                      dest="loglevel", default=logging.WARNING,
                      help="Produce verbose output")

    parser.add_option("--no-progress",
                      action="store_const", dest="progressStream",
                      const=None, default=sys.stdout,
                      help="turn off the progress bar")

    parser.add_option("-i", "--input",
                      action="store", dest="infileName",
                      help="Input raster")

    parser.add_option("--bandIndex",
                      action="store", dest="bandIndex",
                      help="Band index to read from",
                      default=1)

    parser.add_option("-o", "--output",
                      action="store", dest="output", default=None,
                      help="Output file")

    parser.add_option("--solidName", default="TOPO",
                      action="store", dest="solidName",
                      help="Name of solid in STL-output")

    parser.add_option("--precision", default=6,
                      action="store", dest="precision",
                      help="Precision of coordinates in STL-output")

    parser.add_option("--buffer",
                      action="store", dest="buffer",
                      help="Add buffer distance to topo, " +
                      "damping out differences in elevation")

    (options, args) = parser.parse_args()

    # configuring logging
    FORMAT = '%(levelname)s %(message)s'
    logging.basicConfig(format=FORMAT)

    # ------------Process and validate options---------------
    if options.doc:
        print __doc__
        sys.exit()

    if len(args) > 0:
        parser.error("Incorrect number of arguments")

    # validate infile path
    if options.infileName is not None:
        inFilePath = options.infileName
        if not path.exists(inFilePath):
            log.error("Input raster does not exist")
            sys.exit(1)
    else:
        log.error("No input file specified")
        sys.exit(1)

    # validate outfile path
    if options.output is None:
        log.error("No output file specified")
        sys.exit(1)

    if options.buffer is not None:
        bufferDist = float(options.buffer)

    # Assure that gdal is present
    if not __gdal_loaded__:
        raise OSError("Function readGDAL needs GDAL with python bindings")

    # register all of the raster drivers
    gdal.AllRegister()
    ds = gdal.Open(inFilePath, GA_ReadOnly)
    if ds is None:
        log.error('Could not open ' + inFilePath)
        sys.exit(1)

    ncols = ds.RasterXSize
    nrows = ds.RasterYSize
    # nbands = ds.RasterCount

    # Info used for georeferencing
    geoTransform = ds.GetGeoTransform()
    xul = geoTransform[0]  # top left x
    cellsizeX = geoTransform[1]  # w-e pixel resolution
    rot1 = geoTransform[2]  # rotation, 0 if image is "north up"
    yul = geoTransform[3]  # top left y
    rot2 = geoTransform[4]  # rotation, 0 if image is "north up"
    cellsizeY = geoTransform[5]  # n-s pixel resolution
    # proj = ds.GetProjection()

    # Calculate lower left corner
    xll = xul
    yll = yul + nrows * cellsizeY  # cellsizeY should be a negative value

    # Rotated rasters not handled...yet
    if rot1 != 0 or rot2 != 0:
        log.error('Handling of rotated rasters are not implemented yet')
        sys.exit(1)

    bandIndex = int(options.bandIndex)
    band = ds.GetRasterBand(bandIndex)

    nodata = band.GetNoDataValue()
    # If no nodata value is present in raster, set to -9999 for completeness
    if nodata is None:
        nodata = -9999

    # Processing of data is made for blocks of the following size
    # two rows are processed at a time since triangles
    # are created between cell centres.
    procXBlockSize = ncols
    procYBlockSize = 2

    with open(options.output, 'w') as stlFile:
        pg = ProgressBar(nrows, options.progressStream)

        stlFile.write("solid " + options.solidName + "\n")

#        avgHeight = 0
        # write original cells to STL
        # Loop over blocks of raster

        for i in range(0, nrows - 1, 1):
            pg.update(i)
            data = band.ReadAsArray(xoff=0, yoff=i,
                                    win_xsize=procXBlockSize,
                                    win_ysize=procYBlockSize)
            if nodata in data:
                log.error("Nodata value found in raster," +
                          " this should be interpolated before" +
                          " converting to STL")
                sys.exit(1)

            # newCellsizeY is negative
            blockYll = yul + (procYBlockSize + i) * cellsizeY
            blockXll = xll

            block2STL(data, stlFile, blockXll, blockYll, cellsizeX,
                      cellsizeY, nodata, int(options.precision))

#            avgHeight += np.mean(data)

#        avgHeight /= (nrows - 1)

        # write buffer cells to STL
        leftBoundary = band.ReadAsArray(
            xoff=0, yoff=0,
            win_xsize=1,
            win_ysize=nrows
        )

        rightBoundary = band.ReadAsArray(
            xoff=ncols - 1, yoff=0,
            win_xsize=1,
            win_ysize=nrows
        )

        topBoundary = band.ReadAsArray(
            xoff=0, yoff=0,
            win_xsize=procXBlockSize,
            win_ysize=1
        )

        bottomBoundary = band.ReadAsArray(
            xoff=0, yoff=nrows - 1,
            win_xsize=procXBlockSize,
            win_ysize=1
        )

        avgHeight = 0.25 * (
            leftBoundary.mean() +
            rightBoundary.mean() +
            topBoundary.mean() +
            bottomBoundary.mean()
        )

        if options.buffer is not None:
            # overlap of one cell since triangles are created between
            # cell centres
            bufferCells = int(bufferDist / cellsizeX) + 1

            leftBuffer = leftBoundary[:]

            for i in range(1, bufferCells):
                dist = i * cellsizeX
                leftBuffer = np.hstack((
                    damp(leftBoundary, avgHeight, dist, bufferDist),
                    leftBuffer))

            block2STL(leftBuffer, stlFile, xll - (bufferCells - 1) * cellsizeX,
                      yll, cellsizeX, cellsizeY, nodata,
                      int(options.precision))

            rightBuffer = rightBoundary[:]
            for i in range(1, bufferCells):
                dist = i * cellsizeX
                rightBuffer = np.hstack((
                    rightBuffer,
                    damp(rightBoundary, avgHeight, dist, bufferDist)))

            block2STL(rightBuffer, stlFile, xll + (ncols - 1) * cellsizeX,
                      yll, cellsizeX, cellsizeY, nodata,
                      int(options.precision))

            topBuffer = topBoundary[:]
            for i in range(1, bufferCells):
                dist = abs(i * cellsizeY)
                topBuffer = np.vstack((
                    damp(topBoundary, avgHeight, dist, bufferDist),
                    topBuffer)
                )

            block2STL(topBuffer, stlFile, xll,
                      yul + cellsizeY,
                      cellsizeX, cellsizeY, nodata,
                      int(options.precision))

            bottomBuffer = bottomBoundary[:]
            for i in range(1, bufferCells):
                dist = abs(i * cellsizeY)
                bottomBuffer = np.vstack((
                    bottomBuffer,
                    damp(bottomBoundary, avgHeight, dist, bufferDist))
                )

            block2STL(bottomBuffer, stlFile, xll,
                      yll + (bufferCells - 1) * cellsizeY, cellsizeX,
                      cellsizeY, nodata,
                      int(options.precision))

            # Add corner buffers
            cornerBlock = np.ones((bufferCells, bufferCells))

            # upper right
            blockXll = xll + (ncols - 1) * cellsizeX
            blockYll = yul + cellsizeY
            startHeight = rightBoundary[0, 0]
            cornerPoint = (xll + (ncols - 0.5) * cellsizeX,
                           yul + 0.5 * cellsizeY)

            for col in range(bufferCells):
                for row in range(bufferCells):
                    centre = getCentreCoords(row, col, blockXll, blockYll,
                                             cellsizeX, cellsizeY,
                                             bufferCells, bufferCells)

                    dist = (np.sqrt(pow(centre[0] - cornerPoint[0], 2) +
                                    pow(centre[1] - cornerPoint[1], 2)))

                    # dist = min(row, col) * cellsizeX
                    cornerBlock[row, col] = damp(startHeight, avgHeight,
                                                 dist, bufferDist)

            cornerBlock[:, 0] = topBuffer[:, -1]
            cornerBlock[-1, :] = rightBuffer[0, :]

            block2STL(cornerBlock, stlFile, blockXll,
                      blockYll, cellsizeX, cellsizeY, nodata,
                      int(options.precision))

            # lower left
            blockXll = xll - (bufferCells - 1) * cellsizeX
            blockYll = yll + (bufferCells - 1) * cellsizeY
            startHeight = leftBoundary[-1, 0]
            cornerPoint = (xll + 0.5 * cellsizeX,
                           yll - 0.5 * cellsizeY)
            for col in range(bufferCells):
                for row in range(bufferCells):
                    centre = getCentreCoords(row, col, blockXll, blockYll,
                                             cellsizeX, cellsizeY,
                                             bufferCells, bufferCells)

                    dist = (np.sqrt(pow(centre[0] - cornerPoint[0], 2) +
                                    pow(centre[1] - cornerPoint[1], 2)))

                    cornerBlock[row, col] = damp(startHeight, avgHeight,
                                                 dist, bufferDist)
            cornerBlock[:, -1] = bottomBuffer[:, 0]
            cornerBlock[0, :] = leftBuffer[-1, :]
            block2STL(cornerBlock, stlFile, blockXll,
                      blockYll, cellsizeX, cellsizeY, nodata,
                      int(options.precision))

            # upper left
            blockXll = xll - (bufferCells - 1) * cellsizeX
            blockYll = yul + cellsizeY
            startHeight = leftBoundary[0, 0]
            cornerPoint = (xll + 0.5 * cellsizeX,
                           yul + 0.5 * cellsizeY)
            for col in range(bufferCells):
                for row in range(bufferCells):
                    centre = getCentreCoords(row, col, blockXll, blockYll,
                                             cellsizeX, cellsizeY,
                                             bufferCells, bufferCells)

                    dist = (np.sqrt(pow(centre[0] - cornerPoint[0], 2) +
                                    pow(centre[1] - cornerPoint[1], 2)))

                    cornerBlock[row, col] = damp(startHeight, avgHeight,
                                                 dist, bufferDist)
            cornerBlock[:, -1] = topBuffer[:, 0]
            cornerBlock[-1, :] = leftBuffer[0, :]
            block2STL(cornerBlock, stlFile, blockXll,
                      blockYll, cellsizeX, cellsizeY, nodata,
                      int(options.precision))

            # lower right
            blockXll = xll + (ncols - 1) * cellsizeX
            blockYll = yll + (bufferCells - 1) * cellsizeY
            startHeight = rightBoundary[-1, 0]
            cornerPoint = (xll + (ncols - 0.5) * cellsizeX,
                           yll - 0.5 * cellsizeY)
            for col in range(bufferCells):
                for row in range(bufferCells):
                    centre = getCentreCoords(row, col, blockXll, blockYll,
                                             cellsizeX, cellsizeY,
                                             bufferCells, bufferCells)

                    dist = (np.sqrt(pow(centre[0] - cornerPoint[0], 2) +
                                    pow(centre[1] - cornerPoint[1], 2)))

                    cornerBlock[row, col] = damp(startHeight, avgHeight,
                                                 dist, bufferDist)

            cornerBlock[:, 0] = bottomBuffer[:, -1]
            cornerBlock[0, :] = rightBuffer[-1, :]
            block2STL(cornerBlock, stlFile, blockXll,
                      blockYll, cellsizeX, cellsizeY, nodata,
                      int(options.precision))

        stlFile.write("endsolid %s\n" % options.solidName)

    pg.finished()
Esempio n. 7
0
def main():
    #-----------Setting up and unsing option parser-----------------------
    parser = OptionParser(usage=usage, version=version)

    parser.add_option("-d",
                      "--doc",
                      action="store_true",
                      dest="doc",
                      help="Prints more detailed documentation and exit")

    parser.add_option("-l",
                      "--loglevel",
                      action="store",
                      dest="loglevel",
                      default=2,
                      help="Sets the loglevel (0-3 where 3=full logging)")

    parser.add_option("--no-progress",
                      action="store_const",
                      dest="progressStream",
                      const=None,
                      default=sys.stdout,
                      help="turn off the progress bar")

    parser.add_option("-o",
                      "--output",
                      action="store",
                      dest="outfileName",
                      default=None,
                      help="Output file")

    parser.add_option("-i",
                      "--input",
                      action="store",
                      dest="infileName",
                      help="Input raster")

    parser.add_option("--bandIndex",
                      action="store",
                      dest="bandIndex",
                      help="Band index to read from",
                      default=1)

    parser.add_option("--dataType",
                      action="store",
                      dest="dataType",
                      help="Output data type",
                      default=None)

    parser.add_option("--featureType",
                      action="store",
                      dest="featureType",
                      help="Type of feature ('poly' or 'point')," +
                      " default='point'",
                      default='point')

    parser.add_option("--fieldName",
                      metavar='FIELD',
                      action="store",
                      dest="fieldName",
                      help="write data in shape file to FIELD," +
                      " default='value'",
                      default='value')

    parser.add_option("--filter",
                      action="store",
                      dest="filter",
                      help="Filter out data equal or below" +
                      " limit in shape output",
                      default=None)

    (options, args) = parser.parse_args()

    #------------Setting up logging capabilities -----------
    rootLogger = logger.RootLogger(int(options.loglevel))
    global log
    log = rootLogger.getLogger(sys.argv[0])

    #------------Process and validate options---------------
    if options.doc:
        print __doc__
        sys.exit()

    if len(args) > 0:
        parser.error("Incorrect number of arguments")

    #validate infile path
    if options.infileName is not None:
        inFilePath = options.infileName
        if not path.exists(inFilePath):
            log.error("Input raster does not exist")
            sys.exit(1)
    else:
        log.error("No input file specified")
        sys.exit(1)

    #validate outfile path
    if options.outfileName is not None:
        outFilePath = path.abspath(options.outfileName)
        if ".shp" not in outFilePath:
            log.error("Output shape must have .shp extension")
            sys.exit(1)
    else:
        log.error("No output file specified")
        sys.exit(1)

    #Validate fieldName option
    fieldName = options.fieldName
    if fieldName == "":
        parser.error("fieldName can't be an empty string")

    #Validate filter option and convert filter to numeric value if present
    if options.filter is not None:
        filter = float(options.filter)
    else:
        filter = None

    #validate featureType
    if options.featureType not in ('point', 'poly'):
        log.error("Invalid feature type, must be either 'point' or 'poly'")
        sys.exit(1)

    #Assure that gdal is present
    if not __gdal_loaded__:
        raise OSError("Function readGDAL needs GDAL with python bindings")

    # register all of the raster drivers
    gdal.AllRegister()
    ds = gdal.Open(inFilePath, GA_ReadOnly)
    if ds is None:
        log.error('Could not open ' + inFilePath)
        sys.exit(1)

    ncols = ds.RasterXSize
    nrows = ds.RasterYSize
    nbands = ds.RasterCount

    #Info used for georeferencing
    geoTransform = ds.GetGeoTransform()
    xul = geoTransform[0]  # top left x
    cellsizeX = geoTransform[1]  # w-e pixel resolution
    rot1 = geoTransform[2]  # rotation, 0 if image is "north up"
    yul = geoTransform[3]  # top left y
    rot2 = geoTransform[4]  # rotation, 0 if image is "north up"
    cellsizeY = geoTransform[5]  # n-s pixel resolution
    proj = ds.GetProjection()

    #Calculate lower left corner
    xll = xul
    yll = yul + nrows * cellsizeY  # cellsizeY should be a negative value

    #Rotated rasters not handled...yet
    if rot1 != 0 or rot2 != 0:
        log.error('Handling of rotated rasters are not implemented yet')
        sys.exit(1)

    bandIndex = int(options.bandIndex)
    band = ds.GetRasterBand(bandIndex)

    nodata = band.GetNoDataValue()
    #If no nodata value is present in raster, set to -9999 for completeness
    if nodata is None:
        nodata = -9999

    rowmin = 0
    colmin = 0

    #Processing of data is made for blocks of the following size
    #Important - blocks are set to cover all columns for simpler processing
    #This might not always be optimal for read/write speed
    procXBlockSize = ncols
    procYBlockSize = 1

    #process option for dataType
    dataTypes, defaultDataType = ogrDataTypes, 'Real'

    try:
        dataType = dataTypes[options.dataType or defaultDataType]
    except KeyError:
        log.error("Unknown datatype choose between: %s" %
                  ",".join(dataTypes.keys()))
        sys.exit(1)

    #Create and inititialize output vector data source
    shapeDriver = ogr.GetDriverByName('ESRI Shapefile')
    if path.exists(outFilePath):
        shapeDriver.DeleteDataSource(outFilePath)
    shapeFile = shapeDriver.CreateDataSource(outFilePath)
    if shapeFile is None:
        log.error("Could not open output shapefile %s" % outFilePath)
        sys.exit(1)
    if options.featureType == "point":
        layer = shapeFile.CreateLayer(outFilePath, geom_type=ogr.wkbPoint)
    else:
        layer = shapeFile.CreateLayer(outFilePath, geom_type=ogr.wkbPolygon)

    fieldDefn = ogr.FieldDefn(fieldName, dataType)
    layer.CreateField(fieldDefn)

    #Loop over block of raster (at least one row in each block)
    rowsOffset = 0
    pg = ProgressBar(nrows, options.progressStream)

    for i in range(0, nrows, procYBlockSize):
        pg.update(i)
        data = band.ReadAsArray(xoff=colmin,
                                yoff=rowmin + i,
                                win_xsize=procXBlockSize,
                                win_ysize=procYBlockSize)

        blockYll = yul + i * cellsizeY  # newCellsizeY is negative
        blockXll = xll
        if options.featureType == 'point':
            block2point(data, layer, blockXll, blockYll, cellsizeX, cellsizeY,
                        nodata, fieldName, filter)
        else:
            block2poly(data, layer, blockXll, blockYll, cellsizeX, cellsizeY,
                       nodata, fieldName, filter)

        rowsOffset += procYBlockSize  # Update offset

    shapeFile.Destroy()
    pg.finished()
Esempio n. 8
0
def main():

    # Parse command line arguments
    parser = argparse.ArgumentParser(description=__doc__)

    utils.add_standard_command_options(parser)

    parser.add_argument("-f",
                        "--format",
                        action="store",
                        dest="format",
                        default="ESRI Shapefile",
                        help="Format of road network")

    parser.add_argument("--inRoads",
                        required=True,
                        action="store",
                        dest="inRoads",
                        help="Input road network")

    parser.add_argument("--outRoads",
                        required=True,
                        action="store",
                        dest="outRoads",
                        help="Output road network")

    parser.add_argument("--buildings",
                        required=True,
                        action="store",
                        dest="buildings",
                        help="Input building roof contours (3D)")

    parser.add_argument("--topo",
                        required=True,
                        action="store",
                        dest="topo",
                        help="Input raster DEM")

    parser.add_argument("--split",
                        type=int,
                        action="store",
                        dest="split",
                        help="Threshold in changed road direction (degrees)" +
                        " for when to split road")

    args = parser.parse_args()

    if not path.exists(args.topo):
        log.error("Input raster does not exist")
        sys.exit(1)

    if not path.exists(args.buildings):
        log.error("Input building contours does not exist")
        sys.exit(1)
        return 1

    log.info("Reading DEM")
    topo = readGDAL(args.topo, bandIndex=1)[0]

    # Opening driver for road networks
    try:
        driver = ogr.GetDriverByName(args.format)
    except:
        log.error("Invalid format for road networks, check ogr documentation")
        sys.exit(1)

    if args.split is None:
        log.info("Do not split roads")
        splitLimit = None
    else:
        splitLimit = float(args.split)
        log.info("Split roads that change direction" +
                 " more than %f" % splitLimit)

    # extract extent from topo raster
    xmin = topo.xll
    ymin = topo.yll
    xmax = topo.xur()
    ymax = topo.yur()

    # Calculate dimensions of spatial index
    ncols = int((xmax - xmin) / CELLSIZE)
    nrows = int((ymax - ymin) / CELLSIZE)

    # Init spatial index of building contours
    spatInd = SpatialIndex(xmin, ymin, nrows, ncols, CELLSIZE)

    log.info("Reading and indexing building contours")
    # Read buildings and store using spatial indices
    spatInd.indexBuildingContours(args.buildings)

    # open road network shape-file
    log.info("Reading road network")
    inRoadFile = driver.Open(args.inRoads, update=0)

    if path.exists(args.outRoads):
        driver.DeleteDataSource(args.outRoads)

    outRoadFile = driver.CreateDataSource(args.outRoads)
    if inRoadFile is None:
        log.error("Could not open file with input road network")
        sys.exit(1)

    if outRoadFile is None:
        log.error("Could not open file with output road network")
        sys.exit(1)

    # Get layer definition and first feature of input road network
    inRoadLayer = inRoadFile.GetLayer()
    inRoadLayerDefn = inRoadLayer.GetLayerDefn()

    outRoadLayer = outRoadFile.CreateLayer("first_layer",
                                           geom_type=inRoadLayer.GetGeomType())

    # create fields on output road file
    for fieldInd in range(inRoadLayerDefn.GetFieldCount()):
        fieldDefn = inRoadLayerDefn.GetFieldDefn(fieldInd)
        outRoadLayer.CreateField(fieldDefn)

    outRoadLayerDefn = outRoadLayer.GetLayerDefn()
    fieldNames = [
        outRoadLayerDefn.GetFieldDefn(i).GetName()
        for i in range(outRoadLayerDefn.GetFieldCount())
    ]

    log.info("Adding attributes to road feature (if missing)")
    # Add attributes for street canyon geometry
    if "BHGT1" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BHGT1", ogr.OFTInteger))
    if "BHGT2" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BHGT2", ogr.OFTInteger))
    if "BHGT1W" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BHGT1W", ogr.OFTInteger))
    if "BHGT2W" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BHGT2W", ogr.OFTInteger))
    if "BANG1" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BANG1", ogr.OFTInteger))
    if "BANG2" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BANG2", ogr.OFTInteger))
    if "BDIST" not in fieldNames:
        outRoadLayer.CreateField(ogr.FieldDefn("BDIST", ogr.OFTInteger))
    if "BSECT" not in fieldNames:
        fieldDefn = ogr.FieldDefn("BSECT", ogr.OFTString)
        fieldDefn.SetWidth(40)
        outRoadLayer.CreateField(fieldDefn)
    if "BSECTW" not in fieldNames:
        fieldDefn = ogr.FieldDefn("BSECTW", ogr.OFTString)
        fieldDefn.SetWidth(40)
        outRoadLayer.CreateField(fieldDefn)

    fig1 = plt.figure(1)
    ax1 = plt.subplot(111)
    ax1.axis('equal')
    if PLOTIND > 0:
        spatInd.plot(ax1)

    roadInd = 0
    noGeom = 0
    nsplit = 0
    # get first road feature
    inRoadFeature = inRoadLayer.GetNextFeature()
    # Loop over all roads
    log.info("Finding nearest facades, setting heights...")
    pg = ProgressBar(inRoadLayer.GetFeatureCount(), sys.stdout)
    while inRoadFeature:
        pg.update(roadInd)
        outRoadFeatures = splitRoad(inRoadFeature, splitLimit,
                                    outRoadLayer.GetLayerDefn())
        if len(outRoadFeatures) > 1:
            log.debug("Raod split into %s parts" % len(outRoadFeatures))
        nsplit += len(outRoadFeatures) - 1
        for outRoadFeature in outRoadFeatures:
            intersections = []
            outRoadGeom = outRoadFeature.GetGeometryRef()
            road = Road(outRoadGeom)
            if outRoadGeom is None or \
               outRoadGeom.GetPointCount() == 0 or not spatInd.inside(road):
                noGeom += 1
                maxHeight1 = None
                maxHeight2 = None
                avgDist = None
                bAngle1 = None
                bAngle2 = None
                avgHeight1 = None
                avgHeight2 = None
            else:
                sumHeight1 = 0
                sumHeight2 = 0
                maxHeight1 = 0
                maxHeight2 = 0
                sumDist = 0
                # Define crossections along the road,
                # Defined by start and endpoints at both side of the road
                cs1List, cs2List = road.defineCrossSections()
                nCS = len(cs1List)
                log.debug("Defined %i cross sections" % nCS)
                # Check intersections with building contours for all cross-sections
                for csInd in range(nCS):
                    cs1 = cs1List[csInd]
                    cs2 = cs2List[csInd]
                    cs1MidPoint = cs1.P0 + 0.5 * (cs1.P1 - cs1.P0)
                    buildingSegments = spatInd.getBuildingSegments(
                        cs1MidPoint[0], cs1MidPoint[1])

                    log.debug("Calculating intersection")
                    if PLOTIND == roadInd and CSIND == csInd:
                        dist1, Pint1 = getIntersectingFacade(
                            ax1, cs1, buildingSegments, True)
                    else:
                        dist1, Pint1 = getIntersectingFacade(
                            ax1, cs1, buildingSegments, False)
                    if Pint1 is None:
                        log.debug("No intersection on side 1")
                        height1 = 0
                        dist1 = MAXDIST
                    else:
                        log.debug("Intersection1 in (%f, %f, %f)" %
                                  (Pint1[0], Pint1[1], Pint1[2]))
                        height1 = spatInd.getBuildingHeight(
                            Pint1[0], Pint1[1], Pint1[2], topo) + HEIGHTCORR
                        intersections.append(Pint1[:2])

                    if PLOTIND == roadInd and csInd == CSIND:
                        plotSegments(ax1,
                                     buildingSegments,
                                     color='red',
                                     width=2.0)
                        row, col = spatInd.getInd(cs1MidPoint[0],
                                                  cs1MidPoint[1])
                        spatInd.plotCell(ax1,
                                         row,
                                         col,
                                         color="purple",
                                         width=2.0)
                        plotSegments(ax1, [cs1List[csInd]],
                                     color="pink",
                                     style="-",
                                     width=1.0)
                        plt.draw()

                    cs2MidPoint = cs2.P0 + 0.5 * (cs2.P1 - cs2.P0)
                    buildingSegments = spatInd.getBuildingSegments(
                        cs2MidPoint[0], cs2MidPoint[1])

                    if PLOTIND == roadInd and csInd == CSIND:
                        plotSegments(ax1,
                                     buildingSegments,
                                     color='red',
                                     width=2.0)
                        row, col = spatInd.getInd(cs2MidPoint[0],
                                                  cs2MidPoint[1])
                        spatInd.plotCell(ax1,
                                         row,
                                         col,
                                         color="brown",
                                         width=2.0)
                        plotSegments(ax1, [cs2List[csInd]],
                                     color="red",
                                     style="-",
                                     width=1.0)
                        plt.draw()

                    log.debug("Calculating intersection")
                    if PLOTIND == roadInd and CSIND == csInd:
                        dist2, Pint2 = getIntersectingFacade(
                            ax1, cs2, buildingSegments, True)
                    else:
                        dist2, Pint2 = getIntersectingFacade(
                            ax1, cs2, buildingSegments, False)

                    if Pint2 is None:
                        log.debug("No intersection on side 2")
                        height2 = 0
                    else:
                        log.debug("Intersection2 in (%f, %f, %f)" %
                                  (Pint2[0], Pint2[1], Pint2[2]))
                        height2 = spatInd.getBuildingHeight(
                            Pint2[0], Pint2[1], Pint2[2], topo) + HEIGHTCORR
                        intersections.append(Pint2[:2])

                    sumHeight1 += height1
                    sumHeight2 += height2
                    sumDist += dist1 + dist2
                    maxHeight1 = int(max(height1, maxHeight1))
                    maxHeight2 = int(max(height2, maxHeight2))
                    if PLOTIND == roadInd and CSIND == csInd:
                        if Pint1 is not None:
                            ax1.text(Pint1[0], Pint1[1], "Distance=%f" % dist1)
                        if Pint2 is not None:
                            ax1.text(Pint2[0], Pint2[1], "Distance=%f" % dist2)

                avgHeight1 = int(sumHeight1 / float(nCS))
                avgHeight2 = int(sumHeight2 / float(nCS))
                # averaging over both sides of street
                # distance refers to between facades on opposite sides
                avgDist = int(round(sumDist / float(nCS)))
                bAngle1, bAngle2 = road.normalAngles()
                if PLOTIND > 0:
                    plotSegments(ax1,
                                 road.getSegments(),
                                 color='grey',
                                 width=0.3)
                if PLOTIND == roadInd:
                    plotSegments(ax1,
                                 road.getSegments(),
                                 color='black',
                                 width=2.0)
                    plotSegments(ax1,
                                 cs1List,
                                 color="green",
                                 style="--",
                                 width=0.5)
                    plotSegments(ax1,
                                 cs2List,
                                 color="green",
                                 style="--",
                                 width=0.5)

                    X = [intersect[0] for intersect in intersections]
                    Y = [intersect[1] for intersect in intersections]
                    if len(X) > 0:
                        ax1.plot(X, Y, "*")
                    plt.title("Road %i, cross-section %i" % (PLOTIND, CSIND))
                    plt.draw()

            # building height as list of sectors
            bsect = bheight2sect(avgHeight1, avgHeight2, bAngle1)
            bsectw = bheight2sect(maxHeight1, maxHeight2, bAngle1)

            outRoadFeature.SetField("BSECT", bsect)
            outRoadFeature.SetField("BSECTW", bsectw)
            outRoadFeature.SetField("BHGT1", avgHeight1)
            outRoadFeature.SetField("BHGT2", avgHeight2)
            outRoadFeature.SetField("BHGT1W", maxHeight1)
            outRoadFeature.SetField("BHGT2W", maxHeight2)
            outRoadFeature.SetField("BANG1", bAngle1)
            outRoadFeature.SetField("BANG2", bAngle2)
            outRoadFeature.SetField("BDIST", avgDist)

            outRoadLayer.CreateFeature(outRoadFeature)
            outRoadFeature.Destroy()
        inRoadFeature.Destroy()
        inRoadFeature = inRoadLayer.GetNextFeature()
        roadInd += 1

    inRoads = inRoadLayer.GetFeatureCount()
    outRoads = outRoadLayer.GetFeatureCount()
    # close datasource for building contours
    inRoadFile.Destroy()
    outRoadFile.Destroy()
    pg.finished()
    if PLOTIND > 0:
        plt.show()

    log.info("Read %i roads, wrote %i roads (created %i by splitting)" %
             (inRoads, outRoads, nsplit))

    if noGeom > 0:
        log.warning("Found %i roads without geometry" % noGeom)

    log.info("Finished")
Esempio n. 9
0
    def indexBuildingContours(self, buildingFile):
        """
        Read building contours from shape file and create a spatial indexing.
        The indexing is implemented as a nested dict
        cols={row1,row2,row3}, where row1..n = {cell1,cell2,...,celln},
        and cell1...n = [contour_1,contour_2,...,contour_n]
        Extent of index is set to extent of the used DEM (topo)
        @param buildingFile: shapefile with 3D building contours
        """
        # open building contours shape-file
        log.info("Reading building contours")
        # Init reading of shape-files using OGR
        shapeDriver = ogr.GetDriverByName('ESRI Shapefile')
        buildings = shapeDriver.Open(buildingFile, update=0)
        if buildings is None:
            log.error("Could not open file with building contours")
            return 1
        buildingsLayer = buildings.GetLayer()

        self.ind = {}

        # set up progress indicator
        pg = ProgressBar(buildingsLayer.GetFeatureCount(), sys.stdout)

        contourInd = 0  # Counter for building contour
        buildHeights = []  # List to store building height for plotting
        noGeom = 0  # Counter for invalid features without geometry reference

        # Read and process building contours
        contour = buildingsLayer.GetNextFeature()  # get first feature
        while contour:
            if log.level == 0:
                pg.update(contourInd)
            log.debug("Contour %i" % contourInd)

            contourGeom = contour.GetGeometryRef()

            if contourGeom is None or contourGeom.GetPointCount() == 0:
                noGeom += 1
            else:
                for i in range(1, contourGeom.GetPointCount()):
                    x1 = contourGeom.GetX(i - 1)
                    y1 = contourGeom.GetY(i - 1)
                    z1 = contourGeom.GetZ(i - 1)

                    x2 = contourGeom.GetX(i)
                    y2 = contourGeom.GetY(i)
                    z2 = contourGeom.GetZ(i)

                    P1 = np.array([x1, y1, z1])
                    P2 = np.array([x2, y2, z2])
                    try:
                        row, col = self.getInd((x2 + x1) / 2.0,
                                               (y1 + y2) / 2.0)
                    except ValueError:  # outside extent
                        row = col = None
                    if row is not None and col is not None:
                        if row not in self.ind:
                            self.ind[row] = {}
                            self.ind[row][col] = []
                        elif col not in self.ind[row]:
                            self.ind[row][col] = []

                        self.ind[row][col].append(Segment(P1, P2))

            contour.Destroy()
            contour = buildingsLayer.GetNextFeature()
            contourInd += 1
        # close datasource for building contours
        buildings.Destroy()
        pg.finished()
        if noGeom > 0:
            log.warning("Found %i building contours without geometry" % noGeom)
Esempio n. 10
0
def main():
    # -----------Setting up and unsing option parser-----------------------
    parser = OptionParser(usage=usage, version=version)

    parser.add_option("-d",
                      "--doc",
                      action="store_true",
                      dest="doc",
                      help="Prints more detailed documentation and exit")

    parser.add_option("-v",
                      action="store_const",
                      const=logging.DEBUG,
                      dest="loglevel",
                      default=get_loglevel(),
                      help="Produce verbose output")

    parser.add_option("--no-progress",
                      action="store_const",
                      dest="progressStream",
                      const=None,
                      default=sys.stdout,
                      help="turn off the progress bar")

    parser.add_option("-o",
                      "--output",
                      action="store",
                      dest="outfileName",
                      default=None,
                      help="Output file")

    parser.add_option("-i",
                      "--input",
                      action="store",
                      dest="infileName",
                      help="Input raster")

    parser.add_option("--bbox",
                      action="store",
                      dest="bbox",
                      help="Only read data within bbox," +
                      " --box <\"x1,y1,x2,y2\"")

    parser.add_option("--reclassify",
                      action="store",
                      dest="classTable",
                      help="Tab-separated table with code " +
                      "and z0 value for each landuse class")

    parser.add_option("--reclassFromColumn",
                      action="store",
                      dest="reclassFromColumn",
                      help="Header of reclass table column " +
                      "containing values to " +
                      "reclass (default is to use first column of classTable)")

    parser.add_option("--reclassToColumn",
                      action="store",
                      dest="reclassToColumn",
                      help="Header of reclass table column containing codes," +
                      " default is to use first column (default is to use " +
                      "second column of classTable)")

    parser.add_option("--resample",
                      action="store",
                      dest="cellFactor",
                      help="Resample grid by dividing cellsize with a" +
                      " factor. Factor <1 results in refinement." +
                      " Reprojection uses temporary refinement")

    parser.add_option("--resamplingMethod",
                      action="store",
                      dest="resamplingMethod",
                      help="For cellFactor > 1: " +
                      "Choose between 'mean', 'sum', 'majority' or" +
                      " 'count', default is sum,"
                      "For cellFactor < 1, choose between: " +
                      "'keepTotal' and 'keepValue', default is 'keepTotal'")

    parser.add_option("--summarize",
                      action="store_true",
                      dest="summarize",
                      help="Print a summary of the input grid properties")

    parser.add_option("--bandIndex",
                      action="store",
                      dest="bandIndex",
                      help="Band index to read from",
                      default=1)

    parser.add_option("--dataType",
                      action="store",
                      dest="dataType",
                      help="Output raster/shape data type",
                      default=None)

    parser.add_option("--toShape",
                      action="store_true",
                      dest="toShape",
                      help="output as shape file",
                      default=None)

    parser.add_option("--fieldName",
                      metavar='FIELD',
                      action="store",
                      dest="fieldName",
                      help="write data in shape file to FIELD," +
                      " default is 'value'",
                      default=None)

    parser.add_option("--filter",
                      action="store",
                      dest="filter",
                      help="Filter out data equal or below" +
                      " limit in shape output",
                      default=None)

    parser.add_option("-t",
                      "--template",
                      action="store",
                      dest="template",
                      help="Header for output raster when reprojecting")

    parser.add_option("--fromProj",
                      dest="fromProj",
                      help="Input raster proj4 definition string")

    parser.add_option("--toProj",
                      dest="toProj",
                      help="Output raster epsg or proj4 definition string")

    (options, args) = parser.parse_args()

    # ------------Setting up logging capabilities -----------
    # Setup logging
    logging.basicConfig(
        format='%(levelname)s:%(name)s: %(message)s',
        level=options.loglevel,
    )
    log = logging.getLogger(__name__)

    # ------------Process and validate options---------------
    if options.doc:
        print __doc__
        sys.exit(0)

    if len(args) > 0:
        parser.error("Incorrect number of arguments")

    # validate infile path
    if options.infileName is not None:
        inFilePath = path.abspath(options.infileName)
        if not path.exists(inFilePath):
            log.error("Input raster %s does not exist" % options.infileName)
            sys.exit(1)
    else:
        parser.error("No input data specified")

    # validate outfile path
    if options.outfileName is not None:
        outFilePath = path.abspath(options.outfileName)
        if options.toShape and ".shp" not in outFilePath:
            parser.error("Output shape has to to be specified with" +
                         " .shp extension")

    else:
        outFilePath = None

    # Validate fieldName option
    if options.toShape:
        if options.fieldName == "":
            parser.error("fieldName can't be an empty string")
        fieldName = options.fieldName or "value"
    elif options.fieldName is not None:
        parser.error("fieldName option only allowed together" +
                     " with shape output")

    # Validate filter option and convert filter to numeric value if present
    if not options.toShape and options.filter is not None:
        parser.error("Filter option only allowed together with shape output")
    elif options.toShape:
        if options.filter is not None:
            filter = float(options.filter)
        else:
            filter = None

    # read and process reclass table file
    if options.classTable is not None:
        reclassFromColumn = options.reclassFromColumn
        reclassToColumn = options.reclassToColumn

        if reclassFromColumn is not None and reclassToColumn is not None:

            desc = [{
                "id": reclassFromColumn,
                "type": float
            }, {
                "id": reclassToColumn,
                "type": float
            }]

            classTable = datatable.DataTable(desc=desc)
            classTable.read(options.classTable)
        else:
            classTable = datatable.DataTable()
            classTable.read(options.classTable)
            reclassFromColumn = classTable.desc[0]["id"]
            reclassToColumn = classTable.desc[1]["id"]
            classTable.convertCol(reclassFromColumn, float)
            classTable.convertCol(reclassToColumn, float)

        classTable.setKeys([reclassFromColumn])

        log.debug("Successfully read landuse class table")

        classDict = {}
        for row in classTable.data:
            classDict[row[classTable.colIndex[reclassFromColumn]]] = row[
                classTable.colIndex[reclassToColumn]]

    if options.cellFactor is not None:
        cellFactor = float(options.cellFactor)
        if cellFactor > 1 and \
                options.resamplingMethod not in ('sum',
                                                 'mean',
                                                 'majority',
                                                 'count',
                                                 None):

            log.error("Invalid resampling method, valid options for grid " +
                      "coarsening are 'sum' " + "and 'mean' and 'majority', " +
                      "specified %s" % options.resamplingMethod)
            sys.exit(1)

        elif cellFactor < 1 and \
                options.resamplingMethod not in ('keepTotal',
                                                 'keepValue',
                                                 None):
            log.error("Invalid resampling method, valid options for grid " +
                      "coarsening are 'keepTotal' and 'keepValue'" +
                      ", specified %s" % resamplingMethod)
            sys.exit(1)

        # setting default resampling methods
        if cellFactor > 1 and \
                options.resamplingMethod is None:
            resamplingMethod = 'sum'

        elif options.resamplingMethod is None:
            resamplingMethod = 'keepTotal'
        else:
            resamplingMethod = options.resamplingMethod

        if options.resamplingMethod == 'majority' or \
                options.resamplingMethod == 'count' and \
                options.toProj is not None:
            log.error("Resampling method " +
                      "%s not possible to " % options.resamplingMethod +
                      "combine with reprojection")
            sys.exit(1)

    # Assure that gdal is present
    if not __gdal_loaded__:
        raise OSError("Function readGDAL needs GDAL with python bindings")

    # register all of the raster drivers
    gdal.AllRegister()
    ds = gdal.Open(inFilePath, GA_ReadOnly)
    if ds is None:
        print 'Could not open ' + inFilePath
        sys.exit(1)

    ncols = ds.RasterXSize
    nrows = ds.RasterYSize
    nbands = ds.RasterCount

    # Info used for georeferencing
    geoTransform = ds.GetGeoTransform()
    xul = geoTransform[0]  # top left x
    cellsizeX = geoTransform[1]  # w-e pixel resolution
    rot1 = geoTransform[2]  # rotation, 0 if image is "north up"
    yul = geoTransform[3]  # top left y
    rot2 = geoTransform[4]  # rotation, 0 if image is "north up"
    cellsizeY = geoTransform[5]  # n-s pixel resolution
    proj = osr.SpatialReference(ds.GetProjection())

    # Calculate lower left corner
    xll = xul
    yll = yul + nrows * cellsizeY  # cellsizeY should be a negative value

    # Calculate upper right corner
    xur = xul + cellsizeX * ncols
    yur = yul

    # Rotated rasters not handled...yet
    if rot1 != 0 or rot2 != 0:
        print 'Rotated rasters are not supported by pyAirviro.geo.raster'
        sys.exit(1)

    if abs(cellsizeX) != abs(cellsizeY):
        print('Non-homogenous cellsizes are not' +
              ' supported by pyAirviro.geo.raster')
        sys.exit(1)

    bandIndex = int(options.bandIndex)

    band = ds.GetRasterBand(bandIndex)
    nodata = band.GetNoDataValue()

    # If no nodata value is present in raster, set to -9999 for completeness
    if nodata is None:
        nodata = -9999
    # Read data from a window defined by option --bbox <"x1,y1,x2,y2">
    if options.bbox is not None:
        try:
            x1, y1, x2, y2 = map(float, options.bbox.split(","))
        except:
            log.error("Invalid value for option --bbox <\"x1,y1,x2,y2\">")
            sys.exit(1)

        # Check if totally outside raster extent
        if x2 < xll or y2 < yll or x1 > xur or y1 > yul:
            log.error("Trying to extract outside grid boundaries")
            sys.exit(1)

        # Limit bbox to raster extent
        if x1 < xll:
            x1 = xll
        if x2 > xur:
            x2 = xur
        if y1 < yll:
            y1 = yll
        if y2 > yul:
            y2 = yul

        # estimate min and max of rows and cols
        colmin = int((x1 - xll) / cellsizeX)
        colmaxdec = (x2 - xll) / float(cellsizeX)
        rowmin = int((yul - y2) / abs(cellsizeY))
        rowmaxdec = (yul - y1) / float(abs(cellsizeY))

        if (colmaxdec - int(colmaxdec)) > 0:
            colmax = int(colmaxdec)
        else:
            colmax = int(colmaxdec - 1)

        if (rowmaxdec - int(rowmaxdec)) > 0:
            rowmax = int(rowmaxdec)
        else:
            rowmax = int(rowmaxdec - 1)

        nrows = rowmax - rowmin + 1
        ncols = colmax - colmin + 1
        xll = xll + colmin * cellsizeX
        yll = yul + (rowmax + 1) * cellsizeY  # cellsizeY is negative
        yul = yll - nrows * cellsizeY
        yur = yul
        xur = xll + ncols * cellsizeX
    else:
        rowmin = 0
        colmin = 0

    # process option for resampling
    if options.cellFactor is not None:
        cellFactor = float(cellFactor)
    else:
        cellFactor = 1

    if cellFactor >= 1:
        procYBlockSize = int(cellFactor)

    else:
        procYBlockSize = 1

    if options.toProj is None:
        # Set output raster dimensions and cellsize
        newNcols = int(ncols / cellFactor)
        newNrows = int(nrows / cellFactor)
        newCellsizeX = cellsizeX * cellFactor
        newCellsizeY = cellsizeY * cellFactor  # is a negative value as before
        newXll = xll
        newYll = yll
        newYul = yul
        newNodata = nodata

    else:
        # Create coordinate transform
        if options.fromProj is None:
            src_srs = proj
        else:
            src_srs = osr.SpatialReference()
            src_srs.ImportFromProj4(options.fromProj)

        tgt_srs = osr.SpatialReference()
        if options.toProj.startswith("epsg"):
            tgt_srs.ImportFromEPSG(int(options.toProj[5:]))
        else:
            tgt_srs.ImportFromProj4(options.toProj)
        coordTrans = osr.CoordinateTransformation(src_srs, tgt_srs)

        newXur = None
        newYur = None
        if options.template is None:
            # estimate extent from input
            newNcols = int(ncols / cellFactor)
            newNrows = int(nrows / cellFactor)
            newXll, newYll, z = coordTrans.TransformPoint(xll, yll)
            newXur, newYur, z = coordTrans.TransformPoint(xur, yur)
            newCellsizeX = (newXur - newXll) / float(newNcols)
            newCellsizeY = (newYur - newYll) / float(newNrows)
            newNodata = nodata
            newXll = newXll
            newYll = newYll
            newYul = newYur
        else:
            header = open(options.template, "r").read()
            newNcols = int(
                re.compile("ncols\s*([0-9]*)").search(header).group(1))
            newNrows = int(
                re.compile("nrows\s*([0-9]*)").search(header).group(1))
            newCellsizeX = float(
                re.compile("cellsize\s*([0-9]*)").search(header).group(1))
            newCellsizeY = -1 * newCellsizeX
            try:
                newNodata = float(
                    re.compile("NODATA_value\s*(.*?)\n").search(header).group(
                        1))
            except AttributeError:
                newNodata = float(
                    re.compile("nodata_value\s*(.*?)\n").search(header).group(
                        1))
            newXll = float(
                re.compile("xllcorner\s*(.*?)\n").search(header).group(1))
            newYll = float(
                re.compile("yllcorner\s*(.*?)\n").search(header).group(1))
            newYul = newYll - newNrows * newCellsizeY

    # Processing of data is made for blocks of the following size
    # Important - blocks are set to cover all columns for simpler processing
    # This might not always be optimal for read/write speed
    procXBlockSize = ncols

    # process option for dataType
    if options.toShape:
        dataTypes, defaultDataType = ogrDataTypes, 'Real'
    else:
        dataTypes, defaultDataType = gdalDataTypes, 'Float32'
    try:
        dataType = dataTypes[options.dataType or defaultDataType]
    except KeyError:
        log.error("Unknown datatype choose between: %s" %
                  ",".join(dataTypes.keys()))
        sys.exit(1)

    # Create and configure output raster data source
    if not options.toShape and outFilePath is not None:
        # Creates a raster dataset with 1 band

        mem_ds = gdal.GetDriverByName('MEM').Create(outFilePath, newNcols,
                                                    newNrows, 1, dataType)

        if mem_ds is None:
            print "Error: could not create output raster"
            sys.exit(1)

        outGeotransform = [newXll, newCellsizeX, 0, newYul, 0, newCellsizeY]
        mem_ds.SetGeoTransform(outGeotransform)
        if options.toProj is not None:
            mem_ds.SetProjection(tgt_srs.ExportToWkt())
        elif isinstance(proj, osr.SpatialReference):
            mem_ds.SetProjection(proj.ExportToProj4())
        else:
            mem_ds.SetProjection(proj)
        outBand = mem_ds.GetRasterBand(1)
        outBand.SetNoDataValue(newNodata)  # Set nodata-value

    if options.toProj is not None:
        outArray = np.zeros((newNrows, newNcols))
        nvals = np.zeros((newNrows, newNcols))
        outDef = {
            "ncols": newNcols,
            "nrows": newNrows,
            "xll": newXll,
            "yll": newYll,
            "yul": newYll - newNrows * newCellsizeY,
            "xur": newXll + newNcols * newCellsizeX,
            "cellsize": newCellsizeX
        }

    # Create and inititialize output vector data source
    if options.toShape:
        shapeDriver = ogr.GetDriverByName('ESRI Shapefile')
        if path.exists(outFilePath):
            shapeDriver.DeleteDataSource(outFilePath)
        shapeFile = shapeDriver.CreateDataSource(outFilePath)
        if shapeFile is None:
            log.error("Could not open output shapefile %s" % outFilePath)
            sys.exit(1)
        layer = shapeFile.CreateLayer(outFilePath, geom_type=ogr.wkbPolygon)
        fieldDefn = ogr.FieldDefn(fieldName, dataType)
        layer.CreateField(fieldDefn)

    # inititialize input grid summary
    inputGridSummary = {
        "sum": 0,
        "mean": 0,
        "nnodata": 0,
        "nnegative": 0,
        "xll": xll,
        "yll": yll,
        "ncols": ncols,
        "nrows": nrows,
        "cellsizeX": cellsizeX,
        "cellsizeY": cellsizeY,
        "nodatavalue": nodata
    }

    outputGridSummary = {
        "sum": 0,
        "mean": 0,
        "nnodata": 0,
        "nnegative": 0,
        "xll": newXll,
        "yll": newYll,
        "ncols": newNcols,
        "nrows": newNrows,
        "cellsizeX": newCellsizeX,
        "cellsizeY": newCellsizeY,
        "nodatavalue": newNodata
    }

    # Loop over block of raster (at least one row in each block)
    rowsOffset = 0
    errDict = {}
    pg = ProgressBar(nrows, options.progressStream)

    for i in range(0, nrows, int(procYBlockSize)):
        pg.update(i)
        data = band.ReadAsArray(xoff=colmin,
                                yoff=rowmin + i,
                                win_xsize=procXBlockSize,
                                win_ysize=procYBlockSize)

        if options.summarize:
            inputGridSummary = updateGridSummary(data, inputGridSummary,
                                                 nodata)

        if options.classTable is not None:
            try:
                data = reclassBlock(data, classDict, errDict)
            except IOError as e:
                log.error(str(e))
                sys.exit(1)

        if options.cellFactor is not None:
            try:
                data = resampleBlock(data[:, :], cellFactor, resamplingMethod,
                                     nodata)

            except ValueError as err:
                log.error(err.message)
                sys.exit(1)
            except IOError as err:
                log.error(err.message)
                sys.exit(1)

        if options.toProj is not None:
            blockDef = {
                "nrows": int(procYBlockSize / cellFactor),
                "ncols": int(procXBlockSize / cellFactor),
                "xll": xll + (colmin) * cellsizeX,
                "yul": yll - (nrows - rowmin - i) * cellsizeY,
                "cellsize": cellsizeX * cellFactor,
                "nodata": nodata
            }

            reprojectBlock(outArray, data, cellFactor, blockDef, outDef,
                           coordTrans, nvals)

        if outFilePath is not None:
            if options.toShape:
                blockYll = yul + i * newCellsizeY  # newCellsizeY is negative
                blockXll = xll
                block2vector(data, layer, blockXll, blockYll, newCellsizeX,
                             newCellsizeY, nodata, fieldName, filter)
            elif options.toProj is None:
                outBand.WriteArray(data, 0,
                                   rowsOffset)  # Write block to raster
                outBand.FlushCache()  # Write data to disk

        if options.summarize:
            outputGridSummary = updateGridSummary(data, outputGridSummary,
                                                  nodata)

        rowsOffset += int(procYBlockSize / cellFactor)  # Update offset

    if options.toShape:
        shapeFile.Destroy()

    if not options.toShape and options.toProj is not None:
        if options.resamplingMethod is not None and resamplingMethod == "mean":
            outArray = np.where(nvals > 0, outArray / nvals, outArray)

        outBand.WriteArray(outArray, 0, 0)
        outBand.FlushCache()  # Write data to disk

    if options.outfileName is not None and not options.toShape:
        outputDriver = ds.GetDriver()
        output_ds = outputDriver.CreateCopy(options.outfileName, mem_ds, 0)
        output_ds = None
        mem_ds = None

    pg.finished()

    if options.summarize:
        print "\nInput raster summary"
        printGridSummary(inputGridSummary, prefix="input")
        print "\nOutput raster summary"
        printGridSummary(outputGridSummary, prefix="output")

    if errDict != {}:
        print "Errors/warnings during processing:"

    for err, nerr in errDict.items():
        print "%s err in %i cells" % (err, nerr)