添加 SlopeResult 显示的开关
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user