Skip to content

Commit

Permalink
Support GeoPackage tiles bigger than tile matrix set bounds.
Browse files Browse the repository at this point in the history
  • Loading branch information
ComBatVision committed Dec 18, 2024
1 parent 64e4cb6 commit 7b3b730
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 17 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ repositories {
}
dependencies {
implementation 'earth.worldwind:worldwind:1.6.1'
implementation 'earth.worldwind:worldwind:1.6.2'
}
```

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ buildscript {

allprojects {
group = "earth.worldwind"
version = "1.6.1"
version = "1.6.2"

extra.apply {
set("minSdk", 21)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ open class TiledSurfaceImage(tileFactory: TileFactory, levelSet: LevelSet): Abst
onProgress?.invoke(downloaded, ++skipped, tileCount)
}
break // Continue downloading the next tile
} catch (throwable: Throwable) {
} catch (_: Throwable) {
delay(if (attempt % makeLocalRetries == 0) makeLocalTimeoutLong else makeLocalTimeoutShort)
}
}
Expand Down Expand Up @@ -176,23 +176,29 @@ open class TiledSurfaceImage(tileFactory: TileFactory, levelSet: LevelSet): Abst
protected open fun createTopLevelTiles() = Tile.assembleTilesForLevel(levelSet.firstLevel, tileFactory, topLevelTiles)

protected open fun addTileOrDescendants(rc: RenderContext, tile: ImageTile) {
// ignore tiles which soes not fit projection limits
// ignore tiles which do not fit projection limits
if (rc.globe.projectionLimits?.let { tile.intersectsSector(it) } == false) return
// ignore the tile and its descendants if it's not needed or not visible
if (!tile.intersectsSector(levelSet.sector) || !tile.intersectsSector(rc.terrain.sector) || !tile.intersectsFrustum(rc)) return
val retrieveCurrentLevel = tile.level.levelNumber >= levelSet.levelOffset
if (tile.level.isLastLevel || !tile.mustSubdivide(rc, detailControl)) {
if (retrieveCurrentLevel) addTile(rc, tile)
// Do not retrieve tiles bigger than level size because they can be simulated by downscaling more detailed tiles
// TODO Remove this restriction when GeoPackage will be able to correctly align tiles bigger than level size
val validSize = tile.level.levelWidth >= tile.level.tileWidth && tile.level.levelHeight >= tile.level.tileHeight
// Do not retrieve tiles from levels before level offset
val retrieveCurrentLevel = validSize && tile.level.levelNumber >= levelSet.levelOffset
// Use current tile if it must not subdivide and should be retrieved, or it is the last level tile
val isLastLevel = tile.level.isLastLevel
val mustSubdivide = tile.mustSubdivide(rc, detailControl)
if (isLastLevel || retrieveCurrentLevel && !mustSubdivide) {
// Skip using last level tile on more detailed levels if using ancestor tiles is switched off
if (!isLastLevel || !mustSubdivide || useAncestorTileTexture) addTile(rc, tile)
return // use the tile if it does not need to be subdivided
}
val currentAncestorTile = ancestorTile
val currentAncestorTexture = ancestorTexture
getTexture(rc, tile, retrieveTopLevelTiles && retrieveCurrentLevel)?.let { tileTexture ->
// tile has a texture; use it as a fallback tile for descendants
if (useAncestorTileTexture) {
ancestorTile = tile
ancestorTexture = tileTexture
}
ancestorTile = tile
ancestorTexture = tileTexture
}
// each tile has a cached size of 1, recursively process the tile's children
val children = tile.subdivideToCache(tileFactory, tileCache, 4)
Expand All @@ -205,14 +211,21 @@ open class TiledSurfaceImage(tileFactory: TileFactory, levelSet: LevelSet): Abst
val texture = getTexture(rc, tile)
val ancestorTile = ancestorTile
val ancestorTexture = ancestorTexture
val absentResourceList = rc.renderResourceCache.absentResourceList
val opacity = if (rc.isPickMode) 1f else rc.currentLayer.opacity
if (texture != null) { // use the tile's own texture
if (texture != null) {
// use the tile's own texture
val pool = rc.getDrawablePool<DrawableSurfaceTexture>()
val drawable = DrawableSurfaceTexture.obtain(pool).set(
activeProgram, tile.sector, opacity, texture, texture.coordTransform, rc.globe.offset
)
rc.offerSurfaceDrawable(drawable, 0.0 /*z-order*/)
} else if (ancestorTile != null && ancestorTexture != null) { // use the ancestor tile's texture, transformed to fill the tile sector
} else if (ancestorTile != null && ancestorTexture != null && (
// Use ancestor tile if it is allowed or previous level tile is still loading
useAncestorTileTexture || tile.level.levelNumber - ancestorTile.level.levelNumber <= 1
&& !absentResourceList.isResourceAbsent(tile.imageSource.hashCode())
)) {
// use the ancestor tile's texture, transformed to fill the tile sector
ancestorTexCoordMatrix.copy(ancestorTexture.coordTransform)
ancestorTexCoordMatrix.multiplyByTileTransform(tile.sector, ancestorTile.sector)
val pool = rc.getDrawablePool<DrawableSurfaceTexture>()
Expand All @@ -236,7 +249,7 @@ open class TiledSurfaceImage(tileFactory: TileFactory, levelSet: LevelSet): Abst
// If a cache source is not absent, then retrieve it instead of an original image source
val isCacheAbsent = cacheSource == null || rc.renderResourceCache.absentResourceList.isResourceAbsent(cacheSource.hashCode())
return rc.getTexture(
if (isCacheAbsent) imageSource else cacheSource!!, imageOptions, retrieve && (!isCacheOnly || !isCacheAbsent)
if (isCacheAbsent) imageSource else cacheSource, imageOptions, retrieve && (!isCacheOnly || !isCacheAbsent)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ open class GpkgTileFactory(

override fun createTile(sector: Sector, level: Level, row: Int, column: Int) =
buildTile(sector, level, row, column).apply {
imageSource = getImageSource(level, row, column)?.also { it.postprocessor = this }
// GeoPackage and WorldWind has different tile origin corners, thus tiles bigger than level will be incorrectly aligned.
// TODO Find solution how to correctly align or transform tiles bigger than level size and remove this restriction.
if (level.levelHeight >= level.tileHeight) {
imageSource = getImageSource(level, row, column)?.also { it.postprocessor = this }
}
}

protected open fun buildTile(sector: Sector, level: Level, row: Int, column: Int) = if (sector is MercatorSector) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ open class GeoPackage(val pathName: String, val isReadOnly: Boolean = true) {
sector.copy(contentSector)
tileOrigin.copy(tmsSector)
firstLevelDelta = Location(
tmsSector.deltaLatitude / minTileMatrix.matrixHeight * (1 shl minZoom),
tmsSector.deltaLongitude / minTileMatrix.matrixWidth * (1 shl minZoom)
tmsSector.deltaLatitude / (tms.maxY - tms.minY) * minTileMatrix.pixelYSize * minTileMatrix.tileHeight,
tmsSector.deltaLongitude / (tms.maxX - tms.minX) * minTileMatrix.pixelXSize * minTileMatrix.tileWidth
)
levelOffset = minZoom
numLevels = maxZoom + 1
Expand Down

0 comments on commit 7b3b730

Please sign in to comment.