Optimize attributes working

This commit is contained in:
Alexander Nozik 2023-01-05 12:15:52 +03:00
parent ea8c5571bb
commit cb160110e7
11 changed files with 107 additions and 42 deletions

View File

@ -11,6 +11,10 @@ import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application import androidx.compose.ui.window.application
import center.sciprog.attributes.AlphaAttribute
import center.sciprog.attributes.Attributes
import center.sciprog.attributes.ColorAttribute
import center.sciprog.attributes.ZAttribute
import center.sciprog.maps.compose.* import center.sciprog.maps.compose.*
import center.sciprog.maps.coordinates.* import center.sciprog.maps.coordinates.*
import center.sciprog.maps.features.* import center.sciprog.maps.features.*

View File

@ -85,6 +85,7 @@ public object WebMercatorSpace : CoordinateSpace<Gmc> {
} }
override fun Gmc.isInsidePolygon(points: List<Gmc>): Boolean = points.zipWithNext().count { (left, right) -> override fun Gmc.isInsidePolygon(points: List<Gmc>): Boolean = points.zipWithNext().count { (left, right) ->
//using raytracing algorithm with the ray pointing "up"
val longitudeRange = if(right.longitude >= left.longitude) { val longitudeRange = if(right.longitude >= left.longitude) {
left.longitude..right.longitude left.longitude..right.longitude
} else { } else {

View File

@ -0,0 +1,29 @@
package center.sciprog.attributes
import androidx.compose.ui.graphics.Color
import center.sciprog.maps.features.DragHandle
import center.sciprog.maps.features.DragListener
import center.sciprog.maps.features.FloatRange
import center.sciprog.maps.features.MouseListener
public interface Attribute<T>
public object ZAttribute : Attribute<Float>
public object DraggableAttribute : Attribute<DragHandle<Any>>
public interface SetAttribute<V> : Attribute<Set<V>>
public object DragListenerAttribute : SetAttribute<DragListener<Any>>
public object ClickListenerAttribute : SetAttribute<MouseListener<Any>>
public object HoverListenerAttribute : SetAttribute<MouseListener<Any>>
public object VisibleAttribute : Attribute<Boolean>
public object ColorAttribute : Attribute<Color>
public object ZoomRangeAttribute : Attribute<FloatRange>
public object AlphaAttribute : Attribute<Float>

View File

@ -1,6 +1,7 @@
package center.sciprog.maps.features package center.sciprog.attributes
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import center.sciprog.maps.features.Feature
import kotlin.jvm.JvmInline import kotlin.jvm.JvmInline
@Stable @Stable
@ -9,16 +10,16 @@ public value class Attributes internal constructor(internal val map: Map<Attribu
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public operator fun <T> get(attribute: Attribute<T>): T? = map[attribute] as? T public operator fun <T> get(attribute: Attribute<T>): T? = map[attribute] as? T
public operator fun <T> Attribute<T>.invoke(value: T?): Attributes = withAttribute(this, value) // public operator fun <T> Attribute<T>.invoke(value: T?): Attributes = withAttribute(this, value)
override fun toString(): String = "AttributeMap(value=${map.entries})" override fun toString(): String = "Attributes(value=${map.entries})"
public companion object { public companion object {
public val EMPTY: Attributes = Attributes(emptyMap()) public val EMPTY: Attributes = Attributes(emptyMap())
} }
} }
public fun <T, A : Attribute<T>> Attributes.withAttribute( public fun <T, A : Attribute<T>> Attributes.attribute(
attribute: A, attribute: A,
attrValue: T?, attrValue: T?,
): Attributes = Attributes( ): Attributes = Attributes(
@ -29,6 +30,34 @@ public fun <T, A : Attribute<T>> Attributes.withAttribute(
} }
) )
/**
* Add an element to a [SetAttribute]
*/
public fun <T, A : SetAttribute<T>> Attributes.addValue(
attribute: A,
attrValue: T,
): Attributes {
val currentSet: Set<T> = get(attribute) ?: emptySet()
return Attributes(
map + (attribute to (currentSet + attrValue))
)
}
/**
* Remove an element from [SetAttribute]
*/
public fun <T, A : SetAttribute<T>> Attributes.removeValue(
attribute: A,
attrValue: T,
): Attributes {
val currentSet: Set<T> = get(attribute) ?: emptySet()
return Attributes(
map + (attribute to (currentSet - attrValue))
)
}
public fun <T : Any, A : Attribute<T>> Attributes( public fun <T : Any, A : Attribute<T>> Attributes(
attribute: A, attribute: A,
attrValue: T, attrValue: T,

View File

@ -1,23 +0,0 @@
package center.sciprog.maps.features
import androidx.compose.ui.graphics.Color
public interface Attribute<T>
public object ZAttribute : Attribute<Float>
public object DraggableAttribute : Attribute<DragHandle<Any>>
public object DragListenerAttribute : Attribute<Set<DragListener<Any>>>
public object ClickListenerAttribute : Attribute<Set<MouseListener<Any>>>
public object HoverListenerAttribute : Attribute<Set<MouseListener<Any>>>
public object VisibleAttribute : Attribute<Boolean>
public object ColorAttribute : Attribute<Color>
public object ZoomRangeAttribute : Attribute<FloatRange>
public object AlphaAttribute : Attribute<Float>

View File

@ -14,6 +14,9 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import center.sciprog.attributes.Attributes
import center.sciprog.attributes.ColorAttribute
import center.sciprog.attributes.ZoomRangeAttribute
public typealias FloatRange = ClosedFloatingPointRange<Float> public typealias FloatRange = ClosedFloatingPointRange<Float>

View File

@ -13,6 +13,7 @@ import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import center.sciprog.attributes.*
import kotlin.jvm.JvmInline import kotlin.jvm.JvmInline
@JvmInline @JvmInline
@ -64,7 +65,7 @@ public data class FeatureGroup<T : Any>(
if (feature is FeatureGroup<T>) { if (feature is FeatureGroup<T>) {
feature.visitUntil(visitor) feature.visitUntil(visitor)
} else { } else {
if (!visitor(this, key, feature)) return@forEach if (!visitor(this, key, feature)) return@visitUntil
} }
} }
} }
@ -79,7 +80,15 @@ public data class FeatureGroup<T : Any>(
} }
public fun <F : Feature<T>, V> FeatureId<F>.attribute(key: Attribute<V>, value: V?): FeatureId<F> { public fun <F : Feature<T>, V> FeatureId<F>.attribute(key: Attribute<V>, value: V?): FeatureId<F> {
feature(this, get(this).withAttributes { withAttribute(key, value) }) feature(this, get(this).withAttributes { attribute(key, value) })
return this
}
/**
* Add multi-entry [SetAttribute] value
*/
public fun <F : Feature<T>, V> FeatureId<F>.addAttribute(key: SetAttribute<V>, value: V): FeatureId<F> {
feature(this, get(this).withAttributes { addValue(key, value) })
return this return this
} }
@ -126,12 +135,9 @@ public data class FeatureGroup<T : Any>(
public fun FeatureId<DraggableFeature<T>>.onDrag( public fun FeatureId<DraggableFeature<T>>.onDrag(
listener: PointerEvent.(from: ViewPoint<T>, to: ViewPoint<T>) -> Unit, listener: PointerEvent.(from: ViewPoint<T>, to: ViewPoint<T>) -> Unit,
) { ) {
attribute( addAttribute(
DragListenerAttribute, DragListenerAttribute,
(getAttribute(this, DragListenerAttribute) ?: emptySet()) + DragListener { event, from, to -> event.listener(from as ViewPoint<T>, to as ViewPoint<T>) }
DragListener { event, from, to ->
event.listener(from as ViewPoint<T>, to as ViewPoint<T>)
}
) )
} }
@ -139,21 +145,20 @@ public data class FeatureGroup<T : Any>(
public fun <F : DomainFeature<T>> FeatureId<F>.onClick( public fun <F : DomainFeature<T>> FeatureId<F>.onClick(
onClick: PointerEvent.(click: ViewPoint<T>) -> Unit, onClick: PointerEvent.(click: ViewPoint<T>) -> Unit,
) { ) {
attribute( addAttribute(
ClickListenerAttribute, ClickListenerAttribute,
(getAttribute(this, ClickListenerAttribute) ?: emptySet()) + MouseListener { event, point -> event.onClick(point as ViewPoint<T>) }
MouseListener { event, point -> event.onClick(point as ViewPoint<T>) }
) )
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
public fun <F : DomainFeature<T>> FeatureId<F>.onHover( public fun <F : DomainFeature<T>> FeatureId<F>.onHover(
onClick: PointerEvent.(move: ViewPoint<T>) -> Unit, onClick: PointerEvent.(move: ViewPoint<T>) -> Unit,
) { ) {
attribute( addAttribute(
HoverListenerAttribute, HoverListenerAttribute,
(getAttribute(this, HoverListenerAttribute) ?: emptySet()) + MouseListener { event, point -> event.onClick(point as ViewPoint<T>) }
MouseListener { event, point -> event.onClick(point as ViewPoint<T>) }
) )
} }

View File

@ -1,5 +1,9 @@
package center.sciprog.maps.features package center.sciprog.maps.features
import center.sciprog.attributes.Attributes
import center.sciprog.attributes.ZAttribute
import center.sciprog.attributes.attribute
public fun <T : Any> FeatureGroup<T>.draggableLine( public fun <T : Any> FeatureGroup<T>.draggableLine(
aId: FeatureId<MarkerFeature<T>>, aId: FeatureId<MarkerFeature<T>>,
@ -16,7 +20,7 @@ public fun <T : Any> FeatureGroup<T>.draggableLine(
get(bId).center, get(bId).center,
lineId?.id ?: id lineId?.id ?: id
) )
if (attributes != null) currentId.modifyAttributes { attributes.withAttribute(ZAttribute, -10f) } if (attributes != null) currentId.modifyAttributes { attributes.attribute(ZAttribute, -10f) }
lineId = currentId lineId = currentId
return currentId return currentId
} }

View File

@ -7,6 +7,9 @@ import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.DpRect import androidx.compose.ui.unit.DpRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import center.sciprog.attributes.ClickListenerAttribute
import center.sciprog.attributes.DraggableAttribute
import center.sciprog.attributes.HoverListenerAttribute
import center.sciprog.maps.features.* import center.sciprog.maps.features.*
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -94,9 +97,15 @@ public fun <T : Any> Modifier.mapControls(
val dragResult = config.dragHandle?.handle(event, dragStart, dragEnd) val dragResult = config.dragHandle?.handle(event, dragStart, dragEnd)
if (dragResult?.handleNext == false) return@drag if (dragResult?.handleNext == false) return@drag
var continueAfter = true
features.forEachWithAttributeUntil(DraggableAttribute) { _, _, handler -> features.forEachWithAttributeUntil(DraggableAttribute) { _, _, handler ->
handler.handle(event, dragStart, dragEnd).handleNext handler.handle(event, dragStart, dragEnd).handleNext.also {
if (!it) continueAfter = false
}
} }
if (!continueAfter) return@drag
} }
if (event.buttons.isPrimaryPressed) { if (event.buttons.isPrimaryPressed) {

View File

@ -11,6 +11,8 @@ import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.nativeCanvas import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import center.sciprog.attributes.AlphaAttribute
import center.sciprog.attributes.plus
import org.jetbrains.skia.Font import org.jetbrains.skia.Font
import org.jetbrains.skia.Paint import org.jetbrains.skia.Paint
import kotlin.math.PI import kotlin.math.PI

View File

@ -8,6 +8,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import center.sciprog.attributes.Attributes
import center.sciprog.attributes.ZAttribute
import center.sciprog.maps.features.* import center.sciprog.maps.features.*
internal fun Pair<Number, Number>.toCoordinates(): XY = XY(first.toFloat(), second.toFloat()) internal fun Pair<Number, Number>.toCoordinates(): XY = XY(first.toFloat(), second.toFloat())