Fix for TAVRIDA-T-5

This commit is contained in:
Alexander Nozik 2022-07-13 21:32:28 +03:00
parent 6f6c4b117b
commit bebd33f859
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357

View File

@ -1,23 +1,20 @@
package centre.sciprog.maps.compose package centre.sciprog.maps.compose
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.gestures.drag
import androidx.compose.foundation.gestures.forEachGesture
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.drawscope.clipRect import androidx.compose.ui.graphics.drawscope.*
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.nativeCanvas import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.input.pointer.PointerEventType import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.onPointerEvent
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.* import androidx.compose.ui.unit.*
import centre.sciprog.maps.* import centre.sciprog.maps.*
import mu.KotlinLogging import mu.KotlinLogging
@ -25,8 +22,8 @@ import org.jetbrains.skia.Font
import org.jetbrains.skia.Paint import org.jetbrains.skia.Paint
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.floor import kotlin.math.floor
import kotlin.math.log2
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.roundToInt
private fun Color.toPaint(): Paint = Paint().apply { private fun Color.toPaint(): Paint = Paint().apply {
@ -39,6 +36,7 @@ private val logger = KotlinLogging.logger("MapView")
/** /**
* A component that renders map and provides basic map manipulation capabilities * A component that renders map and provides basic map manipulation capabilities
*/ */
@OptIn(ExperimentalComposeUiApi::class)
@Composable @Composable
actual fun MapView( actual fun MapView(
initialViewPoint: MapViewPoint, initialViewPoint: MapViewPoint,
@ -73,20 +71,62 @@ actual fun MapView(
*/ */
fun DpOffset.toGeodetic() = WebMercatorProjection.toGeodetic(toMercator()) fun DpOffset.toGeodetic() = WebMercatorProjection.toGeodetic(toMercator())
@OptIn(ExperimentalComposeUiApi::class) // Selection rectangle. If null - no selection
val canvasModifier = modifier.onPointerEvent(PointerEventType.Press) { var selectRect by remember { mutableStateOf<Rect?>(null) }
val (xPos, yPos) = it.changes.first().position
onClick(DpOffset(xPos.toDp(), yPos.toDp()).toGeodetic()) val canvasModifier = modifier.pointerInput(Unit) {
forEachGesture {
awaitPointerEventScope {
val event: PointerEvent = awaitPointerEvent()
event.changes.forEach { change ->
if (event.buttons.isPrimaryPressed) {
//Evaluating selection frame
if (event.keyboardModifiers.isShiftPressed) {
selectRect = Rect(change.position, change.position)
drag(change.id) { dragChange ->
selectRect?.let { rect ->
val offset = dragChange.position
selectRect = Rect(
kotlin.math.min(offset.x, rect.left),
kotlin.math.min(offset.y, rect.top),
kotlin.math.max(offset.x, rect.right),
kotlin.math.max(offset.y, rect.bottom)
)
}
}
selectRect?.let { rect ->
val (centerX, centerY) = rect.center
val centerGmc = DpOffset(centerX.toDp(), centerY.toDp()).toGeodetic()
val horizontalZoom: Float = log2(canvasSize.width.toPx() / rect.width)
val verticalZoom: Float = log2(canvasSize.height.toPx() / rect.height)
viewPoint = MapViewPoint(centerGmc, viewPoint.zoom + kotlin.math.min(verticalZoom, horizontalZoom))
selectRect = null
}
} else {
val dragStart = change.position
val dpPos = DpOffset(dragStart.x.toDp(), dragStart.y.toDp())
onClick(dpPos.toGeodetic())
drag(change.id) { dragChange ->
val dragAmount = dragChange.position - dragChange.previousPosition
viewPoint = viewPoint.move(
-dragAmount.x.toDp().value / tileScale,
+dragAmount.y.toDp().value / tileScale
)
}
}
}
}
}
}
}.onPointerEvent(PointerEventType.Scroll) { }.onPointerEvent(PointerEventType.Scroll) {
val change = it.changes.first() val change = it.changes.first()
val (xPos, yPos) = change.position val (xPos, yPos) = change.position
//compute invariant point of translation //compute invariant point of translation
val invariant = DpOffset(xPos.toDp(), yPos.toDp()).toGeodetic() val invariant = DpOffset(xPos.toDp(), yPos.toDp()).toGeodetic()
viewPoint = viewPoint.zoom(-change.scrollDelta.y.toDouble() * config.zoomSpeed, invariant) viewPoint = viewPoint.zoom(-change.scrollDelta.y.toDouble() * config.zoomSpeed, invariant)
}.pointerInput(Unit) {
detectDragGestures { _: PointerInputChange, dragAmount: Offset ->
viewPoint = viewPoint.move(-dragAmount.x.toDp().value / tileScale, +dragAmount.y.toDp().value / tileScale)
}
}.fillMaxSize() }.fillMaxSize()
@ -189,5 +229,17 @@ actual fun MapView(
drawFeature(zoom, feature) drawFeature(zoom, feature)
} }
} }
selectRect?.let { rect ->
drawRect(
color = Color.Blue,
topLeft = rect.topLeft,
size = rect.size,
alpha = 0.5f,
style = Stroke(
width = 2f,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
)
)
}
} }
} }