From f38ba0a0bf5cbe96c9300247923f6979a5059529 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期二, 23 十二月 2025 19:09:07 +0800
Subject: [PATCH] 解决了异形无障碍物边界路径bug,另外优化了首页显示效果
---
src/gecaoji/lujingdraw.java | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 270 insertions(+), 22 deletions(-)
diff --git a/src/gecaoji/lujingdraw.java b/src/gecaoji/lujingdraw.java
index 813472d..95ed85a 100644
--- a/src/gecaoji/lujingdraw.java
+++ b/src/gecaoji/lujingdraw.java
@@ -8,12 +8,23 @@
import java.awt.geom.Point2D; // 寮曞叆浜岀淮鐐圭被
import java.util.ArrayList; // 寮曞叆鍔ㄦ�佹暟缁�
import java.util.List; // 寮曞叆鍒楄〃鎺ュ彛
+import lujing.Lunjingguihua; // 寮曞叆璺緞瑙勫垝绫�
+import org.locationtech.jts.geom.Coordinate; // 寮曞叆鍧愭爣绫�
+import org.locationtech.jts.geom.GeometryFactory; // 寮曞叆鍑犱綍宸ュ巶绫�
+import org.locationtech.jts.geom.Polygon; // 寮曞叆澶氳竟褰㈢被
/** // 鏂囨。娉ㄩ噴寮�澶�
* 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); // 璺緞棰滆壊锛堢孩鑹插崐閫忔槑锛�
+ // 椹皵鏂豢鑹� (RGB: 102, 205, 170) - 鐢ㄤ簬鍐呯缉杈圭晫锛堝洿杈癸級
+ private static final Color INNER_BOUNDARY_COLOR = new Color(102, 205, 170);
+ // 鎻愰绾㈤�忔槑搴�70% (RGB: 210, 4, 45, alpha: 178) - 鐢ㄤ簬鍓茶崏浣滀笟璺緞
+ private static final Color MOWING_PATH_COLOR = new Color(210, 4, 45, 178);
+ // 钃濊壊 - 鐢ㄤ簬闈炰綔涓氱Щ鍔ㄨ矾寰�
+ private static final Color TRAVEL_PATH_COLOR = new Color(0, 0, 255);
+ // 铏氱嚎鏍峰紡 - 鐢ㄤ簬闈炰綔涓氱Щ鍔ㄨ矾寰�
+ private static final float[] DASH_PATTERN = {10.0f, 5.0f};
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); // 缁堢偣绠ご棰滆壊
@@ -71,37 +82,274 @@
* Draw the planned mowing path. // 缁樺埗璺緞
*/ // 鏂囨。娉ㄩ噴缁撴潫
public static void drawPlannedPath(Graphics2D g2d, List<Point2D.Double> path, double scale, double arrowScale) { // 缁樺埗涓绘柟娉�
+ drawPlannedPath(g2d, path, scale, arrowScale, null, null, null, null, null); // 璋冪敤閲嶈浇鏂规硶
+ } // 鏂规硶缁撴潫
+
+ /** // 鏂囨。娉ㄩ噴寮�濮�
+ * Draw the planned mowing path with segment information. // 缁樺埗璺緞锛堝甫娈典俊鎭級
+ * @param boundaryCoords 鍦板潡杈圭晫鍧愭爣瀛楃涓诧紝鐢ㄤ簬缁樺埗鍐呯缉杈圭晫
+ * @param mowingWidth 鍓茶崏瀹藉害锛堢背锛夛紝瀛楃涓叉牸寮�
+ * @param safetyDistance 瀹夊叏璺濈锛堢背锛夛紝瀛楃涓叉牸寮�
+ * @param obstaclesCoords 闅滅鐗╁潗鏍囧瓧绗︿覆
+ * @param mowingPattern 鍓茶崏妯″紡锛�"parallel"鎴�"spiral"锛�
+ */ // 鏂囨。娉ㄩ噴缁撴潫
+ 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; // 鏁版嵁涓嶈冻鐩存帴杩斿洖
} // 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); // 缁樺埗鎶樼嚎
+
+ // 1. 缁樺埗鍐呯缉杈圭晫锛堝洿杈癸級- 椹皵鏂豢鑹�
+ if (boundaryCoords != null && !boundaryCoords.trim().isEmpty() && !"-1".equals(boundaryCoords.trim())) {
+ drawInnerBoundary(g2d, boundaryCoords, safetyDistance, scale);
+ }
+
+ // 2. 灏濊瘯閲嶆柊鐢熸垚璺緞娈典互鍖哄垎浣滀笟璺緞鍜岀Щ鍔ㄨ矾寰�
+ List<Lunjingguihua.PathSegment> segments = null;
+ if (boundaryCoords != null && mowingWidth != null) {
+ try {
+ // 瑙f瀽鍓茶崏妯″紡
+ String mode = "parallel"; // 榛樿骞宠妯″紡
+ if (mowingPattern != null && !mowingPattern.trim().isEmpty()) {
+ String pattern = mowingPattern.trim().toLowerCase();
+ if ("1".equals(pattern) || "spiral".equals(pattern) || "铻烘棆寮�".equals(pattern) || "铻烘棆".equals(pattern)) {
+ mode = "spiral";
+ } else if ("parallel".equals(pattern) || "骞宠绾�".equals(pattern) || "骞宠".equals(pattern)) {
+ mode = "parallel";
+ }
+ }
+ segments = Lunjingguihua.generatePathSegments(
+ boundaryCoords,
+ obstaclesCoords != null ? obstaclesCoords : "",
+ mowingWidth,
+ safetyDistance,
+ mode
+ );
+ } catch (Exception e) {
+ // 濡傛灉閲嶆柊鐢熸垚澶辫触锛屼娇鐢ㄧ畝鍗曠粯鍒舵柟寮�
+ segments = null;
+ }
+ }
+
+ // 3. 鏍规嵁鏄惁鏈夋淇℃伅閫夋嫨涓嶅悓鐨勭粯鍒舵柟寮�
+ if (segments != null && !segments.isEmpty()) {
+ // 鏈夋淇℃伅锛氬垎鍒粯鍒朵綔涓氳矾寰勫拰绉诲姩璺緞
+ drawPathSegments(g2d, segments, scale, arrowScale);
+ } else {
+ // 鏃犳淇℃伅锛氫娇鐢ㄧ畝鍗曠粯鍒舵柟寮忥紙鎵�鏈夎矾寰勪娇鐢ㄤ綔涓氳矾寰勯鑹诧級
+ 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); // 缁樺埗鎶樼嚎
+
+ 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); // 鍊掓暟绗簩涓偣
- 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); // 缁樺埗缁堢偣绠ご
+ drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale); // 缁樺埗璧风偣绠ご
+ drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale); // 缁樺埗缁堢偣绠ご
+ }
g2d.setStroke(previous); // 鎭㈠鍘熸弿杈�
} // 鏂规硶缁撴潫
+
+ /** // 鏂囨。娉ㄩ噴寮�濮�
+ * 缁樺埗鍐呯缉杈圭晫锛堝洿杈癸級- 椹皵鏂豢鑹�
+ */ // 鏂囨。娉ㄩ噴缁撴潫
+ private static void drawInnerBoundary(Graphics2D g2d, String boundaryCoords, String safetyDistanceStr, double scale) {
+ try {
+ List<Coordinate> boundary = Lunjingguihua.parseCoordinates(boundaryCoords);
+ if (boundary.size() < 4) {
+ return; // 杈圭晫鐐逛笉瓒�
+ }
+
+ // 瑙f瀽瀹夊叏璺濈
+ double safetyDistance = 0.2; // 榛樿0.2绫�
+ if (safetyDistanceStr != null && !safetyDistanceStr.trim().isEmpty()) {
+ try {
+ safetyDistance = Double.parseDouble(safetyDistanceStr.trim());
+ } catch (NumberFormatException e) {
+ // 浣跨敤榛樿鍊�
+ }
+ }
+
+ // 鍒涘缓澶氳竟褰㈠苟鍐呯缉
+ 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;
+ }
+
+ // 缁樺埗鍐呯缉杈圭晫
+ g2d.setColor(INNER_BOUNDARY_COLOR); // 椹皵鏂豢鑹�
+ float strokeWidth = (float) (3.0 / Math.max(0.5, scale));
+ g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+
+ // 灏咼TS鍑犱綍浣撹浆鎹负Path2D骞剁粯鍒�
+ Path2D.Double innerPath = geometryToPath2D(innerBoundary);
+ if (innerPath != null) {
+ g2d.draw(innerPath);
+ }
+ } catch (Exception e) {
+ // 缁樺埗澶辫触鏃跺拷鐣ワ紝涓嶅奖鍝嶅叾浠栬矾寰勭粯鍒�
+ }
+ } // 鏂规硶缁撴潫
+
+ /** // 鏂囨。娉ㄩ噴寮�濮�
+ * 灏咼TS鍑犱綍浣撹浆鎹负Path2D
+ */ // 鏂囨。娉ㄩ噴缁撴潫
+ private static Path2D.Double geometryToPath2D(org.locationtech.jts.geom.Geometry geom) {
+ if (geom == null) {
+ return null;
+ }
+ Path2D.Double path = new Path2D.Double();
+ if (geom instanceof Polygon) {
+ Polygon poly = (Polygon) geom;
+ addRingToPath(path, poly.getExteriorRing().getCoordinates(), true);
+ for (int i = 0; i < poly.getNumInteriorRing(); i++) {
+ addRingToPath(path, poly.getInteriorRingN(i).getCoordinates(), true);
+ }
+ } else if (geom instanceof org.locationtech.jts.geom.MultiPolygon) {
+ org.locationtech.jts.geom.MultiPolygon mp = (org.locationtech.jts.geom.MultiPolygon) geom;
+ for (int i = 0; i < mp.getNumGeometries(); i++) {
+ Polygon poly = (Polygon) mp.getGeometryN(i);
+ addRingToPath(path, poly.getExteriorRing().getCoordinates(), true);
+ for (int j = 0; j < poly.getNumInteriorRing(); j++) {
+ addRingToPath(path, poly.getInteriorRingN(j).getCoordinates(), true);
+ }
+ }
+ }
+ return path;
+ } // 鏂规硶缁撴潫
+
+ /** // 鏂囨。娉ㄩ噴寮�濮�
+ * 灏嗗潗鏍囩幆娣诲姞鍒癙ath2D
+ */ // 鏂囨。娉ㄩ噴缁撴潫
+ private static void addRingToPath(Path2D.Double path, Coordinate[] coords, boolean close) {
+ if (coords == null || coords.length < 2) {
+ return;
+ }
+ path.moveTo(coords[0].x, coords[0].y);
+ for (int i = 1; i < coords.length; i++) {
+ path.lineTo(coords[i].x, coords[i].y);
+ }
+ if (close) {
+ path.closePath();
+ }
+ } // 鏂规硶缁撴潫
+
+ /** // 鏂囨。娉ㄩ噴寮�濮�
+ * 缁樺埗璺緞娈碉紙鍖哄垎浣滀笟璺緞鍜岀Щ鍔ㄨ矾寰勶級
+ */ // 鏂囨。娉ㄩ噴缁撴潫
+ private static void drawPathSegments(Graphics2D g2d, List<Lunjingguihua.PathSegment> segments, double scale, double arrowScale) {
+ if (segments == null || segments.isEmpty()) {
+ return;
+ }
+
+ float strokeWidth = (float) (2.5 / Math.max(0.5, scale));
+ Stroke previous = g2d.getStroke();
+
+ // 鍒嗗埆缁樺埗浣滀笟璺緞鍜岀Щ鍔ㄨ矾寰�
+ Path2D.Double mowingPath = new Path2D.Double();
+ Path2D.Double travelPath = new Path2D.Double();
+ boolean mowingStarted = false;
+ boolean travelStarted = false;
+
+ Coordinate lastMowingEnd = null;
+ Coordinate lastTravelEnd = null;
+
+ for (Lunjingguihua.PathSegment seg : segments) {
+ if (seg == null || seg.start == null || seg.end == null) {
+ continue;
+ }
+
+ if (seg.isMowing) {
+ // 浣滀笟璺緞 - 鎻愰绾�70%閫忔槑搴�
+ if (!mowingStarted || lastMowingEnd == null || !equals2D(lastMowingEnd, seg.start)) {
+ mowingPath.moveTo(seg.start.x, seg.start.y);
+ mowingStarted = true;
+ }
+ mowingPath.lineTo(seg.end.x, seg.end.y);
+ lastMowingEnd = seg.end;
+ } else {
+ // 绉诲姩璺緞 - 钃濊壊铏氱嚎
+ if (!travelStarted || lastTravelEnd == null || !equals2D(lastTravelEnd, seg.start)) {
+ travelPath.moveTo(seg.start.x, seg.start.y);
+ travelStarted = true;
+ }
+ travelPath.lineTo(seg.end.x, seg.end.y);
+ lastTravelEnd = seg.end;
+ }
+ }
+
+ // 缁樺埗浣滀笟璺緞
+ if (mowingStarted) {
+ g2d.setColor(MOWING_PATH_COLOR); // 鎻愰绾�70%閫忔槑搴�
+ g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+ g2d.draw(mowingPath);
+ }
+
+ // 缁樺埗绉诲姩璺緞锛堣櫄绾匡級
+ if (travelStarted) {
+ g2d.setColor(TRAVEL_PATH_COLOR); // 钃濊壊
+ g2d.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 0, DASH_PATTERN, 0));
+ g2d.draw(travelPath);
+ }
+
+ // 缁樺埗璧风偣鍜岀粓鐐圭澶�
+ if (!segments.isEmpty()) {
+ Lunjingguihua.PathSegment firstSeg = segments.get(0);
+ if (firstSeg != null && firstSeg.start != null && segments.size() > 1) {
+ Lunjingguihua.PathSegment secondSeg = segments.get(1);
+ if (secondSeg != null && secondSeg.start != null) {
+ Point2D.Double start = new Point2D.Double(firstSeg.start.x, firstSeg.start.y);
+ Point2D.Double second = new Point2D.Double(secondSeg.start.x, secondSeg.start.y);
+ drawArrowMarker(g2d, start, second, START_POINT_COLOR, scale, arrowScale);
+ }
+ }
+
+ Lunjingguihua.PathSegment lastSeg = segments.get(segments.size() - 1);
+ if (lastSeg != null && lastSeg.end != null && segments.size() > 1) {
+ Lunjingguihua.PathSegment prevSeg = segments.get(segments.size() - 2);
+ if (prevSeg != null && prevSeg.end != null) {
+ Point2D.Double prev = new Point2D.Double(prevSeg.end.x, prevSeg.end.y);
+ Point2D.Double end = new Point2D.Double(lastSeg.end.x, lastSeg.end.y);
+ drawArrowMarker(g2d, prev, end, END_POINT_COLOR, scale, arrowScale);
+ }
+ }
+ }
+
+ g2d.setStroke(previous);
+ } // 鏂规硶缁撴潫
+
+ /** // 鏂囨。娉ㄩ噴寮�濮�
+ * 姣旇緝涓や釜鍧愭爣鏄惁鐩稿悓锛堝宸級
+ */ // 鏂囨。娉ㄩ噴缁撴潫
+ private static boolean equals2D(Coordinate a, Coordinate b) {
+ if (a == b) return true;
+ if (a == null || b == null) return false;
+ return a.distance(b) < 1e-4;
+ } // 鏂规硶缁撴潫
private static void drawArrowMarker(Graphics2D g2d, Point2D.Double from, Point2D.Double to, Color color, double scale, double sizeScale) { // 缁樺埗绠ご杈呭姪
if (from == null || to == null) { // 鍒ょ┖
--
Gitblit v1.10.0