package refactoring

This commit is contained in:
Alexander Nozik 2022-07-23 13:49:47 +03:00
parent 8867388e85
commit 4c3aefcfae
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
13 changed files with 115 additions and 122 deletions

View File

@ -15,11 +15,12 @@ import center.sciprog.maps.coordinates.GmcBox
import center.sciprog.maps.coordinates.wrapAll import center.sciprog.maps.coordinates.wrapAll
//TODO replace zoom range with zoom-based representation change //TODO replace zoom range with zoom-based representation change
sealed class MapFeature(val zoomRange: IntRange) { public sealed interface MapFeature {
abstract fun getBoundingBox(zoom: Int): GmcBox? public val zoomRange: IntRange
public fun getBoundingBox(zoom: Int): GmcBox?
} }
fun Iterable<MapFeature>.computeBoundingBox(zoom: Int): GmcBox? = public fun Iterable<MapFeature>.computeBoundingBox(zoom: Int): GmcBox? =
mapNotNull { it.getBoundingBox(zoom) }.wrapAll() mapNotNull { it.getBoundingBox(zoom) }.wrapAll()
internal fun Pair<Double, Double>.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second) internal fun Pair<Double, Double>.toCoordinates() = GeodeticMapCoordinates.ofDegrees(first, second)
@ -29,68 +30,72 @@ internal val defaultZoomRange = 1..18
/** /**
* A feature that decides what to show depending on the zoom value (it could change size of shape) * A feature that decides what to show depending on the zoom value (it could change size of shape)
*/ */
class MapFeatureSelector(val selector: (zoom: Int) -> MapFeature) : MapFeature(defaultZoomRange) { public class MapFeatureSelector(
public val selector: (zoom: Int) -> MapFeature,
) : MapFeature {
override val zoomRange: IntRange get() = defaultZoomRange
override fun getBoundingBox(zoom: Int): GmcBox? = selector(zoom).getBoundingBox(zoom) override fun getBoundingBox(zoom: Int): GmcBox? = selector(zoom).getBoundingBox(zoom)
} }
class MapDrawFeature( public class MapDrawFeature(
val position: GeodeticMapCoordinates, public val position: GeodeticMapCoordinates,
zoomRange: IntRange = defaultZoomRange, override val zoomRange: IntRange = defaultZoomRange,
val drawFeature: DrawScope.() -> Unit, public val drawFeature: DrawScope.() -> Unit,
) : MapFeature(zoomRange) { ) : MapFeature{
override fun getBoundingBox(zoom: Int): GmcBox { override fun getBoundingBox(zoom: Int): GmcBox {
//TODO add box computation //TODO add box computation
return GmcBox(position, position) return GmcBox(position, position)
} }
} }
class MapCircleFeature( public class MapCircleFeature(
val center: GeodeticMapCoordinates, public val center: GeodeticMapCoordinates,
zoomRange: IntRange = defaultZoomRange, override val zoomRange: IntRange = defaultZoomRange,
val size: Float = 5f, public val size: Float = 5f,
val color: Color = Color.Red, public val color: Color = Color.Red,
) : MapFeature(zoomRange) { ) : MapFeature {
override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(center, center) override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(center, center)
} }
class MapLineFeature( public class MapLineFeature(
val a: GeodeticMapCoordinates, public val a: GeodeticMapCoordinates,
val b: GeodeticMapCoordinates, public val b: GeodeticMapCoordinates,
zoomRange: IntRange = defaultZoomRange, override val zoomRange: IntRange = defaultZoomRange,
val color: Color = Color.Red, public val color: Color = Color.Red,
) : MapFeature(zoomRange) { ) : MapFeature {
override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(a, b) override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(a, b)
} }
class MapTextFeature( public class MapTextFeature(
val position: GeodeticMapCoordinates, public val position: GeodeticMapCoordinates,
val text: String, public val text: String,
zoomRange: IntRange = defaultZoomRange, override val zoomRange: IntRange = defaultZoomRange,
val color: Color = Color.Red, public val color: Color = Color.Red,
) : MapFeature(zoomRange) { ) : MapFeature {
override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(position, position) override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(position, position)
} }
class MapBitmapImageFeature( public class MapBitmapImageFeature(
val position: GeodeticMapCoordinates, public val position: GeodeticMapCoordinates,
val image: ImageBitmap, public val image: ImageBitmap,
val size: IntSize = IntSize(15, 15), public val size: IntSize = IntSize(15, 15),
zoomRange: IntRange = defaultZoomRange, override val zoomRange: IntRange = defaultZoomRange,
) : MapFeature(zoomRange) { ) : MapFeature{
override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(position, position) override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(position, position)
} }
class MapVectorImageFeature( public class MapVectorImageFeature(
val position: GeodeticMapCoordinates, public val position: GeodeticMapCoordinates,
val painter: Painter, public val painter: Painter,
val size: DpSize, public val size: DpSize,
zoomRange: IntRange = defaultZoomRange, override val zoomRange: IntRange = defaultZoomRange,
) : MapFeature(zoomRange) { ) : MapFeature {
override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(position, position) override fun getBoundingBox(zoom: Int): GmcBox = GmcBox(position, position)
} }
@Composable @Composable
fun MapVectorImageFeature( public fun MapVectorImageFeature(
position: GeodeticMapCoordinates, position: GeodeticMapCoordinates,
image: ImageVector, image: ImageVector,
size: DpSize = DpSize(20.dp, 20.dp), size: DpSize = DpSize(20.dp, 20.dp),
@ -100,9 +105,9 @@ fun MapVectorImageFeature(
/** /**
* A group of other features * A group of other features
*/ */
class MapFeatureGroup( public class MapFeatureGroup(
val children: Map<FeatureId, MapFeature>, public val children: Map<FeatureId, MapFeature>,
zoomRange: IntRange = defaultZoomRange, override val zoomRange: IntRange = defaultZoomRange,
) : MapFeature(zoomRange) { ) : MapFeature{
override fun getBoundingBox(zoom: Int): GmcBox? = children.values.mapNotNull { it.getBoundingBox(zoom) }.wrapAll() override fun getBoundingBox(zoom: Int): GmcBox? = children.values.mapNotNull { it.getBoundingBox(zoom) }.wrapAll()
} }

View File

@ -10,15 +10,15 @@ import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import center.sciprog.maps.coordinates.GeodeticMapCoordinates import center.sciprog.maps.coordinates.GeodeticMapCoordinates
typealias FeatureId = String public typealias FeatureId = String
interface FeatureBuilder { public interface MapFeatureBuilder {
fun addFeature(id: FeatureId?, feature: MapFeature): FeatureId public fun addFeature(id: FeatureId?, feature: MapFeature): FeatureId
fun build(): SnapshotStateMap<FeatureId, MapFeature> public fun build(): SnapshotStateMap<FeatureId, MapFeature>
} }
internal class MapFeatureBuilder(initialFeatures: Map<FeatureId, MapFeature>) : FeatureBuilder { internal class MapFeatureBuilderImpl(initialFeatures: Map<FeatureId, MapFeature>) : MapFeatureBuilder {
private val content: SnapshotStateMap<FeatureId, MapFeature> = mutableStateMapOf<FeatureId, MapFeature>().apply { private val content: SnapshotStateMap<FeatureId, MapFeature> = mutableStateMapOf<FeatureId, MapFeature>().apply {
putAll(initialFeatures) putAll(initialFeatures)
@ -35,72 +35,72 @@ internal class MapFeatureBuilder(initialFeatures: Map<FeatureId, MapFeature>) :
override fun build(): SnapshotStateMap<FeatureId, MapFeature> = content override fun build(): SnapshotStateMap<FeatureId, MapFeature> = content
} }
fun FeatureBuilder.circle( public fun MapFeatureBuilder.circle(
center: GeodeticMapCoordinates, center: GeodeticMapCoordinates,
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
size: Float = 5f, size: Float = 5f,
color: Color = Color.Red, color: Color = Color.Red,
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature( ): FeatureId = addFeature(
id, MapCircleFeature(center, zoomRange, size, color) id, MapCircleFeature(center, zoomRange, size, color)
) )
fun FeatureBuilder.circle( public fun MapFeatureBuilder.circle(
centerCoordinates: Pair<Double, Double>, centerCoordinates: Pair<Double, Double>,
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
size: Float = 5f, size: Float = 5f,
color: Color = Color.Red, color: Color = Color.Red,
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature( ): FeatureId = addFeature(
id, MapCircleFeature(centerCoordinates.toCoordinates(), zoomRange, size, color) id, MapCircleFeature(centerCoordinates.toCoordinates(), zoomRange, size, color)
) )
fun FeatureBuilder.custom( public fun MapFeatureBuilder.custom(
position: Pair<Double, Double>, position: Pair<Double, Double>,
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
id: FeatureId? = null, id: FeatureId? = null,
drawFeature: DrawScope.() -> Unit, drawFeature: DrawScope.() -> Unit,
) = addFeature(id, MapDrawFeature(position.toCoordinates(), zoomRange, drawFeature)) ): FeatureId = addFeature(id, MapDrawFeature(position.toCoordinates(), zoomRange, drawFeature))
fun FeatureBuilder.line( public fun MapFeatureBuilder.line(
aCoordinates: Pair<Double, Double>, aCoordinates: Pair<Double, Double>,
bCoordinates: Pair<Double, Double>, bCoordinates: Pair<Double, Double>,
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
color: Color = Color.Red, color: Color = Color.Red,
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature(id, MapLineFeature(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), zoomRange, color)) ): FeatureId = addFeature(id, MapLineFeature(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), zoomRange, color))
fun FeatureBuilder.text( public fun MapFeatureBuilder.text(
position: GeodeticMapCoordinates, position: GeodeticMapCoordinates,
text: String, text: String,
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
color: Color = Color.Red, color: Color = Color.Red,
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature(id, MapTextFeature(position, text, zoomRange, color)) ): FeatureId = addFeature(id, MapTextFeature(position, text, zoomRange, color))
fun FeatureBuilder.text( public fun MapFeatureBuilder.text(
position: Pair<Double, Double>, position: Pair<Double, Double>,
text: String, text: String,
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
color: Color = Color.Red, color: Color = Color.Red,
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature(id, MapTextFeature(position.toCoordinates(), text, zoomRange, color)) ): FeatureId = addFeature(id, MapTextFeature(position.toCoordinates(), text, zoomRange, color))
@Composable @Composable
fun FeatureBuilder.image( public fun MapFeatureBuilder.image(
position: Pair<Double, Double>, position: Pair<Double, Double>,
image: ImageVector, image: ImageVector,
size: DpSize = DpSize(20.dp, 20.dp), size: DpSize = DpSize(20.dp, 20.dp),
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature(id, MapVectorImageFeature(position.toCoordinates(), image, size, zoomRange)) ): FeatureId = addFeature(id, MapVectorImageFeature(position.toCoordinates(), image, size, zoomRange))
fun FeatureBuilder.group( public fun MapFeatureBuilder.group(
zoomRange: IntRange = defaultZoomRange, zoomRange: IntRange = defaultZoomRange,
id: FeatureId? = null, id: FeatureId? = null,
builder: FeatureBuilder.() -> Unit, builder: MapFeatureBuilder.() -> Unit,
): FeatureId { ): FeatureId {
val map = MapFeatureBuilder(emptyMap()).apply(builder).build() val map = MapFeatureBuilderImpl(emptyMap()).apply(builder).build()
val feature = MapFeatureGroup(map, zoomRange) val feature = MapFeatureGroup(map, zoomRange)
return addFeature(id, feature) return addFeature(id, feature)
} }

View File

@ -5,27 +5,27 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Deferred
import kotlin.math.floor import kotlin.math.floor
data class TileId( public data class TileId(
val zoom: Int, val zoom: Int,
val i: Int, val i: Int,
val j: Int, val j: Int,
) )
data class MapTile( public data class MapTile(
val id: TileId, val id: TileId,
val image: ImageBitmap, val image: ImageBitmap,
) )
interface MapTileProvider { public interface MapTileProvider {
fun CoroutineScope.loadTileAsync(tileId: TileId): Deferred<MapTile> public fun CoroutineScope.loadTileAsync(tileId: TileId): Deferred<MapTile>
val tileSize: Int get() = DEFAULT_TILE_SIZE public val tileSize: Int get() = DEFAULT_TILE_SIZE
fun toIndex(d: Double): Int = floor(d / tileSize).toInt() public fun toIndex(d: Double): Int = floor(d / tileSize).toInt()
fun toCoordinate(i: Int): Double = (i * tileSize).toDouble() public fun toCoordinate(i: Int): Double = (i * tileSize).toDouble()
companion object { public companion object {
const val DEFAULT_TILE_SIZE = 256 public const val DEFAULT_TILE_SIZE: Int = 256
} }
} }

View File

@ -11,7 +11,7 @@ import kotlin.math.min
//TODO consider replacing by modifier //TODO consider replacing by modifier
data class MapViewConfig( public data class MapViewConfig(
val zoomSpeed: Double = 1.0 / 3.0, val zoomSpeed: Double = 1.0 / 3.0,
val inferViewBoxFromFeatures: Boolean = false, val inferViewBoxFromFeatures: Boolean = false,
val onClick: MapViewPoint.() -> Unit = {}, val onClick: MapViewPoint.() -> Unit = {},
@ -21,7 +21,7 @@ data class MapViewConfig(
) )
@Composable @Composable
expect fun MapView( public expect fun MapView(
mapTileProvider: MapTileProvider, mapTileProvider: MapTileProvider,
computeViewPoint: (canvasSize: DpSize) -> MapViewPoint, computeViewPoint: (canvasSize: DpSize) -> MapViewPoint,
features: Map<FeatureId, MapFeature>, features: Map<FeatureId, MapFeature>,
@ -30,15 +30,15 @@ expect fun MapView(
) )
@Composable @Composable
fun MapView( public fun MapView(
mapTileProvider: MapTileProvider, mapTileProvider: MapTileProvider,
initialViewPoint: MapViewPoint, initialViewPoint: MapViewPoint,
features: Map<FeatureId, MapFeature> = emptyMap(), features: Map<FeatureId, MapFeature> = emptyMap(),
config: MapViewConfig = MapViewConfig(), config: MapViewConfig = MapViewConfig(),
modifier: Modifier = Modifier.fillMaxSize(), modifier: Modifier = Modifier.fillMaxSize(),
buildFeatures: @Composable (FeatureBuilder.() -> Unit) = {}, buildFeatures: @Composable (MapFeatureBuilder.() -> Unit) = {},
) { ) {
val featuresBuilder = MapFeatureBuilder(features) val featuresBuilder = MapFeatureBuilderImpl(features)
featuresBuilder.buildFeatures() featuresBuilder.buildFeatures()
MapView( MapView(
mapTileProvider, mapTileProvider,
@ -66,9 +66,9 @@ public fun MapView(
features: Map<FeatureId, MapFeature> = emptyMap(), features: Map<FeatureId, MapFeature> = emptyMap(),
config: MapViewConfig = MapViewConfig(), config: MapViewConfig = MapViewConfig(),
modifier: Modifier = Modifier.fillMaxSize(), modifier: Modifier = Modifier.fillMaxSize(),
buildFeatures: @Composable (FeatureBuilder.() -> Unit) = {}, buildFeatures: @Composable (MapFeatureBuilder.() -> Unit) = {},
) { ) {
val featuresBuilder = MapFeatureBuilder(features) val featuresBuilder = MapFeatureBuilderImpl(features)
featuresBuilder.buildFeatures() featuresBuilder.buildFeatures()
MapView( MapView(
mapTileProvider, mapTileProvider,

View File

@ -33,7 +33,7 @@ private fun Color.toPaint(): Paint = Paint().apply {
private fun IntRange.intersect(other: IntRange) = max(first, other.first)..min(last, other.last) private fun IntRange.intersect(other: IntRange) = max(first, other.first)..min(last, other.last)
internal fun MapViewPoint.move(deltaX: Double, deltaY: Double): MapViewPoint { internal fun MapViewPoint.move(deltaX: Double, deltaY: Double): MapViewPoint {
val newCoordinates = center.sciprog.maps.coordinates.GeodeticMapCoordinates.ofRadians( val newCoordinates = GeodeticMapCoordinates.ofRadians(
(focus.latitude + deltaY / scaleFactor).coerceIn( (focus.latitude + deltaY / scaleFactor).coerceIn(
-MercatorProjection.MAXIMUM_LATITUDE, -MercatorProjection.MAXIMUM_LATITUDE,
MercatorProjection.MAXIMUM_LATITUDE MercatorProjection.MAXIMUM_LATITUDE
@ -50,7 +50,7 @@ private val logger = KotlinLogging.logger("MapView")
*/ */
@Composable @Composable
actual fun MapView( public actual fun MapView(
mapTileProvider: MapTileProvider, mapTileProvider: MapTileProvider,
computeViewPoint: (canvasSize: DpSize) -> MapViewPoint, computeViewPoint: (canvasSize: DpSize) -> MapViewPoint,
features: Map<FeatureId, MapFeature>, features: Map<FeatureId, MapFeature>,

View File

@ -1,11 +0,0 @@
package center.sciprog.maps.coordinates
/**
* A marker interface for flat coordinates
*/
public interface Coordinates2D
public interface CoordinateBox<T: Coordinates2D>{
public val a: T
public val b :T
}

View File

@ -8,7 +8,7 @@ import kotlin.math.PI
public class GeodeticMapCoordinates private constructor( public class GeodeticMapCoordinates private constructor(
public val latitude: Double, public val latitude: Double,
public val longitude: Double, public val longitude: Double,
): Coordinates2D { ){
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true

View File

@ -5,9 +5,9 @@ import kotlin.math.max
import kotlin.math.min import kotlin.math.min
public data class GmcBox( public data class GmcBox(
public override val a: GeodeticMapCoordinates, public val a: GeodeticMapCoordinates,
public override val b: GeodeticMapCoordinates, public val b: GeodeticMapCoordinates,
) : CoordinateBox<GeodeticMapCoordinates> )
public fun GmcBox( public fun GmcBox(
latitudes: ClosedFloatingPointRange<Double>, latitudes: ClosedFloatingPointRange<Double>,

View File

@ -25,7 +25,6 @@ kotlin {
sourceSets { sourceSets {
commonMain { commonMain {
dependencies { dependencies {
api(projects.mapsKtCore)
api("io.github.microutils:kotlin-logging:2.1.23") api("io.github.microutils:kotlin-logging:2.1.23")
api(compose.foundation) api(compose.foundation)
} }

View File

@ -1,17 +1,15 @@
package center.sciprog.maps.scheme package center.sciprog.maps.scheme
import center.sciprog.maps.coordinates.CoordinateBox
import center.sciprog.maps.coordinates.Coordinates2D
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
data class SchemeCoordinates(val x: Float, val y: Float) : Coordinates2D data class SchemeCoordinates(val x: Float, val y: Float)
data class SchemeCoordinateBox( data class SchemeCoordinateBox(
override val a: SchemeCoordinates, val a: SchemeCoordinates,
override val b: SchemeCoordinates, val b: SchemeCoordinates,
) : CoordinateBox<SchemeCoordinates> )
val SchemeCoordinateBox.top get() = max(a.y, b.y) val SchemeCoordinateBox.top get() = max(a.y, b.y)
val SchemeCoordinateBox.bottom get() = min(a.y, b.y) val SchemeCoordinateBox.bottom get() = min(a.y, b.y)

View File

@ -14,13 +14,15 @@ import center.sciprog.maps.scheme.SchemeFeature.Companion.defaultScaleRange
typealias FeatureId = String typealias FeatureId = String
interface FeatureBuilder { interface SchemeFeatureBuilder {
fun addFeature(id: FeatureId?, feature: SchemeFeature): FeatureId fun addFeature(id: FeatureId?, feature: SchemeFeature): FeatureId
fun build(): SnapshotStateMap<FeatureId, SchemeFeature> fun build(): SnapshotStateMap<FeatureId, SchemeFeature>
} }
internal class SchemeFeatureBuilder(initialFeatures: Map<FeatureId, SchemeFeature>) : FeatureBuilder { internal class SchemeFeatureBuilderImpl(
initialFeatures: Map<FeatureId, SchemeFeature>,
) : SchemeFeatureBuilder {
private val content: SnapshotStateMap<FeatureId, SchemeFeature> = private val content: SnapshotStateMap<FeatureId, SchemeFeature> =
mutableStateMapOf<FeatureId, SchemeFeature>().apply { mutableStateMapOf<FeatureId, SchemeFeature>().apply {
@ -38,7 +40,7 @@ internal class SchemeFeatureBuilder(initialFeatures: Map<FeatureId, SchemeFeatur
override fun build(): SnapshotStateMap<FeatureId, SchemeFeature> = content override fun build(): SnapshotStateMap<FeatureId, SchemeFeature> = content
} }
fun FeatureBuilder.background( fun SchemeFeatureBuilder.background(
painter: Painter, painter: Painter,
box: SchemeCoordinateBox, box: SchemeCoordinateBox,
id: FeatureId? = null, id: FeatureId? = null,
@ -47,7 +49,7 @@ fun FeatureBuilder.background(
SchemeBackgroundFeature(box, painter) SchemeBackgroundFeature(box, painter)
) )
fun FeatureBuilder.background( fun SchemeFeatureBuilder.background(
painter: Painter, painter: Painter,
size: Size = painter.intrinsicSize, size: Size = painter.intrinsicSize,
offset: SchemeCoordinates = SchemeCoordinates(0f, 0f), offset: SchemeCoordinates = SchemeCoordinates(0f, 0f),
@ -60,7 +62,7 @@ fun FeatureBuilder.background(
return background(painter, box, id) return background(painter, box, id)
} }
fun FeatureBuilder.circle( fun SchemeFeatureBuilder.circle(
center: SchemeCoordinates, center: SchemeCoordinates,
scaleRange: FloatRange = defaultScaleRange, scaleRange: FloatRange = defaultScaleRange,
size: Float = 5f, size: Float = 5f,
@ -70,7 +72,7 @@ fun FeatureBuilder.circle(
id, SchemeCircleFeature(center, scaleRange, size, color) id, SchemeCircleFeature(center, scaleRange, size, color)
) )
fun FeatureBuilder.circle( fun SchemeFeatureBuilder.circle(
centerCoordinates: Pair<Number, Number>, centerCoordinates: Pair<Number, Number>,
scaleRange: FloatRange = defaultScaleRange, scaleRange: FloatRange = defaultScaleRange,
size: Float = 5f, size: Float = 5f,
@ -80,14 +82,14 @@ fun FeatureBuilder.circle(
id, SchemeCircleFeature(centerCoordinates.toCoordinates(), scaleRange, size, color) id, SchemeCircleFeature(centerCoordinates.toCoordinates(), scaleRange, size, color)
) )
fun FeatureBuilder.custom( fun SchemeFeatureBuilder.custom(
position: Pair<Number, Number>, position: Pair<Number, Number>,
scaleRange: FloatRange = defaultScaleRange, scaleRange: FloatRange = defaultScaleRange,
id: FeatureId? = null, id: FeatureId? = null,
drawFeature: DrawScope.() -> Unit, drawFeature: DrawScope.() -> Unit,
) = addFeature(id, SchemeDrawFeature(position.toCoordinates(), scaleRange, drawFeature)) ) = addFeature(id, SchemeDrawFeature(position.toCoordinates(), scaleRange, drawFeature))
fun FeatureBuilder.line( fun SchemeFeatureBuilder.line(
aCoordinates: Pair<Number, Number>, aCoordinates: Pair<Number, Number>,
bCoordinates: Pair<Number, Number>, bCoordinates: Pair<Number, Number>,
scaleRange: FloatRange = defaultScaleRange, scaleRange: FloatRange = defaultScaleRange,
@ -95,7 +97,7 @@ fun FeatureBuilder.line(
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature(id, SchemeLineFeature(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), scaleRange, color)) ) = addFeature(id, SchemeLineFeature(aCoordinates.toCoordinates(), bCoordinates.toCoordinates(), scaleRange, color))
fun FeatureBuilder.text( fun SchemeFeatureBuilder.text(
position: SchemeCoordinates, position: SchemeCoordinates,
text: String, text: String,
scaleRange: FloatRange = defaultScaleRange, scaleRange: FloatRange = defaultScaleRange,
@ -103,7 +105,7 @@ fun FeatureBuilder.text(
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature(id, SchemeTextFeature(position, text, scaleRange, color)) ) = addFeature(id, SchemeTextFeature(position, text, scaleRange, color))
fun FeatureBuilder.text( fun SchemeFeatureBuilder.text(
position: Pair<Number, Number>, position: Pair<Number, Number>,
text: String, text: String,
scaleRange: FloatRange = defaultScaleRange, scaleRange: FloatRange = defaultScaleRange,
@ -112,7 +114,7 @@ fun FeatureBuilder.text(
) = addFeature(id, SchemeTextFeature(position.toCoordinates(), text, scaleRange, color)) ) = addFeature(id, SchemeTextFeature(position.toCoordinates(), text, scaleRange, color))
@Composable @Composable
fun FeatureBuilder.image( fun SchemeFeatureBuilder.image(
position: Pair<Number, Number>, position: Pair<Number, Number>,
image: ImageVector, image: ImageVector,
size: DpSize = DpSize(20.dp, 20.dp), size: DpSize = DpSize(20.dp, 20.dp),
@ -120,12 +122,12 @@ fun FeatureBuilder.image(
id: FeatureId? = null, id: FeatureId? = null,
) = addFeature(id, SchemeVectorImageFeature(position.toCoordinates(), image, size, scaleRange)) ) = addFeature(id, SchemeVectorImageFeature(position.toCoordinates(), image, size, scaleRange))
fun FeatureBuilder.group( fun SchemeFeatureBuilder.group(
scaleRange: FloatRange = defaultScaleRange, scaleRange: FloatRange = defaultScaleRange,
id: FeatureId? = null, id: FeatureId? = null,
builder: FeatureBuilder.() -> Unit, builder: SchemeFeatureBuilder.() -> Unit,
): FeatureId { ): FeatureId {
val map = SchemeFeatureBuilder(emptyMap()).apply(builder).build() val map = SchemeFeatureBuilderImpl(emptyMap()).apply(builder).build()
val feature = SchemeFeatureGroup(map, scaleRange) val feature = SchemeFeatureGroup(map, scaleRange)
return addFeature(id, feature) return addFeature(id, feature)
} }

View File

@ -249,9 +249,9 @@ fun SchemeView(
features: Map<FeatureId, SchemeFeature> = emptyMap(), features: Map<FeatureId, SchemeFeature> = emptyMap(),
config: SchemeViewConfig = SchemeViewConfig(), config: SchemeViewConfig = SchemeViewConfig(),
modifier: Modifier = Modifier.fillMaxSize(), modifier: Modifier = Modifier.fillMaxSize(),
buildFeatures: @Composable (FeatureBuilder.() -> Unit) = {}, buildFeatures: @Composable (SchemeFeatureBuilder.() -> Unit) = {},
) { ) {
val featuresBuilder = SchemeFeatureBuilder(features) val featuresBuilder = SchemeFeatureBuilderImpl(features)
featuresBuilder.buildFeatures() featuresBuilder.buildFeatures()
SchemeView( SchemeView(
{ initialViewPoint }, { initialViewPoint },