157 lines
4.3 KiB
Kotlin
157 lines
4.3 KiB
Kotlin
package com.icegps.maps.layer
|
|
|
|
import android.graphics.Canvas
|
|
import android.graphics.Color
|
|
import android.graphics.DashPathEffect
|
|
import android.graphics.Paint
|
|
import android.util.Log
|
|
import com.icegps.maps.CoordinateManager
|
|
import com.icegps.maps.ktx.TAG
|
|
import com.icegps.maps.model.ScreenPoint
|
|
import com.icegps.math.geometry.Line
|
|
|
|
/**
|
|
* @author tabidachinokaze
|
|
* @date 2025/6/13
|
|
*/
|
|
class BoundaryLayer(
|
|
private val coordinateManager: CoordinateManager,
|
|
paintBuilder: (Paint) -> Unit = {
|
|
it.color = Color.BLACK
|
|
it.strokeWidth = 2f
|
|
}
|
|
) : BaseLayer(zIndex = 1) {
|
|
private val lines = mutableListOf<Line>()
|
|
var extendLines = true // 是否延长边界线
|
|
|
|
var lineStyle: LineStyle = LineStyle.SOLID
|
|
set(value) {
|
|
field = value
|
|
when (value) {
|
|
LineStyle.SOLID -> {
|
|
paint.style = Paint.Style.STROKE
|
|
paint.pathEffect = null
|
|
}
|
|
|
|
LineStyle.DASHED -> {
|
|
paint.style = Paint.Style.STROKE
|
|
paint.pathEffect = DashPathEffect(floatArrayOf(20f, 10f), 0f)
|
|
}
|
|
|
|
LineStyle.DOTTED -> {
|
|
paint.style = Paint.Style.STROKE
|
|
paint.pathEffect = DashPathEffect(floatArrayOf(5f, 10f), 0f)
|
|
}
|
|
}
|
|
}
|
|
|
|
init {
|
|
paintBuilder(paint)
|
|
}
|
|
|
|
override fun onDraw(canvas: Canvas) {
|
|
val (width, height) = coordinateManager.mapSize
|
|
if (width <= 0 || height <= 0) return
|
|
|
|
lines.forEachIndexed { index, it ->
|
|
val start = coordinateManager.worldToScreen(it.a)
|
|
val end = coordinateManager.worldToScreen(it.b)
|
|
val line = if (extendLines) extendLine(start, end) else it
|
|
canvas.drawLine(
|
|
line.a.x,
|
|
line.a.y,
|
|
line.b.x,
|
|
line.b.y,
|
|
paint
|
|
)
|
|
Log.d(TAG, "绘制边界线: 线$index(${line.a.x}, ${line.a.y}) - (${line.b.x}, ${line.b.y})")
|
|
}
|
|
}
|
|
|
|
fun setBoundaryLines(lines: List<Line>) {
|
|
this.lines.clear()
|
|
this.lines.addAll(lines)
|
|
}
|
|
|
|
/**
|
|
* 延长线段至屏幕边缘
|
|
*/
|
|
private fun extendLine(start: ScreenPoint, end: ScreenPoint): Line {
|
|
val mapSize = coordinateManager.mapSize
|
|
val width = mapSize.width.toFloat()
|
|
val height = mapSize.height.toFloat()
|
|
// 计算线段方向向量
|
|
val dx = end.x - start.x
|
|
val dy = end.y - start.y
|
|
|
|
// 如果线段是垂直的
|
|
if (dx == 0f) {
|
|
return Line(
|
|
ScreenPoint(start.x, 0f),
|
|
ScreenPoint(start.x, height)
|
|
)
|
|
}
|
|
|
|
// 如果线段是水平的
|
|
if (dy == 0f) {
|
|
return Line(
|
|
ScreenPoint(0f, start.y),
|
|
ScreenPoint(width, start.y)
|
|
)
|
|
}
|
|
|
|
// 计算线段与屏幕边界的交点
|
|
val slope = dy / dx
|
|
val yIntercept = start.y - slope * start.x
|
|
|
|
// 计算与左边界的交点
|
|
val leftX = 0f
|
|
val leftY = yIntercept
|
|
|
|
// 计算与右边界的交点
|
|
val rightX = width
|
|
val rightY = slope * width + yIntercept
|
|
|
|
// 计算与上边界的交点
|
|
val topY = 0f
|
|
val topX = (topY - yIntercept) / slope
|
|
|
|
// 计算与下边界的交点
|
|
val bottomY = height
|
|
val bottomX = (bottomY - yIntercept) / slope
|
|
|
|
// 收集所有在屏幕内的交点
|
|
val intersections = mutableListOf<ScreenPoint>()
|
|
|
|
if (leftY in 0f..height) {
|
|
intersections.add(ScreenPoint(leftX, leftY))
|
|
}
|
|
|
|
if (rightY in 0f..height) {
|
|
intersections.add(ScreenPoint(rightX, rightY))
|
|
}
|
|
|
|
if (topX in 0f..width) {
|
|
intersections.add(ScreenPoint(topX, topY))
|
|
}
|
|
|
|
if (bottomX in 0f..width) {
|
|
intersections.add(ScreenPoint(bottomX, bottomY))
|
|
}
|
|
|
|
// 如果找到了两个交点,返回这两个点
|
|
if (intersections.size >= 2) {
|
|
return Line(intersections[0], intersections[1])
|
|
}
|
|
|
|
// 如果没有找到足够的交点,返回原始线段
|
|
return Line(start, end)
|
|
}
|
|
|
|
}
|
|
|
|
enum class LineStyle {
|
|
SOLID,
|
|
DASHED,
|
|
DOTTED,
|
|
} |