commonMain.earth.worldwind.util.AbstractTile.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of worldwind-jvm Show documentation
Show all versions of worldwind-jvm Show documentation
The WorldWind Kotlin SDK (WWK) includes the library, examples and tutorials for building multiplatform 3D virtual globe applications for Android, Web and Java.
package earth.worldwind.util
import earth.worldwind.geom.Angle.Companion.degrees
import earth.worldwind.geom.BoundingBox
import earth.worldwind.geom.Sector
import earth.worldwind.geom.Vec3
import earth.worldwind.globe.Globe
import earth.worldwind.render.RenderContext
import kotlin.math.abs
import kotlin.math.min
abstract class AbstractTile(
/**
* The sector spanned by this tile.
*/
val sector: Sector
) {
/**
* The tile's Cartesian bounding box.
*/
protected val extent by lazy { BoundingBox() }
protected open val heightLimits by lazy { FloatArray(2) }
protected var heightLimitsTimestamp = 0L
protected var extentExaggeration = 0.0f
protected var extentGlobeState: Globe.State? = null
protected var extentGlobeOffset: Globe.Offset? = null
private val nearestPoint = Vec3()
/**
* Indicates whether this tile's Cartesian extent intersects a frustum.
*
* @param rc the current render context
*
* @return true if the frustum intersects this tile's extent, otherwise false
*/
fun intersectsFrustum(rc: RenderContext) = getExtent(rc).intersectsFrustum(rc.frustum)
/**
* Indicates whether this tile intersects a specified sector.
*
* @param sector the sector of interest
*
* @return true if the specified sector intersects this tile's sector, otherwise false
*/
fun intersectsSector(sector: Sector) = this.sector.intersects(sector)
/**
* Calculates the distance from this tile to the camera point which ensures front to back sorting.
*
* @param rc the render context which provides the current camera point
*
* @return the L1 distance in degrees
*/
protected open fun drawSortOrder(rc: RenderContext): Double {
val cameraPosition = rc.camera.position
// determine the nearest latitude
val latAbsDifference = abs(cameraPosition.latitude.inDegrees - sector.centroidLatitude.inDegrees)
// determine the nearest longitude and account for the antimeridian discontinuity
val lonAbsDifference = abs(cameraPosition.longitude.inDegrees - sector.centroidLongitude.inDegrees)
val lonAbsDifferenceCorrected = min(lonAbsDifference, 360.0 - lonAbsDifference)
return latAbsDifference + lonAbsDifferenceCorrected // L1 distance on cylinder
}
/**
* Calculates nearest point of this tile to the camera position associated with the specified render context.
* Altitude value is based on the minimum height for the tile.
*
* @param rc the render context which provides the current camera point
*
* @return the nearest point
*/
protected open fun nearestPoint(rc: RenderContext): Vec3 {
val cameraPosition = rc.camera.position
// determine the nearest latitude
val nearestLat = cameraPosition.latitude.inDegrees.coerceIn(sector.minLatitude.inDegrees, sector.maxLatitude.inDegrees)
// determine the nearest longitude and account for the antimeridian discontinuity
val lonDifference = cameraPosition.longitude.inDegrees - sector.centroidLongitude.inDegrees
val nearestLon = when {
lonDifference < -180.0 -> sector.maxLongitude.inDegrees
lonDifference > 180.0 -> sector.minLongitude.inDegrees
else -> cameraPosition.longitude.inDegrees.coerceIn(sector.minLongitude.inDegrees, sector.maxLongitude.inDegrees)
}
val minHeight = heightLimits[0] * rc.verticalExaggeration
return rc.globe.geographicToCartesian(nearestLat.degrees, nearestLon.degrees, minHeight, nearestPoint)
}
protected open fun getExtent(rc: RenderContext): BoundingBox {
val globe = rc.globe
val timestamp = rc.elevationModelTimestamp
if (timestamp != heightLimitsTimestamp) {
if (globe.is2D) heightLimits.fill(0f) else calcHeightLimits(globe)
}
val ve = rc.verticalExaggeration.toFloat()
val state = rc.globeState
val offset = rc.globe.offset
if (timestamp != heightLimitsTimestamp || ve != extentExaggeration
|| state != extentGlobeState || offset != extentGlobeOffset) {
val minHeight = heightLimits[0] * ve
val maxHeight = heightLimits[1] * ve
extent.setToSector(sector, globe, minHeight, maxHeight)
}
heightLimitsTimestamp = timestamp
extentExaggeration = ve
extentGlobeState = state
extentGlobeOffset = offset
return extent
}
protected open fun calcHeightLimits(globe: Globe) {
// initialize the heights for elevation model scan
heightLimits[0] = Float.MAX_VALUE
heightLimits[1] = -Float.MAX_VALUE
globe.elevationModel.getHeightLimits(sector, heightLimits)
// check for valid height limits
if (heightLimits[0] > heightLimits[1]) heightLimits.fill(0f)
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy