1
1
mirror of https://github.com/Pygmalion69/OpenTopoMapViewer.git synced 2025-10-06 00:02:42 +02:00

Add elevation endpoints

This commit is contained in:
Pygmalion69
2025-08-24 13:52:39 +02:00
parent 206b36df85
commit 2feecd92c5
6 changed files with 233 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
package org.nitri.ors
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.nitri.ors.client.OpenRouteServiceClient
import org.nitri.ors.repository.ElevationRepository
@RunWith(AndroidJUnit4::class)
class ElevationInstrumentedTest {
private fun createRepository(context: Context): ElevationRepository {
val apiKey = context.getString(R.string.ors_api_key)
val api = OpenRouteServiceClient.create(apiKey, context)
return ElevationRepository(api)
}
@Test
fun testElevation_point_successful() = runBlocking {
val context = ApplicationProvider.getApplicationContext<Context>()
val repository = createRepository(context)
// A point near Heidelberg, Germany
val lon = 8.681495
val lat = 49.41461
val response = repository.getElevationPoint(lon = lon, lat = lat)
assertNotNull("Elevation point response should not be null", response)
assertNotNull("Geometry should not be null", response.geometry)
assertEquals("Geometry type should be Point", "Point", response.geometry.type)
val coords = response.geometry.coordinates
assertTrue("Point coordinates should contain at least [lon, lat]", coords.size >= 2)
// Typically API returns elevation as third value
if (coords.size >= 3) {
// elevation could be any double, just ensure it's a number
val elevation = coords[2]
assertTrue("Elevation should be a finite number", elevation.isFinite())
}
}
@Test
fun testElevation_line_successful() = runBlocking {
val context = ApplicationProvider.getApplicationContext<Context>()
val repository = createRepository(context)
// A short line segment around Heidelberg
val coordinates = listOf(
listOf(8.681495, 49.41461),
listOf(8.687872, 49.420318)
)
val response = repository.getElevationLine(coordinates = coordinates)
assertNotNull("Elevation line response should not be null", response)
assertEquals("Geometry type should be LineString", "LineString", response.geometry.type)
val lineCoords = response.geometry.coordinates
assertTrue("LineString should have at least 2 points", lineCoords.size >= 2)
val first = lineCoords.first()
assertTrue("Each coordinate should have at least [lon, lat]", first.size >= 2)
if (first.size >= 3) {
val elevation = first[2]
assertTrue("Elevation should be a finite number", elevation.isFinite())
}
}
}

View File

@@ -0,0 +1,35 @@
package org.nitri.ors.model.elevation
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
@Serializable
data class ElevationLineRequest(
/** One of: "geojson", "polyline", "encodedpolyline5", "encodedpolyline6" */
@SerialName("format_in") val formatIn: String,
/** One of: "geojson", "polyline", "encodedpolyline5", "encodedpolyline6" */
@SerialName("format_out") val formatOut: String,
/**
* Geometry payload. The API accepts different shapes depending on format:
* - format_in = "geojson" -> a GeoJSON LineString object
* - format_in = "polyline" -> [[lon,lat], [lon,lat], ...]
* - format_in = "encodedpolyline5/6"-> a single encoded polyline string
*
* Using JsonElement keeps this field flexible for all variants.
*/
val geometry: JsonElement,
/** Optional: pick a specific elevation dataset (e.g., "SRTM", "COP90", …) */
val dataset: String? = null
)
object ElevationFormats {
const val GEOJSON = "geojson"
const val POLYLINE = "polyline"
const val ENCODED_5 = "encodedpolyline5"
const val ENCODED_6 = "encodedpolyline6"
}

View File

@@ -0,0 +1,18 @@
package org.nitri.ors.model.elevation
import kotlinx.serialization.Serializable
@Serializable
data class ElevationLineResponse(
val attribution: String? = null,
val geometry: ElevationLineGeometry,
val timestamp: Long? = null,
val version: String? = null
)
@Serializable
data class ElevationLineGeometry(
val type: String, // "LineString"
/** Coordinates with elevation: [lon, lat, ele] (API may return [lon,lat] if ele missing) */
val coordinates: List<List<Double>>
)

View File

@@ -0,0 +1,17 @@
package org.nitri.ors.model.elevation
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class ElevationPointRequest(
@SerialName("format_in")
val formatIn: String, // Input format, must be provided (e.g., "point")
@SerialName("format_out")
val formatOut: String = "geojson", // "geojson" or "point"
val dataset: String? = null, // Optional dataset, e.g. "srtm"
val geometry: List<Double> // [lon, lat]
)

View File

@@ -0,0 +1,17 @@
package org.nitri.ors.model.elevation
import kotlinx.serialization.Serializable
@Serializable
data class ElevationPointResponse(
val attribution: String,
val geometry: ElevationPointGeometry,
val timestamp: Long,
val version: String
)
@Serializable
data class ElevationPointGeometry(
val coordinates: List<Double>, // [lon, lat, elevation]
val type: String // "Point"
)

View File

@@ -0,0 +1,72 @@
package org.nitri.ors.repository
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import org.nitri.ors.api.OpenRouteServiceApi
import org.nitri.ors.model.elevation.ElevationLineRequest
import org.nitri.ors.model.elevation.ElevationLineResponse
import org.nitri.ors.model.elevation.ElevationPointRequest
import org.nitri.ors.model.elevation.ElevationPointResponse
class ElevationRepository(private val api: OpenRouteServiceApi) {
/**
* Calls the ORS elevation/line POST endpoint with a prepared request.
*/
suspend fun getElevationLine(request: ElevationLineRequest): ElevationLineResponse =
api.getElevationLine(request)
/**
* Convenience helper to request elevation for a LineString provided as list of [lon, lat] pairs.
* Builds a GeoJSON LineString payload and requests GeoJSON output.
*/
suspend fun getElevationLine(
coordinates: List<List<Double>>, // [[lon,lat], [lon,lat], ...]
dataset: String? = null,
formatOut: String = "geojson",
): ElevationLineResponse {
val geometry: JsonElement = JsonObject(
mapOf(
"type" to JsonPrimitive("LineString"),
"coordinates" to JsonArray(
coordinates.map { pair ->
JsonArray(pair.map { JsonPrimitive(it) })
}
)
)
)
val request = ElevationLineRequest(
formatIn = "geojson",
formatOut = formatOut,
geometry = geometry,
dataset = dataset
)
return api.getElevationLine(request)
}
/**
* Calls the ORS elevation/point POST endpoint for a single coordinate.
*
* @param lon longitude
* @param lat latitude
* @param formatOut either "geojson" or "point"
* @param dataset optional dataset (e.g., "srtm")
*/
suspend fun getElevationPoint(
lon: Double,
lat: Double,
formatOut: String = "geojson",
dataset: String? = null,
): ElevationPointResponse {
val request = ElevationPointRequest(
formatIn = "point",
formatOut = formatOut,
dataset = dataset,
geometry = listOf(lon, lat)
)
return api.getElevationPoint(request)
}
}