Compare commits

..

3 commits

Author SHA1 Message Date
47cd68fcfe Fixed quick scaling 2025-08-12 15:42:55 +03:00
be85e92397 Optimized drawing 2025-08-11 16:56:43 +03:00
2f15a6f625 Proper scaling 2025-08-08 13:27:12 +03:00
5 changed files with 45 additions and 13 deletions

View file

@ -4,6 +4,14 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-08-08T10:50:02.571721922Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/home/secondbeam/.android/avd/Pixel_3.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState> </SelectionState>
</selectionStates> </selectionStates>
</component> </component>

View file

@ -12,13 +12,13 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.KtHeightMap" android:theme="@style/Theme.KtHeightMap"
tools:targetApi="31"> tools:targetApi="31">
<profileable android:shell="true" />
<activity <activity
android:name=".SettingsActivity" android:name=".SettingsActivity"
android:exported="false" /> android:exported="false" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.KtHeightMap"> android:theme="@style/Theme.KtHeightMap">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View file

@ -21,6 +21,7 @@ import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.rememberTextMeasurer 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
@Composable @Composable
fun MapCanvas( fun MapCanvas(
@ -30,8 +31,8 @@ fun MapCanvas(
tileContainer: TileContainer, tileContainer: TileContainer,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val offsetX = rememberSaveable { mutableFloatStateOf(0F) } val offsetX = rememberSaveable { mutableFloatStateOf(-TILE_SIZE) }
val offsetY = rememberSaveable { mutableFloatStateOf(0F) } val offsetY = rememberSaveable { mutableFloatStateOf(-TILE_SIZE) }
val textMeasurer = rememberTextMeasurer() val textMeasurer = rememberTextMeasurer()
Canvas( Canvas(
modifier = modifier.fillMaxSize() modifier = modifier.fillMaxSize()
@ -46,15 +47,31 @@ fun MapCanvas(
color = backColor, color = backColor,
size = size size = size
) )
val oldLevel = tileContainer.getLevel()
val level = scale.floatValue.toInt()
val levelDiff = level - oldLevel
if (levelDiff < 0) {
repeat (levelDiff.absoluteValue) {
offsetX.floatValue -= size.width / 2F + TILE_SIZE
offsetY.floatValue -= size.height / 2F + TILE_SIZE
offsetX.floatValue /= 2F
offsetY.floatValue /= 2F
}
} else if (levelDiff > 0) {
repeat (levelDiff) {
offsetX.floatValue *= 2F
offsetY.floatValue *= 2F
offsetX.floatValue += size.width / 2F + TILE_SIZE
offsetY.floatValue += size.height / 2F + TILE_SIZE
}
}
val tileOffsetX = (offsetX.floatValue / TILE_SIZE).toInt() val tileOffsetX = (offsetX.floatValue / TILE_SIZE).toInt()
val tileOffsetY = (offsetY.floatValue / TILE_SIZE).toInt() val tileOffsetY = (offsetY.floatValue / TILE_SIZE).toInt()
val strippedOffsetX = offsetX.floatValue % TILE_SIZE val strippedOffsetX = offsetX.floatValue % TILE_SIZE
val strippedOffsetY = offsetY.floatValue % TILE_SIZE val strippedOffsetY = offsetY.floatValue % TILE_SIZE
val level = scale.floatValue.toInt()
val offset = Offset(strippedOffsetX, strippedOffsetY) val offset = Offset(strippedOffsetX, strippedOffsetY)
val grid = size / TILE_SIZE val grid = size / TILE_SIZE
@ -62,7 +79,7 @@ fun MapCanvas(
val gridWidth = grid.width.toInt() val gridWidth = grid.width.toInt()
val gridHeight = grid.height.toInt() val gridHeight = grid.height.toInt()
val tiles = tileContainer.getTiles(tileOffsetX, tileOffsetY, tileOffsetX + gridWidth, tileOffsetY + gridHeight, level) val tiles = tileContainer.getTiles(tileOffsetX, tileOffsetY, tileOffsetX + gridWidth + 2, tileOffsetY + gridHeight + 2, level)
for (cellX in 0 .. gridWidth + 2) { for (cellX in 0 .. gridWidth + 2) {
val tileX = tileOffsetX + cellX val tileX = tileOffsetX + cellX
@ -71,7 +88,7 @@ fun MapCanvas(
val tileY = tileOffsetY + cellY val tileY = tileOffsetY + cellY
val localOffsetY = TILE_SIZE * (cellY - 1) val localOffsetY = TILE_SIZE * (cellY - 1)
val bitmap = tiles.find { it.x == tileX && it.y == tileY && it.level == level }?.getBitmap() val bitmap = tiles.find { it.x == tileX && it.y == tileY && it.level == level }?.toBitmap()
bitmap?.let { bitmap?.let {
val imageBitmap = bitmap.asImageBitmap() val imageBitmap = bitmap.asImageBitmap()
@ -80,7 +97,7 @@ fun MapCanvas(
topLeft = Offset(localOffsetX, localOffsetY) - offset topLeft = Offset(localOffsetX, localOffsetY) - offset
) )
} }
/*
drawRect( drawRect(
color = gridColor, color = gridColor,
size = Size(TILE_SIZE, TILE_SIZE), size = Size(TILE_SIZE, TILE_SIZE),
@ -100,6 +117,7 @@ fun MapCanvas(
topLeft = Offset(localOffsetX, localOffsetY) - offset, topLeft = Offset(localOffsetX, localOffsetY) - offset,
size = Size(TILE_SIZE, TILE_SIZE) size = Size(TILE_SIZE, TILE_SIZE)
) )
*/
} }
} }
} }

View file

@ -4,6 +4,7 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Ignore
import java.util.Base64 import java.util.Base64
@Entity(tableName = "tiles", primaryKeys = [ "x", "y", "level" ]) @Entity(tableName = "tiles", primaryKeys = [ "x", "y", "level" ])
@ -20,6 +21,9 @@ class Tile {
@ColumnInfo(name = "data") @ColumnInfo(name = "data")
var base64: String? = null var base64: String? = null
@Ignore
var bitmap: Bitmap? = null
constructor() constructor()
constructor(x: Int, y: Int, level: Int) { constructor(x: Int, y: Int, level: Int) {
@ -35,11 +39,11 @@ class Tile {
this.base64 = base64 this.base64 = base64
} }
fun getBitmap(): Bitmap? { fun toBitmap(): Bitmap? {
if (this.base64 == null) if (bitmap != null || base64 == null)
return null return bitmap
val ba = Base64.getDecoder().decode(this.base64) val ba = Base64.getDecoder().decode(this.base64)
val bmp = BitmapFactory.decodeByteArray(ba, 0, ba.size) bitmap = BitmapFactory.decodeByteArray(ba, 0, ba.size)
return bmp return bitmap
} }
} }

View file

@ -13,6 +13,8 @@ class TileContainer(private val vm: TileViewModel, private val coroutineScope: C
private var level = 1 private var level = 1
fun getLevel(): Int = level
fun getTiles(_startX: Int, _startY: Int, _endX: Int, _endY: Int, _level: Int): List<Tile> { fun getTiles(_startX: Int, _startY: Int, _endX: Int, _endY: Int, _level: Int): List<Tile> {
val newParams = arrayOf( _startX, _startY, _endX, _endY, _level ) val newParams = arrayOf( _startX, _startY, _endX, _endY, _level )
val oldParams = arrayOf( startX, startY, endX, endY, level ) val oldParams = arrayOf( startX, startY, endX, endY, level )