添加 SlopeResult 显示的开关

This commit is contained in:
2025-11-26 18:56:31 +08:00
parent a58486bff0
commit 204c8fd599
5 changed files with 133 additions and 126 deletions

View File

@@ -11,6 +11,7 @@ import com.google.android.material.slider.RangeSlider
import com.google.android.material.slider.Slider
import com.icegps.common.helper.GeoHelper
import com.icegps.geotools.databinding.ActivityMainBinding
import com.icegps.math.geometry.Angle
import com.icegps.math.geometry.degrees
import com.icegps.shared.model.GeoPoint
import com.mapbox.geojson.Point
@@ -21,7 +22,10 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@@ -166,11 +170,16 @@ class MainActivity : AppCompatActivity() {
showDesignHeight.value = isChecked
}
earthworkManager.setupOnMoveListener()
binding.switchSlopeResult.setOnCheckedChangeListener { _, isChecked ->
slopeResultVisible.value = isChecked
}
initData()
}
private val showDesignHeight = MutableStateFlow(false)
private val slopeResultVisible = MutableStateFlow(false)
@OptIn(ExperimentalUuidApi::class)
private fun initData() {
viewModel.points.onEach {
contoursManager.updatePoints(it)
@@ -183,14 +192,32 @@ class MainActivity : AppCompatActivity() {
earthworkManager.slopeDirection.onEach {
binding.slopeDirection.value = it.degrees.toFloat()
}.launchIn(lifecycleScope)
val slopeResultSourceId: String = Uuid.random().toString()
val slopeResultLayerId: String = Uuid.random().toString()
combine(
earthworkManager.slopeDirection,
earthworkManager.slopePercentage,
earthworkManager.baseHeightOffset,
contoursManager.gridModel,
showDesignHeight
) { slopeDirection, slopePercentage, baseHeightOffset, gridModel, showDesignHeight ->
gridModel?.let { gridModel ->
showDesignHeight,
slopeResultVisible
) {
Params6(
p1 = it[0] as Angle,
p2 = it[1] as Double,
p3 = it[2] as Double,
p4 = it[3] as? GridModel?,
p5 = it[4] as Boolean,
p6 = it[5] as Boolean
)
}.map { (slopeDirection, slopePercentage, baseHeightOffset, gridModel, showDesignHeight, slopeResultVisible) ->
if (!slopeResultVisible) {
mapView.mapboxMap.getStyle { style ->
style.removeStyleLayer(slopeResultLayerId)
style.removeStyleLayer("${slopeResultLayerId}-outline")
style.removeStyleSource(slopeResultSourceId)
}
} else gridModel?.let { gridModel ->
val slopeResult: SlopeResult = SlopeCalculator.calculateSlope(
grid = gridModel,
slopeDirection = slopeDirection.degrees,
@@ -200,6 +227,8 @@ class MainActivity : AppCompatActivity() {
mapView.displaySlopeResult(
originalGrid = gridModel,
slopeResult = slopeResult,
sourceId = slopeResultSourceId,
layerId = slopeResultLayerId,
palette = contoursManager.simplePalette::palette,
showDesignHeight = showDesignHeight
)
@@ -208,6 +237,22 @@ class MainActivity : AppCompatActivity() {
}
}
data class Params6<
out P1,
out P2,
out P3,
out P4,
out P5,
out P6,
>(
val p1: P1,
val p2: P2,
val p3: P3,
val p4: P4,
val p5: P5,
val p6: P6,
)
val home = GeoPoint(114.476060, 22.771073, 30.897)
fun initGeoHelper(base: GeoPoint = home) {

View File

@@ -1,123 +0,0 @@
package com.icegps.geotools
import android.graphics.Color
import com.icegps.common.helper.GeoHelper
import com.icegps.math.geometry.Vector3D
import com.icegps.geotools.ktx.toMapboxPoint
import com.mapbox.geojson.Feature
import com.mapbox.geojson.FeatureCollection
import com.mapbox.geojson.LineString
import com.mapbox.geojson.Polygon
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
class PolygonTest(
private val mapView: MapView
) {
private val geoHelper = GeoHelper.Companion.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 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)
}
Feature.fromGeometry(LineString.fromLngLats(otherPoints)).also {
lineFeatures.add(it)
}
//val polygon = Polygon.fromOuterInner(outerLine, innerLine)
val polygon = Polygon.fromLngLats(listOf(outerPoints, otherPoints, innerPoints))
mapView.mapboxMap.getStyle { style ->
if (false) 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.Companion.ROUND)
lineJoin(LineJoin.Companion.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

@@ -178,6 +178,13 @@
android:layout_height="wrap_content"
android:switchPadding="16dp"
android:text="显示设计面" />
<Switch
android:id="@+id/switch_slope_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:switchPadding="16dp"
android:text="显示计算的坡面" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -169,6 +169,13 @@
android:layout_height="wrap_content"
android:switchPadding="16dp"
android:text="显示设计面" />
<Switch
android:id="@+id/switch_slope_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:switchPadding="16dp"
android:text="显示计算的坡面" />
</LinearLayout>
<com.mapbox.maps.MapView

View File

@@ -0,0 +1,71 @@
package com.icegps.geotools
import com.icegps.geotools.ktx.area
import com.icegps.geotools.ktx.niceStr
import com.icegps.math.geometry.Vector3D
import com.icegps.triangulation.delaunayTriangulation
import org.junit.Test
import kotlin.math.max
/**
* @author tabidachinokaze
* @date 2025/11/26
*/
class TriangulationToGridTest {
@Test
fun testTriangulationToGrid() {
val points = listOf(
Vector3D(-10.0, 10.0, 0.0),
Vector3D(10.0, 10.0, 10.0),
Vector3D(-10.0, -10.0, 20.0),
Vector3D(10.0, -10.0, 30.0),
)
points.map {
it / 8
}.niceStr().let(::println)
val area = points.area
val cellSize = max(area.x + area.width, area.y + area.height) / 10
val triangulation = points.delaunayTriangulation()
val triangles = triangulation.triangles()
val grid = triangulationToGrid(
delaunator = triangulation,
cellSize = cellSize,
)
grid.string().let(::println)
val slopeResult = SlopeCalculator.calculateSlope(
grid = grid,
slopeDirection = 0.0,
slopePercentage = 100.0,
baseHeightOffset = 0.0
)
slopeResult.designSurface.string().let(::println)
println("原来的 Volume: ${grid.volumeSum()}")
println("做坡的 Volume: ${slopeResult.designSurface.volumeSum()}")
println(slopeResult.earthworkResult)
}
}
fun GridModel.string() = buildString {
for (r in 0 until rows) {
for (c in 0 until cols) {
val originalElev = getValue(r, c) ?: continue
append("${originalElev.format()}, ")
}
appendLine()
}
}
fun GridModel.volumeSum(): Double {
var volume = 0.0
for (r in 0 until rows) {
for (c in 0 until cols) {
val height = getValue(r, c) ?: continue
volume += height
}
}
return volume
}
fun Double.format(): String {
return "%.1f".format(this)
}