Beispiel #1
0
def createTerrainBasedTileJSON(params):
    baseUrls = getBaseUrls(params)
    with open('configs/terrain/layer.json') as f:
        terrainConfig = json.loads(f.read())

    # Delete unrelevant fields
    if 'extensions' in terrainConfig:
        del terrainConfig['extensions']
    # Overwrite
    terrainConfig['minzoom'] = params.minZoom
    terrainConfig['maxzoom'] = params.maxZoom
    terrainConfig['name'] = params.name
    terrainConfig['format'] = params.format
    terrainConfig['description'] = params.description
    terrainConfig['attribution'] = params.attribution
    terrainConfig['tiles'] = baseUrls

    geodetic = GlobalGeodetic(True)
    # Fix with empty ranges if we start with a biggeer min zoom
    for i in range(0, params.maxZoom + 1):
        if i < params.minZoom:
            terrainConfig['available'][i] = []
        # Max zoom is heigher than max terrain zoom level
        # In that case we include the full range within the bounds
        if i >= len(terrainConfig['available']):
            tileMinX, tileMinY = geodetic.LonLatToTile(params.bounds[0],
                                                       params.bounds[1], i)
            tileMaxX, tileMaxY = geodetic.LonLatToTile(params.bounds[2],
                                                       params.bounds[3], i)
            terrainConfig['available'].append(
                dict(startX=tileMinX,
                     endX=tileMaxX,
                     startY=tileMinY,
                     endY=tileMaxY))
    return json.dumps(terrainConfig)
    def testWatermaskOnlyReader(self):
        z = 9
        x = 769
        y = 319
        geodetic = GlobalGeodetic(True)

        ter = TerrainTile()
        [minx, miny, maxx, maxy] = geodetic.TileBounds(x, y, z)
        ter.fromFile('forge/data/quantized-mesh/%s_%s_%s_watermask.terrain' %
                     (z, x, y),
                     minx,
                     miny,
                     maxx,
                     maxy,
                     hasWatermask=True)

        self.assertEqual(len(ter.watermask), 256)
        for row in ter.watermask:
            self.assertEqual(len(row), 256)
            for val in row:
                self.assertTrue(val >= 0)
                self.assertTrue(val <= 255)

        ter.toFile(self.tmpfile)

        ter2 = TerrainTile()
        ter2.fromFile(self.tmpfile, minx, miny, maxx, maxy, hasWatermask=True)

        self.assertEqual(len(ter2.watermask), 256)

        for i in range(0, len(ter.watermask)):
            for j in range(0, len(ter.watermask[i])):
                self.assertEqual(ter.watermask[i][j], ter2.watermask[i][j])
