Compare commits

...

7 commits

Author SHA1 Message Date
86a2dc3786 Fixed reversing 2025-09-24 17:49:30 +03:00
6e47b724e8 Removed unused reports 2025-09-24 17:31:53 +03:00
32cfa000c7 Moved everything out of loop 2025-09-24 17:16:14 +03:00
c7b22f012b Optimized heights parsing 2025-09-24 16:20:10 +03:00
71f012dc6b Changed multiple heights parsing 2025-09-23 16:39:53 +03:00
470535cac8 Height on distance 2025-09-23 12:51:23 +03:00
af7429fad7 Deducing height on the move 2025-09-22 12:36:51 +03:00
6 changed files with 249 additions and 88 deletions

View file

@ -4,7 +4,7 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-08-26T11:06:03.805342749Z"> <DropdownSelection timestamp="2025-09-22T09:08:24.101225364Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/home/secondbeam/.config/.android/avd/Virtual_Pixel_3.avd" /> <DeviceId pluginId="LocalEmulator" identifier="path=/home/secondbeam/.config/.android/avd/Virtual_Pixel_3.avd" />

View file

@ -1,9 +1,10 @@
package com.mirenkov.ktheightmap package com.mirenkov.ktheightmap
import android.content.Context import android.content.Context
import android.util.Log
import java.io.DataInputStream import java.io.DataInputStream
import java.io.FileInputStream import java.io.FileInputStream
import kotlin.math.max
import kotlin.math.min
private data class HeightInfo( private data class HeightInfo(
val minLon: Float, val minLon: Float,
@ -16,46 +17,116 @@ private data class HeightInfo(
class KhmParser { class KhmParser {
companion object { companion object {
private var header: HeightInfo? = null
const val HEIGHT_FILE: String = "height.khm" const val HEIGHT_FILE: String = "height.khm"
fun load(filePath: String, ctx: Context) { fun load(filePath: String, ctx: Context) {
if (ctx.getFileStreamPath(HEIGHT_FILE).exists()) { if (ctx.getFileStreamPath(HEIGHT_FILE).exists()) {
Log.i(TAG, "height.khm already exists")
return return
} }
val inp = FileInputStream(filePath) val inp = FileInputStream(filePath)
ctx.openFileOutput(HEIGHT_FILE, Context.MODE_PRIVATE).use { ctx.openFileOutput(HEIGHT_FILE, Context.MODE_PRIVATE).use {
it.write(inp.readBytes()) it.write(inp.readBytes())
Log.i(TAG, "Copied %s to height.khm".format(filePath))
} }
} }
private fun getOffset(header: HeightInfo, x: Int, y: Int): Int { private fun getOffset(header: HeightInfo, x: Int, y: Int): Int {
Log.i(TAG, "Offset for (%d, %d) = %d".format(x, y, y * header.height + x))
return (x * header.width + y) * 2 return (x * header.width + y) * 2
} }
private fun readHeader(dis: DataInputStream): HeightInfo { private fun readHeader(dis: DataInputStream): HeightInfo {
return with(dis) { if (header == null) {
val minLon = readFloat() header = with(dis) {
val minLat = readFloat() val minLon = readFloat()
val lonPerValue = readFloat() val minLat = readFloat()
val latPerValue = readFloat() val lonPerValue = readFloat()
val width = readInt() val latPerValue = readFloat()
val height = readInt() val width = readInt()
Log.i(TAG, "Header: %.6f, %.6f, %.6f, %.6f, %d, %d".format(minLon, minLat, lonPerValue, latPerValue, width, height)) val height = readInt()
HeightInfo( minLon, minLat, lonPerValue, latPerValue, width, height ) HeightInfo(minLon, minLat, lonPerValue, latPerValue, width, height)
}
} else {
dis.skipBytes(4 * 6)
} }
return header!!
}
private fun inBounds(header: HeightInfo, lon: Float, lat: Float): Boolean {
val maxLon = header.minLon + (header.lonPerValue * header.width)
val maxLat = header.minLat + (header.latPerValue * header.height)
val miLon = min(header.minLon, maxLon)
val maLon = max(header.minLon, maxLon)
val miLat = min(header.minLat, maxLat)
val maLat = max(header.minLat, maxLat)
return lon > miLon && lat > miLat && lon < maLon && lat < maLat
} }
fun getHeight(lon: Float, lat: Float, ctx: Context): UShort { fun getHeight(lon: Float, lat: Float, ctx: Context): UShort {
val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE)) val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE))
val header = readHeader(dis) dis.use {
val x = ((lon - header.minLon) / header.lonPerValue).toInt() val header = readHeader(dis)
val y = ((lat - header.minLat) / header.latPerValue).toInt() if (!inBounds(header, lon, lat))
val offset = getOffset(header, x, y) return 0u
dis.skipBytes(offset) val x = ((lon - header.minLon) / header.lonPerValue).toInt()
return dis.readUnsignedShort().toUShort() val y = ((lat - header.minLat) / header.latPerValue).toInt()
val offset = getOffset(header, x, y)
dis.skipBytes(offset)
val height = dis.readUnsignedShort().toUShort()
return height
}
}
@OptIn(ExperimentalUnsignedTypes::class)
fun getHeightsMul(ctx: Context, coords: Array<Pair<Float, Float>>): Pair<UShortArray, Array<Pair<Float, Float>>> {
if (coords.isEmpty()) return Pair(ushortArrayOf(), coords)
val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE))
dis.use {
val header = readHeader(dis)
val reversed = coords[0].first < coords[coords.size - 1].first
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)
glist.put(coord, offset)
}
val sortedGlist = glist.toList().sortedBy { (_, v) -> v }.toMap()
val glistKeys = sortedGlist.keys.toTypedArray()
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)
}
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 ->
if (cutOffsets[i] > 0) {
dis.skipBytes(cutOffsets[i])
dis.readUnsignedShort().toUShort()
} else 0u },
if (reversed) coords else coords.reversed().toTypedArray())
}
}
fun getLonPerValue(): Float {
return header?.lonPerValue ?: 0F
}
fun getLatPerValue(): Float {
return header?.latPerValue ?: 0F
} }
} }
} }

