Moved everything out of loop

This commit is contained in:
Alexey 2025-09-24 17:16:14 +03:00
commit 32cfa000c7
2 changed files with 109 additions and 101 deletions

View file

@ -23,6 +23,9 @@ class KhmParser {
private var header: HeightInfo? = null private var header: HeightInfo? = null
const val HEIGHT_FILE: String = "height.khm" const val HEIGHT_FILE: String = "height.khm"
@OptIn(ExperimentalUnsignedTypes::class)
var cachedHeights: Pair<UShortArray, Array<Pair<Float, Float>>>? = null
fun load(filePath: String, ctx: Context) { fun load(filePath: String, ctx: Context) {
if (ctx.getFileStreamPath(HEIGHT_FILE).exists()) { if (ctx.getFileStreamPath(HEIGHT_FILE).exists()) {
return return
@ -84,6 +87,7 @@ class KhmParser {
@OptIn(ExperimentalUnsignedTypes::class) @OptIn(ExperimentalUnsignedTypes::class)
fun getHeightsMul(ctx: Context, coords: Array<Pair<Float, Float>>): Pair<UShortArray, Array<Pair<Float, Float>>> { fun getHeightsMul(ctx: Context, coords: Array<Pair<Float, Float>>): Pair<UShortArray, Array<Pair<Float, Float>>> {
if (coords.isEmpty()) return Pair(ushortArrayOf(), coords) if (coords.isEmpty()) return Pair(ushortArrayOf(), coords)
if (cachedHeights != null) return cachedHeights!!
val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE)) val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE))
dis.use { dis.use {
val header = readHeader(dis) val header = readHeader(dis)
@ -112,12 +116,13 @@ class KhmParser {
} else break } else break
} }
return Pair(UShortArray(coords.size) { i -> cachedHeights = Pair(UShortArray(coords.size) { i ->
if (cutOffsets[i] > 0) { if (cutOffsets[i] > 0) {
dis.skipBytes(cutOffsets[i]) dis.skipBytes(cutOffsets[i])
dis.readUnsignedShort().toUShort() dis.readUnsignedShort().toUShort()
} else 0u } else 0u
}, coords) }, coords)
return cachedHeights!!
} }
} }

View file

@ -1,5 +1,6 @@
package com.mirenkov.ktheightmap package com.mirenkov.ktheightmap
import android.util.Log
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -54,9 +55,11 @@ fun MapCanvas(
.pointerInput(Unit) { .pointerInput(Unit) {
detectDragGestures ( detectDragGestures (
onDragEnd = { onDragEnd = {
KhmParser.cachedHeights = null
invokeHeightCalc = true invokeHeightCalc = true
}, },
onDragCancel = { onDragCancel = {
KhmParser.cachedHeights = null
invokeHeightCalc = true invokeHeightCalc = true
} }
) { _, distance -> ) { _, distance ->
@ -137,6 +140,7 @@ fun MapCanvas(
size = size size = size
) )
// Tiles
for (cellX in 0 .. gridWidth + 2) { for (cellX in 0 .. gridWidth + 2) {
val tileX = tileOffsetX + cellX val tileX = tileOffsetX + cellX
val localOffsetX = TILE_SIZE * (cellX - 1) val localOffsetX = TILE_SIZE * (cellX - 1)
@ -181,110 +185,109 @@ fun MapCanvas(
size = Size(TILE_SIZE, TILE_SIZE) size = Size(TILE_SIZE, TILE_SIZE)
) )
} }
}
// Placed point and line to center }
if (pointLat != 0F) { // Placed point and line to center
val pointOffsetX = SphereMercator.mercateLon(pointLon.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetX if (pointLat != 0F) {
val pointOffsetY = SphereMercator.mercateLat(pointLat.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetY val pointOffsetX = SphereMercator.mercateLon(pointLon.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetX
drawRect( val pointOffsetY = SphereMercator.mercateLat(pointLat.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetY
color = gridColor, drawRect(
size = Size(8F, 8F), color = gridColor,
topLeft = Offset(pointOffsetX - 4, pointOffsetY - 4) size = Size(8F, 8F),
) topLeft = Offset(pointOffsetX - 4, pointOffsetY - 4)
drawLine( )
color = gridColor, drawLine(
start = Offset(pointOffsetX, pointOffsetY), color = gridColor,
end = Offset(halvedX, halvedY) 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) val startHeight = KhmParser.getHeight(pointLon, pointLat, ctx)
drawText( if (pointOffsetX >= 0 && pointOffsetY >= 0 && pointOffsetX < size.width && pointOffsetY < size.height)
textMeasurer = textMeasurer, drawText(
text = buildAnnotatedString { withStyle(SpanStyle(color = Color.White)) { textMeasurer = textMeasurer,
append("${startHeight}m") text = buildAnnotatedString { withStyle(SpanStyle(color = Color.White)) {
} }, append("${startHeight}m")
topLeft = Offset(pointOffsetX, pointOffsetY - 32) } },
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<Pair<Float, Float>> = 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 // Cursor path
val lonDiff = lon - pointLon val path = Path()
val distance = sqrt((latDiff).pow(2) + (lonDiff).pow(2)) path.moveTo(halvedX - crossRadius, halvedY)
val valuesCount = floor(distance / valueDistance).toInt() path.lineTo(halvedX + crossRadius, halvedY)
val array: Array<Pair<Float, Float>> = Array(valuesCount) { step -> path.moveTo(halvedX, halvedY - crossRadius)
val interCoef = 1F - step.toFloat() / valuesCount path.lineTo(halvedX, halvedY + crossRadius)
Pair(lon - lonDiff * interCoef, lat - latDiff * interCoef) path.close()
}
val heightPair = KhmParser.getHeightsMul(ctx, array) // Cursor
val heights = heightPair.first drawPath(
val coords = heightPair.second.reversed() path,
for (step in 0 until coords.size) { Color.White,
val stepLat = coords[step].second style = Stroke(width = 6F)
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 // Info box
if (stepOffsetX >= 0 && stepOffsetY >= 0 && stepOffsetX < size.width && stepOffsetY < size.height) drawRect(
drawRect( color = backColor,
color = if (heights[step] > startHeight) Color.Red else Color.Green, size = latLonSize,
size = Size(8F, 8F), topLeft = latLonOffset
topLeft = Offset(stepOffsetX - 4, stepOffsetY - 4) )
)
// 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 // Height under cursor
val path = Path() drawText(
path.moveTo(halvedX - crossRadius, halvedY) textMeasurer = textMeasurer,
path.lineTo(halvedX + crossRadius, halvedY) text = buildAnnotatedString {
path.moveTo(halvedX, halvedY - crossRadius) withStyle(SpanStyle(color = Color.White)) {
path.lineTo(halvedX, halvedY + crossRadius) append("${KhmParser.getHeight(lon, lat, ctx)}m")
path.close() }
},
// Cursor topLeft = Offset(halvedX + crossRadius, halvedY + crossRadius)
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)
)
}
}
} }
} }