Compare commits
No commits in common. "b70b98feb62d522866d782f8adcd1eb794137d9b" and "86a2dc3786183bb91eb24a15af0c5a35c3256945" have entirely different histories.
b70b98feb6
...
86a2dc3786
6 changed files with 20 additions and 95 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,4 @@ interface TileDao {
|
|||
|
||||
@Query("delete from tiles")
|
||||
fun clearTiles()
|
||||
|
||||
@Query("select max(level) from tiles")
|
||||
fun maxLevel(): Int?
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue