Skip to content
This repository was archived by the owner on Dec 2, 2025. It is now read-only.

Commit 34fb886

Browse files
Merge pull request #4 from jgillich/pr
2 parents 72b9c4b + a19d26e commit 34fb886

17 files changed

Lines changed: 177 additions & 59 deletions

build.gradle.kts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2-
31
group = "be.yellowduck"
42
version = "1.0.10"
53

@@ -17,9 +15,9 @@ val myLicenseUrl = "https://raw.githubusercontent.com/pieterclaerhout/kotlin-yel
1715
val myDeveloperName = "Pieter Claerhout"
1816

1917
plugins {
20-
kotlin("jvm") version "1.5.0"
21-
kotlin("plugin.serialization") version "1.5.0"
22-
id("org.jetbrains.dokka") version "1.4.32"
18+
kotlin("jvm") version "2.1.21"
19+
kotlin("plugin.serialization") version "1.9.25"
20+
id("org.jetbrains.dokka") version "1.9.20"
2321
`maven-publish`
2422
`java-library`
2523
}
@@ -31,9 +29,9 @@ repositories {
3129
dependencies {
3230
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
3331
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1")
34-
implementation("com.fasterxml.jackson.core:jackson-core:2.12.3")
32+
implementation("com.fasterxml.jackson.core:jackson-core:2.19.2")
3533
implementation("com.fasterxml.jackson.core:jackson-annotations:2.12.3")
36-
implementation("com.fasterxml.jackson.core:jackson-databind:2.12.3")
34+
implementation("com.fasterxml.jackson.core:jackson-databind:2.13.4.2")
3735
implementation("org.glassfish.jaxb:txw2:2.2.11")
3836

3937
testImplementation("org.assertj:assertj-core:3.18.1")
@@ -42,13 +40,13 @@ dependencies {
4240
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.2")
4341
}
4442

45-
tasks.withType<KotlinCompile> {
46-
kotlinOptions {
47-
freeCompilerArgs = listOf("-Xjsr305=strict")
48-
jvmTarget = "11"
43+
java {
44+
toolchain {
45+
languageVersion.set(JavaLanguageVersion.of(11))
4946
}
5047
}
5148

49+
5250
tasks.withType<Test> {
5351
useJUnitPlatform()
5452
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

src/main/kotlin/be/yellowduck/gpx/DistanceSerializer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import kotlinx.serialization.encoding.Encoder
1313
import java.io.IOException
1414

1515

16-
class DistanceSerializer @JvmOverloads constructor(t: Class<Distance>? = null) : KSerializer<Distance>, StdSerializer<Distance>(t) {
16+
class DistanceSerializer : KSerializer<Distance>, StdSerializer<Distance>(Distance::class.java) {
1717

1818
@Throws(IOException::class, JsonProcessingException::class)
1919
override fun serialize(

src/main/kotlin/be/yellowduck/gpx/Extensions.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import org.w3c.dom.NodeList
55
import javax.xml.stream.XMLStreamWriter
66

77
internal fun NodeList.items() : List<Node> {
8-
var items = mutableListOf<Node>()
8+
val items = mutableListOf<Node>()
99
for (i in 0..this.length - 1) {
1010
items.add(item(i))
1111
}
@@ -33,7 +33,7 @@ internal fun Node.doubleAttribute(name: String) : Double {
3333
}
3434

3535
internal fun Node.stringAttribute(name: String) : String {
36-
return this.attributes.getNamedItem(name).nodeValue ?: ""
36+
return this.attributes.getNamedItem(name)?.nodeValue ?: ""
3737
}
3838

3939
internal fun XMLStreamWriter.document(init: XMLStreamWriter.() -> Unit): XMLStreamWriter {

src/main/kotlin/be/yellowduck/gpx/GPX.kt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class GPX {
7373
throw GPXDocumentException()
7474
}
7575

76+
gpx.name = parseName(doc)
7677
gpx.version = parseVersion(doc)
7778
gpx.creator = parseCreator(doc)
7879

@@ -81,16 +82,20 @@ class GPX {
8182
gpx.tracks.add(track)
8283
}
8384

84-
} catch (e: SAXParseException) {
85-
throw GPXDocumentException()
86-
} catch (e: Exception) {
85+
} catch (_: SAXParseException) {
8786
throw GPXDocumentException()
8887
}
8988

9089
return gpx
9190

9291
}
9392

93+
private fun parseName(doc: org.w3c.dom.Document): String {
94+
return doc.getElementsByTagName("metadata").items().firstOrNull()?.let { metadata ->
95+
metadata.childNodes.itemsByName("name").firstOrNull()?.textContent
96+
} ?: ""
97+
}
98+
9499
private fun parseVersion(doc: org.w3c.dom.Document): String {
95100
val node = doc.firstChild
96101
return node.stringAttribute("version")
@@ -101,7 +106,7 @@ class GPX {
101106
val node = doc.firstChild
102107

103108
val creator = node.stringAttribute("creator")
104-
if (!creator.isNullOrBlank()) {
109+
if (creator.isNotBlank()) {
105110
return creator
106111
}
107112

@@ -116,8 +121,8 @@ class GPX {
116121
}
117122

118123
private fun parseTrack(node: Node): Track {
119-
var trackName = node.firstChildByName("name")?.textContent.orEmpty()
120-
var track = Track(trackName)
124+
val trackName = node.firstChildByName("name")?.textContent.orEmpty()
125+
val track = Track(trackName)
121126
for (child in node.childrenByName("trkseg")) {
122127
val segment = parseSegment(child)
123128
track.segments.add(segment)
@@ -126,7 +131,7 @@ class GPX {
126131
}
127132

128133
private fun parseSegment(node: Node): Segment {
129-
var segment = Segment()
134+
val segment = Segment()
130135
for (child in node.childrenByName("trkpt")) {
131136
val trackPoint = parseTrackPoint(child)
132137
segment.points.add(trackPoint)
@@ -135,9 +140,9 @@ class GPX {
135140
}
136141

137142
private fun parseTrackPoint(node: Node): TrackPoint {
138-
139-
var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")
140-
var parsedDate = LocalDateTime.parse(node.firstChildByName("time")?.textContent ?: "", formatter)
143+
val parsedDate = node.firstChildByName("time")?.textContent?.let {
144+
LocalDateTime.parse(it, DateTimeFormatter.ISO_DATE_TIME)
145+
}
141146

142147
return TrackPoint(
143148
lat = node.doubleAttribute("lat"),

src/main/kotlin/be/yellowduck/gpx/GPXDocumentException.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ package be.yellowduck.gpx
55
*
66
* @since v1.0.6
77
*/
8-
class GPXDocumentException(message: String = "Not a GPX document") : Exception(message) {
9-
}
8+
class GPXDocumentException(message: String = "Not a GPX document") : Exception(message)

src/main/kotlin/be/yellowduck/gpx/GPXFile.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ data class GPXFile(
3434
*/
3535
val asGPXString: String
3636
get() {
37-
return writers.get("gpx")!!.toString(this)
37+
return writers["gpx"]!!.toString(this)
3838
}
3939

4040
/**
4141
* This can be used to write the data back to a TCX file
4242
*/
4343
val asTCXString: String
4444
get() {
45-
return writers.get("tcx")!!.toString(this)
45+
return writers["tcx"]!!.toString(this)
4646
}
4747

4848
/**

src/main/kotlin/be/yellowduck/gpx/GPXWriter.kt

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package be.yellowduck.gpx
33
import com.sun.xml.txw2.output.IndentingXMLStreamWriter
44
import java.io.ByteArrayOutputStream
55
import java.io.OutputStream
6+
import java.time.temporal.ChronoUnit
67
import javax.xml.stream.XMLOutputFactory
78

89
class GPXWriter : IWriter {
@@ -13,16 +14,22 @@ class GPXWriter : IWriter {
1314
* @param stream The OutputStream to write to
1415
*/
1516
override fun toStream(gpxFile: GPXFile, stream: OutputStream) {
17+
var factory: XMLOutputFactory
18+
try {
19+
factory = XMLOutputFactory.newFactory()
20+
} catch (_: NoSuchMethodError) {
21+
factory = XMLOutputFactory.newInstance()
22+
}
1623

17-
val writer = IndentingXMLStreamWriter(XMLOutputFactory.newFactory().createXMLStreamWriter(stream, "UTF-8"))
24+
val writer = IndentingXMLStreamWriter(factory.createXMLStreamWriter(stream, "UTF-8"))
1825

1926
writer.setIndentStep(" ")
2027
writer.document {
2128
element("gpx") {
22-
if (!gpxFile.version.isNullOrBlank()) {
29+
if (gpxFile.version.isNotBlank()) {
2330
attribute("version", gpxFile.version)
2431
}
25-
if (!gpxFile.creator.isNullOrBlank()) {
32+
if (gpxFile.creator.isNotBlank()) {
2633
attribute("creator", gpxFile.creator)
2734
}
2835
if (gpxFile.version == "1.0") {
@@ -31,14 +38,14 @@ class GPXWriter : IWriter {
3138
if (gpxFile.version == "1.1") {
3239
attribute("xmlns", "http://www.topografix.com/GPX/1/1")
3340
}
34-
if (!gpxFile.name.isNullOrBlank()) {
41+
if (gpxFile.name.isNotBlank()) {
3542
element("metadata") {
3643
element("name", gpxFile.name)
3744
}
3845
}
3946
gpxFile.tracks.forEach { track ->
4047
element("trk") {
41-
if (!track.name.isNullOrBlank()) {
48+
if (track.name.isNotBlank()) {
4249
element("name", track.name)
4350
}
4451
track.segments.forEach { segment ->
@@ -47,6 +54,14 @@ class GPXWriter : IWriter {
4754
element("trkpt") {
4855
attribute("lat", point.lat.toString())
4956
attribute("lon", point.lon.toString())
57+
58+
if (point.ele != 0.0) {
59+
element("ele", point.ele.toString())
60+
}
61+
62+
point.time?.let { time ->
63+
element("time", time.truncatedTo(ChronoUnit.SECONDS).toString())
64+
}
5065
}
5166
}
5267
}
@@ -66,7 +81,7 @@ class GPXWriter : IWriter {
6681
* @return The GPX as a GPX XML string
6782
*/
6883
override fun toString(gpxFile: GPXFile): String {
69-
var stream = ByteArrayOutputStream()
84+
val stream = ByteArrayOutputStream()
7085
toStream(gpxFile, stream)
7186
return stream.toString("UTF-8")
7287
}

src/main/kotlin/be/yellowduck/gpx/Polyline.kt

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package be.yellowduck.gpx
22

3+
import kotlin.math.abs
4+
import kotlin.math.pow
5+
import kotlin.math.sqrt
6+
37
class Polyline {
48

59
companion object {
@@ -29,7 +33,7 @@ class Polyline {
2933
}
3034

3135
private fun encodeValue(value: Int): String {
32-
var actualValue = if (value < 0) (value shl 1).inv() else (value shl 1)
36+
val actualValue = if (value < 0) (value shl 1).inv() else (value shl 1)
3337
val chunks: List<Int> = splitIntoChunks(actualValue)
3438
return chunks.map { (it + 63).toChar() }.joinToString("")
3539
}
@@ -74,7 +78,7 @@ class Polyline {
7478

7579
coordinateChunks.removeAt(coordinateChunks.lastIndex)
7680

77-
var coordinates: MutableList<Double> = mutableListOf()
81+
val coordinates: MutableList<Double> = mutableListOf()
7882

7983
for (coordinateChunk in coordinateChunks) {
8084
var coordinate = coordinateChunk.mapIndexed { i, chunk -> chunk shl (i * 5) }.reduce { i, j -> i or j }
@@ -113,16 +117,16 @@ class Polyline {
113117
}
114118

115119
private fun round(value: Double, precision: Int) =
116-
(value * Math.pow(10.0, precision.toDouble())).toInt().toDouble() / Math.pow(10.0, precision.toDouble())
120+
(value * 10.0.pow(precision.toDouble())).toInt().toDouble() / 10.0.pow(precision.toDouble())
117121

118122
fun simplify(points: List<TrackPoint>, epsilon: Double): List<TrackPoint> {
119123

120124
var dmax = 0.0
121125
var index = 0
122-
var end = points.size
126+
val end = points.size
123127

124128
for (i in 1..(end - 2)) {
125-
var d = perpendicularDistance(points[i], points[0], points[end - 1])
129+
val d = perpendicularDistance(points[i], points[0], points[end - 1])
126130
if (d > dmax) {
127131
index = i
128132
dmax = d
@@ -140,12 +144,9 @@ class Polyline {
140144
}
141145

142146
private fun perpendicularDistance(pt: TrackPoint, lineFrom: TrackPoint, lineTo: TrackPoint): Double {
143-
return Math.abs((lineTo.lon - lineFrom.lon) * (lineFrom.lat - pt.lat) - (lineFrom.lon - pt.lon) * (lineTo.lat - lineFrom.lat)) /
144-
Math.sqrt(
145-
Math.pow(
146-
lineTo.lon - lineFrom.lon,
147-
2.0
148-
) + Math.pow(lineTo.lat - lineFrom.lat, 2.0)
147+
return abs((lineTo.lon - lineFrom.lon) * (lineFrom.lat - pt.lat) - (lineFrom.lon - pt.lon) * (lineTo.lat - lineFrom.lat)) /
148+
sqrt(
149+
(lineTo.lon - lineFrom.lon).pow(2.0) + (lineTo.lat - lineFrom.lat).pow(2.0)
149150
)
150151
}
151152

src/main/kotlin/be/yellowduck/gpx/Segment.kt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package be.yellowduck.gpx;
1+
package be.yellowduck.gpx
22

33
/**
44
* A segment is a sorted list of waypoints.
@@ -26,14 +26,31 @@ data class Segment(
2626
}
2727

2828
/**
29-
* Returns the segment as a encoded polyline string.
29+
* Returns the total elevation gain of the segment
30+
*/
31+
val elevationGain: Double
32+
get() {
33+
var total = 0.0
34+
points.forEachIndexed { index, point ->
35+
if (index > 0) {
36+
val ele = points[index].ele - points[index - 1].ele
37+
if (ele > 0) {
38+
total += ele
39+
}
40+
}
41+
}
42+
return total
43+
}
44+
45+
/**
46+
* Returns the segment as an encoded polyline string.
3047
*
3148
* [Encoded Polyline Algorithm Format](https://developers.google.com/maps/documentation/utilities/polylinealgorithm)
3249
*
3350
* @return A string with the encoded polyline
3451
*/
3552
fun toPolyline(): String {
36-
return Polyline.encode(points);
53+
return Polyline.encode(points)
3754
}
3855

3956
}

0 commit comments

Comments
 (0)