| | |
| | | |
| | | drawMower(g2d); |
| | | |
| | | // 绘制导航预览速度(如果正在导航预览) |
| | | if (navigationPreviewSpeed > 0 && mower != null && mower.hasValidPosition()) { |
| | | drawNavigationPreviewSpeed(g2d, scale); |
| | | } |
| | | // 已按需求移除:不在割草机图标上方显示速度 |
| | | |
| | | // 绘制测量模式(如果激活) |
| | | if (measurementModeActive) { |
| | |
| | | g2d.setFont(labelFont); |
| | | FontMetrics metrics = g2d.getFontMetrics(labelFont); |
| | | |
| | | // 计算文字位置(在割草机图标上方) |
| | | // 计算文字位置(在割草机图标正上方,间隔20像素固定) |
| | | int textWidth = metrics.stringWidth(speedText); |
| | | int textHeight = metrics.getHeight(); |
| | | int textX = (int)Math.round(screenPos.x - textWidth / 2.0); |
| | | // 在割草机图标上方,留出一定间距 |
| | | // 图标在世界坐标系中的大小约为 48 * 0.8 / scale 米 |
| | | // 转换为屏幕像素:图标高度(像素)= (48 * 0.8 / scale) * scale = 48 * 0.8 = 38.4 像素 |
| | | double iconSizePixels = 48.0 * 0.8; // 图标在屏幕上的大小(像素) |
| | | int spacing = 8; // 间距(像素) |
| | | int textY = (int)Math.round(screenPos.y - iconSizePixels / 2.0 - spacing - textHeight); |
| | | // 在割草机图标正上方,间隔20像素 |
| | | // 从mower对象获取图标在世界坐标系中的半径,然后转换为屏幕像素 |
| | | double iconWorldRadius = mower.getWorldRadius(scale); |
| | | double iconSizePixels = Double.isNaN(iconWorldRadius) ? 38.4 : (iconWorldRadius * 2.0 * scale); // 图标在屏幕上的大小(像素) |
| | | int spacing = 20; // 间距(像素) |
| | | // 图标顶部位置 = 图标中心Y - 图标高度/2 |
| | | double iconTopY = screenPos.y - iconSizePixels / 2.0; |
| | | // 精确约束:让背景矩形的底边与图标顶部相距固定spacing像素 |
| | | // 背景底边 = textY + metrics.getDescent() + 2(矩形下方内边距) |
| | | // 令 背景底边 = iconTopY - spacing,解得: |
| | | int textY = (int)Math.round(iconTopY - spacing - metrics.getDescent() - 2); |
| | | |
| | | // 绘制文字背景(半透明白色,增强可读性) |
| | | g2d.setColor(new Color(255, 255, 255, 200)); |
| | |
| | | |
| | | // 如果从地块获取到了路径,使用地块的路径;否则使用currentPlannedPath |
| | | List<Point2D.Double> pathToDraw = currentPlannedPath; |
| | | List<Boolean> flags = null; |
| | | if (plannedPathStr != null && !plannedPathStr.trim().isEmpty() && !"-1".equals(plannedPathStr.trim())) { |
| | | // 从地块获取的路径 |
| | | pathToDraw = lujingdraw.parsePlannedPath(plannedPathStr); |
| | | // 优先解析带标注格式 |
| | | lujingdraw.ParsedPath parsed = lujingdraw.parsePlannedPathWithFlags(plannedPathStr); |
| | | pathToDraw = parsed.points; |
| | | flags = parsed.isMowingFlags; |
| | | } |
| | | |
| | | // 调用带地块信息的绘制方法 |
| | | |
| | | // 调用带地块信息的绘制方法(如有标注优先使用) |
| | | if (pathToDraw != null && pathToDraw.size() >= 2) { |
| | | lujingdraw.drawPlannedPath(g2d, pathToDraw, scale, arrowScale, |
| | | boundaryCoords, mowingWidth, safetyDistance, obstaclesCoords, mowingPattern); |
| | | if (flags != null && flags.size() == pathToDraw.size() - 1) { |
| | | lujingdraw.drawPlannedPath(g2d, pathToDraw, flags, scale, arrowScale, |
| | | boundaryCoords, mowingWidth, safetyDistance, obstaclesCoords, mowingPattern); |
| | | } else { |
| | | lujingdraw.drawPlannedPath(g2d, pathToDraw, scale, arrowScale, |
| | | boundaryCoords, mowingWidth, safetyDistance, obstaclesCoords, mowingPattern); |
| | | } |
| | | } |
| | | } |
| | | |