Files
icegps-maps-view/maps-view/src/main/java/com/icegps/maps/layer/BoundaryLayer.kt
2025-06-13 21:03:42 +08:00

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,
}