Beispiel #3
0
    def populateLakes(self):
        self.setupDatabase()
        logger.info('Action: populateLakes()')

        # For now we never reproject lakes
        with self.userSession() as session:
            shpFile = self.config.get('Data', 'lakes')

            if not os.path.exists(shpFile):
                logger.error('Shapefile %s does not exists' % (shpFile))
                sys.exit(1)

            count = 1
            shp = ShpToGDALFeatures(shpFile)
            logger.info('Processing %s' % (shpFile))
            bulk = BulkInsert(Lakes, session, withAutoCommit=1000)

            for feature in shp.getFeatures():
                polygon = feature.GetGeometryRef()
                # Force 2D for lakes
                polygon.FlattenTo2D()
                # add shapefile path to dict
                # self.shpFilePath
                bulk.add(
                    dict(the_geom=WKTElement(polygon.ExportToWkt(), 4326)))
                count += 1
            bulk.commit()
            logger.info('Commit %s features for %s.' % (count, shpFile))
            # Once all features have been commited, start creating all
            # the simplified versions of the lakes
            logger.info('Simplifying lakes')
            tiles = TerrainTiles(self.dbConfigFile, tmsConfig, time.time())
            geodetic = GlobalGeodetic(True)
            bounds = (tiles.minLon, tiles.minLat, tiles.maxLon, tiles.maxLat)
            zooms = range(tiles.tileMinZ, tiles.tileMaxZ + 1)
            for i in xrange(0, len(zooms)):
                zoom = zooms[i]
                tablename = 'lakes_%s' % zoom
                tileMinX, tileMinY = geodetic.LonLatToTile(
                    bounds[0], bounds[1], zoom)
                tileMaxX, tileMaxY = geodetic.LonLatToTile(
                    bounds[2], bounds[3], zoom)
                tileBounds = geodetic.TileBounds(tileMinX, tileMinY, zoom)
                pointA = transformCoordinate(
                    'POINT(%s %s)' % (tileBounds[0], tileBounds[1]), 4326,
                    21781).GetPoints()[0]
                pointB = transformCoordinate(
                    'POINT(%s %s)' % (tileBounds[2], tileBounds[3]), 4326,
                    21781).GetPoints()[0]
                length = c2d.distance(pointA, pointB)
                pixelArea = pow(length, 2) / pow(256.0, 2)
                pixelLength = math.sqrt(pixelArea)
                session.execute(
                    create_simplified_geom_table(tablename, pixelLength))
                session.commit()
                logger.info('Commit table public.%s with %s meters '
                            'tolerance' % (tablename, pixelLength))
    def testExtensionsReader(self):
        z = 10
        x = 1563
        y = 590
        geodetic = GlobalGeodetic(True)

        ter = TerrainTile()
        [minx, miny, maxx, maxy] = geodetic.TileBounds(x, y, z)
        ter.fromFile(
            'forge/data/quantized-mesh/%s_%s_%s_light_watermask.terrain' %
            (z, x, y),
            minx,
            miny,
            maxx,
            maxy,
            hasLighting=True,
            hasWatermask=True)

        # check indices
        self.assertTrue(len(ter.indices) > 0)

        # check edges
        self.assertTrue(len(ter.westI) > 0)
        self.assertTrue(len(ter.southI) > 0)
        self.assertTrue(len(ter.eastI) > 0)
        self.assertTrue(len(ter.northI) > 0)

        # check extensions
        self.assertEqual(len(ter.watermask), 1)
        self.assertEqual(len(ter.watermask[0]), 1)
        # Water only -> 255
        self.assertEqual(ter.watermask[0][0], 255)
        ter.toFile(self.tmpfile)

        ter2 = TerrainTile()
        ter2.fromFile(self.tmpfile,
                      minx,
                      miny,
                      maxx,
                      maxy,
                      hasLighting=True,
                      hasWatermask=True)

        self.assertEqual(len(ter.watermask), len(ter2.watermask))
        self.assertEqual(len(ter.watermask[0]), len(ter2.watermask[0]))

        sign = lambda a: 1 if a > 0 else -1 if a < 0 else 0
        for i in range(0, len(ter.vLight)):
            for j in range(0, 3):
                # We cannot have an exact equality with successive
                # oct encoding and decoding
                # Thus we only check the sign
                self.assertEqual(sign(ter.vLight[i][j]),
                                 sign(ter2.vLight[i][j]))
Beispiel #5
0
def grid(bounds, zoomLevels, fullonly):
    geodetic = GlobalGeodetic(True)

    for tileZ in zoomLevels:
        tileMinX, tileMinY = geodetic.LonLatToTile(bounds[0], bounds[1], tileZ)
        tileMaxX, tileMaxY = geodetic.LonLatToTile(bounds[2], bounds[3], tileZ)

        for tileX in xrange(tileMinX, tileMaxX + 1):
            for tileY in xrange(tileMinY, tileMaxY + 1):
                tilebounds = geodetic.TileBounds(tileX, tileY, tileZ)
                if fullonly == 0 or isInside(tilebounds, bounds):
                    yield (tilebounds, (tileX, tileY, tileZ))
