GeoJson 测试

This commit is contained in:
2025-11-25 01:09:45 +08:00
parent a1a9a9e0e4
commit de15029b2b
2 changed files with 225 additions and 13 deletions

View File

@@ -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() {
} }
} }

View File

@@ -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>