Closed kttary closed 6 years ago
instead of latlong, i tried web mercator. Both did not give me correct result. Here is my snippet:
let srs2: GPKGSpatialReferenceSystem = srsDao.query(forOrganization: PROJ_AUTHORITY_EPSG, andCoordsysId: 3857)
let trans: SFPProjectionTransform = SFPProjectionTransform(fromEpsg: 4326, andToEpsg: 3857)
let myEnvelope = SFGeometryEnvelope(minX: -180, andMinY: -85, andMaxX: 0, andMaxY: 85)
let envelope2 = trans.transform(with: myEnvelope)
geoPackage.createTileMatrixSetTable()
geoPackage.createTileMatrixTable()
contents = GPKGContents()
contents.tableName = "MYTILE"
contents.setContentsDataType(GPKG_CDT_TILES)
contents.identifier = "MYTILE"
contents.theDescription = "MY FIRST TILE"
contents.lastChange = Date()
contents.minX = envelope2?.minX
contents.minY = envelope2?.minY
contents.maxX = envelope2?.maxX
contents.maxY = envelope2?.maxY
contents.setSrs(srs2)
let tileColumns = GPKGTileTable.createRequiredColumns()
let tileTable: GPKGTileTable = GPKGTileTable(table: "MYTILE", andColumns: tileColumns)
geoPackage.createTileTable(tileTable)
contentsDao.create(contents);
let tileMatrixSetDao: GPKGTileMatrixSetDao = geoPackage.getTileMatrixSetDao()
let tileMatrixSet: GPKGTileMatrixSet = GPKGTileMatrixSet()
tileMatrixSet.setContents(contents)
tileMatrixSet.setSrs(srs2)
tileMatrixSet.minX = envelope2?.minX
tileMatrixSet.minY = envelope2?.minY
tileMatrixSet.maxX = envelope2?.maxX
tileMatrixSet.maxY = envelope2?.maxY
tileMatrixSetDao.create(tileMatrixSet)
let tileMatrixDao: GPKGTileMatrixDao = geoPackage.getTileMatrixDao()
let fm = FileManager.default
let myPath: String = Bundle.main.path(forResource:"tile", ofType: "png")!
let tilePathData: Data? = fm.contents(atPath: myPath)
let image: UIImage = GPKGImageConverter.toImage(tilePathData)
let tileWidth : Int = Int(image.size.width);
let tileHeight : Int = Int(image.size.height);
var matrixWidthAndHeight = 2;
var pixelXSize: Double = (tileMatrixSet.maxX.doubleValue - tileMatrixSet.minX.doubleValue) / (Double)(matrixWidthAndHeight * tileWidth)
var pixelYSize: Double = (tileMatrixSet.maxY.doubleValue - tileMatrixSet.minY.doubleValue) / (Double)(matrixWidthAndHeight * tileHeight)
let tileData: Data = GPKGImageConverter.toData(image, andFormat: GPKGCompressFormats.fromName("png"))
for zoom in 0..<2 {
let tileMatrix: GPKGTileMatrix = GPKGTileMatrix()
tileMatrix.setContents(contents)
tileMatrix.zoomLevel = zoom as NSNumber
tileMatrix.matrixWidth = matrixWidthAndHeight as NSNumber
tileMatrix.matrixHeight = matrixWidthAndHeight as NSNumber
tileMatrix.tileWidth = tileWidth as NSNumber
tileMatrix.tileHeight = tileHeight as NSNumber
tileMatrix.pixelXSize = NSDecimalNumber(value: pixelXSize)
tileMatrix.pixelYSize = NSDecimalNumber(value: pixelYSize)
tileMatrixDao.create(tileMatrix)
matrixWidthAndHeight = matrixWidthAndHeight*2
pixelXSize = pixelXSize / 2.0
pixelYSize = pixelYSize / 2.0;
let myDao = geoPackage.getTileDao(withTableName: tileMatrix.tableName)
for column in 0..<tileMatrix.matrixHeight.int32Value {
for row in 0..<tileMatrix.matrixHeight.int32Value{
let newRow: GPKGTileRow = myDao!.newRow()
newRow.setZoomLevel(tileMatrix.zoomLevel as! Int32)
newRow.setTileColumn(column)
newRow.setTileRow(row)
newRow.setTileData(tileData)
myDao?.create(newRow)
}
}
}
today i try some changing, and the image aligned corectly on QGIS. However emulator can't show the tile. it logs some error as follow: 2018-07-31 14:56:54.489399+0700 MyGeopackage[1863:69373] [VKDefault] Tile 28.20.5 (128) in current unloaded state for 0.00 seconds - Raster Overlays Above Labels - Failed to decode (terminal) (0.00 sec) 2018-07-31 14:56:54.489563+0700 MyGeopackage[1863:69373] [VKDefault] Tile 24.20.5 (128) in current unloaded state for 0.00 seconds - Raster Overlays Above Labels - Failed to decode (terminal) (0.00 sec) 2018-07-31 14:56:54.489678+0700 MyGeopackage[1863:69373] [VKDefault] Tile 25.20.5 (128) in current unloaded state for 0.00 seconds - Raster Overlays Above Labels - Failed to decode (terminal) (0.00 sec) 2018-07-31 14:56:54.489829+0700 MyGeopackage[1863:69373] [VKDefault] Tile 26.20.5 (128) in current unloaded state for 0.00 seconds - Raster Overlays Above Labels - Failed to decode (terminal) (0.00 sec) 2018-07-31 14:56:54.489973+0700 MyGeopackage[1863:69373] [VKDefault] Tile 27.20.5 (128) in current unloaded state for 0.00 seconds - Raster Overlays Above Labels - Failed to decode (terminal) (0.00 sec) 2018-07-31 14:56:54.490122+0700 MyGeopackage[1863:69373] [VKDefault] Tile 28.18.5 (128) in current unloaded state for 0.00 seconds - Raster Overlays Above Labels - Failed to decode (terminal) (0.00 sec) 2018-07-31 14:56:54.490284+0700 MyGeopackage[1863:69373] [VKDefault] Tile 28.19.5 (128) in current unloaded state for 0.00 seconds - Raster Overlays Above Labels - Failed to decode (terminal) (0.00 sec) 2018-07-31 14:56:54.490438+0700 MyGeopackage[1863:69373] [VKDefault] Tile 26.18.5 (128) in current unloaded state for 0.00 seconds - Raster Overlays Above Labels - Failed to decode (terminal) (0.00 sec)
Pls some advice
Here is your code slightly modified and with tiles downloaded for convenience. On a phone simulator and based on zoom levels, tiles may not show up till about zoom 3.
func makeTiles(geoPackage: GPKGGeoPackage){
let srsDao: GPKGSpatialReferenceSystemDao = geoPackage.getSpatialReferenceSystemDao()
let srs2: GPKGSpatialReferenceSystem = srsDao.query(forOrganization: PROJ_AUTHORITY_EPSG, andCoordsysId: 3857)
let trans: SFPProjectionTransform = SFPProjectionTransform(fromEpsg: 4326, andToEpsg: 3857)
let myEnvelope = SFGeometryEnvelope(minXDouble: -180, andMinYDouble: PROJ_WEB_MERCATOR_MIN_LAT_RANGE, andMaxXDouble: 180, andMaxYDouble: PROJ_WEB_MERCATOR_MAX_LAT_RANGE)
let envelope2 = trans.transform(with: myEnvelope)
geoPackage.createTileMatrixSetTable()
geoPackage.createTileMatrixTable()
let contents: GPKGContents = GPKGContents()
contents.tableName = "MYTILE"
contents.setContentsDataType(GPKG_CDT_TILES)
contents.identifier = "MYTILE"
contents.theDescription = "MY FIRST TILE"
contents.lastChange = Date()
contents.minX = envelope2?.minX
contents.minY = envelope2?.minY
contents.maxX = envelope2?.maxX
contents.maxY = envelope2?.maxY
contents.setSrs(srs2)
let tileColumns = GPKGTileTable.createRequiredColumns()
let tileTable: GPKGTileTable = GPKGTileTable(table: "MYTILE", andColumns: tileColumns)
geoPackage.createTileTable(tileTable)
let contentsDao: GPKGContentsDao = geoPackage.getContentsDao()
contentsDao.create(contents)
let tileMatrixSetDao: GPKGTileMatrixSetDao = geoPackage.getTileMatrixSetDao()
let tileMatrixSet: GPKGTileMatrixSet = GPKGTileMatrixSet()
tileMatrixSet.setContents(contents)
tileMatrixSet.setSrs(srs2)
tileMatrixSet.minX = envelope2?.minX
tileMatrixSet.minY = envelope2?.minY
tileMatrixSet.maxX = envelope2?.maxX
tileMatrixSet.maxY = envelope2?.maxY
tileMatrixSetDao.create(tileMatrixSet)
let tileMatrixDao: GPKGTileMatrixDao = geoPackage.getTileMatrixDao()
let data: Data = downloadTile(z: 0, x: 0, y: 0)
let image: UIImage = GPKGImageConverter.toImage(data)
let tileWidth : Int = Int(image.size.width)
let tileHeight : Int = Int(image.size.height)
var matrixWidthAndHeight = 1
var pixelXSize: Double = (tileMatrixSet.maxX.doubleValue - tileMatrixSet.minX.doubleValue) / (Double)(matrixWidthAndHeight * tileWidth)
var pixelYSize: Double = (tileMatrixSet.maxY.doubleValue - tileMatrixSet.minY.doubleValue) / (Double)(matrixWidthAndHeight * tileHeight)
for zoom in 0..<4 {
let tileMatrix: GPKGTileMatrix = GPKGTileMatrix()
tileMatrix.setContents(contents)
tileMatrix.zoomLevel = zoom as NSNumber
tileMatrix.matrixWidth = matrixWidthAndHeight as NSNumber
tileMatrix.matrixHeight = matrixWidthAndHeight as NSNumber
tileMatrix.tileWidth = tileWidth as NSNumber
tileMatrix.tileHeight = tileHeight as NSNumber
tileMatrix.pixelXSize = NSDecimalNumber(value: pixelXSize)
tileMatrix.pixelYSize = NSDecimalNumber(value: pixelYSize)
tileMatrixDao.create(tileMatrix)
matrixWidthAndHeight = matrixWidthAndHeight*2
pixelXSize = pixelXSize / 2.0
pixelYSize = pixelYSize / 2.0
let myDao = geoPackage.getTileDao(withTableName: tileMatrix.tableName)
for column in 0..<tileMatrix.matrixHeight.int32Value {
for row in 0..<tileMatrix.matrixHeight.int32Value{
let newRow: GPKGTileRow = myDao!.newRow()
newRow.setZoomLevel(tileMatrix.zoomLevel as! Int32)
newRow.setTileColumn(column)
newRow.setTileRow(row)
let tileData: Data = downloadTile(z: zoom, x: column, y: row)
newRow.setTileData(tileData)
myDao?.create(newRow)
}
}
}
let tileDao: GPKGTileDao = geoPackage.getTileDao(withTableName: contents.tableName)
let tileOverlay: MKTileOverlay = GPKGOverlayFactory.tileOverlay(with: tileDao)
tileOverlay.canReplaceMapContent = false
DispatchQueue.main.async { [unowned self] in
self.mapView.add(tileOverlay)
}
}
func downloadTile(z: Int, x: Int32, y: Int32) -> Data {
var tileData: Data? = nil
let url: String = String(format: "https://osm.geointservices.io/osm_tiles/%d/%d/%d.png", z, x, y)
do {
tileData = try Data.init(contentsOf: URL(string: url)!)
} catch {
}
return tileData!;
}
Thank you for reply. When i tried to download for certain area of interest for example area between 152.921111, -27.604734 to 153.108080, -27.372853 from zoom level 4 to 5, the tiles look misaligned. What variable should i adjust and how to get those values? Thank you in advance
You'll need to make sure the tile matrix set bounds are correct and work for all tile matrix zoom levels. The tile matrix dimensions, tile size dimensions, and pixel sizes must all be correct with the zoom level and the tile matrix set.
This site is very useful for determining the required bounds if you are using XYZ tiles.
This method will give you an encompassing tile grid from a web mercator bounding box and this one will do the same for a wgs84 bounding box.
This method will give you the web mercator bounding box of a single XYZ tile and this one will give you one for a range of tiles.
Cannot fully got your clue.. Im looping through encopasing tilegrid but no luck
let srs2: GPKGSpatialReferenceSystem = srsDao.query(forOrganization: PROJ_AUTHORITY_EPSG, andCoordsysId: 3857)
let trans: SFPProjectionTransform = SFPProjectionTransform(fromEpsg: 4326, andToEpsg: 3857)
let myEnvelope = SFGeometryEnvelope(minXDouble: 0, andMinYDouble: PROJ_WEB_MERCATOR_MIN_LAT_RANGE, andMaxXDouble: 180, andMaxYDouble: 0)
let envelope2 = trans.transform(with: myEnvelope)
let totalTileGrid: GPKGTileGrid = GPKGTileBoundingBoxUtils.getTileGrid(withWebMercatorBoundingBox: GPKGBoundingBox(minLongitudeDouble: envelope2!.minX as! Double, andMinLatitudeDouble: envelope2!.minY as! Double, andMaxLongitudeDouble: envelope2!.maxX as! Double, andMaxLatitudeDouble: envelope2!.maxY as! Double), andZoom: 1)
let totalBoundingBox: GPKGBoundingBox = GPKGTileBoundingBoxUtils.getWebMercatorBoundingBox(with: totalTileGrid, andZoom: 1)
geoPackage.createTileMatrixSetTable()
geoPackage.createTileMatrixTable()
contents = GPKGContents()
contents.tableName = "MYTILE"
contents.setContentsDataType(GPKG_CDT_TILES)
contents.identifier = "MYTILE"
contents.theDescription = "MY FIRST TILE"
contents.lastChange = Date()
contents.minX = totalBoundingBox.minLongitude
contents.minY = totalBoundingBox.minLatitude
contents.maxX = totalBoundingBox.maxLongitude
contents.maxY = totalBoundingBox.maxLatitude
contents.setSrs(srs2)
let tileColumns = GPKGTileTable.createRequiredColumns()
let tileTable: GPKGTileTable = GPKGTileTable(table: "MYTILE", andColumns: tileColumns)
geoPackage.createTileTable(tileTable)
contentsDao.create(contents);
let tileMatrixSetDao: GPKGTileMatrixSetDao = geoPackage.getTileMatrixSetDao()
let tileMatrixSet: GPKGTileMatrixSet = GPKGTileMatrixSet()
tileMatrixSet.setContents(contents)
tileMatrixSet.setSrs(srs2)
tileMatrixSet.minX = contents.minX
tileMatrixSet.minY = contents.minY
tileMatrixSet.maxX = contents.maxX
tileMatrixSet.maxY = contents.maxY
tileMatrixSetDao.create(tileMatrixSet)
let tileMatrixDao: GPKGTileMatrixDao = geoPackage.getTileMatrixDao()
var tileGrid : GPKGTileGrid = totalTileGrid
let myDao = geoPackage.getTileDao(withTableName: "MYTILE")
for zoom:Int in 1..<4 {
let tileData: Data = downloadTile(z: zoom, x: tileGrid.minX, y: tileGrid.minY)
let image: UIImage = GPKGImageConverter.toImage(tileData)
let tileWidth : Int = Int(image.size.width)
let tileHeight : Int = Int(image.size.height)
for x in tileGrid.minX..<tileGrid.maxX+1 {
for y in tileGrid.minY..<tileGrid.maxY+1 {
let tileData: Data = downloadTile(z: zoom, x: x, y: y)
let newRow: GPKGTileRow = myDao!.newRow()
newRow.setZoomLevel(Int32(zoom))
newRow.setTileColumn(x-tileGrid.minX)
newRow.setTileRow(y-tileGrid.minY)
newRow.setTileData(tileData)
myDao?.create(newRow)
}
}
let matrixWidth = tileGrid.maxX - tileGrid.minX + 1
let matrixHeight = tileGrid.maxY - tileGrid.minY + 1;
let pixelXSize = (tileMatrixSet.maxX.doubleValue - tileMatrixSet.minX.doubleValue) / Double(matrixWidth * Int32(tileWidth))
let pixelYSize = (tileMatrixSet.maxY.doubleValue - tileMatrixSet.minY.doubleValue) / Double(matrixHeight * Int32(tileHeight))
let tileMatrix: GPKGTileMatrix = GPKGTileMatrix()
tileMatrix.setContents(contents)
tileMatrix.zoomLevel = zoom as NSNumber
tileMatrix.matrixWidth = matrixWidth as NSNumber
tileMatrix.matrixHeight = matrixHeight as NSNumber
tileMatrix.tileWidth = tileWidth as NSNumber
tileMatrix.tileHeight = tileHeight as NSNumber
tileMatrix.pixelXSize = NSDecimalNumber(value: pixelXSize)
tileMatrix.pixelYSize = NSDecimalNumber(value: pixelYSize)
tileMatrixDao.create(tileMatrix)
tileGrid = GPKGTileBoundingBoxUtils.tileGrid(tileGrid, zoomIncrease: 1)
}
got it. Thank you
I'm trying to insert the zoom level 0 of osm (attached) to a tiletable with following values:
tileMatrixSet.minX = -180 tileMatrixSet.minY = -85 tileMatrixSet.maxX = 180 tileMatrixSet.maxY = 85
Unfortunately the result look misaligned. What is the proper value for minX, minY, maxX and maxY?