From 7881cef5c3dcea8e6037101db2c3eeb2fd3ba5da Mon Sep 17 00:00:00 2001
From: 826220679@qq.com <826220679@qq.com>
Date: 星期六, 27 十二月 2025 23:42:36 +0800
Subject: [PATCH] 1211
---
src/gecaoji/lujingdraw.java | 210 ++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 192 insertions(+), 18 deletions(-)
diff --git a/src/gecaoji/lujingdraw.java b/src/gecaoji/lujingdraw.java
index 5d54008..4d14fda 100644
--- a/src/gecaoji/lujingdraw.java
+++ b/src/gecaoji/lujingdraw.java
@@ -29,6 +29,16 @@
private lujingdraw() { // 绉佹湁鏋勯�犻槻姝㈠疄渚嬪寲
} // 绌哄疄鐜�
+ // 瑙f瀽缁撴灉锛氬寘鍚偣涓庢瘡涓浉閭绘鐨勪綔涓氭爣娉紙size=points.size()-1锛�
+ public static final class ParsedPath {
+ public final List<Point2D.Double> points;
+ public final List<Boolean> isMowingFlags; // 姣忔瀵瑰簲鏍囨敞锛歵rue=浣滀笟娈碉紝false=鏃呰娈�
+ public ParsedPath(List<Point2D.Double> points, List<Boolean> flags) {
+ this.points = points;
+ this.isMowingFlags = flags;
+ }
+ }
+
/** // 鏂囨。娉ㄩ噴寮�濮�
* Parse the planned path string (semicolon-separated "x,y" pairs) into a list of points in meters. // 鏂规硶璇存槑
*/ // 鏂囨。娉ㄩ噴缁撴潫
@@ -76,6 +86,58 @@
return points; // 杩斿洖缁撴灉
} // 鏂规硶缁撴潫
+ /**
+ * 瑙f瀽甯︽鏍囨敞鐨勮矾寰勫瓧绗︿覆銆傛牸寮忥細绗竴涓偣 "x,y"锛涘悗缁偣鍙负 "x,y,M" 鎴� "x,y,T"锛屽垎鍒〃绀轰笂涓�鐐硅嚦褰撳墠鐐逛负浣滀笟娈垫垨鏃呰娈点��
+ * 鍏煎鏃ф牸寮忥紙鏃犵涓夊瓧娈碉級锛屾鏃� flags 杩斿洖 null銆�
+ */
+ public static ParsedPath parsePlannedPathWithFlags(String plannedPath) {
+ List<Point2D.Double> points = new ArrayList<>();
+ List<Boolean> flags = new ArrayList<>();
+ if (plannedPath == null) {
+ return new ParsedPath(points, null);
+ }
+ String normalized = plannedPath.trim();
+ if (normalized.isEmpty() || "-1".equals(normalized)) {
+ return new ParsedPath(points, null);
+ }
+ int commentIndex = normalized.indexOf('#');
+ if (commentIndex >= 0) {
+ normalized = normalized.substring(0, commentIndex).trim();
+ }
+ if (normalized.isEmpty()) {
+ return new ParsedPath(points, null);
+ }
+ String[] segments = normalized.split(";");
+ boolean sawTypeField = false;
+ for (int i = 0; i < segments.length; i++) {
+ String segment = segments[i];
+ if (segment == null) continue;
+ String trimmed = segment.trim();
+ if (trimmed.isEmpty()) continue;
+ String[] parts = trimmed.split(",");
+ if (parts.length < 2) continue;
+ try {
+ double x = Double.parseDouble(parts[0].trim());
+ double y = Double.parseDouble(parts[1].trim());
+ points.add(new Point2D.Double(x, y));
+ if (i > 0) {
+ // 绗竴涓偣鏃犳爣娉紱鍚庣画鑻ュ瓨鍦ㄧ涓夊瓧娈靛垯瑙f瀽
+ if (parts.length >= 3) {
+ String t = parts[2].trim();
+ boolean isMowing = t.equalsIgnoreCase("M") || t.equalsIgnoreCase("m") || t.equals("1") || t.equalsIgnoreCase("WORK");
+ flags.add(isMowing);
+ sawTypeField = true;
+ } else {
+ flags.add(Boolean.TRUE); // 榛樿浣滀笟娈碉紝渚夸簬鍚戝悗鍏煎
+ }
+ }
+ } catch (NumberFormatException ignored) {
+ // 蹇界暐闈炴硶鍧愭爣
+ }
+ }
+ return new ParsedPath(points, sawTypeField ? flags : null);
+ }
+
/** // 鏂囨。娉ㄩ噴寮�濮�
* Draw the planned mowing path. // 缁樺埗璺緞
*/ // 鏂囨。娉ㄩ噴缁撴潫
@@ -91,7 +153,7 @@
* @param obstaclesCoords 闅滅鐗╁潗鏍囧瓧绗︿覆
* @param mowingPattern 鍓茶崏妯″紡锛�"parallel"鎴�"spiral"锛�
*/ // 鏂囨。娉ㄩ噴缁撴潫
- public static void drawPlannedPath(Graphics2D g2d, List<Point2D.Double> path, double scale, double arrowScale,
+ public static void drawPlannedPath(Graphics2D g2d, List<Point2D.Double> path, double scale, double arrowScale,
String boundaryCoords, String mowingWidth, String safetyDistance, String obstaclesCoords, String mowingPattern) { // 缁樺埗涓绘柟娉曪紙閲嶈浇锛�
if (path == null || path.size() < 2) { // 鍒ゅ畾鐐规暟
return; // 鏁版嵁涓嶈冻鐩存帴杩斿洖
@@ -105,32 +167,144 @@
drawInnerBoundary(g2d, boundaryCoords, safetyDistance, scale);
}
- // 2. 鐩存帴缁樺埗璺緞锛堜笉鍐嶉噸鏂扮敓鎴愶級
- 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缁撴潫
-
- g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); // 璁剧疆鍦嗗ご鍦嗚鎻忚竟
- g2d.setColor(MOWING_PATH_COLOR); // 璁剧疆浣滀笟璺緞棰滆壊锛堟彁棣欑孩70%閫忔槑搴︼級
- g2d.draw(polyline); // 缁樺埗鎶樼嚎
+ // 2. 鎸夋缁樺埗璺緞锛堥�愭缁樺埗锛岄伩鍏嶅皢涓嶇浉閭绘棣栧熬杩炴垚瓒婄晫鐩寸嚎锛�
+ org.locationtech.jts.geom.Geometry innerBoundaryGeom = buildInnerBoundaryGeom(boundaryCoords, safetyDistance);
+ for (int i = 1; i < path.size(); i++) {
+ Point2D.Double a = path.get(i - 1);
+ Point2D.Double b = path.get(i);
+
+ Path2D segment = new Path2D.Double();
+ segment.moveTo(a.x, a.y);
+ segment.lineTo(b.x, b.y);
+
+ boolean inside = true; // 榛樿鎸変綔涓氭缁樺埗
+ if (innerBoundaryGeom != null) {
+ inside = isSegmentInsideInnerBoundary(innerBoundaryGeom, a, b);
+ }
+
+ if (inside) {
+ // 浣滀笟娈碉細瀹炵嚎 + 鎻愰绾�
+ g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ g2d.setColor(MOWING_PATH_COLOR);
+ } else {
+ // 鏃呰娈碉紙鎴栨部杈圭晫娈碉級锛氳櫄绾� + 钃濊壊
+ g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, DASH_PATTERN, 0.0f));
+ g2d.setColor(TRAVEL_PATH_COLOR);
+ }
+ g2d.draw(segment);
+ }
Point2D.Double start = path.get(0); // 璧风偣
- Point2D.Double second = path.get(1); // 绗簩涓偣
+ Point2D.Double second = path.size() > 1 ? path.get(1) : path.get(0); // 绗簩涓偣
Point2D.Double end = path.get(path.size() - 1); // 缁堢偣
- Point2D.Double prev = path.get(path.size() - 2); // 鍊掓暟绗簩涓偣
+ Point2D.Double prev = path.size() > 1 ? path.get(path.size() - 2) : path.get(path.size() - 1); // 鍊掓暟绗簩涓偣
drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale); // 缁樺埗璧风偣绠ご
drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale); // 缁樺埗缁堢偣绠ご
g2d.setStroke(previous); // 鎭㈠鍘熸弿杈�
} // 鏂规硶缁撴潫
+
+ /**
+ * 浣跨敤绠楁硶绔彁渚涚殑娈垫爣娉ㄧ粯鍒惰矾寰勶紙浼樺厛浣跨敤鏍囨敞锛屼笉鍋氬唴缂╄竟鐣屾帹鏂級銆�
+ * flags.size() 蹇呴』涓� path.size()-1銆�
+ */
+ public static void drawPlannedPath(Graphics2D g2d, List<Point2D.Double> path, List<Boolean> flags,
+ double scale, double arrowScale,
+ String boundaryCoords, String mowingWidth, String safetyDistance,
+ String obstaclesCoords, String mowingPattern) {
+ if (path == null || path.size() < 2 || flags == null || flags.size() != path.size() - 1) {
+ // 鍥為��鍒版帹鏂増鏈�
+ drawPlannedPath(g2d, path, scale, arrowScale, boundaryCoords, mowingWidth, safetyDistance, obstaclesCoords, mowingPattern);
+ return;
+ }
+
+ Stroke previous = g2d.getStroke();
+ float strokeWidth = (float) (2.5 / Math.max(0.5, scale));
+
+ // 1. 缁樺埗鍐呯缉杈圭晫锛堝洿杈癸級
+ if (boundaryCoords != null && !boundaryCoords.trim().isEmpty() && !"-1".equals(boundaryCoords.trim())) {
+ drawInnerBoundary(g2d, boundaryCoords, safetyDistance, scale);
+ }
+
+ // 2. 鎸夋缁樺埗锛屽畬鍏ㄩ伒寰畻娉曠鏍囨敞
+ for (int i = 1; i < path.size(); i++) {
+ Point2D.Double a = path.get(i - 1);
+ Point2D.Double b = path.get(i);
+ boolean isMowing = Boolean.TRUE.equals(flags.get(i - 1));
+
+ Path2D segment = new Path2D.Double();
+ segment.moveTo(a.x, a.y);
+ segment.lineTo(b.x, b.y);
+
+ if (isMowing) {
+ g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ g2d.setColor(MOWING_PATH_COLOR);
+ } else {
+ g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, DASH_PATTERN, 0.0f));
+ g2d.setColor(TRAVEL_PATH_COLOR);
+ }
+ g2d.draw(segment);
+ }
+
+ Point2D.Double start = path.get(0);
+ Point2D.Double second = path.size() > 1 ? path.get(1) : path.get(0);
+ Point2D.Double end = path.get(path.size() - 1);
+ Point2D.Double prev = path.size() > 1 ? path.get(path.size() - 2) : path.get(path.size() - 1);
+
+ drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale);
+ drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale);
+
+ g2d.setStroke(previous);
+ }
+
+ // 鏋勫缓鍐呯缉杈圭晫鍑犱綍浣擄紝鐢ㄤ簬瀹夊叏妫�娴嬩笌鍒嗘缁樺埗
+ private static org.locationtech.jts.geom.Geometry buildInnerBoundaryGeom(String boundaryCoords, String safetyDistanceStr) {
+ try {
+ if (boundaryCoords == null || boundaryCoords.trim().isEmpty() || "-1".equals(boundaryCoords.trim())) {
+ return null;
+ }
+ List<Coordinate> boundary = parseCoordinates(boundaryCoords);
+ if (boundary.size() < 4) {
+ return null; // 杈圭晫鐐逛笉瓒�
+ }
+ double safetyDistance = 0.2; // 榛樿0.2绫�
+ if (safetyDistanceStr != null && !safetyDistanceStr.trim().isEmpty()) {
+ try {
+ safetyDistance = Double.parseDouble(safetyDistanceStr.trim());
+ } catch (NumberFormatException ignored) {}
+ }
+ GeometryFactory gf = new GeometryFactory();
+ Polygon poly = gf.createPolygon(gf.createLinearRing(boundary.toArray(new Coordinate[0])));
+ if (!poly.isValid()) {
+ poly = (Polygon) poly.buffer(0);
+ }
+ org.locationtech.jts.geom.Geometry innerBoundary = poly.buffer(-safetyDistance);
+ if (innerBoundary == null || innerBoundary.isEmpty()) {
+ return null;
+ }
+ return innerBoundary;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ // 鍒ゆ柇涓�娈垫槸鍚﹀湪鍐呯缉杈圭晫鍐呮垨娌胯竟鐣岋紙涓嶈秺鐣岋級
+ private static boolean isSegmentInsideInnerBoundary(org.locationtech.jts.geom.Geometry innerBoundary, Point2D.Double a, Point2D.Double b) {
+ try {
+ GeometryFactory gf = new GeometryFactory();
+ Coordinate[] seg = new Coordinate[] { new Coordinate(a.x, a.y), new Coordinate(b.x, b.y) };
+ org.locationtech.jts.geom.LineString ls = gf.createLineString(seg);
+ // 鍖呭惈鎴栬鐩栧潎瑙嗕负鍚堟硶锛屼笉涓庡唴杈圭晫澶栭儴浜ゅ弶
+ if (innerBoundary.contains(ls) || innerBoundary.covers(ls)) {
+ return true;
+ }
+ // 濡備笌鍐呰竟鐣岃竟鐣岀浉浜わ紝瑙嗕负涓嶅湪鍐呴儴锛堢敤浜庢敼鍙樻牱寮忓苟鏂紑杩炵嚎锛�
+ return !ls.crosses(innerBoundary.getBoundary());
+ } catch (Exception e) {
+ return true; // 妫�娴嬪紓甯告椂锛屾寜浣滀笟娈靛鐞嗕互涓嶄腑鏂粯鍒�
+ }
+ }
/** // 鏂囨。娉ㄩ噴寮�濮�
* 缁樺埗鍐呯缉杈圭晫锛堝洿杈癸級- 椹皵鏂豢鑹�
--
Gitblit v1.10.0