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])
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]))
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))
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)
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
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) fieldKey.SetWidth(24) layer.CreateField(fieldKey) for tx in range(tminx, tmaxx + 1): for ty in range(tminy, tmaxy + 1): tileKey = '%s/%s/%s' % (tz, tx, ty) [xmin, ymin, xmax, ymax] = geodetic.TileBounds(tx, ty, tz) print 'Tile key' print tileKey print 'Tile bounds' print geodetic.TileBounds(tx, ty, tz) # Create polygon from bounds # https://pcjericks.github.io/py-gdalogr-cookbook/ # vector_layers.html#create-a-new-shapefile-and-add-data feature = ogr.Feature(layer.GetLayerDefn()) feature.SetField('Key', tileKey) wkt = 'POLYGON ((%f %f, %f %f, %f %f, %f %f, %f %f))' % ( xmin, ymin, xmax, ymin, xmax, ymax, xmin, ymax, xmin, ymin) polygon = ogr.CreateGeometryFromWkt(wkt) feature.SetGeometry(polygon) layer.CreateFeature(feature) feature.Destroy()
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)