package gecaoji; // 包声明 import java.awt.BasicStroke; // 引入基础描边类 import java.awt.Color; // 引入颜色类 import java.awt.Graphics2D; // 引入2D图形上下文 import java.awt.Stroke; // 引入描边接口 import java.awt.geom.Path2D; // 引入路径绘制类 import java.awt.geom.Point2D; // 引入二维点类 import java.util.ArrayList; // 引入动态数组 import java.util.List; // 引入列表接口 /** // 文档注释开头 * Helper class to parse and render planned mowing paths. // 辅助类说明 */ // 文档注释结尾 public final class lujingdraw { // 类定义,防止继承 private static final Color PATH_COLOR = new Color(255, 0, 0, 220); // 路径颜色(红色半透明) private static final Color START_POINT_COLOR = new Color(0, 0, 0, 220); // 起点箭头颜色 private static final Color END_POINT_COLOR = new Color(0, 0, 0, 220); // 终点箭头颜色 private lujingdraw() { // 私有构造防止实例化 } // 空实现 /** // 文档注释开始 * Parse the planned path string (semicolon-separated "x,y" pairs) into a list of points in meters. // 方法说明 */ // 文档注释结束 public static List parsePlannedPath(String plannedPath) { // 解析路径字符串 List points = new ArrayList<>(); // 存放解析后的点集 if (plannedPath == null) { // 判空 return points; // 返回空集合 } // if结束 String normalized = plannedPath.trim(); // 去除首尾空格 if (normalized.isEmpty() || "-1".equals(normalized)) { // 无效判断 return points; // 返回空集合 } // if结束 int commentIndex = normalized.indexOf('#'); // 查找注释符号 if (commentIndex >= 0) { // 找到注释 normalized = normalized.substring(0, commentIndex).trim(); // 截取注释前内容 } // if结束 if (normalized.isEmpty()) { // 再次判空 return points; // 返回空集合 } // if结束 String[] segments = normalized.split(";"); // 切分各段 for (String segment : segments) { // 遍历每段 if (segment == null) { // 判空 continue; // 跳过 } // if结束 String trimmed = segment.trim(); // 去除空格 if (trimmed.isEmpty()) { // 空段 continue; // 跳过 } // if结束 String[] parts = trimmed.split(","); // 切分坐标 if (parts.length < 2) { // 检查长度 continue; // 跳过 } // if结束 try { // 数值解析 double x = Double.parseDouble(parts[0].trim()); // 解析X坐标 double y = Double.parseDouble(parts[1].trim()); // 解析Y坐标 points.add(new Point2D.Double(x, y)); // 加入点集 } catch (NumberFormatException ignored) { // 捕获格式异常 // Ignore malformed coordinates // 忽略非法坐标 } // try结束 } // for结束 return points; // 返回结果 } // 方法结束 /** // 文档注释开始 * Draw the planned mowing path. // 绘制路径 */ // 文档注释结束 public static void drawPlannedPath(Graphics2D g2d, List path, double scale, double arrowScale) { // 绘制主方法 if (path == null || path.size() < 2) { // 判定点数 return; // 数据不足直接返回 } // if结束 Path2D polyline = new Path2D.Double(); // 创建折线 boolean move = true; // 首段标记 for (Point2D.Double point : path) { // 遍历点集 if (move) { // 第一段 polyline.moveTo(point.x, point.y); // 移动到首点 move = false; // 更新标记 } else { // 后续段 polyline.lineTo(point.x, point.y); // 连线到下一点 } // if结束 } // for结束 Stroke previous = g2d.getStroke(); // 保存原描边 float strokeWidth = (float) (2.5 / Math.max(0.5, scale)); // 根据缩放计算线宽 g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // 设置圆头圆角描边 g2d.setColor(PATH_COLOR); // 设置线路颜色 g2d.draw(polyline); // 绘制折线 Point2D.Double start = path.get(0); // 起点 Point2D.Double second = path.get(1); // 第二个点 Point2D.Double end = path.get(path.size() - 1); // 终点 Point2D.Double prev = path.get(path.size() - 2); // 倒数第二个点 drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale); // 绘制起点箭头 drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale); // 绘制终点箭头 g2d.setStroke(previous); // 恢复原描边 } // 方法结束 private static void drawArrowMarker(Graphics2D g2d, Point2D.Double from, Point2D.Double to, Color color, double scale, double sizeScale) { // 绘制箭头辅助 if (from == null || to == null) { // 判空 return; // 数据不足返回 } // if结束 double dx = to.x - from.x; // 计算X增量 double dy = to.y - from.y; // 计算Y增量 double length = Math.hypot(dx, dy); // 计算向量长度 if (length == 0) { // 防止零长度 return; // 无方向返回 } // if结束 double arrowLength = Math.max(2.5, 5.5 / Math.max(0.5, scale)); // 计算箭头长度 double clampedScale = sizeScale > 0 ? sizeScale : 1.0; // 防止非法缩放 arrowLength *= 0.25 * clampedScale; // 缩小箭头至原来的一半 double arrowWidth = arrowLength * 0.45; // 计算箭头宽度 double ux = dx / length; // 单位向量X double uy = dy / length; // 单位向量Y double tipX = to.x; // 箭头尖端X double tipY = to.y; // 箭头尖端Y double baseX = tipX - ux * arrowLength; // 箭头底部X double baseY = tipY - uy * arrowLength; // 箭头底部Y double perpX = -uy; // 垂直向量X double perpY = ux; // 垂直向量Y double leftX = baseX + perpX * arrowWidth * 0.5; // 左侧点X double leftY = baseY + perpY * arrowWidth * 0.5; // 左侧点Y double rightX = baseX - perpX * arrowWidth * 0.5; // 右侧点X double rightY = baseY - perpY * arrowWidth * 0.5; // 右侧点Y Path2D arrow = new Path2D.Double(); // 创建箭头路径 arrow.moveTo(tipX, tipY); // 起点移动到尖端 arrow.lineTo(leftX, leftY); // 连到左侧 arrow.lineTo(rightX, rightY); // 连到右侧 arrow.closePath(); // 闭合形成三角形 g2d.setColor(color); // 设置颜色 g2d.fill(arrow); // 填充箭头 } // 方法结束 } // 类结束