Compare commits

..

No commits in common. "b70b98feb62d522866d782f8adcd1eb794137d9b" and "86a2dc3786183bb91eb24a15af0c5a35c3256945" have entirely different histories.

6 changed files with 20 additions and 95 deletions

View file

@ -63,8 +63,6 @@ class KhmParser {
}
fun getHeight(lon: Float, lat: Float, ctx: Context): UShort {
if (!ctx.getFileStreamPath(HEIGHT_FILE).exists())
return 0u.toUShort()
val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE))
dis.use {
val header = readHeader(dis)
@ -82,7 +80,7 @@ class KhmParser {
@OptIn(ExperimentalUnsignedTypes::class)
fun getHeightsMul(ctx: Context, coords: Array<Pair<Float, Float>>): Pair<UShortArray, Array<Pair<Float, Float>>> {
if (coords.isEmpty() || !ctx.getFileStreamPath(HEIGHT_FILE).exists()) return Pair(ushortArrayOf(), coords)
if (coords.isEmpty()) return Pair(ushortArrayOf(), coords)
val dis = DataInputStream(ctx.openFileInput(HEIGHT_FILE))
dis.use {
val header = readHeader(dis)

View file

@ -3,7 +3,6 @@ package com.mirenkov.ktheightmap
import android.app.Application
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@ -85,7 +84,6 @@ class MainActivity : ComponentActivity() {
@Composable
fun Main(vm: TileViewModel = viewModel()) {
var scale by rememberSaveable { vm.scale }
val maxScale by rememberSaveable { vm.maxLevel }
val coroutineScope = rememberCoroutineScope()
val tileContainer = TileContainer(vm, coroutineScope)
KtHeightMapTheme {
@ -113,7 +111,7 @@ fun Main(vm: TileViewModel = viewModel()) {
Slider(
value = scale,
onValueChange = { scale = it },
valueRange = 2F..maxScale.toFloat(),
valueRange = 1F..14F,
modifier = Modifier.align(Alignment.CenterStart)
)
}

View file

@ -18,7 +18,6 @@ import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
@ -31,19 +30,6 @@ import kotlin.math.floor
import kotlin.math.pow
import kotlin.math.sqrt
fun distanceString(targetMeters: Int): AnnotatedString {
return buildAnnotatedString {
withStyle(ParagraphStyle(textAlign = TextAlign.Center)) {
withStyle(SpanStyle(color = Color.White)) {
val text = if (targetMeters >= 100000)
"${targetMeters / 1000}km"
else
"${targetMeters}m"
append(text)
}
}
}
}
@OptIn(ExperimentalUnsignedTypes::class)
@Composable
fun MapCanvas(
@ -63,7 +49,6 @@ fun MapCanvas(
var pointLat by rememberSaveable { viewModel.rememberedPointLat }
var pointLon by rememberSaveable { viewModel.rememberedPointLon }
var invokeHeightCalc by remember { mutableStateOf(false) }
val startTargetMeters = 64 * 1000 * 1000
Canvas(
modifier = modifier.fillMaxSize()
.pointerInput(Unit) {
@ -108,10 +93,6 @@ fun MapCanvas(
}
}
val targetMeters = startTargetMeters shr level
val targetPixels = (targetMeters).toFloat() / SphereMercator.scaledMetersPerPixel(level)
val measurerHeight = 24F
val centerTileX = (1 + (offsetX + halvedX) / TILE_SIZE).toDouble()
val centerTileY = (1 + (offsetY + halvedY) / TILE_SIZE).toDouble()
@ -203,7 +184,6 @@ fun MapCanvas(
}
}
}
// Placed point and line to center
if (pointLat != 0F) {
val pointOffsetX = SphereMercator.mercateLon(pointLon.toDouble(), level, -TILE_SIZE.toDouble()).toFloat() - offsetX
@ -218,13 +198,12 @@ fun MapCanvas(
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")
append("${startHeight}m")
} },
topLeft = Offset(pointOffsetX, pointOffsetY - 32)
)
@ -249,7 +228,7 @@ fun MapCanvas(
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 && heights[step] > 0u)
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),
@ -257,49 +236,22 @@ fun MapCanvas(
)
}
}
val lineLength = sqrt((pointOffsetX - halvedX).pow(2) + (pointOffsetY - halvedY).pow(2))
val lineMeters = (lineLength * SphereMercator.scaledMetersPerPixel(level + 1)).toInt()
drawText(
textMeasurer = textMeasurer,
text = distanceString(lineMeters),
size = Size(160F, 48F),
topLeft = Offset(
halvedX - 80F,
halvedY - 80F
)
)
}
// Cursor path
val cursorPath = Path()
with(cursorPath) {
moveTo(halvedX - crossRadius, halvedY)
lineTo(halvedX + crossRadius, halvedY)
moveTo(halvedX, halvedY - crossRadius)
lineTo(halvedX, halvedY + crossRadius)
close()
}
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(
cursorPath,
path,
Color.White,
style = Stroke(width = 6F)
)
// Height under cursor
KhmParser.getHeight(lon, lat, ctx).let {
if (it < 1u) return@let
drawText(
textMeasurer = textMeasurer,
text = buildAnnotatedString {
withStyle(SpanStyle(color = Color.White)) {
append("${it}m")
}
},
topLeft = Offset(halvedX, halvedY + crossRadius)
)
}
// Info box
drawRect(
@ -307,6 +259,7 @@ fun MapCanvas(
size = latLonSize,
topLeft = latLonOffset
)
// Info box content
drawText(
textMeasurer = textMeasurer,
@ -324,29 +277,15 @@ fun MapCanvas(
topLeft = latLonOffset
)
// Distance measurer path
val measurerPath = Path()
with(measurerPath) {
moveTo((halvedX - targetPixels).toFloat(), 8F)
relativeLineTo(0F, measurerHeight)
relativeMoveTo(targetPixels.toFloat() * 2F, 0F)
relativeLineTo(0F, -measurerHeight)
relativeMoveTo(0F, measurerHeight / 2F)
relativeLineTo(-2F * targetPixels.toFloat(), 0F)
close()
}
// Distance measurer
drawPath(
measurerPath,
Color.White,
style = Stroke(width = 6F)
)
// Distance measurer text
// Height under cursor
drawText(
textMeasurer = textMeasurer,
text = distanceString(targetMeters),
topLeft = Offset(targetPixels.toFloat() * 2F, measurerHeight),
size = Size(targetPixels.toFloat() * 2F, 48F)
text = buildAnnotatedString {
withStyle(SpanStyle(color = Color.White)) {
append("${KhmParser.getHeight(lon, lat, ctx)}m")
}
},
topLeft = Offset(halvedX + crossRadius, halvedY + crossRadius)
)
}
}

View file

@ -14,7 +14,4 @@ interface TileDao {
@Query("delete from tiles")
fun clearTiles()
@Query("select max(level) from tiles")
fun maxLevel(): Int?
}

View file

@ -21,8 +21,4 @@ class TileRepository(private val tileDao: TileDao) {
fun clearTiles() {
coroutineScope.launch(Dispatchers.IO) { tileDao.clearTiles() }
}
fun getMaxLevel(): Int {
return coroutineScope.future(Dispatchers.IO){ tileDao.maxLevel() }.join() ?: 2
}
}

View file

@ -2,7 +2,6 @@ package com.mirenkov.ktheightmap
import android.app.Application
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel
@ -18,8 +17,7 @@ class TileViewModel(application: Application): ViewModel() {
val mapOffsetX = mutableFloatStateOf(-646.65625F)
val mapOffsetY = mutableFloatStateOf(-1157.2814F)
val scale = mutableFloatStateOf(2F)
var maxLevel = mutableIntStateOf(2)
val scale = mutableFloatStateOf(1F)
var halvedOffsetX: Float? = null
var halvedOffsetY: Float? = null
@ -31,6 +29,5 @@ class TileViewModel(application: Application): ViewModel() {
val tileDb = TileDB.getInstance(application)
val tileDao = tileDb.tileDao()
repository = TileRepository(tileDao)
maxLevel.intValue = repository.getMaxLevel()
}
}