GeoJson 测试
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.icegps.orx
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
@@ -9,6 +10,10 @@ import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.icegps.common.helper.GeoHelper
|
||||
import com.icegps.math.geometry.Angle
|
||||
import com.icegps.math.geometry.Line3D
|
||||
import com.icegps.math.geometry.Vector3D
|
||||
import com.icegps.math.geometry.degrees
|
||||
import com.icegps.orx.databinding.ActivityMainBinding
|
||||
import com.icegps.shared.SharedHttpClient
|
||||
import com.icegps.shared.SharedJson
|
||||
@@ -16,7 +21,21 @@ import com.icegps.shared.api.OpenElevation
|
||||
import com.icegps.shared.api.OpenElevationApi
|
||||
import com.icegps.shared.ktx.TAG
|
||||
import com.icegps.shared.model.GeoPoint
|
||||
import com.mapbox.geojson.Feature
|
||||
import com.mapbox.geojson.FeatureCollection
|
||||
import com.mapbox.geojson.LineString
|
||||
import com.mapbox.geojson.Point
|
||||
import com.mapbox.geojson.Polygon
|
||||
import com.mapbox.maps.CameraOptions
|
||||
import com.mapbox.maps.MapView
|
||||
import com.mapbox.maps.Style
|
||||
import com.mapbox.maps.extension.style.layers.addLayer
|
||||
import com.mapbox.maps.extension.style.layers.generated.fillLayer
|
||||
import com.mapbox.maps.extension.style.layers.generated.lineLayer
|
||||
import com.mapbox.maps.extension.style.layers.properties.generated.LineCap
|
||||
import com.mapbox.maps.extension.style.layers.properties.generated.LineJoin
|
||||
import com.mapbox.maps.extension.style.sources.addSource
|
||||
import com.mapbox.maps.extension.style.sources.generated.geoJsonSource
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -25,20 +44,218 @@ import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.openrndr.extra.triangulation.DelaunayTriangulation
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.YPolarity
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private lateinit var mapView: MapView
|
||||
|
||||
init {
|
||||
initGeoHelper()
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
mapView = binding.mapView
|
||||
setContentView(binding.root)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
mapView.mapboxMap.setCamera(
|
||||
CameraOptions.Builder()
|
||||
.center(Point.fromLngLat(home.longitude, home.latitude))
|
||||
.pitch(0.0)
|
||||
.zoom(18.0)
|
||||
.bearing(0.0)
|
||||
.build()
|
||||
)
|
||||
|
||||
val points = coordinateGenerate1()
|
||||
val polygonTest = PolygonTest(mapView)
|
||||
polygonTest.clear()
|
||||
val innerPoints = points.map { it[0] }
|
||||
val outerPoints = points.map { it[1] }
|
||||
polygonTest.update(
|
||||
outer = outerPoints,
|
||||
inner = innerPoints,
|
||||
other = points.map { it[2] }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val home = GeoPoint(114.476060, 22.771073, 30.897)
|
||||
|
||||
fun initGeoHelper(base: GeoPoint = home) {
|
||||
val geoHelper = GeoHelper.getSharedInstance()
|
||||
geoHelper.wgs84ToENU(
|
||||
lon = base.longitude,
|
||||
lat = base.latitude,
|
||||
hgt = base.altitude
|
||||
)
|
||||
}
|
||||
|
||||
fun fromPoints(
|
||||
points: List<Vector3D>,
|
||||
closed: Boolean,
|
||||
polarity: YPolarity = YPolarity.CW_NEGATIVE_Y
|
||||
) = if (points.isEmpty()) {
|
||||
emptyList()
|
||||
} else {
|
||||
if (!closed) {
|
||||
(0 until points.size - 1).map {
|
||||
Line3D(
|
||||
points[it],
|
||||
points[it + 1]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
val d = (points.last() - points.first()).length
|
||||
val usePoints = if (d > 1E-6) points else points.dropLast(1)
|
||||
(usePoints.indices).map {
|
||||
Line3D(
|
||||
usePoints[it],
|
||||
usePoints[(it + 1) % usePoints.size]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun coordinateGenerate1(): List<List<Vector3D>> {
|
||||
/**
|
||||
* 绕 Z 轴旋转指定角度(弧度)
|
||||
*/
|
||||
fun Vector3D.rotateAroundZ(angle: Angle): Vector3D {
|
||||
val cosAngle = cos(angle.radians)
|
||||
val sinAngle = sin(angle.radians)
|
||||
|
||||
return Vector3D(
|
||||
x = x * cosAngle - y * sinAngle,
|
||||
y = x * sinAngle + y * cosAngle,
|
||||
z = z
|
||||
)
|
||||
}
|
||||
|
||||
val center = Vector3D()
|
||||
val direction = Vector3D(0.0, 1.0, -1.0)
|
||||
return (0..360).step(10).map {
|
||||
val nowDirection = direction.rotateAroundZ(it.degrees)
|
||||
listOf(2, 6, 10).map {
|
||||
center + nowDirection * it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PolygonTest(
|
||||
private val mapView: MapView
|
||||
) {
|
||||
private val geoHelper = GeoHelper.getSharedInstance()
|
||||
|
||||
private val contourSourceId = "contour-source-id-0"
|
||||
private val contourLayerId = "contour-layer-id-0"
|
||||
|
||||
private val fillSourceId = "fill-source-id-0"
|
||||
private val fillLayerId = "fill-layer-id-0"
|
||||
|
||||
fun Vector3D.toMapboxPoint(): Point {
|
||||
return geoHelper.enuToWGS84Object(GeoHelper.ENU(x, y, z)).run {
|
||||
Point.fromLngLat(lon, lat, hgt)
|
||||
}
|
||||
}
|
||||
|
||||
fun update(
|
||||
outer: List<Vector3D>,
|
||||
inner: List<Vector3D>,
|
||||
other: List<Vector3D>
|
||||
) {
|
||||
val lineFeatures = mutableListOf<Feature>()
|
||||
val fillFeatures = mutableListOf<Feature>()
|
||||
|
||||
val outerPoints = outer.map { it.toMapboxPoint() }
|
||||
val innerPoints = inner.map { it.toMapboxPoint() }
|
||||
val otherPoints = other.map { it.toMapboxPoint() }
|
||||
val outerLine = LineString.fromLngLats(outerPoints)
|
||||
Feature.fromGeometry(outerLine).also {
|
||||
lineFeatures.add(it)
|
||||
}
|
||||
val innerLine = LineString.fromLngLats(innerPoints)
|
||||
Feature.fromGeometry(innerLine).also {
|
||||
lineFeatures.add(it)
|
||||
}
|
||||
|
||||
//val polygon = Polygon.fromOuterInner(outerLine, innerLine)
|
||||
val polygon = Polygon.fromLngLats(listOf(outerPoints, otherPoints, innerPoints))
|
||||
|
||||
mapView.mapboxMap.getStyle { style ->
|
||||
setupLineLayer(
|
||||
style = style,
|
||||
sourceId = contourSourceId,
|
||||
layerId = contourLayerId,
|
||||
features = lineFeatures
|
||||
)
|
||||
setupFillLayer(
|
||||
style = style,
|
||||
sourceId = fillSourceId,
|
||||
layerId = fillLayerId,
|
||||
features = listOf(Feature.fromGeometry(polygon))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLineLayer(
|
||||
style: Style,
|
||||
sourceId: String,
|
||||
layerId: String,
|
||||
features: List<Feature>
|
||||
) {
|
||||
style.removeStyleLayer(layerId)
|
||||
style.removeStyleSource(sourceId)
|
||||
|
||||
val source = geoJsonSource(sourceId) {
|
||||
featureCollection(FeatureCollection.fromFeatures(features))
|
||||
}
|
||||
style.addSource(source)
|
||||
|
||||
val layer = lineLayer(layerId, sourceId) {
|
||||
lineColor(Color.RED)
|
||||
lineWidth(2.0)
|
||||
lineCap(LineCap.ROUND)
|
||||
lineJoin(LineJoin.ROUND)
|
||||
lineOpacity(0.8)
|
||||
}
|
||||
style.addLayer(layer)
|
||||
}
|
||||
|
||||
private fun setupFillLayer(
|
||||
style: Style,
|
||||
sourceId: String,
|
||||
layerId: String,
|
||||
features: List<Feature>
|
||||
) {
|
||||
style.removeStyleLayer(layerId)
|
||||
style.removeStyleSource(sourceId)
|
||||
|
||||
val source = geoJsonSource(sourceId) {
|
||||
featureCollection(FeatureCollection.fromFeatures(features))
|
||||
}
|
||||
style.addSource(source)
|
||||
|
||||
val layer = fillLayer(fillLayerId, fillSourceId) {
|
||||
fillColor(Color.YELLOW)
|
||||
fillOpacity(0.3)
|
||||
fillAntialias(true)
|
||||
}
|
||||
style.addLayer(layer)
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World!"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<com.mapbox.maps.MapView
|
||||
android:id="@+id/map_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user