Beispiel #6
0
def createTileFromQueue(tq):
    pid = os.getpid()
    try:
        (qName, t0, dbConfigFile, hasLighting, hasWatermask) = tq
        sqs = getSQS()
        q = sqs.get_queue(qName)
        geodetic = GlobalGeodetic(True)
        # we do this as long as we are finding messages in the queue
        while True:
            parseOk = True
            try:
                # 20 is maximum wait time
                m = q.read(visibility_timeout=visibility_timeout,
                           wait_time_seconds=20)
                if m is None:
                    logger.info(
                        '[%s] No more messages found. Closing process' % pid)
                    break
                body = m.get_body()
                tiles = map(int, body.split(','))
            except Exception as e:
                parseOk = False

            if not parseOk or len(tiles) % 3 != 0:
                logger.warning('[%s] Unparsable message received.'
                               'Skipping...and removing message [%s]' %
                               (pid, m.get_body()))
                q.delete_message(m)
                continue

            for i in range(0, len(tiles), 3):
                try:
                    tileXYZ = [tiles[i], tiles[i + 1], tiles[i + 2]]
                    tilebounds = geodetic.TileBounds(tileXYZ[0], tileXYZ[1],
                                                     tileXYZ[2])
                    createTile((tilebounds, tileXYZ, t0, dbConfigFile,
                                hasLighting, hasWatermask))
                except Exception as e:
                    logger.error('[%s] Error while processing '
                                 'specific tile %s' % (pid, str(e)),
                                 exc_info=True)

            # when successfull, we delete the message from the queue
            logger.info('[%s] Successfully treated an SQS message: %s' %
                        (pid, body))
            q.delete_message(m)
    except Exception as e:
        logger.error('[%s] Error occured during processing. '
                     'Halting process ' % str(e),
                     exc_info=True)
Beispiel #7
0
 def _initPyramidMetadata(self):
     # It keeps track of the starting and ending tiles
     # and the missing tiles in between
     self.metadata = {}
     self.ranges = {}
     geodetic = GlobalGeodetic(True)
     bounds = self.meta['bounds']
     # Assume the whole extent is available
     for z in range(self.tileMinZoom, self.tileMaxZoom + 1):
         tileMinX, tileMinY = geodetic.LonLatToTile(bounds[0], bounds[1], z)
         tileMaxX, tileMaxY = geodetic.LonLatToTile(bounds[2], bounds[3], z)
         self.metadata[z] = dict(
             x=[tileMinX, tileMaxX],
             y=[tileMinY, tileMaxY]
         )
         self.ranges[z] = {}
Beispiel #8
0
def tileNotExists(tile):
    h = {'Referer': 'http://geo.admin.ch'}
    (bounds, tileXYZ, t0, basePath, tFormat, gridOrigin, tilesURLs) = tile
    # Only native tiles for now
    entryPoint = 'http:%s' % (random.choice(tilesURLs))

    # Account for a different origin
    if gridOrigin == 'topLeft':
        geodetic = GlobalGeodetic(True)
        nbYTiles = geodetic.GetNumberOfYTilesAtZoom(tileXYZ[2])
        tilexyz = (tileXYZ[0], nbYTiles - tileXYZ[1] - 1, tileXYZ[2])
        tileAdress = '/'.join(
            (str(tilexyz[2]), str(tilexyz[1]), str(tilexyz[0])))
    else:
        tileAdress = '/'.join(
            (str(tileXYZ[2]), str(tileXYZ[1]), str(tileXYZ[0])))

    url = '%s%s%s.%s' % (entryPoint, basePath, tileAdress, tFormat)
    tilecount.value += 1

    try:
        exists = resourceExists(url, headers=h)
    except Exception as e:
        logger.error('Connection Error', exc_info=True)
        logger.error('%s was skipped' % url, exc_info=True)
        raise Exception(e)

    if not exists:
        tileskipped.value += 1
    if tilecount.value % 1000 == 0:
        tend = time.time()
        logger.info('It took %s to (HEAD) request %s tiles. %s skipped' %
                    (str(datetime.timedelta(seconds=tend - t0)),
                     tilecount.value, tileskipped.value))
        logger.info('Last tile checked:')
        logger.info(url)
    if not exists:
        # Return everything in terrain coordinates
        # e.g. starting at the bottom left (Transformation is performed in Cesium)
        # https://github.com/camptocamp/cesium/blob/c2c_patches/Source/
        #     Scene/UrlTemplateImageryProvider.js#L500
        return tileXYZ
from forge.terrain import TerrainTile
from forge.terrain.topology import TerrainTopology
from forge.lib.shapefile_utils import ShpToGDALFeatures
from forge.lib.global_geodetic import GlobalGeodetic

basename = '7_133_98'
directory = '.tmp'
extension = '.terrain'

curDir = os.getcwd()
filePathSource = '%s/forge/data/shapefile-features/%s.shp' % (curDir, basename)
filePathTarget = '%s/%s%s' % (directory, basename, extension)

shapefile = ShpToGDALFeatures(shpFilePath=filePathSource)
features = shapefile.__read__()

terrainTopo = TerrainTopology(features=features)
terrainTopo.fromGDALFeatures()
terrainFormat = TerrainTile()

geodetic = GlobalGeodetic(True)
zxy = basename.split('_')
bounds = geodetic.TileBounds(float(zxy[1]), float(zxy[2]), float(zxy[0]))

terrainFormat.fromTerrainTopology(terrainTopo, bounds)
terrainFormat.toFile(filePathTarget)

# Display SwissCoordinates
terrainFormat.computeVerticesCoordinates(epsg=21781)
print terrainFormat
def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'f:t:', ['from=', 'to='])
    except getopt.GetoptError as err:
        error(str(err), 2, usage=usage)

    ffrom = None
    to = None
    ffile = None

    for o, a in opts:
        if o in ('-f', '--from'):
            ffrom = a
        if o in ('-t', '--to'):
            to = a

    if ffrom is None or to is None:
        if len(args) != 1:
            error("Please specify a file.", 4, usage=usage)
        ffile = args[0]

    tiles = []

    # We have file, so we get the tiles from the file
    if ffile is not None:
        with open(ffile) as f:
            for line in f:
                line = line.rstrip()
                if len(line) > 2:
                    tiles.append(map(int, line.split('/')))

    # If we have from to, we catch layers.json from poc and use from to for levels
    if ffrom is not None and to is not None:
        req = urlopen(poc_base_url + 'layer.json')
        layers = {}
        for line in req:
            layers = json.loads(line)
        for zoom in range(int(ffrom), int(to) + 1):
            level = layers['available'][zoom][0]
            for x in range(int(level['startX']), int(level['endX']) + 1):
                for y in range(int(level['startY']), int(level['endY']) + 1):
                    tiles.append([zoom, x, y])

    bucket = getBucket()
    g = GlobalGeodetic(tmscompatible=True)
    if not os.path.isdir('tmp'):
        os.mkdir('tmp')
    for tile in tiles:
        req = None
        tilebounds = g.TileBounds(tile[1], tile[2], tile[0])
        tilestring = str(tile[0]) + "/" + str(tile[1]) + "/" + str(tile[2])
        try:
            url = poc_base_url + tilestring + ".terrain?v=2.0.0"
            req = urlopen(url)
            with open(gzip_file_name, 'wb') as fp:
                fp.write(req.read())
            ff = gzip.open(gzip_file_name)
            with open(temp_file_name, 'wb') as fp:
                fp.write(ff.read())

            ter = TerrainTile()
            ter.fromFile(
                temp_file_name, tilebounds[0],
                tilebounds[2], tilebounds[1], tilebounds[3]
            )
            '''
            if os.path.isfile(tms_file_name):
                os.remove(tms_file_name)

            if os.path.isfile(shape_file_name):
                os.remove(shape_file_name)

            if os.path.isfile(tms_from_shape_file_name):
                os.remove(tms_from_shape_file_name)

            ter.toFile(tms_file_name)
            ter.toShapefile(shape_file_name)

            shapefile = ShpToGDALFeatures(shpFilePath=shape_file_name)
            features = shapefile.__read__()
            topology = TerrainTopology(features=features)
            topology.fromGDALFeatures()

            terFromPoc = TerrainTile()
            terFromPoc.fromFile(
                tms_file_name, tilebounds[0], tilebounds[2], tilebounds[1], tilebounds[3]
            )

            terFromShape = TerrainTile()
            terFromShape.fromTerrainTopology(topology)
            terFromShape.toFile(tms_from_shape_file_name)

            # Use this to select what is written to s3
            ter2 = terFromShape
            '''
            ter2 = ter

            fileObject = ter2.toStringIO()
            compressedFile = gzipFileObject(fileObject)

            bucketKey = tilestring + '.terrain'
            print 'Uploading %s to S3' % bucketKey
            writeToS3(bucket, bucketKey, compressedFile, 'POC Tiles copy',
                contentType=ter.getContentType())

        except Exception as e:
            print "error with " + line + " " + str(e)
        finally:
            if req:
                req.close()
    return 0
