From 32cfa000c7a94abdf84392c21bf74e65113c20ff Mon Sep 17 00:00:00 2001 From: 2ndbeam <2ndbeam@disroot.org> Date: Wed, 24 Sep 2025 17:16:14 +0300 Subject: [PATCH] Moved everything out of loop --- .../com/mirenkov/ktheightmap/KhmParser.kt | 7 +- .../com/mirenkov/ktheightmap/MapCanvas.kt | 203 +++++++++--------- 2 files changed, 109 insertions(+), 101 deletions(-) diff --git a/app/src/main/java/com/mirenkov/ktheightmap/KhmParser.kt b/app/src/main/java/com/mirenkov/ktheightmap/KhmParser.kt index 43118af..883bc7c 100644 --- a/app/src/main/java/com/mirenkov/ktheightmap/KhmParser.kt +++ b/app/src/main/java/com/mirenkov/ktheightmap/KhmParser.kt @@ -23,6 +23,9 @@ class KhmParser { private var header: HeightInfo? = null const val HEIGHT_FILE: String = "height.khm" + @OptIn(ExperimentalUnsignedTypes::class) + var cachedHeights: Pair>>? = null + fun load(filePath: String, ctx: Context) { if (ctx.getFileStreamPath(HEIGHT_FILE).exists()) { return @@ -84,6 +87,7 @@ class KhmParser { @OptIn(ExperimentalUnsignedTypes::class) fun getHeightsMul(ctx: Context, coords: Array>): Pair>> { if (coords.isEmpty()) return Pair(ushortArrayOf(), coords) + if (cachedHeights != null) return cachedHeights!! val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE)) dis.use { val header = readHeader(dis) @@ -112,12 +116,13 @@ class KhmParser { } else break } - return Pair(UShortArray(coords.size) { i -> + cachedHeights = Pair(UShortArray(coords.size) { i -> if (cutOffsets[i] > 0) { dis.skipBytes(cutOffsets[i]) dis.readUnsignedShort().toUShort() } else 0u }, coords) + return cachedHeights!! } } diff --git a/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt b/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt index b1789e5..af3560e 100644 --- a/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt +++ b/app/src/main/java/com/mirenkov/ktheightmap/MapCanvas.kt @@ -1,5 +1,6 @@ package com.mirenkov.ktheightmap +import android.util.Log import androidx.compose.foundation.Canvas import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.fillMaxSize @@ -54,9 +55,11 @@ fun MapCanvas( .pointerInput(Unit) { detectDragGestures ( onDragEnd = { + KhmParser.cachedHeights = null invokeHeightCalc = true }, onDragCancel = { + KhmParser.cachedHeights = null invokeHeightCalc = true } ) { _, distance -> @@ -137,6 +140,7 @@ fun MapCanvas( size = size ) + // Tiles for (cellX in 0 .. gridWidth + 2) { val tileX = tileOffsetX + cellX val localOffsetX = TILE_SIZE * (cellX - 1) @@ -181,110 +185,109 @@ fun MapCanvas( size = Size(TILE_SIZE, TILE_SIZE) ) } - - // Placed point and line to center - if (pointLat != 0F) { - val pointOffsetX = SphereMercator.mercateLon(pointLon.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetX - val pointOffsetY = SphereMercator.mercateLat(pointLat.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetY - drawRect( - color = gridColor, - size = Size(8F, 8F), - topLeft = Offset(pointOffsetX - 4, pointOffsetY - 4) - ) - drawLine( - color = gridColor, - start = Offset(pointOffsetX, pointOffsetY), - end = Offset(halvedX, halvedY) - ) - val startHeight = KhmParser.getHeight(pointLon, pointLat, ctx) - if (pointOffsetX >= 0 && pointOffsetY >= 0 && pointOffsetX < size.width && pointOffsetY < size.height) - drawText( - textMeasurer = textMeasurer, - text = buildAnnotatedString { withStyle(SpanStyle(color = Color.White)) { - append("${startHeight}m") - } }, - topLeft = Offset(pointOffsetX, pointOffsetY - 32) + } + } + // Placed point and line to center + if (pointLat != 0F) { + val pointOffsetX = SphereMercator.mercateLon(pointLon.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetX + val pointOffsetY = SphereMercator.mercateLat(pointLat.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetY + drawRect( + color = gridColor, + size = Size(8F, 8F), + topLeft = Offset(pointOffsetX - 4, pointOffsetY - 4) + ) + drawLine( + color = gridColor, + start = Offset(pointOffsetX, pointOffsetY), + end = Offset(halvedX, halvedY) + ) + val startHeight = KhmParser.getHeight(pointLon, pointLat, ctx) + if (pointOffsetX >= 0 && pointOffsetY >= 0 && pointOffsetX < size.width && pointOffsetY < size.height) + drawText( + textMeasurer = textMeasurer, + text = buildAnnotatedString { withStyle(SpanStyle(color = Color.White)) { + append("${startHeight}m") + } }, + topLeft = Offset(pointOffsetX, pointOffsetY - 32) + ) + if (invokeHeightCalc) { + val latPV = KhmParser.getLatPerValue() + val lonPV = KhmParser.getLonPerValue() + val valueDistance = sqrt(latPV.pow(2) + lonPV.pow(2)) + val latDiff = lat - pointLat + val lonDiff = lon - pointLon + val distance = sqrt((latDiff).pow(2) + (lonDiff).pow(2)) + val valuesCount = floor(distance / valueDistance).toInt() + val array: Array> = Array(valuesCount) { step -> + val interCoef = 1F - step.toFloat() / valuesCount + Pair(lon - lonDiff * interCoef, lat - latDiff * interCoef) + } + val heightPair = KhmParser.getHeightsMul(ctx, array) + val heights = heightPair.first + val coords = heightPair.second.reversed() + 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 + if (stepOffsetX >= 0 && stepOffsetY >= 0 && stepOffsetX < size.width && stepOffsetY < size.height) + drawRect( + color = if (heights[step] > startHeight) Color.Red else Color.Green, + size = Size(8F, 8F), + topLeft = Offset(stepOffsetX - 4, stepOffsetY - 4) ) - if (invokeHeightCalc) { - val latPV = KhmParser.getLatPerValue() - val lonPV = KhmParser.getLonPerValue() - val valueDistance = sqrt(latPV.pow(2) + lonPV.pow(2)) - val latDiff = lat - pointLat - val lonDiff = lon - pointLon - val distance = sqrt((latDiff).pow(2) + (lonDiff).pow(2)) - val valuesCount = floor(distance / valueDistance).toInt() - val array: Array> = Array(valuesCount) { step -> - val interCoef = 1F - step.toFloat() / valuesCount - Pair(lon - lonDiff * interCoef, lat - latDiff * interCoef) - } - val heightPair = KhmParser.getHeightsMul(ctx, array) - val heights = heightPair.first - val coords = heightPair.second.reversed() - 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 - if (stepOffsetX >= 0 && stepOffsetY >= 0 && stepOffsetX < size.width && stepOffsetY < size.height) - drawRect( - color = if (heights[step] > startHeight) Color.Red else Color.Green, - size = Size(8F, 8F), - topLeft = Offset(stepOffsetX - 4, stepOffsetY - 4) - ) + } + } + } + + // Cursor path + val path = Path() + path.moveTo(halvedX - crossRadius, halvedY) + path.lineTo(halvedX + crossRadius, halvedY) + path.moveTo(halvedX, halvedY - crossRadius) + path.lineTo(halvedX, halvedY + crossRadius) + path.close() + + // Cursor + drawPath( + path, + Color.White, + style = Stroke(width = 6F) + ) + + // Info box + drawRect( + color = backColor, + size = latLonSize, + topLeft = latLonOffset + ) + + // Info box content + drawText( + textMeasurer = textMeasurer, + text = buildAnnotatedString { + withStyle(ParagraphStyle(textAlign = TextAlign.Center)) { + withStyle(SpanStyle(color = gridColor)) { + append("%.6f\n%.6f".format(lat, lon)) + if (debug) { + append("\n%.0f\n%.0f".format(offsetX, offsetY)) } } } + }, + size = latLonSize, + topLeft = latLonOffset + ) - // Cursor path - val path = Path() - path.moveTo(halvedX - crossRadius, halvedY) - path.lineTo(halvedX + crossRadius, halvedY) - path.moveTo(halvedX, halvedY - crossRadius) - path.lineTo(halvedX, halvedY + crossRadius) - path.close() - - // Cursor - drawPath( - path, - Color.White, - style = Stroke(width = 6F) - ) - - // Info box - drawRect( - color = backColor, - size = latLonSize, - topLeft = latLonOffset - ) - - // Info box content - drawText( - textMeasurer = textMeasurer, - text = buildAnnotatedString { - withStyle(ParagraphStyle(textAlign = TextAlign.Center)) { - withStyle(SpanStyle(color = gridColor)) { - append("%.6f\n%.6f".format(lat, lon)) - if (debug) { - append("\n%.0f\n%.0f".format(offsetX, offsetY)) - } - } - } - }, - size = latLonSize, - topLeft = latLonOffset - ) - - // Height under cursor - drawText( - textMeasurer = textMeasurer, - text = buildAnnotatedString { - withStyle(SpanStyle(color = Color.White)) { - append("${KhmParser.getHeight(lon, lat, ctx)}m") - } - }, - topLeft = Offset(halvedX + crossRadius, halvedY + crossRadius) - ) - } - } + // Height under cursor + drawText( + textMeasurer = textMeasurer, + text = buildAnnotatedString { + withStyle(SpanStyle(color = Color.White)) { + append("${KhmParser.getHeight(lon, lat, ctx)}m") + } + }, + topLeft = Offset(halvedX + crossRadius, halvedY + crossRadius) + ) } } \ No newline at end of file