From f38ba0a0bf5cbe96c9300247923f6979a5059529 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期二, 23 十二月 2025 19:09:07 +0800
Subject: [PATCH] 解决了异形无障碍物边界路径bug,另外优化了首页显示效果
---
src/lujing/YixinglujingNoObstacle.java | 122 +++++++++++++++++++++-------------------
1 files changed, 64 insertions(+), 58 deletions(-)
diff --git a/src/lujing/YixinglujingNoObstacle.java b/src/lujing/YixinglujingNoObstacle.java
index 67a5bb0..1672ccc 100644
--- a/src/lujing/YixinglujingNoObstacle.java
+++ b/src/lujing/YixinglujingNoObstacle.java
@@ -3,8 +3,8 @@
import java.util.*;
/**
- * 寮傚舰鑽夊湴璺緞瑙勫垝 - 鍥磋竟+鍏ㄥ眬鎵弿鐗� V4.1
- * 浼樺寲锛氬洿杈圭粓鐐逛笌寮撳瓧褰㈣捣鐐硅嚜鍔ㄥ榻愶紝瀹炵幇鏃犵紳鍒囨崲锛岀‘淇濊矾寰勪笉瓒婄晫
+ * 寮傚舰鑽夊湴璺緞瑙勫垝 - 鍑瑰杈瑰舰鍏煎浼樺寲鐗� V5.0
+ * 淇锛氳В鍐冲嚬澶氳竟褰㈡壂鎻忕嚎璺ㄨ秺杈圭晫鐨勯棶棰橈紝浼樺寲璺緞瀵归綈
*/
public class YixinglujingNoObstacle {
@@ -15,31 +15,33 @@
double mowWidth = Double.parseDouble(widthStr);
double safeMargin = Double.parseDouble(marginStr);
- // 1. 棰勫鐞嗭細閫嗘椂閽堝寲
+ // 1. 棰勫鐞嗭細纭繚閫嗘椂閽堥『搴�
ensureCounterClockwise(rawPoints);
- // 2. 鐢熸垚鍐呯缉澶氳竟褰�
+ // 2. 鐢熸垚鍐呯缉澶氳竟褰紙瀹夊叏杈圭晫锛�
List<Point> boundary = getInsetPolygon(rawPoints, safeMargin);
if (boundary.size() < 3) return new ArrayList<>();
- // 3. 纭畾鏈�浼樻壂鎻忚搴﹀苟鎵惧埌寮撳瓧褰㈣矾寰勭殑绗竴涓綔涓氳捣鐐�
+ // 3. 纭畾鏈�浼樹綔涓氳搴�
double bestAngle = findOptimalAngle(boundary);
+
+ // 4. 鑾峰彇棣栦釜浣滀笟鐐癸紝鐢ㄤ簬瀵归綈鍥磋竟璧风偣
Point firstScanStart = getFirstScanPoint(boundary, mowWidth, bestAngle);
- // 4. 瀵归綈鍥磋竟璧风偣锛氶噸鏂版帓鍒楀洿杈瑰潗鏍囷紝浣挎渶鍚庝竴涓偣闈犺繎(鎴栫瓑浜�)鎵弿璧风偣
+ // 5. 瀵归綈鍥磋竟锛氫娇鍥磋竟鏈�鍚庣粨鏉熶簬闈犺繎鎵弿璧风偣鐨勪綅缃�
List<Point> alignedBoundary = alignBoundaryStart(boundary, firstScanStart);
List<PathSegment> finalPath = new ArrayList<>();
- // 5. 銆愮涓�姝ャ�戠敓鎴愬洿杈硅矾寰�
+ // 6. 绗竴闃舵锛氬洿杈硅矾寰�
for (int i = 0; i < alignedBoundary.size(); i++) {
Point pStart = alignedBoundary.get(i);
Point pEnd = alignedBoundary.get((i + 1) % alignedBoundary.size());
finalPath.add(new PathSegment(pStart, pEnd, true));
}
- // 6. 銆愮浜屾銆戜粠瀵归綈鍚庣殑缁堢偣寮�濮嬬敓鎴愬唴閮ㄦ壂鎻忚矾寰�
- Point lastEdgePos = alignedBoundary.get(0); // 鍥磋竟闂悎鍥炲埌璧风偣
+ // 7. 绗簩闃舵锛氱敓鎴愬唴閮ㄦ壂鎻忚矾寰勶紙淇鍑归儴绌鸿秺闂锛�
+ Point lastEdgePos = alignedBoundary.get(0);
List<PathSegment> scanPath = generateGlobalScanPath(boundary, mowWidth, bestAngle, lastEdgePos);
finalPath.addAll(scanPath);
@@ -47,43 +49,6 @@
return finalPath;
}
- /**
- * 璁$畻骞惰幏鍙栨壂鎻忚矾寰勭殑绗竴琛岃捣鐐�
- */
- private static Point getFirstScanPoint(List<Point> polygon, double width, double angle) {
- List<Point> rotatedPoly = new ArrayList<>();
- for (Point p : polygon) rotatedPoly.add(rotatePoint(p, -angle));
-
- double minY = Double.MAX_VALUE;
- for (Point p : rotatedPoly) minY = Math.min(minY, p.y);
-
- double firstY = minY + width;
- List<Double> xIntersections = getXIntersections(rotatedPoly, firstY);
-
- if (xIntersections.isEmpty()) return polygon.get(0);
- return rotatePoint(new Point(Collections.min(xIntersections), firstY), angle);
- }
-
- /**
- * 閲嶆柊鎺掑垪澶氳竟褰㈤《鐐癸紝浣胯捣濮嬬偣涓庢壂鎻忚捣鐐瑰鎺�
- */
- private static List<Point> alignBoundaryStart(List<Point> boundary, Point targetStart) {
- int bestIdx = 0;
- double minDist = Double.MAX_VALUE;
- for (int i = 0; i < boundary.size(); i++) {
- double d = Math.hypot(boundary.get(i).x - targetStart.x, boundary.get(i).y - targetStart.y);
- if (d < minDist) {
- minDist = d;
- bestIdx = i;
- }
- }
- List<Point> aligned = new ArrayList<>();
- for (int i = 0; i < boundary.size(); i++) {
- aligned.add(boundary.get((bestIdx + i) % boundary.size()));
- }
- return aligned;
- }
-
private static List<PathSegment> generateGlobalScanPath(List<Point> polygon, double width, double angle, Point currentPos) {
List<PathSegment> segments = new ArrayList<>();
List<Point> rotatedPoly = new ArrayList<>();
@@ -96,29 +61,32 @@
}
boolean leftToRight = true;
- // 浠� minY + width 寮�濮嬶紝閬垮紑鍥磋竟宸插壊鍖哄煙
- for (double y = minY + width; y <= maxY - width/2; y += width) {
+ // 姝ラ暱 y 浠庢渶灏忓埌鏈�澶ф壂鎻�
+ for (double y = minY + width/2; y <= maxY - width/2; y += width) {
List<Double> xIntersections = getXIntersections(rotatedPoly, y);
if (xIntersections.size() < 2) continue;
Collections.sort(xIntersections);
- List<PathSegment> lineRows = new ArrayList<>();
+ // 澶勭悊鍑瑰杈瑰舰锛氭瘡涓や釜鐐圭粍鎴愪竴涓湁鏁堜綔涓氭
+ List<PathSegment> lineSegmentsInRow = new ArrayList<>();
for (int i = 0; i < xIntersections.size() - 1; i += 2) {
Point pS = rotatePoint(new Point(xIntersections.get(i), y), angle);
Point pE = rotatePoint(new Point(xIntersections.get(i + 1), y), angle);
- lineRows.add(new PathSegment(pS, pE, true));
+ lineSegmentsInRow.add(new PathSegment(pS, pE, true));
}
+ // 鏍规嵁褰撳墠S鍨嬫柟鍚戞帓搴忎綔涓氭
if (!leftToRight) {
- Collections.reverse(lineRows);
- for (PathSegment s : lineRows) {
- Point t = s.start; s.start = s.end; s.end = t;
+ Collections.reverse(lineSegmentsInRow);
+ for (PathSegment s : lineSegmentsInRow) {
+ Point temp = s.start; s.start = s.end; s.end = temp;
}
}
- for (PathSegment s : lineRows) {
- // 濡傛灉闂磋窛鏋佸皬锛岃涓烘棤缂濊鎺�
- if (Math.hypot(currentPos.x - s.start.x, currentPos.y - s.start.y) > 0.05) {
+ // 灏嗕綔涓氭杩炴帴鍒版�昏矾寰�
+ for (PathSegment s : lineSegmentsInRow) {
+ if (Math.hypot(currentPos.x - s.start.x, currentPos.y - s.start.y) > 0.01) {
+ // 濡傛灉闂磋窛澶т簬1cm锛屾坊鍔犵┖璧拌矾寰�
segments.add(new PathSegment(currentPos, s.start, false));
}
segments.add(s);
@@ -129,6 +97,33 @@
return segments;
}
+ private static Point getFirstScanPoint(List<Point> polygon, double width, double angle) {
+ List<Point> rotatedPoly = new ArrayList<>();
+ for (Point p : polygon) rotatedPoly.add(rotatePoint(p, -angle));
+ double minY = Double.MAX_VALUE;
+ for (Point p : rotatedPoly) minY = Math.min(minY, p.y);
+
+ double firstY = minY + width/2;
+ List<Double> xInter = getXIntersections(rotatedPoly, firstY);
+ if (xInter.isEmpty()) return polygon.get(0);
+ Collections.sort(xInter);
+ return rotatePoint(new Point(xInter.get(0), firstY), angle);
+ }
+
+ private static List<Point> alignBoundaryStart(List<Point> boundary, Point targetStart) {
+ int bestIdx = 0;
+ double minDist = Double.MAX_VALUE;
+ for (int i = 0; i < boundary.size(); i++) {
+ double d = Math.hypot(boundary.get(i).x - targetStart.x, boundary.get(i).y - targetStart.y);
+ if (d < minDist) { minDist = d; bestIdx = i; }
+ }
+ List<Point> aligned = new ArrayList<>();
+ for (int i = 0; i < boundary.size(); i++) {
+ aligned.add(boundary.get((bestIdx + i) % boundary.size()));
+ }
+ return aligned;
+ }
+
private static List<Double> getXIntersections(List<Point> rotatedPoly, double y) {
List<Double> xIntersections = new ArrayList<>();
for (int i = 0; i < rotatedPoly.size(); i++) {
@@ -170,19 +165,30 @@
Point pPrev = points.get((i - 1 + n) % n);
Point pCurr = points.get(i);
Point pNext = points.get((i + 1) % n);
+
double d1x = pCurr.x - pPrev.x, d1y = pCurr.y - pPrev.y;
double l1 = Math.hypot(d1x, d1y);
double d2x = pNext.x - pCurr.x, d2y = pNext.y - pCurr.y;
double l2 = Math.hypot(d2x, d2y);
+
if (l1 < 1e-6 || l2 < 1e-6) continue;
+
+ // 鍗曚綅娉曞悜閲�
double n1x = -d1y / l1, n1y = d1x / l1;
double n2x = -d2y / l2, n2y = d2x / l2;
+
+ // 瑙掑钩鍒嗙嚎鏂瑰悜
double bisectorX = n1x + n2x, bisectorY = n1y + n2y;
double bLen = Math.hypot(bisectorX, bisectorY);
if (bLen < 1e-6) { bisectorX = n1x; bisectorY = n1y; }
else { bisectorX /= bLen; bisectorY /= bLen; }
+
double cosHalfAngle = n1x * bisectorX + n1y * bisectorY;
- double dist = margin / Math.max(cosHalfAngle, 0.1);
+ double dist = margin / Math.max(cosHalfAngle, 0.1);
+
+ // 闄愬埗鏈�澶т綅绉婚噺锛岄槻姝㈡瀬灏栬鐣稿彉
+ dist = Math.min(dist, margin * 5);
+
result.add(new Point(pCurr.x + bisectorX * dist, pCurr.y + bisectorY * dist));
}
return result;
@@ -226,7 +232,7 @@
public static class PathSegment {
public Point start, end;
- public boolean isMowing;
+ public boolean isMowing; // true: 鍓茶崏涓�, false: 绌鸿浇绉诲姩
public PathSegment(Point s, Point e, boolean m) { this.start = s; this.end = e; this.isMowing = m; }
}
}
\ No newline at end of file
--
Gitblit v1.10.0