Skip to content

Commit

Permalink
nailed it?
Browse files Browse the repository at this point in the history
  • Loading branch information
jillesvangurp committed Nov 17, 2023
1 parent 300300b commit 81d32b5
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 83 deletions.
105 changes: 56 additions & 49 deletions src/commonMain/kotlin/com/jillesvangurp/geo/mgrs.kt
Expand Up @@ -9,13 +9,13 @@ import kotlin.math.roundToInt
data class MgrsCoordinate(
val longitudeZone: Int,
val latitudeZoneLetter: Char,
val colLetter: Char,
val rowLetter: Char,
val firstLetter: Char, // aka col
val secondLetter: Char, //aka row
val easting: Int,
val northing: Int
) {
override fun toString(): String {
return "$longitudeZone$latitudeZoneLetter $colLetter$rowLetter $easting $northing"
return "$longitudeZone$latitudeZoneLetter $firstLetter$secondLetter $easting $northing"
}
}

Expand Down Expand Up @@ -75,6 +75,7 @@ fun UtmCoordinate.convertUTMToMGRS(): MgrsCoordinate {

val mgrsEasting = floor(easting % BLOCK_SIZE).toInt()
val mgrsNorthing = floor(northing % BLOCK_SIZE).toInt()
// println("cols ${northing.toInt() / BLOCK_SIZE} $northing ${(northing / 1000).toInt()}")
return MgrsCoordinate(
longitudeZone,
latitudeZoneLetter,
Expand All @@ -85,55 +86,61 @@ fun UtmCoordinate.convertUTMToMGRS(): MgrsCoordinate {
)
}

data class LatitudeBandConstants(
val firstLetter: Char, // col
val minNorthing: Double,
val northLat: Double,
val southLat: Double,
val northingOffset: Double
)

private val latitudeBandConstants = listOf(
LatitudeBandConstants('C', 1100000.0, -72.0, -80.5, 0.0),
LatitudeBandConstants('D', 2000000.0, -64.0, -72.0, 2000000.0),
LatitudeBandConstants('E', 2800000.0, -56.0, -64.0, 2000000.0),
LatitudeBandConstants('F', 3700000.0, -48.0, -56.0, 2000000.0),
LatitudeBandConstants('G', 4600000.0, -40.0, -48.0, 4000000.0),
LatitudeBandConstants('H', 5500000.0, -32.0, -40.0, 4000000.0),
LatitudeBandConstants('J', 6400000.0, -24.0, -32.0, 6000000.0),
LatitudeBandConstants('K', 7300000.0, -16.0, -24.0, 6000000.0),
LatitudeBandConstants('L', 8200000.0, -8.0, -16.0, 8000000.0),
LatitudeBandConstants('M', 9100000.0, 0.0, -8.0, 8000000.0),
LatitudeBandConstants('N', 0.0, 8.0, 0.0, 0.0),
LatitudeBandConstants('P', 800000.0, 16.0, 8.0, 0.0),
LatitudeBandConstants('Q', 1700000.0, 24.0, 16.0, 0.0),
LatitudeBandConstants('R', 2600000.0, 32.0, 24.0, 2000000.0),
LatitudeBandConstants('S', 3500000.0, 40.0, 32.0, 2000000.0),
LatitudeBandConstants('T', 4400000.0, 48.0, 40.0, 4000000.0),
LatitudeBandConstants('U', 5300000.0, 56.0, 48.0, 4000000.0),
LatitudeBandConstants('V', 6200000.0, 64.0, 56.0, 6000000.0),
LatitudeBandConstants('W', 7000000.0, 72.0, 64.0, 6000000.0),
LatitudeBandConstants('X', 7900000.0, 84.5, 72.0, 6000000.0)
).associateBy { it.firstLetter }

val eastingArray = listOf("", "AJS", "BKT", "CLU", "DMV", "ENW", "FPX", "GQY", "HRZ")

private const val TWO_MILLION = 2000000

fun MgrsCoordinate.toUtm(): UtmCoordinate {
val eastingArray = listOf("", "AJS", "BKT", "CLU", "DMV", "ENW", "FPX", "GQY", "HRZ")
val zoneBase = listOf(
1.1,
2.0,
2.8,
3.7,
4.6,
5.5,
6.4,
7.3,
8.2,
9.1,
0.0,
0.8,
1.7,
2.6,
3.5,
4.4,
5.3,
6.2,
7.0,
7.9
).map { it * 1000000 }

var utmEasting = -1
for ((i, letters) in eastingArray.withIndex()) {
if (colLetter in letters) {
utmEasting = i * BLOCK_SIZE + easting
break
}

val bandConstants = latitudeBandConstants[latitudeZoneLetter]!!

val utmEasting = eastingArray.withIndex().first { (i,letters) ->
firstLetter in letters
}.let { (i, letters) ->
i * BLOCK_SIZE + easting
}

var utmNorthing = 0.0
if (rowLetter != ' ') {
utmNorthing = if (longitudeZone % 2 == 0) {
("FGHJKLMNPQRSTUVABCDE".indexOf(rowLetter) * 100000).toDouble()
} else {
("ABCDEFGHJKLMNPQRSTUV".indexOf(rowLetter) * 100000).toDouble()
}

while (utmNorthing < zoneBase["CDEFGHJKLMNPQRSTUVWX".indexOf(rowLetter)-1]) {
utmNorthing += 2000000
}
utmNorthing += northing

} else {
utmNorthing = zoneBase["CDEFGHJKLMNPQRSTUVWX".indexOf(rowLetter)] + 499600
val setNumber = longitudeZone.setForZone()

val rowLettersForZone = setNumber.rowLetters()
var utmNorthing = (rowLettersForZone.indexOf(secondLetter) * 100000).toDouble()

utmNorthing += bandConstants.northingOffset
while(utmNorthing < bandConstants.minNorthing) {
utmNorthing += TWO_MILLION
}
utmNorthing += northing

return UtmCoordinate(longitudeZone, latitudeZoneLetter, utmEasting.toDouble(), utmNorthing)
}
}
57 changes: 23 additions & 34 deletions src/commonTest/kotlin/com/jillesvangurp/geogeometry/MGRSTest.kt
@@ -1,53 +1,42 @@
package com.jillesvangurp.geogeometry

import com.jillesvangurp.geo.convertUTMToMGRS
import com.jillesvangurp.geo.toPointCoordinates
import com.jillesvangurp.geo.toUtm
import com.jillesvangurp.geo.toUtmCoordinate
import com.jillesvangurp.geo.*
import com.jillesvangurp.geojson.distanceTo
import io.kotest.assertions.assertSoftly
import io.kotest.assertions.withClue
import io.kotest.matchers.doubles.shouldBeLessThan
import io.kotest.matchers.shouldBe
import kotlin.math.abs
import kotlin.test.Test

class MGRSTest {
@Test
fun shouldCalculateMgrsForBrandenburgerTor() {
assertSoftly {
var utm = brandenBurgerGate.toUtmCoordinate()
utm.convertUTMToMGRS().let {
withClue(it) {
it.longitudeZone shouldBe 33
it.latitudeZoneLetter shouldBe 'U'
it.colLetter shouldBe 'U'
it.rowLetter shouldBe 'U'
it.easting shouldBe 89880
it.northing shouldBe 19700
println(utm)
val toUtm = it.toUtm()
println(toUtm)
toUtm.toPointCoordinates().distanceTo(brandenBurgerGate) shouldBeLessThan 2.0
}

}
testMgrsConversion(brandenBurgerGate)
val skagen = doubleArrayOf(10.591979, 57.724205)
utm = skagen.toUtmCoordinate()
utm.convertUTMToMGRS().let {
withClue(it) {
it.longitudeZone shouldBe 32
it.latitudeZoneLetter shouldBe 'V'
it.colLetter shouldBe 'N'
it.rowLetter shouldBe 'J'
it.easting shouldBe 94817
it.northing shouldBe 99119
testMgrsConversion(skagen)
testMgrsConversion(rioFootballStadium)
testMgrsConversion(sydneyOpera)
}
}

println(utm)
val toUtm = it.toUtm()
println(toUtm)
toUtm.toPointCoordinates().distanceTo(skagen) shouldBeLessThan 2.0
}
private fun testMgrsConversion(p: DoubleArray) {
val utm = p.toUtmCoordinate()
utm.toPointCoordinates().distanceTo(p) shouldBeLessThan 2.0

utm.convertUTMToMGRS().let {
val toUtm = it.toUtm()
withClue("$utm -> $it -> $toUtm") {
it.longitudeZone shouldBe utm.longitudeZone
it.latitudeZoneLetter shouldBe utm.latitudeZoneLetter

abs(utm.easting-toUtm.easting) shouldBeLessThan 2.0
abs(utm.northing-toUtm.northing) shouldBeLessThan 2.0
// toUtm.toPointCoordinates().distanceTo(p) shouldBeLessThan 2.0
}

}

}
}

0 comments on commit 81d32b5

Please sign in to comment.