Add abstraction for coordinate projections
This commit is contained in:
parent
cda8d8e76f
commit
42e0a4c46d
@ -27,7 +27,8 @@ public interface DraggableMapFeature : MapFeature {
|
||||
public fun Iterable<MapFeature>.computeBoundingBox(zoom: Double): GmcRectangle? =
|
||||
mapNotNull { it.getBoundingBox(zoom) }.wrapAll()
|
||||
|
||||
internal fun Pair<Double, Double>.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second)
|
||||
internal fun Pair<Number, Number>.toCoordinates() =
|
||||
GeodeticMapCoordinates.ofDegrees(first.toDouble(), second.toDouble())
|
||||
|
||||
internal val defaultZoomRange = 1..18
|
||||
|
||||
|
@ -171,6 +171,16 @@ public fun MapFeatureBuilder.points(
|
||||
id: FeatureId? = null,
|
||||
): FeatureId = addFeature(id, MapPointsFeature(points, zoomRange, stroke, color, pointMode))
|
||||
|
||||
@JvmName("pointsFromPairs")
|
||||
public fun MapFeatureBuilder.points(
|
||||
points: List<Pair<Double, Double>>,
|
||||
zoomRange: IntRange = defaultZoomRange,
|
||||
stroke: Float = 2f,
|
||||
color: Color = Color.Red,
|
||||
pointMode: PointMode = PointMode.Points,
|
||||
id: FeatureId? = null,
|
||||
): FeatureId = addFeature(id, MapPointsFeature(points.map { it.toCoordinates() }, zoomRange, stroke, color, pointMode))
|
||||
|
||||
@Composable
|
||||
public fun MapFeatureBuilder.image(
|
||||
position: Pair<Double, Double>,
|
||||
|
@ -10,7 +10,16 @@ import kotlin.math.atan
|
||||
import kotlin.math.ln
|
||||
import kotlin.math.sinh
|
||||
|
||||
public data class MercatorCoordinates(val x: Distance, val y: Distance)
|
||||
public data class ProjectionCoordinates(val x: Distance, val y: Distance)
|
||||
|
||||
/**
|
||||
* @param T the type of projection coordinates
|
||||
*/
|
||||
public interface MapProjection<T: Any>{
|
||||
public fun toGeodetic(pc: T): GeodeticMapCoordinates
|
||||
public fun toProjection(gmc: GeodeticMapCoordinates): T
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param baseLongitude the longitude offset in radians
|
||||
@ -21,18 +30,18 @@ public open class MercatorProjection(
|
||||
public val baseLongitude: Angle = Angle.zero,
|
||||
protected val radius: Distance = DEFAULT_EARTH_RADIUS,
|
||||
private val correctedRadius: ((GeodeticMapCoordinates) -> Distance)? = null,
|
||||
) {
|
||||
): MapProjection<ProjectionCoordinates> {
|
||||
|
||||
public fun toGeodetic(mc: MercatorCoordinates): GeodeticMapCoordinates {
|
||||
override fun toGeodetic(pc: ProjectionCoordinates): GeodeticMapCoordinates {
|
||||
val res = GeodeticMapCoordinates.ofRadians(
|
||||
atan(sinh(mc.y / radius)),
|
||||
baseLongitude.radians.value + (mc.x / radius),
|
||||
atan(sinh(pc.y / radius)),
|
||||
baseLongitude.radians.value + (pc.x / radius),
|
||||
)
|
||||
return if (correctedRadius != null) {
|
||||
val r = correctedRadius.invoke(res)
|
||||
GeodeticMapCoordinates.ofRadians(
|
||||
atan(sinh(mc.y / r)),
|
||||
baseLongitude.radians.value + mc.x / r,
|
||||
atan(sinh(pc.y / r)),
|
||||
baseLongitude.radians.value + pc.x / r,
|
||||
)
|
||||
} else {
|
||||
res
|
||||
@ -42,10 +51,10 @@ public open class MercatorProjection(
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/Web_Mercator_projection#Formulas
|
||||
*/
|
||||
public fun toMercator(gmc: GeodeticMapCoordinates): MercatorCoordinates {
|
||||
override fun toProjection(gmc: GeodeticMapCoordinates): ProjectionCoordinates {
|
||||
require(abs(gmc.latitude) <= MAXIMUM_LATITUDE) { "Latitude exceeds the maximum latitude for mercator coordinates" }
|
||||
val r: Distance = correctedRadius?.invoke(gmc) ?: radius
|
||||
return MercatorCoordinates(
|
||||
return ProjectionCoordinates(
|
||||
x = r * (gmc.longitude - baseLongitude).radians.value,
|
||||
y = r * ln(tan(pi / 4 + gmc.latitude / 2))
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user