173 lines
5.1 KiB
Kotlin
Raw Normal View History

2022-12-23 22:16:16 +03:00
package center.sciprog.maps.compose
2023-03-15 15:24:23 +03:00
import androidx.compose.ui.graphics.Color
2022-12-23 22:16:16 +03:00
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
2023-09-10 13:12:45 +03:00
import center.sciprog.maps.coordinates.*
2022-12-23 22:16:16 +03:00
import center.sciprog.maps.features.*
2023-02-06 10:37:22 +03:00
import space.kscience.kmath.geometry.Angle
2023-03-15 15:24:23 +03:00
import kotlin.math.ceil
2022-12-23 22:16:16 +03:00
2023-01-02 14:08:20 +03:00
internal fun FeatureGroup<Gmc>.coordinatesOf(pair: Pair<Number, Number>) =
2022-12-23 22:16:16 +03:00
GeodeticMapCoordinates.ofDegrees(pair.first.toDouble(), pair.second.toDouble())
public typealias MapFeature = Feature<Gmc>
2023-01-02 14:08:20 +03:00
public fun FeatureGroup<Gmc>.circle(
2022-12-23 22:16:16 +03:00
centerCoordinates: Pair<Number, Number>,
size: Dp = 5.dp,
id: String? = null,
2023-02-06 10:37:22 +03:00
): FeatureRef<Gmc, CircleFeature<Gmc>> = feature(
2023-01-02 14:08:20 +03:00
id, CircleFeature(space, coordinatesOf(centerCoordinates), size)
2022-12-23 22:16:16 +03:00
)
2023-01-02 14:08:20 +03:00
public fun FeatureGroup<Gmc>.rectangle(
2022-12-23 22:16:16 +03:00
centerCoordinates: Pair<Number, Number>,
size: DpSize = DpSize(5.dp, 5.dp),
id: String? = null,
2023-02-06 10:37:22 +03:00
): FeatureRef<Gmc, RectangleFeature<Gmc>> = feature(
2023-02-13 16:49:36 +03:00
id, RectangleFeature(space, coordinatesOf(centerCoordinates), size)
2022-12-23 22:16:16 +03:00
)
2023-01-02 14:08:20 +03:00
public fun FeatureGroup<Gmc>.draw(
2022-12-23 22:16:16 +03:00
position: Pair<Number, Number>,
id: String? = null,
draw: DrawScope.() -> Unit,
2023-02-06 10:37:22 +03:00
): FeatureRef<Gmc, DrawFeature<Gmc>> = feature(
2022-12-23 22:16:16 +03:00
id,
2023-01-02 14:08:20 +03:00
DrawFeature(space, coordinatesOf(position), drawFeature = draw)
2022-12-23 22:16:16 +03:00
)
2023-01-02 14:08:20 +03:00
public fun FeatureGroup<Gmc>.line(
2022-12-23 22:16:16 +03:00
curve: GmcCurve,
id: String? = null,
2023-02-06 10:37:22 +03:00
): FeatureRef<Gmc, LineFeature<Gmc>> = feature(
2022-12-23 22:16:16 +03:00
id,
2023-01-02 14:08:20 +03:00
LineFeature(space, curve.forward.coordinates, curve.backward.coordinates)
2022-12-23 22:16:16 +03:00
)
2023-09-10 13:12:45 +03:00
/**
* A segmented geodetic curve
*/
public fun FeatureGroup<Gmc>.geodeticLine(
curve: GmcCurve,
ellipsoid: GeoEllipsoid = GeoEllipsoid.WGS84,
maxLineDistance: Distance = 100.kilometers,
id: String? = null,
): FeatureRef<Gmc, Feature<Gmc>> = if (curve.distance < maxLineDistance) {
feature(
id,
LineFeature(space, curve.forward.coordinates, curve.backward.coordinates)
)
} else {
val segments = ceil(curve.distance / maxLineDistance).toInt()
val segmentSize = curve.distance / segments
val points = buildList<GmcPose> {
add(curve.forward)
repeat(segments) {
val segment = ellipsoid.curveInDirection(this.last(), segmentSize, 1e-2)
add(segment.backward)
}
}
multiLine(points.map { it.coordinates }, id = id)
}
public fun FeatureGroup<Gmc>.geodeticLine(
from: Gmc,
to: Gmc,
ellipsoid: GeoEllipsoid = GeoEllipsoid.WGS84,
maxLineDistance: Distance = 100.kilometers,
id: String? = null,
): FeatureRef<Gmc, Feature<Gmc>> = geodeticLine(ellipsoid.curveBetween(from, to), ellipsoid, maxLineDistance, id)
2022-12-23 22:16:16 +03:00
2023-01-02 14:08:20 +03:00
public fun FeatureGroup<Gmc>.line(
2022-12-23 22:16:16 +03:00
aCoordinates: Pair<Double, Double>,
bCoordinates: Pair<Double, Double>,
id: String? = null,
2023-02-06 10:37:22 +03:00
): FeatureRef<Gmc, LineFeature<Gmc>> = feature(
2022-12-23 22:16:16 +03:00
id,
2023-01-02 14:08:20 +03:00
LineFeature(space, coordinatesOf(aCoordinates), coordinatesOf(bCoordinates))
2022-12-23 22:16:16 +03:00
)
2023-01-02 14:08:20 +03:00
public fun FeatureGroup<Gmc>.arc(
2022-12-23 22:16:16 +03:00
center: Pair<Double, Double>,
radius: Distance,
startAngle: Angle,
arcLength: Angle,
id: String? = null,
2023-02-06 10:37:22 +03:00
): FeatureRef<Gmc, ArcFeature<Gmc>> = feature(
2022-12-23 22:16:16 +03:00
id,
ArcFeature(
2023-01-01 09:10:01 +03:00
space,
oval = space.Rectangle(coordinatesOf(center), radius, radius),
2023-02-06 17:19:51 +03:00
startAngle = startAngle,
arcLength = arcLength,
2022-12-23 22:16:16 +03:00
)
)
2023-01-02 14:08:20 +03:00
public fun FeatureGroup<Gmc>.points(
2022-12-23 22:16:16 +03:00
points: List<Pair<Double, Double>>,
id: String? = null,
2023-02-13 16:49:36 +03:00
): 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)))
2022-12-23 22:16:16 +03:00
2023-04-11 17:08:28 +03:00
public fun FeatureGroup<Gmc>.icon(
2022-12-23 22:16:16 +03:00
position: Pair<Double, Double>,
image: ImageVector,
size: DpSize = DpSize(20.dp, 20.dp),
id: String? = null,
2023-04-11 17:08:28 +03:00
): FeatureRef<Gmc, VectorIconFeature<Gmc>> = feature(
2022-12-23 22:16:16 +03:00
id,
2023-04-11 17:08:28 +03:00
VectorIconFeature(
2023-01-01 09:10:01 +03:00
space,
2022-12-23 22:16:16 +03:00
coordinatesOf(position),
size,
image,
)
)
2023-01-02 14:08:20 +03:00
public fun FeatureGroup<Gmc>.text(
2022-12-23 22:16:16 +03:00
position: Pair<Double, Double>,
text: String,
font: FeatureFont.() -> Unit = { size = 16f },
id: String? = null,
2023-02-06 10:37:22 +03:00
): FeatureRef<Gmc, TextFeature<Gmc>> = feature(
2022-12-23 22:16:16 +03:00
id,
2023-01-02 14:08:20 +03:00
TextFeature(space, coordinatesOf(position), text, fontConfig = font)
2022-12-23 22:16:16 +03:00
)
2023-03-15 15:24:23 +03:00
public fun FeatureGroup<Gmc>.pixelMap(
rectangle: Rectangle<Gmc>,
latitudeDelta: Angle,
longitudeDelta: Angle,
id: String? = null,
builder: (Gmc) -> Color?,
2023-03-16 10:10:53 +03:00
): FeatureRef<Gmc, PixelMapFeature<Gmc>> = feature(
id,
PixelMapFeature(
space,
rectangle,
Structure2D(
ceil(rectangle.longitudeDelta / latitudeDelta).toInt(),
ceil(rectangle.latitudeDelta / longitudeDelta).toInt()
) { (i, j) ->
val longitude = rectangle.left + longitudeDelta * i
val latitude = rectangle.bottom + latitudeDelta * j
builder(
Gmc(latitude, longitude)
)
}
2023-03-15 15:24:23 +03:00
)
2023-03-16 10:10:53 +03:00
)