From de15029b2be1243142c38e266f833084cc6a80ad Mon Sep 17 00:00:00 2001 From: tabidachinokaze Date: Tue, 25 Nov 2025 01:09:45 +0800 Subject: [PATCH] =?UTF-8?q?GeoJson=20=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/icegps/orx/MainActivity.kt | 219 +++++++++++++++++- android/src/main/res/layout/activity_main.xml | 19 +- 2 files changed, 225 insertions(+), 13 deletions(-) diff --git a/android/src/main/java/com/icegps/orx/MainActivity.kt b/android/src/main/java/com/icegps/orx/MainActivity.kt index 727e01d0..68f5d909 100644 --- a/android/src/main/java/com/icegps/orx/MainActivity.kt +++ b/android/src/main/java/com/icegps/orx/MainActivity.kt @@ -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, + 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> { + /** + * 绕 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, + inner: List, + other: List + ) { + val lineFeatures = mutableListOf() + val fillFeatures = mutableListOf() + + 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 + ) { + 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 + ) { + 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() { + } } diff --git a/android/src/main/res/layout/activity_main.xml b/android/src/main/res/layout/activity_main.xml index 86a5d977..b02beaa1 100644 --- a/android/src/main/res/layout/activity_main.xml +++ b/android/src/main/res/layout/activity_main.xml @@ -1,19 +1,14 @@ - - - - \ No newline at end of file + + \ No newline at end of file