Beispiel #11
0
minWKT = 'POINT (%f %f)' % (MINX, MINY)
maxWKT = 'POINT (%f %f)' % (MAXX, MAXY)

minPoint = transformCoordinate(minWKT, 21781, 4326)
maxPoint = transformCoordinate(maxWKT, 21781, 4326)

MINX = minPoint.GetX()
MINY = minPoint.GetY()
MAXX = maxPoint.GetX()
MAXY = maxPoint.GetY()
print 'Extent :'
print[MINX, MINY, MAXX, MAXY]
MINZOOM = 3
MAXZOOM = 17

geodetic = GlobalGeodetic(True)
drv = ogr.GetDriverByName('ESRI Shapefile')
directory = '.tmp/'
extension = '.shp'

# Generate table with min max tile coordinates for all zoomlevels
for tz in range(MINZOOM, MAXZOOM + 1):
    filePathTarget = '%s%s%s' % (directory, tz, extension)
    tminx, tminy = geodetic.LonLatToTile(MINX, MINY, tz)
    tmaxx, tmaxy = geodetic.LonLatToTile(MAXX, MAXY, tz)

    dataSource = drv.CreateDataSource(filePathTarget)
    srs = osr.SpatialReference()
    srs.ImportFromEPSG(4326)
    layer = dataSource.CreateLayer('%s' % tz, srs, ogr.wkbPolygon)
    fieldKey = ogr.FieldDefn('Key', ogr.OFTString)
Beispiel #12
0
def createModelBasedTileJSON(params):
    tilecount = 0
    t0 = time.time()
    baseUrls = getBaseUrls(params)

    engine = getEngine(params)
    metadata = sqlalchemy.MetaData(bind=engine, schema=params.dbSchema)
    metadata.reflect()
    try:
        table = metadata.tables[params.dbSchema + '.' + params.tableName]
    except KeyError:
        raise ValueError('Table %s in schema %s could not be found' %
                         (params.tableName, params.dbSchema))
    # We assume a pkey is defined by only one column for now.
    pkColumn = table.primary_key.columns.items()[0]
    pkColumnName = pkColumn[0].__str__()
    pkColumnType = pkColumn[1].type.__class__
    model = getOrmModel(pkColumnName, pkColumnType, params)
    # Bounds generated from DB
    try:
        conn = engine.connect()
        bounds = conn.execute(
            tableExtentLiteral(params.dbSchema, params.tableName,
                               params.sridFrom)).fetchone()
        strBounds = tuple(['{:2f}'.format(i) for i in bounds])
        # Tuple to list for json converison
        bounds = [b for b in bounds]
        logger.info('Bounds are %s, %s, %s, %s' % strBounds)
    except Exception as e:
        logger.error('An error occured while determining the bounds',
                     exc_info=True)
        raise Exception(e)
    finally:
        conn.close()

    # pre-calculate the maximazed buffers in degrees
    if params.pxTolerance:
        geodetic = GlobalGeodetic(True)
        buffers = {}
        for z in range(params.minZoom, params.maxZoom):
            buffers[z] = degreesToMeters(
                geodetic.Resolution(z) * float(params.pxTolerance))

    try:
        session = scoped_session(sessionmaker(bind=engine))
        # We usually don't scan the last levels
        tiles = Tiles(bounds, params.minZoom, params.maxScanZoom, t0,
                      params.fullonly)
        tMeta = LayerMetadata(bounds=bounds,
                              minzoom=params.minZoom,
                              maxzoom=params.maxZoom,
                              baseUrls=baseUrls,
                              description=params.description,
                              attribution=params.attribution,
                              name=params.name)
        for tile in tiles:
            metaBuffer = 0.
            tilecount += 1
            if params.pxTolerance:
                xyz = tile[1]
                metaBuffer = buffers[xyz[2]]

            noGeom = scanLayer(tile, session, model, params.sridFrom,
                               params.sridTo, metaBuffer, tilecount)
            if noGeom:
                tMeta.removeTile(noGeom[0], noGeom[1], noGeom[2])
    finally:
        session.close()
        engine.dispose()
    return (tMeta.toJSON(), tilecount)