View file

@ -3,7 +3,6 @@ package com.mirenkov.ktheightmap
import android.app.Application import android.app.Application
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
@ -32,7 +31,6 @@ import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
@ -43,7 +41,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.toUpperCase
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
@ -122,12 +119,13 @@ fun Main(vm: TileViewModel = viewModel()) {
} }
} }
@Suppress("VariableNeverRead", "AssignedValueIsNeverRead")
@Composable @Composable
fun ToolButton(viewModel: TileViewModel) { fun ToolButton(viewModel: TileViewModel) {
val context = LocalContext.current val context = LocalContext.current
var expanded by rememberSaveable{ mutableStateOf(false) } var expanded by rememberSaveable{ mutableStateOf(false) }
var debug by rememberSaveable{ viewModel.debug } var debug by rememberSaveable{ viewModel.debug }
var logRequested by remember{ viewModel.logRequested } var pointRequested by remember{ viewModel.pointRequested }
val dialogShown = rememberSaveable{ mutableStateOf(false) } val dialogShown = rememberSaveable{ mutableStateOf(false) }
FloatingActionButton( FloatingActionButton(
onClick = { onClick = {
@ -147,9 +145,9 @@ fun ToolButton(viewModel: TileViewModel) {
} }
) )
DropdownMenuItem( DropdownMenuItem(
text = { Text("Log") }, text = { Text("Place point") },
onClick = { onClick = {
logRequested = true pointRequested = true
expanded = false expanded = false
} }
) )
@ -175,7 +173,6 @@ fun ToolButton(viewModel: TileViewModel) {
@Suppress("VariableNeverRead", "AssignedValueIsNeverRead") @Suppress("VariableNeverRead", "AssignedValueIsNeverRead")
@Composable @Composable
fun SetLocationDialog(vm: TileViewModel, dialogShown: MutableState<Boolean>) { fun SetLocationDialog(vm: TileViewModel, dialogShown: MutableState<Boolean>) {
val ctx = LocalContext.current
var showLocationDialog by dialogShown var showLocationDialog by dialogShown
if (showLocationDialog) { if (showLocationDialog) {
var latitudeText by remember { vm.latitudeText } var latitudeText by remember { vm.latitudeText }
@ -210,12 +207,8 @@ fun SetLocationDialog(vm: TileViewModel, dialogShown: MutableState<Boolean>) {
confirmButton = { TextButton(onClick = { confirmButton = { TextButton(onClick = {
val latitude = latitudeText.text.toDoubleOrNull() ?: 0.0 val latitude = latitudeText.text.toDoubleOrNull() ?: 0.0
val longitude = longitudeText.text.toDoubleOrNull() ?: 0.0 val longitude = longitudeText.text.toDoubleOrNull() ?: 0.0
Log.i(TAG, "Lat: %.6f, Lon: %.6f".format(latitude, longitude))
Log.i(TAG, "X = %.6f".format(SphereMercator.mercateLon(longitude, vm.scale.floatValue.toInt(), -TILE_SIZE.toDouble())))
Log.i(TAG, "Y = %.6f".format(SphereMercator.mercateLat(latitude, vm.scale.floatValue.toInt(), -TILE_SIZE.toDouble())))
offsetX = SphereMercator.mercateLon(longitude, vm.scale.floatValue.toInt(), -vm.halvedOffsetX!!.toDouble() - TILE_SIZE).toFloat() offsetX = SphereMercator.mercateLon(longitude, vm.scale.floatValue.toInt(), -vm.halvedOffsetX!!.toDouble() - TILE_SIZE).toFloat()
offsetY = SphereMercator.mercateLat(latitude, vm.scale.floatValue.toInt(), -vm.halvedOffsetY!!.toDouble() - TILE_SIZE).toFloat() offsetY = SphereMercator.mercateLat(latitude, vm.scale.floatValue.toInt(), -vm.halvedOffsetY!!.toDouble() - TILE_SIZE).toFloat()
Log.i(TAG, "%d".format(KhmParser.getHeight(longitude.toFloat(), latitude.toFloat(), ctx).toInt()))
}) { }) {
Text("Confirm".uppercase()) Text("Confirm".uppercase())
} }, } },

View file

@ -1,11 +1,12 @@
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
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue 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.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -16,6 +17,7 @@ import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.ParagraphStyle import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.buildAnnotatedString
@ -24,7 +26,11 @@ import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle import androidx.compose.ui.text.withStyle
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
import kotlin.math.floor
import kotlin.math.pow
import kotlin.math.sqrt
@OptIn(ExperimentalUnsignedTypes::class)
@Composable @Composable
fun MapCanvas( fun MapCanvas(
viewModel: TileViewModel, viewModel: TileViewModel,
@ -33,18 +39,30 @@ fun MapCanvas(
tileContainer: TileContainer, tileContainer: TileContainer,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val ctx = LocalContext.current
var offsetX by rememberSaveable { viewModel.mapOffsetX } var offsetX by rememberSaveable { viewModel.mapOffsetX }
var offsetY by rememberSaveable { viewModel.mapOffsetY } var offsetY by rememberSaveable { viewModel.mapOffsetY }
val scale by rememberSaveable { viewModel.scale } val scale by rememberSaveable { viewModel.scale }
val textMeasurer = rememberTextMeasurer() val textMeasurer = rememberTextMeasurer()
val debug by rememberSaveable { viewModel.debug } val debug by rememberSaveable { viewModel.debug }
var logRequested by rememberSaveable { viewModel.logRequested } 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( Canvas(
modifier = modifier.fillMaxSize() modifier = modifier.fillMaxSize()
.pointerInput(Unit) { .pointerInput(Unit) {
detectDragGestures { _, distance -> detectDragGestures (
onDragEnd = {
invokeHeightCalc = true
},
onDragCancel = {
invokeHeightCalc = true
}
) { _, distance ->
offsetX -= distance.x offsetX -= distance.x
offsetY -= distance.y offsetY -= distance.y
invokeHeightCalc = false
} }
} }
) { ) {
@ -55,16 +73,6 @@ fun MapCanvas(
val halvedX = viewModel.halvedOffsetX!! val halvedX = viewModel.halvedOffsetX!!
val halvedY = viewModel.halvedOffsetY!! val halvedY = viewModel.halvedOffsetY!!
drawRect(
color = backColor,
size = size
)
if (logRequested) {
Log.i(TAG, "Offset: %.6f, %.6f".format(offsetX, offsetY))
logRequested = false
}
val oldLevel = tileContainer.getLevel() val oldLevel = tileContainer.getLevel()
val level = scale.toInt() val level = scale.toInt()
val levelDiff = level - oldLevel val levelDiff = level - oldLevel
@ -84,12 +92,27 @@ fun MapCanvas(
offsetY += halvedY + TILE_SIZE offsetY += halvedY + TILE_SIZE
} }
} }
val tileOffsetX = (offsetX / TILE_SIZE).toInt()
val tileOffsetY = (offsetY / TILE_SIZE).toInt()
val centerTileX = (1 + (offsetX + halvedX) / TILE_SIZE).toDouble() val centerTileX = (1 + (offsetX + halvedX) / TILE_SIZE).toDouble()
val centerTileY = (1 + (offsetY + halvedY) / TILE_SIZE).toDouble() val centerTileY = (1 + (offsetY + halvedY) / TILE_SIZE).toDouble()
val lon = SphereMercator.mercateX(centerTileX, level).toFloat()
val lat = SphereMercator.mercateY(centerTileY, level).toFloat()
if (pointRequested) {
if (pointLat == 0F) {
pointLat = lat
pointLon = lon
} else {
pointLat = 0F
pointLon = 0F
}
pointRequested = false
}
val tileOffsetX = (offsetX / TILE_SIZE).toInt()
val tileOffsetY = (offsetY / TILE_SIZE).toInt()
val strippedOffsetX = offsetX % TILE_SIZE val strippedOffsetX = offsetX % TILE_SIZE
val strippedOffsetY = offsetY % TILE_SIZE val strippedOffsetY = offsetY % TILE_SIZE
@ -108,6 +131,13 @@ fun MapCanvas(
val latLonSize = Size(216F, 96F + additionalSize) val latLonSize = Size(216F, 96F + additionalSize)
val latLonOffset = Offset(16F, 16F) val latLonOffset = Offset(16F, 16F)
// Background
drawRect(
color = backColor,
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)
@ -119,6 +149,7 @@ fun MapCanvas(
val bitmap = tile.toBitmap() val bitmap = tile.toBitmap()
val totalOffset = Offset(localOffsetX, localOffsetY) - offset val totalOffset = Offset(localOffsetX, localOffsetY) - offset
// Tile
bitmap?.let { bitmap?.let {
val imageBitmap = bitmap.asImageBitmap() val imageBitmap = bitmap.asImageBitmap()
drawImage( drawImage(
@ -127,6 +158,7 @@ fun MapCanvas(
) )
} }
// Debug grid
if (debug) { if (debug) {
drawRect( drawRect(
color = gridColor, color = gridColor,
@ -150,44 +182,110 @@ fun MapCanvas(
size = Size(TILE_SIZE, TILE_SIZE) size = Size(TILE_SIZE, TILE_SIZE)
) )
} }
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()
drawPath(
path,
Color.White,
style = Stroke(width = 6F)
)
drawRect(
color = backColor,
size = latLonSize,
topLeft = latLonOffset
)
drawText(
textMeasurer = textMeasurer,
text = buildAnnotatedString {
withStyle(ParagraphStyle(textAlign = TextAlign.Center)) {
withStyle(SpanStyle(color = gridColor)) {
val lon = SphereMercator.mercateX(centerTileX, level)
val lat = SphereMercator.mercateY(centerTileY, level)
append("%.6f\n%.6f".format(lon, lat))
if (debug) {
append("\n%.0f\n%.0f".format(offsetX, offsetY))
}
}
}
},
size = latLonSize,
topLeft = latLonOffset
)
} }
} }
// 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<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
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
)
// 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)
)
} }
} }

View file

@ -89,10 +89,7 @@ fun SettingsMain(vm: TileViewModel, launcher: ActivityResultLauncher<DocumentFil
val t = getTile(it.x, it.y, it.level) val t = getTile(it.x, it.y, it.level)
if (t == null) { if (t == null) {
pushTile(it) pushTile(it)
Log.i(TAG, "pushed to db: %d, %d, %d".format(it.level, it.x, it.y))
} }
else
Log.i(TAG, "found in db: %d, %d, %d".format(t.level, t.x, t.y))
} }
} }
} }, } },
@ -124,7 +121,6 @@ suspend fun processZip(filePath: String?): List<Tile> = coroutineScope {
if (entry == null) if (entry == null)
break break
} }
Log.i(TAG, "got list")
} }
} }
return@coroutineScope list return@coroutineScope list

View file

@ -10,7 +10,7 @@ class TileViewModel(application: Application): ViewModel() {
val repository: TileRepository val repository: TileRepository
var debug = mutableStateOf(false) var debug = mutableStateOf(false)
var logRequested = mutableStateOf(false) var pointRequested = mutableStateOf(false)
var latitudeText = mutableStateOf(TextFieldValue("")) var latitudeText = mutableStateOf(TextFieldValue(""))
var longitudeText = mutableStateOf(TextFieldValue("")) var longitudeText = mutableStateOf(TextFieldValue(""))
@ -22,6 +22,9 @@ class TileViewModel(application: Application): ViewModel() {
var halvedOffsetX: Float? = null var halvedOffsetX: Float? = null
var halvedOffsetY: Float? = null var halvedOffsetY: Float? = null
var rememberedPointLon = mutableFloatStateOf(0F)
var rememberedPointLat = mutableFloatStateOf(0F)
init { init {
val tileDb = TileDB.getInstance(application) val tileDb = TileDB.getInstance(application)
val tileDao = tileDb.tileDao() val tileDao = tileDb.tileDao()