Optimized heights parsing

This commit is contained in:
Alexey 2025-09-24 16:20:10 +03:00
commit c7b22f012b
2 changed files with 68 additions and 48 deletions

View file

@ -88,30 +88,35 @@ class KhmParser {
dis.use {
val header = readHeader(dis)
val glist: Array<Pair<Pair<Float, Float>, 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 glist: MutableMap<Pair<Float, Float>, Int> = mutableMapOf()
for (coord in coords) {
val x = ((coord.first - header.minLon) / header.lonPerValue).toInt()
val y = ((coord.second - header.minLat) / header.latPerValue).toInt()
val offset = getOffset(header, x, y)
Pair(coords[i], offset)
}
glist.sortBy {
it.second
glist.put(coord, offset)
}
val sortedGlist = glist.toList().sortedBy { (_, v) -> v }.toMap()
val glistKeys = sortedGlist.keys.toTypedArray()
coords.sortBy { oit ->
glist.find { it.first == oit }!!.second
val cutOffsets = IntArray(glist.size) {-1}
if (inBounds(header, coords[0].first, coords[0].second)) {
val key = glistKeys[0]
cutOffsets[0] = sortedGlist.getOrDefault(key, 0)
}
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)
for (i in 1 until sortedGlist.size) {
if (inBounds(header, coords[i].first, coords[i].second) && cutOffsets[i-1] >= 0) {
val prevKey = glistKeys[i-1]
val key = glistKeys[i]
cutOffsets[i] = sortedGlist.getOrDefault(key, 0) - sortedGlist.getOrDefault(prevKey, 0) - 2
} else break
}
return Pair(UShortArray(coords.size) { i ->
dis.skipBytes(cutOffsets[i])
dis.readUnsignedShort().toUShort()
if (cutOffsets[i] > 0) {
dis.skipBytes(cutOffsets[i])
dis.readUnsignedShort().toUShort()
} else 0u
}, coords)
}
}

View file

@ -5,6 +5,8 @@ import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
@ -46,12 +48,21 @@ fun MapCanvas(
var pointRequested by rememberSaveable { viewModel.pointRequested }
var pointLat by rememberSaveable { viewModel.rememberedPointLat }
var pointLon by rememberSaveable { viewModel.rememberedPointLon }
var invokeHeightCalc by remember { mutableStateOf(false) }
Canvas(
modifier = modifier.fillMaxSize()
.pointerInput(Unit) {
detectDragGestures { _, distance ->
detectDragGestures (
onDragEnd = {
invokeHeightCalc = true
},
onDragCancel = {
invokeHeightCalc = true
}
) { _, distance ->
offsetX -= distance.x
offsetY -= distance.y
invokeHeightCalc = false
}
}
) {
@ -186,37 +197,41 @@ fun MapCanvas(
end = Offset(halvedX, halvedY)
)
val startHeight = KhmParser.getHeight(pointLon, pointLat, ctx)
drawText(
textMeasurer = textMeasurer,
text = buildAnnotatedString { withStyle(SpanStyle(color = Color.White)) {
append("${startHeight}m")
} },
topLeft = Offset(pointOffsetX, pointOffsetY - 32)
)
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
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
drawRect(
color = if (heights[step] > startHeight) Color.Red else Color.Green,
size = Size(8F, 8F),
topLeft = Offset(stepOffsetX - 4, stepOffsetY - 4)
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<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)
)
}
}
}