diff --git a/app/src/main/java/com/mirenkov/ktheightmap/KhmParser.kt b/app/src/main/java/com/mirenkov/ktheightmap/KhmParser.kt index 02f6914..460e126 100644 --- a/app/src/main/java/com/mirenkov/ktheightmap/KhmParser.kt +++ b/app/src/main/java/com/mirenkov/ktheightmap/KhmParser.kt @@ -2,10 +2,12 @@ package com.mirenkov.ktheightmap import android.content.Context import android.util.Log +import java.io.DataInput import java.io.DataInputStream import java.io.FileInputStream import kotlin.math.max import kotlin.math.min +import kotlin.math.sign private data class HeightInfo( val minLon: Float, @@ -20,6 +22,7 @@ class KhmParser { companion object { private var header: HeightInfo? = null const val HEIGHT_FILE: String = "height.khm" + fun load(filePath: String, ctx: Context) { if (ctx.getFileStreamPath(HEIGHT_FILE).exists()) { return @@ -77,6 +80,42 @@ class KhmParser { } } + + @OptIn(ExperimentalUnsignedTypes::class) + fun getHeightsMul(ctx: Context, coords: Array>): Pair>> { + if (coords.isEmpty()) return Pair(ushortArrayOf(), coords) + val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE)) + dis.use { + val header = readHeader(dis) + + val glist: Array, Int>> = Array(coords.size) { i -> + val x = ((coords[i].first - header.minLon) / header.lonPerValue).toInt() + val y = ((coords[i].second - header.minLat) / header.latPerValue).toInt() + val offset = getOffset(header, x, y) + Pair(coords[i], offset) + } + glist.sortBy { + it.second + } + + coords.sortBy { oit -> + glist.find { it.first == oit }!!.second + } + + val cutOffsets = IntArray(glist.size) + cutOffsets[0] = glist[0].second + for (i in 1 until glist.size) { + cutOffsets[i] = glist[i].second - glist[i-1].second - 2 + assert(cutOffsets[i] >= 0) + } + + return Pair(UShortArray(coords.size) { i -> + dis.skipBytes(cutOffsets[i]) + dis.readUnsignedShort().toUShort() + }, coords) + } + } + fun getLonPerValue(): Float { return header?.lonPerValue ?: 0F } diff --git a/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt b/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt index 0a8e7e5..d186ac7 100644 --- a/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt +++ b/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt @@ -24,11 +24,11 @@ import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.withStyle import kotlin.math.absoluteValue -import kotlin.math.ceil import kotlin.math.floor import kotlin.math.pow import kotlin.math.sqrt +@OptIn(ExperimentalUnsignedTypes::class) @Composable fun MapCanvas( viewModel: TileViewModel, @@ -200,15 +200,20 @@ fun MapCanvas( val lonDiff = lon - pointLon val distance = sqrt((latDiff).pow(2) + (lonDiff).pow(2)) val valuesCount = floor(distance / valueDistance).toInt() - for (step in 0 .. valuesCount) { + val array: Array> = Array(valuesCount) { step -> val interCoef = 1F - step.toFloat() / valuesCount - val stepLat = lat - latDiff * interCoef - val stepLon = lon - lonDiff * interCoef + Pair(lon - lonDiff * interCoef, lat - latDiff * interCoef) + } + val heightPair = KhmParser.getHeightsMul(ctx, array) + val heights = heightPair.first + val coords = heightPair.second + for (step in 0 until coords.size) { + val stepLat = coords[step].second + val stepLon = coords[step].first val stepOffsetX = SphereMercator.mercateLon(stepLon.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetX val stepOffsetY = SphereMercator.mercateLat(stepLat.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetY - val height = KhmParser.getHeight(stepLon, stepLat, ctx) drawRect( - color = if (height > startHeight) Color.Red else Color.Green, + color = if (heights[step] > startHeight) Color.Red else Color.Green, size = Size(8F, 8F), topLeft = Offset(stepOffsetX - 4, stepOffsetY - 4) )