commit b6d207be598d881cbd24e2793d04a3507346d45d Author: bvn13 Date: Sun Sep 25 00:14:31 2022 +0300 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7f6c769 --- /dev/null +++ b/.gitignore @@ -0,0 +1,370 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/java,gradle,git,intellij,linux,windows,macos,node +# Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle,git,intellij,linux,windows,macos,node + +### Git ### +# Created by git for backups. To disable backups in Git: +# $ git config --global mergetool.keepBackup false +*.orig + +# Created by git when using merge tools for conflicts +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/.gitignore +.idea/**/.name +.idea/**/compiler.xml +.idea/**/jarRepositories.xml +.idea/**/libraries-with-intellij-classes.xml +.idea/**/misc.xml +.idea/**/vcs.xml +.idea/**/wallet-external-api.iml +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Node ### +# Logs +logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env*.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Storybook build outputs +.out +.storybook-out +storybook-static + +# rollup.js default build output +dist/ + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# Temporary folders +tmp/ +temp/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### Gradle Patch ### +**/build/ + +# End of https://www.toptal.com/developers/gitignore/api/java,gradle,git,intellij,linux,windows,macos,node diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..5a6fb06 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,19 @@ + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..6e6eec1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..942f3a2 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jpa-buddy.xml b/.idea/jpa-buddy.xml new file mode 100644 index 0000000..966d5f5 --- /dev/null +++ b/.idea/jpa-buddy.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..b1077fb --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8832a39 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/GpxAndroidSdk.iml b/GpxAndroidSdk.iml new file mode 100644 index 0000000..80463c4 --- /dev/null +++ b/GpxAndroidSdk.iml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0a8e56f --- /dev/null +++ b/pom.xml @@ -0,0 +1,112 @@ + + + 4.0.0 + + GpxAndroidSdk + me.bvn13.sdk.android.gpx + 1.0-SNAPSHOT + jar + + consoleApp + + + UTF-8 + official + 1.8 + + + + + mavenCentral + https://repo1.maven.org/maven2/ + + + + + src/main/kotlin + src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + 1.7.10 + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + maven-surefire-plugin + 2.22.2 + + false + + + + maven-failsafe-plugin + 2.22.2 + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + + + + org.jetbrains.kotlin + kotlin-test-junit5 + 1.7.10 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.8.2 + test + + + org.junit.jupiter + junit-jupiter-api + 5.8.2 + test + + + org.jetbrains.kotlin + kotlin-stdlib-jdk8 + 1.7.10 + + + io.kotest + kotest-runner-junit5-jvm + 5.4.2 + test + + + io.kotest + kotest-assertions-core-jvm + 5.4.2 + test + + + + \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/ExtensionType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/ExtensionType.kt new file mode 100644 index 0000000..aaf81c9 --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/ExtensionType.kt @@ -0,0 +1,26 @@ +package me.bvn13.sdk.android.gpx + +/** + * XML Node describer + * + * will be composed into XML in following format: + * + * ```xml + * + * value + * + * ``` + * + * [nodeName] XmlTag + * + * [value] Xml inner text + * + * [parameters] Map of key-value pairs + */ +class ExtensionType(val nodeName: String, val value: String? = null, val parameters: Map? = null) { + init { + require(value != null || parameters != null) { + "value or parameters must be specified" + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/FixType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/FixType.kt new file mode 100644 index 0000000..47b909c --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/FixType.kt @@ -0,0 +1,12 @@ +package me.bvn13.sdk.android.gpx + +/** + * Type of GPS fix. none means GPS had no fix. To signify "the fix info is unknown", leave out fixType entirely. pps = military signal used + */ +enum class FixType(val value: String) { + NONE("none"), + _2D("2d"), + _3D("3d"), + DGPS("dgps"), + PPS("pps") +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/GpxType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/GpxType.kt new file mode 100644 index 0000000..a59026f --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/GpxType.kt @@ -0,0 +1,27 @@ +package me.bvn13.sdk.android.gpx + +/** + * GPX documents contain a metadata header, followed by waypoints, routes, and tracks. You can add your own elements to the extensions section of the GPX document. + * + * See [official documentation](https://www.topografix.com/GPX/1/1/#element_gpx) + * + * [metadata] Metadata about the file. + * + * [wpt] A list of waypoints. + * + * [rte] A list of routes. + * + * [trk] A list of tracks. + * + * [extensions] You can add extend GPX by adding your own elements from another schema here. + */ +class GpxType( + val metadata: MetadataType, + val creator: String = "me.bvn13.sdk.android.gpx", + val wpt: List? = null, + val rte: List? = null, + val trk: List? = null, + val extensions: ExtensionType? = null +) { + val version: String = "1.1" +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/GpxWriter.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/GpxWriter.kt new file mode 100644 index 0000000..d27e4fb --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/GpxWriter.kt @@ -0,0 +1,212 @@ +package me.bvn13.sdk.android.gpx + +import me.bvn13.sdk.android.gpx.GpxWriter.Companion.DTF +import me.bvn13.sdk.android.gpx.GpxWriter.Companion.HEADER +import me.bvn13.sdk.android.gpx.GpxWriter.Companion.SCHEMA_LOCATION +import me.bvn13.sdk.android.gpx.GpxWriter.Companion.XMLNS +import me.bvn13.sdk.android.gpx.GpxWriter.Companion.XMLNS_XSI +import java.time.Clock +import java.time.OffsetDateTime +import java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME +import java.time.format.DateTimeFormatterBuilder + +fun GpxType.toXmlString(): String = this.toXmlString(null) + +fun GpxType.toXmlString(clock: Clock?): String = """ + $HEADER + + + ${this.metadata.toXmlString()} + ${this.wpt?.toXmlString()} + ${this.rte?.toXmlString()} + ${this.trk?.toXmlString()} + +""".trim() + +fun MetadataType.toXmlString(): String = """ + + ${this.name} + ${this.description} + + ${this.authorName} + + +""".trim() + +private fun now(clock: Clock?) = OffsetDateTime.now(clock ?: Clock.systemDefaultZone()).format(DTF) + +fun WptType.toXmlString(nodeName: String? = null) = + if (nodeName != null) { + this.toXmlString(nodeName) + } else { + this.toXmlString("wpt") + } + +@JvmName("toXmlStringNamed") +fun WptType.toXmlString(nodeName: String) = """ + <${nodeName} lat="${this.lat}" lon="${this.lon}"> + ${toXmlString(ele, "ele")} + ${toXmlString(time, "time")} + ${toXmlString(magvar, "magvar")} + ${toXmlString(geoidheight, "geoidheight")} + ${toXmlString(name, "name")} + ${toXmlString(cmt, "cmt")} + ${toXmlString(desc, "desc")} + ${toXmlString(src, "src")} + ${link?.toXmlString()} + ${toXmlString(sym, "sym")} + ${toXmlString(type, "type")} + ${fix?.toXmlString()} + ${toXmlString(sat, "sat")} + ${toXmlString(hdop, "hdop")} + ${toXmlString(vdop, "vdop")} + ${toXmlString(pdop, "pdop")} + ${toXmlString(ageofgpsdata, "ageofgpsdata")} + ${toXmlString(dgpsid, "dgpsid")} + ${extensions?.toXmlString()} + +""".trim() + +fun RteType.toXmlString() = """ + + ${toXmlString(this.name, "name")} + ${toXmlString(this.cmt, "cmt")} + ${toXmlString(this.desc, "desc")} + ${toXmlString(this.src, "src")} + ${this.link?.toXmlString()} + ${toXmlString(this.number, "number")} + ${toXmlString(this.type, "type")} + ${this.extensions?.toXmlString()} + ${this.rtept?.toXmlString()} + +""".trim() + +fun TrkType.toXmlString() = """ + + ${toXmlString(this.name, "name")} + ${toXmlString(this.cmt, "cmt")} + ${toXmlString(this.desc, "desc")} + ${toXmlString(this.src, "src")} + ${this.link?.toXmlString()} + ${toXmlString(this.number, "number")} + ${toXmlString(this.type, "type")} + ${this.extensions?.toXmlString()} + ${this.trkseg?.toXmlString()} + +""".trim() + +fun List.toXmlString(nodeName: String?) = + this.joinToString(prefix = "", postfix = "", separator = "") { + it.toXmlString(nodeName) + } + +@JvmName("toXmlStringWptType") +fun List.toXmlString() = + this.joinToString(prefix = "", postfix = "", separator = "") { + it.toXmlString() + } + +@JvmName("toXmlStringLinkType") +fun List.toXmlString() = + this.joinToString(prefix = "", postfix = "", separator = "\n", transform = LinkType::toXmlString) + +@JvmName("toXmlStringRteType") +fun List.toXmlString() = + this.joinToString(prefix = "", postfix = "", separator = "", transform = RteType::toXmlString) + +@JvmName("toXmlStringTrkType") +fun List.toXmlString() = + this.joinToString(prefix = "", postfix = "", separator = "", transform = TrkType::toXmlString) + +@JvmName("toXmlStringTrksegType") +fun List.toXmlString() = + this.joinToString(prefix = "", postfix = "", separator = "", transform = TrksegType::toXmlString) + +fun List.toXmlString() = + this.joinToString( + prefix = "\n", + postfix = "\n", + separator = "\n", + transform = ExtensionType::toXmlString + ) + +fun LinkType.toXmlString() = """ + + ${this.text} + ${this.type} + +""".trim() + +fun FixType.toXmlString() = """ + ${this.value} +""".trim() + +fun ExtensionType.toXmlString() = """ + <${this.nodeName}${toXmlString(this.parameters)}>${this.value ?: ""} + """.trim() + +fun TrksegType.toXmlString() = """ + + ${this.trkpt?.toXmlString("trkpt")} + +""".trim() + +fun toXmlString(value: String?, nodeName: String) = + if (value != null) { + """ + <${nodeName}>${value} + """.trim() + } else { + "" + } + +fun toXmlString(value: Int?, nodeName: String) = + if (value != null) { + """ + <${nodeName}>${value} + """.trim() + } else { + "" + } + +fun toXmlString(value: Double?, nodeName: String) = + if (value != null) { + """ + <${nodeName}>${value} + """.trim() + } else { + "" + } + +fun toXmlString(value: OffsetDateTime?, nodeName: String) = + if (value != null) { + """ + <${nodeName}>${value.format(DTF)} + """.trim() + } else { + "" + } + +fun toXmlString(value: Map?) = + value?.entries?.joinToString(separator = "") { + " ${it.key}=\"${it.value}\"" + } ?: "" + +class GpxWriter { + companion object { + const val HEADER = "" + const val XMLNS = "http://www.topografix.com/GPX/1/1" + const val XMLNS_XSI = "http://www.w3.org/2001/XMLSchema-instance" + const val SCHEMA_LOCATION = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" + + internal val DTF = DateTimeFormatterBuilder() + .append(ISO_LOCAL_DATE_TIME) // use the existing formatter for date time + .appendOffset("+HH:MM", "+00:00") // set 'noOffsetText' to desired '+00:00' + .toFormatter() + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/LinkType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/LinkType.kt new file mode 100644 index 0000000..143c02e --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/LinkType.kt @@ -0,0 +1,13 @@ +package me.bvn13.sdk.android.gpx + +/** + * A link to an external resource (Web page, digital photo, video clip, etc) with additional information. + * + * [href] URL of hyperlink. + * + * [text] Text of hyperlink. + * + * [type] Mime type of content (image/jpeg) + */ +class LinkType(val href: String, val text: String? = null, val type: String? = null) { +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/MetadataType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/MetadataType.kt new file mode 100644 index 0000000..cfbee86 --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/MetadataType.kt @@ -0,0 +1,8 @@ +package me.bvn13.sdk.android.gpx + +/** + * Information about the GPX file, author, and copyright restrictions goes in the metadata section. + * Providing rich, meaningful information about your GPX files allows others to search for and use your GPS data. + */ +class MetadataType(val name: String, val description: String = "", val authorName: String = "") { +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/RteType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/RteType.kt new file mode 100644 index 0000000..4d63711 --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/RteType.kt @@ -0,0 +1,40 @@ +package me.bvn13.sdk.android.gpx + +/** + * rte represents route - an ordered list of waypoints representing a series of turn points leading to a destination. + * + * [namee] GPS name of track. + * + * [cmt] GPS comment for track. + * + * [desc] User description of track. + * + * [src] Source of data. Included to give user some idea of reliability and accuracy of data. + * + * [link] Links to external information about track. + * + * [number] GPS track number. + * + * [type] Type (classification) of track. + * + * [extensions] You can add extend GPX by adding your own elements from another schema here. + * + * [rtept] A list of route points. + */ +class RteType( + val name: String? = null, + val cmt: String? = null, + val desc: String? = null, + val src: String? = null, + val link: List? = null, + val number: Int? = null, + val type: String? = null, + val extensions: List? = null, + val rtept: List? = null +) { + init { + require(number == null || number >= 0) { + "number must be non negative Integer" + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/TrkType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/TrkType.kt new file mode 100644 index 0000000..0d9324b --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/TrkType.kt @@ -0,0 +1,42 @@ +package me.bvn13.sdk.android.gpx + +/** + * trk represents a track - an ordered list of points describing a path. + * + * [namee] GPS name of route. + * + * [cmt] GPS comment for route. + * + * [desc] Text description of route for user. Not sent to GPS. + * + * [src] Source of data. Included to give user some idea of reliability and accuracy of data. + * + * [link] Links to external information about the route. + * + * [number] GPS route number. + * + * [type] Type (classification) of route. + * + * [extensions] You can add extend GPX by adding your own elements from another schema here. + * + * [trkseg] A Track Segment holds a list of Track Points which are logically connected in order. + * To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, + * start a new Track Segment for each continuous span of track data + */ +class TrkType( + val name: String? = null, + val cmt: String? = null, + val desc: String? = null, + val src: String? = null, + val link: List? = null, + val number: Int? = null, + val type: String? = null, + val extensions: ExtensionType? = null, + val trkseg: List? = null +) { + init { + require(number == null || number >= 0) { + "number must be non negative Integer" + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/TrksegType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/TrksegType.kt new file mode 100644 index 0000000..732fe50 --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/TrksegType.kt @@ -0,0 +1,14 @@ +package me.bvn13.sdk.android.gpx + +/** + * A Track Segment holds a list of Track Points which are logically connected in order. To represent a single GPS track where GPS reception was lost, or the GPS receiver was turned off, start a new Track Segment for each continuous span of track data. + * + * [trkpt] A Track Point holds the coordinates, elevation, timestamp, and metadata for a single point in a track. + * + * [extensions] You can add extend GPX by adding your own elements from another schema here. + */ +class TrksegType( + val trkpt: List? = null, + val extensions: ExtensionType? = null +) { +} \ No newline at end of file diff --git a/src/main/kotlin/me/bvn13/sdk/android/gpx/WptType.kt b/src/main/kotlin/me/bvn13/sdk/android/gpx/WptType.kt new file mode 100644 index 0000000..99a5d33 --- /dev/null +++ b/src/main/kotlin/me/bvn13/sdk/android/gpx/WptType.kt @@ -0,0 +1,88 @@ +package me.bvn13.sdk.android.gpx + +import java.time.OffsetDateTime +import java.time.ZonedDateTime + +/** + * wpt represents a waypoint, point of interest, or named feature on a map. + * + * [lat] The latitude of the point. Decimal degrees + * + * [lon] The longitude of the point. Decimal degrees + * + * [ele] Elevation (in meters) of the point. + * + * [time] Creation/modification timestamp for element. Date and time in are in Univeral Coordinated Time (UTC), not local time! + * Conforms to ISO 8601 specification for date/time representation. Fractional seconds are allowed for millisecond timing in tracklogs. + * + * [magvar] Magnetic variation (in degrees) at the point + * + * [geoidheight] Height (in meters) of geoid (mean sea level) above WGS84 earth ellipsoid. As defined in NMEA GGA message. + * + * [name] The GPS name of the waypoint. This field will be transferred to and from the GPS. GPX does not place restrictions + * on the length of this field or the characters contained in it. It is up to the receiving application to validate the field before sending it to the GPS. + * + * [cmt] GPS waypoint comment. Sent to GPS as comment. + * + * [desc] A text description of the element. Holds additional information about the element intended for the user, not the GPS. + * + * [src] Source of data. Included to give user some idea of reliability and accuracy of data. "Garmin eTrex", "USGS quad Boston North", e.g. + * + * [link] Link to additional information about the waypoint. + * + * [sym] Text of GPS symbol name. For interchange with other programs, use the exact spelling of the symbol as displayed on the GPS. + * If the GPS abbreviates words, spell them out. + * + * [type] Type (classification) of the waypoint. + * + * [fix] Type of GPX fix. + * + * [sat] Number of satellites used to calculate the GPX fix. + * + * [hdop] Horizontal dilution of precision. + * + * [vdop] Vertical dilution of precision. + * + * [pdop] Position dilution of precision. + * + * [ageofgpsdata] Number of seconds since last DGPS update. + * + * [dgpsid] ID of DGPS station used in differential correction. + * + * [extensions] You can add extend GPX by adding your own elements from another schema here. + */ +class WptType( + val lat: Double, + val lon: Double, + val ele: Double? = null, + val time: OffsetDateTime? = null, + val magvar: Double? = null, + val geoidheight: Double? = null, + val name: String? = null, + val cmt: String? = null, + val desc: String? = null, + val src: String? = null, + val link: List? = null, + val sym: String? = null, + val type: String? = null, + val fix: FixType? = null, + val sat: Int? = null, + val hdop: Double? = null, + val vdop: Double? = null, + val pdop: Double? = null, + val ageofgpsdata: Int? = null, + val dgpsid: Int? = null, + val extensions: List? = null +) { + init { + require(sat == null || sat >= 0) { + "sat must be non-negative integer" + } + require(magvar == null || magvar in 0.0..360.0) { + "magvar must be degree in (0)..(360) in Double" + } + require(dgpsid in 0..1023) { + "dgpsid must be in 0..1023" + } + } +} diff --git a/src/test/kotlin/me/bvn13/sdk/android/gpx/GpxWriterTest.kt b/src/test/kotlin/me/bvn13/sdk/android/gpx/GpxWriterTest.kt new file mode 100644 index 0000000..9af57d6 --- /dev/null +++ b/src/test/kotlin/me/bvn13/sdk/android/gpx/GpxWriterTest.kt @@ -0,0 +1,333 @@ +package me.bvn13.sdk.android.gpx + +import io.kotest.core.spec.style.FunSpec +import java.time.* +import kotlin.test.assertEquals + +class GpxWriterTest : FunSpec() { + init { + test("first test") { + val clock = Clock.fixed( + LocalDateTime.of(2022, 9, 24, 15, 4, 0, 0).toInstant(ZoneOffset.ofHours(3)), ZoneId.of("Europe/Moscow") + ) + + val gpxType = GpxType( + MetadataType("test name", description = "test description", authorName = "bvn13"), + wpt = listOf( + WptType( + lat = 14.64736838389662, + lon = 7.93212890625, + ele = 10.toDouble(), + time = OffsetDateTime.now(clock), + magvar = 3.toDouble(), + geoidheight = 45.toDouble(), + name = "test point 1", + cmt = "comment 1", + desc = "description of point 1", + link = listOf( + LinkType( + href = "http://link-to.site.href", + text = "text", + type = "hyperlink" + ), + LinkType( + href = "http://link2-to.site.href", + text = "text2", + type = "hyperlink2" + ) + ), + src = "source 1", + sym = "sym 1", + type = "type 1", + fix = FixType.DGPS, + sat = 1, + hdop = 55.toDouble(), + vdop = 66.toDouble(), + pdop = 77.toDouble(), + ageofgpsdata = 44, + dgpsid = 88, + extensions = listOf( + ExtensionType( + "extension1", + parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) + ), + ExtensionType( + "extension2", + parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) + ) + ) + ) + ), + rte = listOf( + RteType( + name = "rte name", + cmt = "cmt", + desc = "desc", + src = "src", + link = listOf( + LinkType( + href = "https://new.link.rte", + text = "new text rte", + type = "hyperlink" + ) + ), + number = 1234, + type = "route", + extensions = listOf( + ExtensionType( + "ext-1", + value = "value1" + ) + ), + rtept = listOf( + WptType( + lat = 14.64736838389662, + lon = 7.93212890625, + ele = 10.toDouble(), + time = OffsetDateTime.now(clock), + magvar = 3.toDouble(), + geoidheight = 45.toDouble(), + name = "test point 1", + cmt = "comment 1", + desc = "description of point 1", + link = listOf( + LinkType( + href = "http://link-to.site.href", + text = "text", + type = "hyperlink" + ), + LinkType( + href = "http://link2-to.site.href", + text = "text2", + type = "hyperlink2" + ) + ), + src = "source 1", + sym = "sym 1", + type = "type 1", + fix = FixType.DGPS, + sat = 1, + hdop = 55.toDouble(), + vdop = 66.toDouble(), + pdop = 77.toDouble(), + ageofgpsdata = 44, + dgpsid = 88, + extensions = listOf( + ExtensionType( + "extension1", + parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) + ), + ExtensionType( + "extension2", + parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) + ) + ) + ) + ) + ) + ), + trk = listOf( + TrkType( + name = "track 1", + cmt = "comment track 1", + desc = "desc track 1", + src = "src track 1", + number = 1234, + type = "type 1", + trkseg = listOf( + TrksegType( + listOf( + WptType( + lat = 14.64736838389662, + lon = 7.93212890625, + ele = 10.toDouble(), + time = OffsetDateTime.now(clock), + magvar = 3.toDouble(), + geoidheight = 45.toDouble(), + name = "test point 1", + cmt = "comment 1", + desc = "description of point 1", + link = listOf( + LinkType( + href = "http://link-to.site.href", + text = "text", + type = "hyperlink" + ), + LinkType( + href = "http://link2-to.site.href", + text = "text2", + type = "hyperlink2" + ) + ), + src = "source 1", + sym = "sym 1", + type = "type 1", + fix = FixType.DGPS, + sat = 1, + hdop = 55.toDouble(), + vdop = 66.toDouble(), + pdop = 77.toDouble(), + ageofgpsdata = 44, + dgpsid = 88, + extensions = listOf( + ExtensionType( + "extension1", + parameters = mapOf(Pair("first", "second"), Pair("third", "fours")) + ), + ExtensionType( + "extension2", + parameters = mapOf(Pair("aa", "bb"), Pair("cc", "dd")) + ) + ) + ) + ) + ) + ) + ) + ) + ) + + assertEquals( + """ + + + + + test name + test description + + bvn13 + + + + 10.0 + + 3.0 + 45.0 + test point 1 + comment 1 + description of point 1 + source 1 + + text + hyperlink + + + text2 + hyperlink2 + + sym 1 + type 1 + dgps + 1 + 55.0 + 66.0 + 77.0 + 44 + 88 + + + + + + + rte name + cmt + desc + src + + new text rte + hyperlink + + 1234 + route + +value1 + + + 10.0 + + 3.0 + 45.0 + test point 1 + comment 1 + description of point 1 + source 1 + + text + hyperlink + + + text2 + hyperlink2 + + sym 1 + type 1 + dgps + 1 + 55.0 + 66.0 + 77.0 + 44 + 88 + + + + + + + + track 1 + comment track 1 + desc track 1 + src track 1 + null + 1234 + type 1 + null + + + 10.0 + + 3.0 + 45.0 + test point 1 + comment 1 + description of point 1 + source 1 + + text + hyperlink + + + text2 + hyperlink2 + + sym 1 + type 1 + dgps + 1 + 55.0 + 66.0 + 77.0 + 44 + 88 + + + + + + + + + """.trim(), + gpxType.toXmlString(clock) + ) + } + } +} \ No newline at end of file diff --git a/target/classes/META-INF/GpxAndroidSdk.kotlin_module b/target/classes/META-INF/GpxAndroidSdk.kotlin_module new file mode 100644 index 0000000..5602915 Binary files /dev/null and b/target/classes/META-INF/GpxAndroidSdk.kotlin_module differ diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..e69de29 diff --git a/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 0000000..e69de29 diff --git a/target/surefire-reports/2022-09-23T16-36-51_543-jvmRun1.dump b/target/surefire-reports/2022-09-23T16-36-51_543-jvmRun1.dump new file mode 100644 index 0000000..2288117 --- /dev/null +++ b/target/surefire-reports/2022-09-23T16-36-51_543-jvmRun1.dump @@ -0,0 +1,27 @@ +# Created at 2022-09-23T16:36:51.955 +org.apache.maven.surefire.util.SurefireReflectionException: java.lang.NoClassDefFoundError: org/junit/platform/commons/util/ClassNamePatternFilterUtils + at org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg(ReflectionUtils.java:139) + at org.apache.maven.surefire.booter.ForkedBooter.createProviderInCurrentClassloader(ForkedBooter.java:403) + at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:383) + at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345) + at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126) + at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418) +Caused by: java.lang.NoClassDefFoundError: org/junit/platform/commons/util/ClassNamePatternFilterUtils + at org.junit.platform.launcher.core.LauncherFactory.loadAndFilterTestExecutionListeners(LauncherFactory.java:122) + at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:108) + at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:75) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.(JUnitPlatformProvider.java:86) + at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) + at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) + at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) + at java.lang.reflect.Constructor.newInstance(Constructor.java:423) + at org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg(ReflectionUtils.java:135) + ... 5 more +Caused by: java.lang.ClassNotFoundException: org.junit.platform.commons.util.ClassNamePatternFilterUtils + at java.net.URLClassLoader.findClass(URLClassLoader.java:387) + at java.lang.ClassLoader.loadClass(ClassLoader.java:418) + at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) + at java.lang.ClassLoader.loadClass(ClassLoader.java:351) + ... 14 more + + diff --git a/target/surefire-reports/2022-09-24T12-12-29_353-jvmRun1.dump b/target/surefire-reports/2022-09-24T12-12-29_353-jvmRun1.dump new file mode 100644 index 0000000..346a349 --- /dev/null +++ b/target/surefire-reports/2022-09-24T12-12-29_353-jvmRun1.dump @@ -0,0 +1,27 @@ +# Created at 2022-09-24T12:12:29.669 +org.apache.maven.surefire.util.SurefireReflectionException: java.lang.NoClassDefFoundError: org/junit/platform/commons/util/ClassNamePatternFilterUtils + at org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg(ReflectionUtils.java:139) + at org.apache.maven.surefire.booter.ForkedBooter.createProviderInCurrentClassloader(ForkedBooter.java:403) + at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:383) + at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345) + at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126) + at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418) +Caused by: java.lang.NoClassDefFoundError: org/junit/platform/commons/util/ClassNamePatternFilterUtils + at org.junit.platform.launcher.core.LauncherFactory.loadAndFilterTestExecutionListeners(LauncherFactory.java:122) + at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:108) + at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:75) + at org.apache.maven.surefire.junitplatform.JUnitPlatformProvider.(JUnitPlatformProvider.java:86) + at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) + at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) + at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) + at java.lang.reflect.Constructor.newInstance(Constructor.java:423) + at org.apache.maven.surefire.util.ReflectionUtils.instantiateOneArg(ReflectionUtils.java:135) + ... 5 more +Caused by: java.lang.ClassNotFoundException: org.junit.platform.commons.util.ClassNamePatternFilterUtils + at java.net.URLClassLoader.findClass(URLClassLoader.java:387) + at java.lang.ClassLoader.loadClass(ClassLoader.java:418) + at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) + at java.lang.ClassLoader.loadClass(ClassLoader.java:351) + ... 14 more + + diff --git a/target/surefire-reports/TEST-me.bvn13.sdk.android.gpx.GpxWriterTest.xml b/target/surefire-reports/TEST-me.bvn13.sdk.android.gpx.GpxWriterTest.xml new file mode 100644 index 0000000..32dcc42 --- /dev/null +++ b/target/surefire-reports/TEST-me.bvn13.sdk.android.gpx.GpxWriterTest.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/target/surefire-reports/me.bvn13.sdk.android.gpx.GpxWriterTest.txt b/target/surefire-reports/me.bvn13.sdk.android.gpx.GpxWriterTest.txt new file mode 100644 index 0000000..9d66f8d --- /dev/null +++ b/target/surefire-reports/me.bvn13.sdk.android.gpx.GpxWriterTest.txt @@ -0,0 +1,4 @@ +------------------------------------------------------------------------------- +Test set: me.bvn13.sdk.android.gpx.GpxWriterTest +------------------------------------------------------------------------------- +Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.205 s - in me.bvn13.sdk.android.gpx.GpxWriterTest diff --git a/target/test-classes/META-INF/GpxAndroidSdk.kotlin_module b/target/test-classes/META-INF/GpxAndroidSdk.kotlin_module new file mode 100644 index 0000000..8c840dd Binary files /dev/null and b/target/test-classes/META-INF/GpxAndroidSdk.kotlin_module differ