GeoJson 测试
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package com.icegps.orx
|
package com.icegps.orx
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
@@ -9,6 +10,10 @@ import androidx.core.view.WindowInsetsCompat
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.icegps.common.helper.GeoHelper
|
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.orx.databinding.ActivityMainBinding
|
||||||
import com.icegps.shared.SharedHttpClient
|
import com.icegps.shared.SharedHttpClient
|
||||||
import com.icegps.shared.SharedJson
|
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.api.OpenElevationApi
|
||||||
import com.icegps.shared.ktx.TAG
|
import com.icegps.shared.ktx.TAG
|
||||||
import com.icegps.shared.model.GeoPoint
|
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.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.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -25,20 +44,218 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import org.openrndr.extra.triangulation.DelaunayTriangulation
|
import org.openrndr.extra.triangulation.DelaunayTriangulation
|
||||||
import org.openrndr.math.Vector2
|
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() {
|
class MainActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
|
private lateinit var mapView: MapView
|
||||||
|
|
||||||
|
init {
|
||||||
|
initGeoHelper()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
|
mapView = binding.mapView
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||||
insets
|
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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main"
|
android:id="@+id/main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
tools:context=".MainActivity">
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
<TextView
|
<com.mapbox.maps.MapView
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/map_view"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:text="Hello World!"
|
android:layout_height="match_parent" />
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
</LinearLayout>
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
Reference in New Issue
Block a user