Skip to content

Commit

Permalink
heading from two points
Browse files Browse the repository at this point in the history
  • Loading branch information
jillesvangurp committed Jan 11, 2021
1 parent 4835e21 commit 19da2b4
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 11 deletions.
43 changes: 32 additions & 11 deletions src/commonMain/kotlin/com/jillesvangurp/geo/GeoGeometry.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,7 @@
*/
package com.jillesvangurp.geo

import kotlin.math.PI
import kotlin.math.abs
import kotlin.math.asin
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
import kotlin.math.roundToLong
import kotlin.math.sin
import kotlin.math.sqrt
import kotlin.math.*

/**
* The methods in this class provides methods that may be used to manipulate geometric shapes. The methods follow the
Expand Down Expand Up @@ -64,7 +55,8 @@ class GeoGeometry {
const val EARTH_RADIUS_METERS = 6371000.0
const val EARTH_CIRCUMFERENCE_METERS = EARTH_RADIUS_METERS * PI * 2.0
const val DEGREE_LATITUDE_METERS = EARTH_RADIUS_METERS * PI / 180.0
const val DEGREES_TO_RADIANS = 2 * PI / 360
const val DEGREES_TO_RADIANS = 2.0 * PI / 360.0
const val RADIANS_TO_DEGREES = 1.0 / DEGREES_TO_RADIANS

/**
* @param pointCoordinates point
Expand Down Expand Up @@ -1031,6 +1023,35 @@ class GeoGeometry {
return (degrees + minutes / 60 + seconds / 60.0 / 60.0) * factor
}

private fun mod(x: Double, m: Double): Double {
return (x % m + m) % m
}

fun wrap(n: Double, min: Double, max: Double): Double {
return if (n >= min && n < max) n else mod(n - min, max - min) + min
}

/**
* Returns the heading from one LatLng to another LatLng. Headings are
* expressed in degrees clockwise from North within the range [-180,180).
*
* @see https://www.igismap.com/formula-to-find-bearing-or-heading-angle-between-two-points-latitude-longitude/
*
* @return The heading in degrees clockwise from north.
*/
fun headingFromTwoPoints(from: PointCoordinates, to: PointCoordinates): Double {
val fromLat = toRadians(from.latitude)
val fromLng = toRadians(from.longitude)
val toLat = toRadians(to.latitude)
val toLng = toRadians(to.longitude)
val dLng = toLng - fromLng
val heading = atan2(
sin(dLng) * cos(toLat),
cos(fromLat) * sin(toLat) - sin(fromLat) * cos(toLat) * cos(dLng)
)
return wrap(RADIANS_TO_DEGREES * heading , -180.0, 180.0)
}

/**
* @param point point
* @return a json representation of the point
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -960,4 +960,10 @@ class GeoGeometryJvmTest {
val point = doubleArrayOf(42.503615, 1.641881)
MatcherAssert.assertThat("should contain the point", polygonContains(point, polygon))
}

@Test
fun headingFromTwoPoints() {
GeoGeometry.headingFromTwoPoints(doubleArrayOf(13.0,52.0), doubleArrayOf(14.0,53.0)) shouldBeApproximately 30.93571619
GeoGeometry.headingFromTwoPoints(doubleArrayOf(14.0,53.0),doubleArrayOf(13.0,52.0)) shouldBeApproximately -148.270892801
}
}

0 comments on commit 19da2b4

Please sign in to comment.