Add geodetic distance measurement.

This commit is contained in:
Alexander Nozik 2022-08-29 22:12:03 +03:00
parent e0cc0bc60b
commit 9ffc9d3d67
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
2 changed files with 28 additions and 38 deletions

View File

@ -1,7 +1,8 @@
package center.sciprog.maps.coordinates package center.sciprog.maps.coordinates
import center.sciprog.maps.coordinates.GeoEllipsoid.Companion.greatCircleAngleBetween import kotlin.math.acos
import kotlin.math.* import kotlin.math.pow
import kotlin.math.sqrt
public class GeoEllipsoid(public val equatorRadius: Distance, public val polarRadius: Distance) { public class GeoEllipsoid(public val equatorRadius: Distance, public val polarRadius: Distance) {
@ -35,12 +36,12 @@ public class GeoEllipsoid(public val equatorRadius: Distance, public val polarRa
polarRadius = Distance(6378.137) polarRadius = Distance(6378.137)
) )
/** // /**
* https://en.wikipedia.org/wiki/Great-circle_distance // * https://en.wikipedia.org/wiki/Great-circle_distance
*/ // */
public fun greatCircleAngleBetween(r1: GMC, r2: GMC): Radians = acos( // public fun greatCircleAngleBetween(r1: GMC, r2: GMC): Radians = acos(
sin(r1.latitude) * sin(r2.latitude) + cos(r1.latitude) * cos(r2.latitude) * cos(r1.longitude - r2.longitude) // sin(r1.latitude) * sin(r2.latitude) + cos(r1.latitude) * cos(r2.latitude) * cos(r1.longitude - r2.longitude)
).radians // ).radians
} }
} }
@ -51,22 +52,22 @@ internal fun GeoEllipsoid.reducedRadius(latitude: Angle): Distance {
val reducedLatitudeTan = (1 - f) * tan(latitude) val reducedLatitudeTan = (1 - f) * tan(latitude)
return equatorRadius / sqrt(1.0 + reducedLatitudeTan.pow(2)) return equatorRadius / sqrt(1.0 + reducedLatitudeTan.pow(2))
} }
//
//
/** ///**
* Compute distance between two map points using giv // * Compute distance between two map points using giv
* https://en.wikipedia.org/wiki/Geographical_distance#Lambert's_formula_for_long_lines // * https://en.wikipedia.org/wiki/Geographical_distance#Lambert's_formula_for_long_lines
*/ // */
public fun GeoEllipsoid.lambertDistanceBetween(r1: GMC, r2: GMC): Distance { //public fun GeoEllipsoid.lambertDistanceBetween(r1: GMC, r2: GMC): Distance {
val s = greatCircleAngleBetween(r1, r2) // val s = greatCircleAngleBetween(r1, r2)
//
val b1: Double = (1 - f) * tan(r1.latitude) // val b1: Double = (1 - f) * tan(r1.latitude)
val b2: Double = (1 - f) * tan(r2.latitude) // val b2: Double = (1 - f) * tan(r2.latitude)
val p = (b1 + b2) / 2 // val p = (b1 + b2) / 2
val q = (b2 - b1) / 2 // val q = (b2 - b1) / 2
//
val x = (s.value - sin(s)) * sin(p).pow(2) * cos(q).pow(2) / cos(s / 2).pow(2) // val x = (s.value - sin(s)) * sin(p).pow(2) * cos(q).pow(2) / cos(s / 2).pow(2)
val y = (s.value + sin(s)) * cos(p).pow(2) * sin(q).pow(2) / sin(s / 2).pow(2) // val y = (s.value + sin(s)) * cos(p).pow(2) * sin(q).pow(2) / sin(s / 2).pow(2)
//
return equatorRadius * (s.value - f / 2 * (x + y)) // return equatorRadius * (s.value - f / 2 * (x + y))
} //}

View File

@ -15,17 +15,6 @@ internal class DistanceTest {
assertEquals(298.257223563, GeoEllipsoid.WGS84.inverseF, 1e-6) assertEquals(298.257223563, GeoEllipsoid.WGS84.inverseF, 1e-6)
} }
@Test
@Ignore
fun greatCircleDistance() {
assertEquals(
expected = 632.035,
actual = GeoEllipsoid.greatCircleAngleBetween(moscow, spb).value *
GeoEllipsoid.WGS84.equatorRadius.kilometers,
absoluteTolerance = 0.1
)
}
@Test @Test
fun curveBetween() { fun curveBetween() {
val curve = GeoEllipsoid.WGS84.curveBetween(moscow, spb) val curve = GeoEllipsoid.WGS84.curveBetween(moscow, spb)