Beispiel #13
0
    def _stats(self, withDb=True):
        self.t0 = time.time()
        total = 0

        msg = '\n'
        tiles = TerrainTiles(self.dbConfigFile, self.tmsConfig, self.t0)
        geodetic = GlobalGeodetic(True)
        bounds = (tiles.minLon, tiles.minLat, tiles.maxLon, tiles.maxLat)
        zooms = range(tiles.tileMinZ, tiles.tileMaxZ + 1)

        db = DB('configs/terrain/database.cfg')
        try:
            with db.userSession() as session:
                for i in xrange(0, len(zooms)):
                    zoom = zooms[i]
                    model = modelsPyramid.getModelByZoom(zoom)
                    nbObjects = None
                    if withDb:
                        nbObjects = session.query(model).filter(
                            model.bboxIntersects(bounds)).count()
                    tileMinX, tileMinY = geodetic.LonLatToTile(
                        bounds[0], bounds[1], zoom)
                    tileMaxX, tileMaxY = geodetic.LonLatToTile(
                        bounds[2], bounds[3], zoom)
                    # Fast approach, but might not be fully correct
                    if tiles.fullonly == 1:
                        tileMinX += 1
                        tileMinY += 1
                        tileMaxX -= 1
                        tileMaxY -= 1
                    tileBounds = geodetic.TileBounds(tileMinX, tileMinY, zoom)
                    xCount = tileMaxX - tileMinX + 1
                    yCount = tileMaxY - tileMinY + 1
                    nbTiles = xCount * yCount
                    total += nbTiles
                    pointA = transformCoordinate(
                        'POINT(%s %s)' % (tileBounds[0], tileBounds[1]), 4326,
                        21781).GetPoints()[0]
                    pointB = transformCoordinate(
                        'POINT(%s %s)' % (tileBounds[2], tileBounds[3]), 4326,
                        21781).GetPoints()[0]
                    length = c2d.distance(pointA, pointB)
                    if tiles.fullonly == 1:
                        msg += 'WARNING: stats are approximative because ' \
                               'fullonly is activated!\n'
                    msg += 'At zoom %s:\n' % zoom
                    msg += 'We expect %s tiles overall\n' % nbTiles
                    msg += 'Min X is %s, Max X is %s\n' % (tileMinX, tileMaxX)
                    msg += '%s columns over X\n' % xCount
                    msg += 'Min Y is %s, Max Y is %s\n' % (tileMinY, tileMaxY)
                    msg += '%s rows over Y\n' % yCount
                    msg += '\n'
                    msg += 'A tile side is around %s meters' % int(
                        round(length))
                    if nbTiles > 0 and nbObjects is not None:
                        msg += 'We have an average of about %s triangles ' \
                               'per tile\n' % int(round(nbObjects / nbTiles))
                    msg += '\n\n'
            msg += '%s tiles in total.' % total
        except Exception as e:
            logger.error('An error occured during statistics collection')
            logger.error('%s' % e, exc_info=True)
            raise Exception(e)
        finally:
            db.userEngine.dispose()

        return (total, msg)