|
@@ -9,17 +9,30 @@ import android.graphics.PointF
|
|
|
import android.util.Pair
|
|
import android.util.Pair
|
|
|
import android.view.MotionEvent
|
|
import android.view.MotionEvent
|
|
|
import com.grkj.iscs_mars.R
|
|
import com.grkj.iscs_mars.R
|
|
|
-import com.grkj.iscs_mars.modbus.ModBusController
|
|
|
|
|
import com.grkj.iscs_mars.util.BitmapUtil
|
|
import com.grkj.iscs_mars.util.BitmapUtil
|
|
|
import com.onlylemi.mapview.library.MapView
|
|
import com.onlylemi.mapview.library.MapView
|
|
|
import com.onlylemi.mapview.library.layer.MapBaseLayer
|
|
import com.onlylemi.mapview.library.layer.MapBaseLayer
|
|
|
|
|
+import kotlinx.coroutines.Runnable
|
|
|
import kotlin.math.cos
|
|
import kotlin.math.cos
|
|
|
import kotlin.math.sin
|
|
import kotlin.math.sin
|
|
|
|
|
|
|
|
class CustomStationLayer @JvmOverloads constructor(
|
|
class CustomStationLayer @JvmOverloads constructor(
|
|
|
- mapView: MapView?, private var pointList: List<IsolationPoint> = mutableListOf()
|
|
|
|
|
|
|
+ mapView: MapView?, private var pointList: MutableList<IsolationPoint> = mutableListOf()
|
|
|
) : MapBaseLayer(mapView) {
|
|
) : MapBaseLayer(mapView) {
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 配置:你当前实现把位图画在“左上角”,保持兼容 =====
|
|
|
|
|
+ private val POS_IS_TOP_LEFT = true
|
|
|
|
|
+
|
|
|
|
|
+ private val ICON_TOP_OFFSET_PX = 0f // 例如想再向上 6px 就写 6f
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 同步 & 选择保持 =====
|
|
|
|
|
+ private val dataLock = Any()
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 绘制与节流 =====
|
|
|
|
|
+ @Volatile
|
|
|
var inDraw: Boolean = false
|
|
var inDraw: Boolean = false
|
|
|
|
|
+ private set
|
|
|
|
|
+
|
|
|
private var listener: MarkIsClickListener? = null
|
|
private var listener: MarkIsClickListener? = null
|
|
|
private var radiusMark = 0f
|
|
private var radiusMark = 0f
|
|
|
private lateinit var paint: Paint
|
|
private lateinit var paint: Paint
|
|
@@ -30,15 +43,20 @@ class CustomStationLayer @JvmOverloads constructor(
|
|
|
private var ratio: Float = 1f
|
|
private var ratio: Float = 1f
|
|
|
private var switchSize: Float = 1f
|
|
private var switchSize: Float = 1f
|
|
|
|
|
|
|
|
|
|
+ private val FRAME_INTERVAL_MS = 32L
|
|
|
|
|
+ private val invalidateRunnable = Runnable {
|
|
|
|
|
+ mapView?.refresh()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
init {
|
|
init {
|
|
|
initLayer()
|
|
initLayer()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private fun initLayer() {
|
|
private fun initLayer() {
|
|
|
radiusMark = setValue(6.0f)
|
|
radiusMark = setValue(6.0f)
|
|
|
- paint = Paint()
|
|
|
|
|
- paint.isAntiAlias = true
|
|
|
|
|
- paint.style = Paint.Style.FILL_AND_STROKE
|
|
|
|
|
|
|
+ paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
|
|
|
|
+ style = Paint.Style.FILL_AND_STROKE
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fun setRatio(ratio: Float) {
|
|
fun setRatio(ratio: Float) {
|
|
@@ -57,83 +75,120 @@ class CustomStationLayer @JvmOverloads constructor(
|
|
|
(78 * ratio).toInt()
|
|
(78 * ratio).toInt()
|
|
|
)!!
|
|
)!!
|
|
|
switchSize = setValue(4 * ratio)
|
|
switchSize = setValue(4 * ratio)
|
|
|
|
|
+ throttleInvalidate()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
override fun onTouch(event: MotionEvent) {
|
|
override fun onTouch(event: MotionEvent) {
|
|
|
-
|
|
|
|
|
|
|
+ // 你原来未实现点击,这里保持空实现,避免改变现有交互。
|
|
|
|
|
+ // 如果要做命中,可按 mapToScreen -> 在屏幕坐标圈选,或直接在 draw 使用的同一锚点上做距离判断。
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
override fun draw(
|
|
override fun draw(
|
|
|
canvas: Canvas, currentMatrix: Matrix, currentZoom: Float, currentRotateDegrees: Float
|
|
canvas: Canvas, currentMatrix: Matrix, currentZoom: Float, currentRotateDegrees: Float
|
|
|
) {
|
|
) {
|
|
|
if (!isVisible) return
|
|
if (!isVisible) return
|
|
|
- if (inDraw) {
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (inDraw) return
|
|
|
inDraw = true
|
|
inDraw = true
|
|
|
this.currentZoom = currentZoom
|
|
this.currentZoom = currentZoom
|
|
|
currentDegree = 360 - currentRotateDegrees
|
|
currentDegree = 360 - currentRotateDegrees
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
canvas.save()
|
|
canvas.save()
|
|
|
try {
|
|
try {
|
|
|
- // 把 mapView 本身的缩放/平移/旋转一次性 concat 到 Canvas
|
|
|
|
|
canvas.concat(currentMatrix)
|
|
canvas.concat(currentMatrix)
|
|
|
- val tempPointList = pointList.toList()
|
|
|
|
|
|
|
+
|
|
|
|
|
+ val tempPointList = synchronized(dataLock) { pointList.toList() }
|
|
|
|
|
+
|
|
|
|
|
+ // 只画可见区域,避免全量遍历导致多余 overdraw
|
|
|
val inv = Matrix().apply { currentMatrix.invert(this) }
|
|
val inv = Matrix().apply { currentMatrix.invert(this) }
|
|
|
- val screen = android.graphics.RectF(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat())
|
|
|
|
|
- inv.mapRect(screen) // screen 现在是“图内坐标系下”的可见区域
|
|
|
|
|
|
|
+ val screen =
|
|
|
|
|
+ android.graphics.RectF(0f, 0f, canvas.width.toFloat(), canvas.height.toFloat())
|
|
|
|
|
+ inv.mapRect(screen) // 图内坐标下的可见区域
|
|
|
|
|
|
|
|
for (point in tempPointList) {
|
|
for (point in tempPointList) {
|
|
|
- // point.pos.x/y 已经是「图内像素坐标」
|
|
|
|
|
- val x = point.pos.x
|
|
|
|
|
- val y = point.pos.y
|
|
|
|
|
-
|
|
|
|
|
|
|
+ val c = centerOf(point) // 当前锚点(左上或中心)
|
|
|
val bw = bgBitmap?.width ?: 0
|
|
val bw = bgBitmap?.width ?: 0
|
|
|
val bh = bgBitmap?.height ?: 0
|
|
val bh = bgBitmap?.height ?: 0
|
|
|
- if (!screen.intersects(x, y, x + bw, y + bh)) continue // ← 屏外跳过
|
|
|
|
|
- // 先画背景(它会被 currentMatrix 自动缩放)
|
|
|
|
|
- bgBitmap?.let {bg->
|
|
|
|
|
- canvas.drawBitmap(
|
|
|
|
|
- bg, x, y, paint
|
|
|
|
|
- )
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 左上锚点:c 就是左上;中心锚点:换算左上绘制位
|
|
|
|
|
+ val drawX = if (POS_IS_TOP_LEFT) c.x else (c.x - bw / 2f)
|
|
|
|
|
+ val drawY = if (POS_IS_TOP_LEFT) c.y else (c.y - bh / 2f)
|
|
|
|
|
+
|
|
|
|
|
+ if (!screen.intersects(drawX, drawY, drawX + bw, drawY + bh)) continue
|
|
|
|
|
+
|
|
|
|
|
+ bgBitmap?.let { bg ->
|
|
|
|
|
+ canvas.drawBitmap(bg, drawX, drawY, paint)
|
|
|
|
|
+
|
|
|
point.icon?.let { raw ->
|
|
point.icon?.let { raw ->
|
|
|
- // 背景里要放图标的“内容槽”大小(自己按 bg 的留白算,这里举例居中正方形)
|
|
|
|
|
- val slot = minOf(bg.width, bg.height) * 0.6f
|
|
|
|
|
- val w = slot.toInt()
|
|
|
|
|
- val h = w
|
|
|
|
|
- val icon = getScaledIcon(raw, w, h) // ← 关键:先缩放再画
|
|
|
|
|
- val dx = x + (bg.width - w) / 2f
|
|
|
|
|
- val dy = y + (bg.height - h) / 2f
|
|
|
|
|
paint.isFilterBitmap = true
|
|
paint.isFilterBitmap = true
|
|
|
paint.isDither = true
|
|
paint.isDither = true
|
|
|
- canvas.drawBitmap(icon, dx, dy, paint)
|
|
|
|
|
|
|
+ paint.alpha = 255
|
|
|
|
|
+
|
|
|
|
|
+ // 如果想彻底禁用 density 影响,也可以加一行(可选):
|
|
|
|
|
+ raw.density = Bitmap.DENSITY_NONE
|
|
|
|
|
+
|
|
|
|
|
+ // 设定图标的“槽位”大小:宽占满背景,高留 70%(下边还能放字)
|
|
|
|
|
+ val slotW = bg.width * 0.8f // 想全宽就是 1.0f
|
|
|
|
|
+ val left = drawX + (bg.width - slotW) / 2f
|
|
|
|
|
+ val top = drawY + (bg.width - slotW) / 2f
|
|
|
|
|
+ val dst = android.graphics.RectF(left, top, left + slotW, top + slotW)
|
|
|
|
|
+
|
|
|
|
|
+ // —— 两种模式,二选一 ——
|
|
|
|
|
+ val USE_COVER = true // true=铺满裁剪更饱满;false=拉伸到槽位(可能变形)
|
|
|
|
|
+
|
|
|
|
|
+ if (!USE_COVER) {
|
|
|
|
|
+ // 拉伸到槽位(简单直接)
|
|
|
|
|
+ canvas.drawBitmap(raw, null, dst, paint)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 居中裁剪成“封面模式”(不变形,铺满槽位)
|
|
|
|
|
+ val src = run {
|
|
|
|
|
+ val sw = raw.width.toFloat();
|
|
|
|
|
+ val sh = raw.height.toFloat()
|
|
|
|
|
+ val dw = dst.width();
|
|
|
|
|
+ val dh = dst.height()
|
|
|
|
|
+ val s = maxOf(dw / sw, dh / sh) // 放大倍数
|
|
|
|
|
+ val cw = dw / s;
|
|
|
|
|
+ val ch = dh / s // 需要的源裁剪宽高
|
|
|
|
|
+ val cx = sw / 2f;
|
|
|
|
|
+ val cy = sh / 2f
|
|
|
|
|
+ android.graphics.Rect(
|
|
|
|
|
+ (cx - cw / 2f).toInt().coerceAtLeast(0),
|
|
|
|
|
+ (cy - ch / 2f).toInt().coerceAtLeast(0),
|
|
|
|
|
+ (cx + cw / 2f).toInt().coerceAtMost(raw.width),
|
|
|
|
|
+ (cy + ch / 2f).toInt().coerceAtMost(raw.height)
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
|
|
+ canvas.drawBitmap(raw, src, dst, paint)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- // 然后画文字
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 文本
|
|
|
paint.style = Paint.Style.FILL
|
|
paint.style = Paint.Style.FILL
|
|
|
paint.strokeWidth = 1f
|
|
paint.strokeWidth = 1f
|
|
|
paint.color = Color.RED
|
|
paint.color = Color.RED
|
|
|
- paint.textSize = radiusMark * ratio // 这里是「图内」的文字大小,后面会跟着缩放
|
|
|
|
|
|
|
+ paint.textSize = radiusMark * ratio
|
|
|
val textW = paint.measureText(point.entityName)
|
|
val textW = paint.measureText(point.entityName)
|
|
|
canvas.drawText(
|
|
canvas.drawText(
|
|
|
point.entityName,
|
|
point.entityName,
|
|
|
- x + (bg.width - textW) / 2,
|
|
|
|
|
- y + (bg.height - radiusMark / 2 - bg.height / 10),
|
|
|
|
|
|
|
+ drawX + (bg.width - textW) / 2,
|
|
|
|
|
+ drawY + (bg.height - radiusMark / 2 - bg.height / 10),
|
|
|
paint
|
|
paint
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- // 如果选中,再叠加一个标记
|
|
|
|
|
|
|
+ // ===== 选中覆盖:放在最上层;确保不透明 =====
|
|
|
if (point.isSelected) {
|
|
if (point.isSelected) {
|
|
|
- coverBitmap?.let {
|
|
|
|
|
- canvas.drawBitmap(
|
|
|
|
|
- it, x, y, paint
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ coverBitmap?.let { cover ->
|
|
|
|
|
+ paint.alpha = 255
|
|
|
|
|
+ canvas.drawBitmap(cover, drawX, drawY, paint)
|
|
|
}
|
|
}
|
|
|
- val checkW = paint.measureText("√")
|
|
|
|
|
|
|
+ val check = "√"
|
|
|
|
|
+ val checkW = paint.measureText(check)
|
|
|
paint.color = Color.WHITE
|
|
paint.color = Color.WHITE
|
|
|
|
|
+ paint.alpha = 255
|
|
|
canvas.drawText(
|
|
canvas.drawText(
|
|
|
- "√",
|
|
|
|
|
- x + (bg.width - checkW) / 2,
|
|
|
|
|
- y + (bg.height / 2 + radiusMark / 2),
|
|
|
|
|
|
|
+ check,
|
|
|
|
|
+ drawX + (bg.width - checkW) / 2f,
|
|
|
|
|
+ drawY + (bg.height / 2f + radiusMark / 2f),
|
|
|
paint
|
|
paint
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
@@ -147,6 +202,141 @@ class CustomStationLayer @JvmOverloads constructor(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // ===================== 新增:对外 API(与 CustomSwitchStationLayer 对齐) =====================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 点位列表:精准 Diff(pos 已是世界坐标);可选保留当前选中
|
|
|
|
|
+ */
|
|
|
|
|
+ fun submitPoints(points: List<IsolationPoint>, keepSelection: Boolean = true) {
|
|
|
|
|
+ val incoming = if (points === pointList) points.map { deepCopyItem(it) } else points
|
|
|
|
|
+
|
|
|
|
|
+ val changedCenters = ArrayList<PointF>(8)
|
|
|
|
|
+ val changedRadiusPx = 120 // 局部刷新半径(像素,按位图尺寸留富余)
|
|
|
|
|
+
|
|
|
|
|
+ synchronized(dataLock) {
|
|
|
|
|
+ val oldById = HashMap<Long, IsolationPoint>(pointList.size)
|
|
|
|
|
+ pointList.forEach { oldById[it.entityId] = it }
|
|
|
|
|
+
|
|
|
|
|
+ val nextList = ArrayList<IsolationPoint>(incoming.size)
|
|
|
|
|
+
|
|
|
|
|
+ for (src in incoming) {
|
|
|
|
|
+ val id = src.entityId
|
|
|
|
|
+ val dst = oldById[id]
|
|
|
|
|
+ if (dst == null) {
|
|
|
|
|
+ val add = deepCopyItem(src).copy(
|
|
|
|
|
+ // 选中保持
|
|
|
|
|
+ isSelected = src.isSelected
|
|
|
|
|
+ )
|
|
|
|
|
+ nextList.add(add)
|
|
|
|
|
+ changedCenters.add(centerOf(add))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ var dirty = false
|
|
|
|
|
+ if (!dst.pos.approxEq(src.pos)) {
|
|
|
|
|
+ dst.pos = deepCopyPoint(src.pos); dirty = true
|
|
|
|
|
+ }
|
|
|
|
|
+ if (dst.entityName != src.entityName) {
|
|
|
|
|
+ dst.entityName = src.entityName; dirty = true
|
|
|
|
|
+ }
|
|
|
|
|
+ if (src.icon != null && dst.icon !== src.icon) {
|
|
|
|
|
+ dst.icon = src.icon; dirty = true
|
|
|
|
|
+ }
|
|
|
|
|
+ // 保持选中
|
|
|
|
|
+ dst.isSelected = dst.isSelected
|
|
|
|
|
+ if (dirty) changedCenters.add(centerOf(dst))
|
|
|
|
|
+ nextList.add(dst)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 删除的点位不再加入 nextList,自然会被移除
|
|
|
|
|
+ pointList.clear()
|
|
|
|
|
+ pointList.addAll(nextList)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (changedCenters.isNotEmpty()) refreshRegionsOrThrottle(changedCenters, changedRadiusPx)
|
|
|
|
|
+ else throttleInvalidate()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 更新图标
|
|
|
|
|
+ */
|
|
|
|
|
+ fun updateIcon(entityId: Long, bmp: Bitmap?) {
|
|
|
|
|
+ synchronized(dataLock) {
|
|
|
|
|
+ val item = pointList.firstOrNull { it.entityId == entityId } ?: return
|
|
|
|
|
+ item.icon = bmp
|
|
|
|
|
+ // 局部刷新就行(pos 是图内坐标)
|
|
|
|
|
+ refreshIfVisible(item.pos, margin = 120f)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private var refreshIfVisibleRunnable: Runnable? = null
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /** 局部刷新(点在屏幕上时) */
|
|
|
|
|
+ fun refreshIfVisible(point: PointF, margin: Float = 0f) {
|
|
|
|
|
+ if (inDraw) {
|
|
|
|
|
+ refreshIfVisibleRunnable?.let {
|
|
|
|
|
+ mapView.removeCallbacks(it)
|
|
|
|
|
+ }
|
|
|
|
|
+ refreshIfVisibleRunnable = Runnable { refreshIfVisible(point, margin) }
|
|
|
|
|
+ mapView.postDelayed(refreshIfVisibleRunnable, 1000)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ val w = mapView.width
|
|
|
|
|
+ val h = mapView.height
|
|
|
|
|
+ if (w == 0 || h == 0) return
|
|
|
|
|
+ val pts = floatArrayOf(point.x, point.y)
|
|
|
|
|
+ mapView.currentMatrix.mapPoints(pts)
|
|
|
|
|
+ val x = pts[0];
|
|
|
|
|
+ val y = pts[1]
|
|
|
|
|
+ if (x + margin >= 0 && x - margin <= w && y + margin >= 0 && y - margin <= h) {
|
|
|
|
|
+ throttleInvalidate()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ===================== 工具 & 刷新 =====================
|
|
|
|
|
+
|
|
|
|
|
+ private fun throttleInvalidate() {
|
|
|
|
|
+ mapView?.postDelayed(invalidateRunnable, FRAME_INTERVAL_MS)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 优先局部刷新;若宿主没有 invalidateRect 方法则回退整图刷新(节流) */
|
|
|
|
|
+ private fun refreshRegionsOrThrottle(centers: List<PointF>, radiusPx: Int) {
|
|
|
|
|
+ val mv = mapView ?: return throttleInvalidate()
|
|
|
|
|
+ var didPartial = false
|
|
|
|
|
+ runCatching {
|
|
|
|
|
+ val m = mv.javaClass.getMethod(
|
|
|
|
|
+ "invalidateRect",
|
|
|
|
|
+ Int::class.java, Int::class.java, Int::class.java, Int::class.java
|
|
|
|
|
+ )
|
|
|
|
|
+ centers.forEach { c ->
|
|
|
|
|
+ val r = radiusPx
|
|
|
|
|
+ val l = (c.x - r).toInt()
|
|
|
|
|
+ val t = (c.y - r).toInt()
|
|
|
|
|
+ val rr = (c.x + r).toInt()
|
|
|
|
|
+ val b = (c.y + r).toInt()
|
|
|
|
|
+ m.invoke(mv, l, t, rr, b)
|
|
|
|
|
+ }
|
|
|
|
|
+ didPartial = true
|
|
|
|
|
+ }.onFailure { /* ignore */ }
|
|
|
|
|
+ if (!didPartial) throttleInvalidate()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun centerOf(p: IsolationPoint): PointF {
|
|
|
|
|
+ if (POS_IS_TOP_LEFT) return PointF(p.pos.x, p.pos.y)
|
|
|
|
|
+ val bw = bgBitmap?.width ?: 0
|
|
|
|
|
+ val bh = bgBitmap?.height ?: 0
|
|
|
|
|
+ return PointF(p.pos.x + bw / 2f, p.pos.y + bh / 2f)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun PointF.approxEq(other: PointF, eps: Float = 0.1f): Boolean {
|
|
|
|
|
+ return kotlin.math.abs(x - other.x) <= eps && kotlin.math.abs(y - other.y) <= eps
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private fun deepCopyPoint(p: PointF) = PointF(p.x, p.y)
|
|
|
|
|
+ private fun deepCopyItem(it: IsolationPoint) = it.copy(pos = deepCopyPoint(it.pos))
|
|
|
|
|
+
|
|
|
|
|
+ // ===================== 你的原有代码 =====================
|
|
|
|
|
+
|
|
|
private val iconCache = object : android.util.LruCache<String, Bitmap>(12 * 1024 * 1024) {
|
|
private val iconCache = object : android.util.LruCache<String, Bitmap>(12 * 1024 * 1024) {
|
|
|
override fun sizeOf(key: String, value: Bitmap) = value.byteCount
|
|
override fun sizeOf(key: String, value: Bitmap) = value.byteCount
|
|
|
}
|
|
}
|
|
@@ -163,13 +353,9 @@ class CustomStationLayer @JvmOverloads constructor(
|
|
|
private fun rotatePoint(
|
|
private fun rotatePoint(
|
|
|
oriX: Float, oriY: Float, desX: Float, desY: Float, rotateDegrees: Float
|
|
oriX: Float, oriY: Float, desX: Float, desY: Float, rotateDegrees: Float
|
|
|
): Pair<Float, Float> {
|
|
): Pair<Float, Float> {
|
|
|
- // 将度数转换为弧度
|
|
|
|
|
val theta = Math.toRadians(rotateDegrees.toDouble())
|
|
val theta = Math.toRadians(rotateDegrees.toDouble())
|
|
|
-
|
|
|
|
|
- // 计算旋转后的坐标
|
|
|
|
|
val newX = (oriX - desX) * cos(theta) - (oriY - desY) * sin(theta) + desX
|
|
val newX = (oriX - desX) * cos(theta) - (oriY - desY) * sin(theta) + desX
|
|
|
val newY = (oriX - desX) * sin(theta) + ((oriY - desY) * cos(theta)) + desY
|
|
val newY = (oriX - desX) * sin(theta) + ((oriY - desY) * cos(theta)) + desY
|
|
|
-
|
|
|
|
|
return Pair(newX.toFloat(), newY.toFloat())
|
|
return Pair(newX.toFloat(), newY.toFloat())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -182,11 +368,12 @@ class CustomStationLayer @JvmOverloads constructor(
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
data class IsolationPoint(
|
|
data class IsolationPoint(
|
|
|
- val pos: PointF,
|
|
|
|
|
- val entityName: String,
|
|
|
|
|
- val icon: Bitmap?,
|
|
|
|
|
|
|
+ var pos: PointF,
|
|
|
|
|
+ var entityName: String,
|
|
|
|
|
+ var icon: Bitmap?,
|
|
|
|
|
+ var iconUrl: String?,
|
|
|
val entityId: Long,
|
|
val entityId: Long,
|
|
|
val pointSerialNumber: String?,
|
|
val pointSerialNumber: String?,
|
|
|
- val isSelected: Boolean,
|
|
|
|
|
|
|
+ var isSelected: Boolean,
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|