Split points and multiline
This commit is contained in:
parent
3219e13fa7
commit
90eb7b4575
@ -10,7 +10,7 @@ val kmathVersion: String by extra("0.3.1-dev-10")
|
||||
|
||||
allprojects {
|
||||
group = "center.sciprog"
|
||||
version = "0.2.2-dev-4"
|
||||
version = "0.2.2-dev-5"
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
|
@ -8,7 +8,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PointMode
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
@ -91,7 +90,7 @@ fun App() {
|
||||
println("line 3 clicked")
|
||||
}
|
||||
|
||||
points(
|
||||
multiLine(
|
||||
points = listOf(
|
||||
55.742465 to 37.615812,
|
||||
55.742713 to 37.616370,
|
||||
@ -100,7 +99,6 @@ fun App() {
|
||||
55.742086 to 37.616566,
|
||||
55.741715 to 37.616716
|
||||
),
|
||||
pointMode = PointMode.Polygon
|
||||
)
|
||||
|
||||
//remember feature ID
|
||||
@ -138,13 +136,11 @@ fun App() {
|
||||
println("Click on ${ref.id}")
|
||||
//draw in top-level scope
|
||||
with(this@MapView) {
|
||||
points(
|
||||
multiLine(
|
||||
ref.resolve().points,
|
||||
stroke = 4f,
|
||||
pointMode = PointMode.Polygon,
|
||||
attributes = Attributes(ZAttribute, 10f),
|
||||
id = "selected",
|
||||
).color(Color.Magenta)
|
||||
).modifyAttribute(StrokeAttribute, 4f).color(Color.Magenta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import androidx.compose.ui.graphics.PointMode
|
||||
import androidx.compose.ui.input.pointer.isSecondaryPressed
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.application
|
||||
@ -26,9 +25,8 @@ fun App() {
|
||||
val myPolygon: SnapshotStateList<XY> = remember { mutableStateListOf<XY>() }
|
||||
|
||||
val featureState: FeatureGroup<XY> = FeatureGroup.remember(XYCoordinateSpace) {
|
||||
points(
|
||||
multiLine(
|
||||
listOf(XY(0f, 0f), XY(0f, 1f), XY(1f, 1f), XY(1f, 0f), XY(0f, 0f)),
|
||||
pointMode = PointMode.Polygon,
|
||||
id = "frame"
|
||||
)
|
||||
}
|
||||
@ -36,9 +34,8 @@ fun App() {
|
||||
|
||||
if(myPolygon.isNotEmpty()) {
|
||||
featureState.group("polygon") {
|
||||
points(
|
||||
multiLine(
|
||||
myPolygon + myPolygon.first(),
|
||||
pointMode = PointMode.Polygon,
|
||||
)
|
||||
myPolygon.forEachIndexed { index, xy ->
|
||||
circle(xy, id = "point[$index]").draggable { _, to ->
|
||||
|
@ -1,6 +1,5 @@
|
||||
package center.sciprog.maps.compose
|
||||
|
||||
import androidx.compose.ui.graphics.PointMode
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.Dp
|
||||
@ -32,7 +31,7 @@ public fun FeatureGroup<Gmc>.rectangle(
|
||||
size: DpSize = DpSize(5.dp, 5.dp),
|
||||
id: String? = null,
|
||||
): FeatureRef<Gmc, RectangleFeature<Gmc>> = feature(
|
||||
id, RectangleFeature(space, coordinatesOf(centerCoordinates), size)
|
||||
id, RectangleFeature(space, coordinatesOf(centerCoordinates), size)
|
||||
)
|
||||
|
||||
|
||||
@ -83,11 +82,13 @@ public fun FeatureGroup<Gmc>.arc(
|
||||
|
||||
public fun FeatureGroup<Gmc>.points(
|
||||
points: List<Pair<Double, Double>>,
|
||||
stroke: Float = 2f,
|
||||
pointMode: PointMode = PointMode.Points,
|
||||
id: String? = null,
|
||||
): FeatureRef<Gmc, PointsFeature<Gmc>> =
|
||||
feature(id, PointsFeature(space, points.map(::coordinatesOf), stroke, pointMode))
|
||||
): FeatureRef<Gmc, PointsFeature<Gmc>> = feature(id, PointsFeature(space, points.map(::coordinatesOf)))
|
||||
|
||||
public fun FeatureGroup<Gmc>.multiLine(
|
||||
points: List<Pair<Double, Double>>,
|
||||
id: String? = null,
|
||||
): FeatureRef<Gmc, MultiLineFeature<Gmc>> = feature(id, MultiLineFeature(space, points.map(::coordinatesOf)))
|
||||
|
||||
public fun FeatureGroup<Gmc>.image(
|
||||
position: Pair<Double, Double>,
|
||||
|
@ -3,7 +3,10 @@ package center.sciprog.maps.features
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.drawscope.DrawStyle
|
||||
import androidx.compose.ui.graphics.drawscope.Fill
|
||||
@ -112,8 +115,6 @@ public data class PathFeature<T : Any>(
|
||||
public data class PointsFeature<T : Any>(
|
||||
override val space: CoordinateSpace<T>,
|
||||
public val points: List<T>,
|
||||
public val stroke: Float = 2f,
|
||||
public val pointMode: PointMode = PointMode.Points,
|
||||
override val attributes: Attributes = Attributes.EMPTY,
|
||||
) : Feature<T> {
|
||||
|
||||
@ -125,6 +126,59 @@ public data class PointsFeature<T : Any>(
|
||||
override fun withAttributes(modify: (Attributes) -> Attributes): Feature<T> = copy(attributes = modify(attributes))
|
||||
}
|
||||
|
||||
|
||||
public interface LineSegmentFeature<T : Any> : Feature<T>
|
||||
|
||||
@Stable
|
||||
public data class LineFeature<T : Any>(
|
||||
override val space: CoordinateSpace<T>,
|
||||
public val a: T,
|
||||
public val b: T,
|
||||
override val attributes: Attributes = Attributes.EMPTY,
|
||||
) : DomainFeature<T>, LineSegmentFeature<T> {
|
||||
override fun getBoundingBox(zoom: Float): Rectangle<T> =
|
||||
space.Rectangle(a, b)
|
||||
|
||||
override fun contains(viewPoint: ViewPoint<T>): Boolean = with(space) {
|
||||
viewPoint.focus in getBoundingBox(viewPoint.zoom) && viewPoint.focus.distanceToLine(
|
||||
a,
|
||||
b,
|
||||
viewPoint.zoom
|
||||
).value < clickRadius
|
||||
}
|
||||
|
||||
override fun withAttributes(modify: (Attributes) -> Attributes): Feature<T> = copy(attributes = modify(attributes))
|
||||
}
|
||||
|
||||
public data class MultiLineFeature<T : Any>(
|
||||
override val space: CoordinateSpace<T>,
|
||||
public val points: List<T>,
|
||||
override val attributes: Attributes = Attributes.EMPTY,
|
||||
) : DomainFeature<T>, LineSegmentFeature<T> {
|
||||
|
||||
private val boundingBox by lazy {
|
||||
with(space) { points.wrapPoints() }
|
||||
}
|
||||
|
||||
override fun getBoundingBox(zoom: Float): Rectangle<T>? = boundingBox
|
||||
override fun withAttributes(modify: (Attributes) -> Attributes): Feature<T> = copy(attributes = modify(attributes))
|
||||
|
||||
override fun contains(viewPoint: ViewPoint<T>): Boolean = with(space) {
|
||||
val boundingBox = getBoundingBox(viewPoint.zoom) ?: return@with false
|
||||
viewPoint.focus in boundingBox && points.zipWithNext().minOf { (a, b) ->
|
||||
viewPoint.focus.distanceToLine(
|
||||
a,
|
||||
b,
|
||||
viewPoint.zoom
|
||||
).value
|
||||
} < clickRadius
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val <T : Any, F : LineSegmentFeature<T>> F.clickRadius get() = attributes[ClickRadius] ?: 10f
|
||||
|
||||
|
||||
@Stable
|
||||
public data class PolygonFeature<T : Any>(
|
||||
override val space: CoordinateSpace<T>,
|
||||
@ -176,29 +230,6 @@ public data class RectangleFeature<T : Any>(
|
||||
override fun withAttributes(modify: (Attributes) -> Attributes): Feature<T> = copy(attributes = modify(attributes))
|
||||
}
|
||||
|
||||
@Stable
|
||||
public data class LineFeature<T : Any>(
|
||||
override val space: CoordinateSpace<T>,
|
||||
public val a: T,
|
||||
public val b: T,
|
||||
override val attributes: Attributes = Attributes.EMPTY,
|
||||
) : DomainFeature<T> {
|
||||
override fun getBoundingBox(zoom: Float): Rectangle<T> =
|
||||
space.Rectangle(a, b)
|
||||
|
||||
private val clickRadius get() = attributes[ClickRadius] ?: 10f
|
||||
|
||||
override fun contains(viewPoint: ViewPoint<T>): Boolean = with(space) {
|
||||
viewPoint.focus in getBoundingBox(viewPoint.zoom) && viewPoint.focus.distanceToLine(
|
||||
a,
|
||||
b,
|
||||
viewPoint.zoom
|
||||
).value < clickRadius
|
||||
}
|
||||
|
||||
override fun withAttributes(modify: (Attributes) -> Attributes): Feature<T> = copy(attributes = modify(attributes))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param startAngle the angle from 3 o'clock downwards for the start of the arc in radians
|
||||
* @param arcLength arc length in radians
|
||||
|
@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateMapOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
||||
import androidx.compose.ui.graphics.PointMode
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
@ -156,56 +155,68 @@ public inline fun <T : Any, reified F : Feature<T>> FeatureGroup<T>.forEachWithT
|
||||
public fun <T : Any> FeatureGroup<T>.circle(
|
||||
center: T,
|
||||
size: Dp = 5.dp,
|
||||
attributes: Attributes = Attributes.EMPTY,
|
||||
id: String? = null,
|
||||
): FeatureRef<T, CircleFeature<T>> = feature(
|
||||
id, CircleFeature(space, center, size)
|
||||
id, CircleFeature(space, center, size, attributes)
|
||||
)
|
||||
|
||||
public fun <T : Any> FeatureGroup<T>.rectangle(
|
||||
centerCoordinates: T,
|
||||
size: DpSize = DpSize(5.dp, 5.dp),
|
||||
attributes: Attributes = Attributes.EMPTY,
|
||||
id: String? = null,
|
||||
): FeatureRef<T, RectangleFeature<T>> = feature(
|
||||
id, RectangleFeature(space, centerCoordinates, size)
|
||||
id, RectangleFeature(space, centerCoordinates, size, attributes)
|
||||
)
|
||||
|
||||
public fun <T : Any> FeatureGroup<T>.draw(
|
||||
position: T,
|
||||
attributes: Attributes = Attributes.EMPTY,
|
||||
id: String? = null,
|
||||
draw: DrawScope.() -> Unit,
|
||||
): FeatureRef<T, DrawFeature<T>> = feature(
|
||||
id,
|
||||
DrawFeature(space, position, drawFeature = draw)
|
||||
DrawFeature(space, position, drawFeature = draw, attributes = attributes)
|
||||
)
|
||||
|
||||
public fun <T : Any> FeatureGroup<T>.line(
|
||||
aCoordinates: T,
|
||||
bCoordinates: T,
|
||||
attributes: Attributes = Attributes.EMPTY,
|
||||
id: String? = null,
|
||||
): FeatureRef<T, LineFeature<T>> = feature(
|
||||
id,
|
||||
LineFeature(space, aCoordinates, bCoordinates)
|
||||
LineFeature(space, aCoordinates, bCoordinates, attributes)
|
||||
)
|
||||
|
||||
public fun <T : Any> FeatureGroup<T>.arc(
|
||||
oval: Rectangle<T>,
|
||||
startAngle: Angle,
|
||||
arcLength: Angle,
|
||||
attributes: Attributes = Attributes.EMPTY,
|
||||
id: String? = null,
|
||||
): FeatureRef<T, ArcFeature<T>> = feature(
|
||||
id,
|
||||
ArcFeature(space, oval, startAngle, arcLength)
|
||||
ArcFeature(space, oval, startAngle, arcLength, attributes)
|
||||
)
|
||||
|
||||
public fun <T : Any> FeatureGroup<T>.points(
|
||||
points: List<T>,
|
||||
stroke: Float = 2f,
|
||||
pointMode: PointMode = PointMode.Points,
|
||||
attributes: Attributes = Attributes.EMPTY,
|
||||
id: String? = null,
|
||||
): FeatureRef<T, PointsFeature<T>> = feature(
|
||||
id,
|
||||
PointsFeature(space, points, stroke, pointMode, attributes)
|
||||
PointsFeature(space, points, attributes)
|
||||
)
|
||||
|
||||
public fun <T : Any> FeatureGroup<T>.multiLine(
|
||||
points: List<T>,
|
||||
attributes: Attributes = Attributes.EMPTY,
|
||||
id: String? = null,
|
||||
): FeatureRef<T, MultiLineFeature<T>> = feature(
|
||||
id,
|
||||
MultiLineFeature(space, points, attributes)
|
||||
)
|
||||
|
||||
public fun <T : Any> FeatureGroup<T>.polygon(
|
||||
|
@ -32,8 +32,18 @@ public object VisibleAttribute : Attribute<Boolean>
|
||||
|
||||
public object ColorAttribute : Attribute<Color>
|
||||
|
||||
|
||||
public fun <T : Any, F : Feature<T>> FeatureRef<T, F>.color(color: Color): FeatureRef<T, F> =
|
||||
modifyAttribute(ColorAttribute, color)
|
||||
|
||||
|
||||
public object ZoomRangeAttribute : Attribute<FloatRange>
|
||||
|
||||
|
||||
public fun <T : Any, F : Feature<T>> FeatureRef<T, F>.zoomRange(range: FloatRange): FeatureRef<T, F> =
|
||||
modifyAttribute(ZoomRangeAttribute, range)
|
||||
|
||||
|
||||
public object AlphaAttribute : Attribute<Float>
|
||||
|
||||
public fun <T : Any, F : Feature<T>> FeatureRef<T, F>.modifyAttributes(modify: AttributesBuilder.() -> Unit): FeatureRef<T, F> {
|
||||
@ -47,7 +57,10 @@ public fun <T : Any, F : Feature<T>> FeatureRef<T, F>.modifyAttributes(modify: A
|
||||
return this
|
||||
}
|
||||
|
||||
public fun <T : Any, F : Feature<T>, V> FeatureRef<T, F>.modifyAttribute(key: Attribute<V>, value: V?): FeatureRef<T, F>{
|
||||
public fun <T : Any, F : Feature<T>, V> FeatureRef<T, F>.modifyAttribute(
|
||||
key: Attribute<V>,
|
||||
value: V?,
|
||||
): FeatureRef<T, F> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
parent.feature(id, resolve().withAttributes { withAttribute(key, value) } as F)
|
||||
return this
|
||||
@ -59,10 +72,10 @@ public fun <T : Any, F : Feature<T>, V> FeatureRef<T, F>.modifyAttribute(key: A
|
||||
* @param constraint optional drag constraint
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun <T: Any, F : DraggableFeature<T>> FeatureRef<T, F>.draggable(
|
||||
public fun <T : Any, F : DraggableFeature<T>> FeatureRef<T, F>.draggable(
|
||||
constraint: ((T) -> T)? = null,
|
||||
listener: (PointerEvent.(from: ViewPoint<T>, to: ViewPoint<T>) -> Unit)? = null,
|
||||
): FeatureRef<T, F> = with(parent){
|
||||
): FeatureRef<T, F> = with(parent) {
|
||||
if (attributes[DraggableAttribute] == null) {
|
||||
val handle = DragHandle.withPrimaryButton<Any> { event, start, end ->
|
||||
val feature = featureMap[id] as? DraggableFeature<T> ?: return@withPrimaryButton DragResult(end)
|
||||
@ -112,7 +125,7 @@ public fun <T : Any, F : DomainFeature<T>> FeatureRef<T, F>.onClick(
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun <T: Any, F : DomainFeature<T>> FeatureRef<T, F>.onClick(
|
||||
public fun <T : Any, F : DomainFeature<T>> FeatureRef<T, F>.onClick(
|
||||
pointerMatcher: PointerMatcher,
|
||||
keyboardModifiers: PointerKeyboardModifiers.() -> Boolean = { true },
|
||||
onClick: PointerEvent.(click: ViewPoint<T>) -> Unit,
|
||||
@ -127,7 +140,7 @@ public fun <T: Any, F : DomainFeature<T>> FeatureRef<T, F>.onClick(
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun <T: Any, F : DomainFeature<T>> FeatureRef<T, F>.onHover(
|
||||
public fun <T : Any, F : DomainFeature<T>> FeatureRef<T, F>.onHover(
|
||||
onClick: PointerEvent.(move: ViewPoint<T>) -> Unit,
|
||||
): FeatureRef<T, F> = modifyAttributes {
|
||||
HoverListenerAttribute.add(
|
||||
@ -147,15 +160,13 @@ public fun <T: Any, F : DomainFeature<T>> FeatureRef<T, F>.onHover(
|
||||
// )
|
||||
// }
|
||||
|
||||
public fun <T: Any, F : Feature<T>> FeatureRef<T, F>.color(color: Color): FeatureRef<T, F> =
|
||||
modifyAttribute(ColorAttribute, color)
|
||||
|
||||
public fun <T: Any, F : Feature<T>> FeatureRef<T, F>.zoomRange(range: FloatRange): FeatureRef<T, F> =
|
||||
modifyAttribute(ZoomRangeAttribute, range)
|
||||
public object PathEffectAttribute : Attribute<PathEffect>
|
||||
|
||||
|
||||
|
||||
public object PathEffectAttribute: Attribute<PathEffect>
|
||||
|
||||
public fun <T: Any> FeatureRef<T, PointsFeature<T>>.pathEffect(effect: PathEffect): FeatureRef<T, PointsFeature<T>> =
|
||||
public fun <T : Any> FeatureRef<T, LineSegmentFeature<T>>.pathEffect(effect: PathEffect): FeatureRef<T, LineSegmentFeature<T>> =
|
||||
modifyAttribute(PathEffectAttribute, effect)
|
||||
|
||||
public object StrokeAttribute : Attribute<Float>
|
||||
|
||||
public fun <T : Any, F : LineSegmentFeature<T>> FeatureRef<T, F>.stroke(width: Float): FeatureRef<T, F> =
|
||||
modifyAttribute(StrokeAttribute, width)
|
@ -94,13 +94,13 @@ public suspend fun PointerInputScope.detectClicks(
|
||||
if (upOrCancel != null) {
|
||||
// tap was successful.
|
||||
if (onDoubleClick == null) {
|
||||
onClick?.invoke(this, upOrCancel) // no need to check for double-tap.
|
||||
onClick?.invoke(this, down) // no need to check for double-tap.
|
||||
} else {
|
||||
// check for second tap
|
||||
val secondDown = awaitSecondDown(upOrCancel.firstChange)
|
||||
|
||||
if (secondDown == null) {
|
||||
onClick?.invoke(this, upOrCancel) // no valid second tap started
|
||||
onClick?.invoke(this, down) // no valid second tap started
|
||||
} else {
|
||||
// Second tap down detected
|
||||
pressScope.reset()
|
||||
@ -115,16 +115,16 @@ public suspend fun PointerInputScope.detectClicks(
|
||||
if (secondUp != null) {
|
||||
secondUp.consume()
|
||||
pressScope.release()
|
||||
onDoubleClick(down)
|
||||
onDoubleClick(secondDown)
|
||||
} else {
|
||||
pressScope.cancel()
|
||||
onClick?.invoke(this, upOrCancel)
|
||||
onClick?.invoke(this, down)
|
||||
}
|
||||
}
|
||||
} catch (e: PointerEventTimeoutCancellationException) {
|
||||
// The first tap was valid, but the second tap is a long press.
|
||||
// notify for the first tap
|
||||
onClick?.invoke(this, upOrCancel)
|
||||
onClick?.invoke(this, down)
|
||||
|
||||
// notify for the long press
|
||||
onLongClick?.invoke(this, secondDown)
|
||||
@ -209,7 +209,6 @@ private suspend fun AwaitPointerEventScope.awaitSecondDown(
|
||||
/**
|
||||
* Reads events until the first down is received. If [requireUnconsumed] is `true` and the first
|
||||
* down is consumed in the [PointerEventPass.Main] pass, that gesture is ignored.
|
||||
* If it was down caused by [PointerType.Mouse], this function reacts only on primary button.
|
||||
*/
|
||||
internal suspend fun AwaitPointerEventScope.awaitFirstDownEvent(
|
||||
requireUnconsumed: Boolean = true,
|
||||
|
@ -2,15 +2,12 @@ package center.sciprog.maps.features
|
||||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
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.painter.Painter
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import center.sciprog.attributes.plus
|
||||
import org.jetbrains.skia.Font
|
||||
import org.jetbrains.skia.Paint
|
||||
@ -28,7 +25,7 @@ public fun <T : Any> DrawScope.drawFeature(
|
||||
feature: Feature<T>,
|
||||
): Unit = with(state) {
|
||||
val color = feature.color ?: Color.Red
|
||||
val alpha = feature.attributes[AlphaAttribute]?:1f
|
||||
val alpha = feature.attributes[AlphaAttribute] ?: 1f
|
||||
fun T.toOffset(): Offset = toOffset(this@drawFeature)
|
||||
|
||||
when (feature) {
|
||||
@ -48,7 +45,14 @@ public fun <T : Any> DrawScope.drawFeature(
|
||||
size = feature.size.toSize()
|
||||
)
|
||||
|
||||
is LineFeature -> drawLine(color, feature.a.toOffset(), feature.b.toOffset())
|
||||
is LineFeature -> drawLine(
|
||||
color,
|
||||
feature.a.toOffset(),
|
||||
feature.b.toOffset(),
|
||||
strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth,
|
||||
pathEffect = feature.attributes[PathEffectAttribute]
|
||||
)
|
||||
|
||||
is ArcFeature -> {
|
||||
val dpRect = feature.oval.toDpRect().toRect()
|
||||
|
||||
@ -119,8 +123,20 @@ public fun <T : Any> DrawScope.drawFeature(
|
||||
drawPoints(
|
||||
points = points,
|
||||
color = color,
|
||||
strokeWidth = feature.stroke,
|
||||
pointMode = feature.pointMode,
|
||||
strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth,
|
||||
pointMode = PointMode.Points,
|
||||
pathEffect = feature.attributes[PathEffectAttribute],
|
||||
alpha = alpha
|
||||
)
|
||||
}
|
||||
|
||||
is MultiLineFeature -> {
|
||||
val points = feature.points.map { it.toOffset() }
|
||||
drawPoints(
|
||||
points = points,
|
||||
color = color,
|
||||
strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth,
|
||||
pointMode = PointMode.Polygon,
|
||||
pathEffect = feature.attributes[PathEffectAttribute],
|
||||
alpha = alpha
|
||||
)
|
||||
@ -131,8 +147,8 @@ public fun <T : Any> DrawScope.drawFeature(
|
||||
val last = points.last()
|
||||
val polygonPath = Path()
|
||||
polygonPath.moveTo(last.x, last.y)
|
||||
for ((x,y) in points){
|
||||
polygonPath.lineTo(x,y)
|
||||
for ((x, y) in points) {
|
||||
polygonPath.lineTo(x, y)
|
||||
}
|
||||
drawPath(
|
||||
path = polygonPath,
|
||||
|
@ -1,7 +1,6 @@
|
||||
package center.sciprog.maps.geojson
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PointMode
|
||||
import center.sciprog.attributes.NameAttribute
|
||||
import center.sciprog.maps.coordinates.Gmc
|
||||
import center.sciprog.maps.features.*
|
||||
@ -17,23 +16,18 @@ public fun FeatureGroup<Gmc>.geoJsonGeometry(
|
||||
geometry: GeoJsonGeometry,
|
||||
id: String? = null,
|
||||
): FeatureRef<Gmc, Feature<Gmc>> = when (geometry) {
|
||||
is GeoJsonLineString -> points(
|
||||
is GeoJsonLineString -> multiLine(
|
||||
geometry.coordinates,
|
||||
pointMode = PointMode.Lines
|
||||
)
|
||||
|
||||
is GeoJsonMultiLineString -> group(id = id) {
|
||||
geometry.coordinates.forEach {
|
||||
points(
|
||||
it,
|
||||
pointMode = PointMode.Lines
|
||||
)
|
||||
multiLine(it)
|
||||
}
|
||||
}
|
||||
|
||||
is GeoJsonMultiPoint -> points(
|
||||
geometry.coordinates,
|
||||
pointMode = PointMode.Points
|
||||
)
|
||||
|
||||
is GeoJsonMultiPolygon -> group(id = id) {
|
||||
|
@ -51,7 +51,7 @@ fun FeatureGroup<XY>.line(
|
||||
aCoordinates: Pair<Number, Number>,
|
||||
bCoordinates: Pair<Number, Number>,
|
||||
id: String? = null,
|
||||
): FeatureRef<XY, LineFeature<XY>> = line(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), id)
|
||||
): FeatureRef<XY, LineFeature<XY>> = line(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), id = id)
|
||||
|
||||
|
||||
public fun FeatureGroup<XY>.arc(
|
||||
|
@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PointMode
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.drawscope.translate
|
||||
@ -77,6 +78,30 @@ fun FeatureStateSnapshot<XY>.generateSvg(
|
||||
alpha = alpha
|
||||
)
|
||||
|
||||
is PointsFeature -> {
|
||||
val points = feature.points.map { it.toOffset() }
|
||||
drawPoints(
|
||||
points = points,
|
||||
color = color,
|
||||
strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth,
|
||||
pointMode = PointMode.Points,
|
||||
pathEffect = feature.attributes[PathEffectAttribute],
|
||||
alpha = alpha
|
||||
)
|
||||
}
|
||||
|
||||
is MultiLineFeature -> {
|
||||
val points = feature.points.map { it.toOffset() }
|
||||
drawPoints(
|
||||
points = points,
|
||||
color = color,
|
||||
strokeWidth = feature.attributes[StrokeAttribute] ?: Stroke.HairlineWidth,
|
||||
pointMode = PointMode.Polygon,
|
||||
pathEffect = feature.attributes[PathEffectAttribute],
|
||||
alpha = alpha
|
||||
)
|
||||
}
|
||||
|
||||
is ArcFeature -> {
|
||||
val topLeft = feature.oval.leftTop.toOffset()
|
||||
val bottomRight = feature.oval.rightBottom.toOffset()
|
||||
|
Loading…
Reference in New Issue
Block a user