From 0930bed760105b81e2e5055801bec6d6e8d57358 Mon Sep 17 00:00:00 2001
From: 张世豪 <979909237@qq.com>
Date: 星期二, 23 十二月 2025 18:40:08 +0800
Subject: [PATCH] 新增了功能
---
src/lujing/AoxinglujingNoObstacle.java | 459 +++++++++++++++++++-------------------------------------
1 files changed, 157 insertions(+), 302 deletions(-)
diff --git a/src/lujing/AoxinglujingNoObstacle.java b/src/lujing/AoxinglujingNoObstacle.java
index 95f5f96..fe884f9 100644
--- a/src/lujing/AoxinglujingNoObstacle.java
+++ b/src/lujing/AoxinglujingNoObstacle.java
@@ -5,381 +5,236 @@
import java.util.List;
/**
- * 鏃犻殰纰嶇墿鍑稿舰鑽夊湴璺緞瑙勫垝绫� (缁堟瀬浼樺寲鐗�)
- * 鐗规�э細
- * 1. 鏈�灏忔姇褰卞搴︽柟鍚戦�夋嫨 (鏁堢巼鏈�楂橈紝杞集鏈�灏�)
- * 2. 杈圭紭杞粨浼樺厛鍒囧壊 (鏃犳瑙掕鐩�)
- * 3. 鏀寔澶栭儴浼犲叆宸插寘鍚噸鍙犵巼鐨勫搴﹀弬鏁�
+ * 鍑稿舰鑽夊湴璺緞瑙勫垝 (鍥磋竟浼樺寲鐗�)
+ * 浼樺寲閲嶇偣锛氬洿杈瑰潗鏍囧榻愭壂鎻忚捣鐐广�佸叏璺緞杩炶疮鎬�
*/
public class AoxinglujingNoObstacle {
- // 寮曞叆鏋佸皬鍊肩敤浜庢诞鐐规暟姣旇緝锛屽鐞嗗嚑浣曠簿搴﹁宸�
private static final double EPSILON = 1e-6;
- /**
- * 璺緞娈电被
- */
- public static class PathSegment {
- public Point start;
- public Point end;
- public boolean isMowing; // true涓哄壊鑽夊伐浣滄锛宖alse涓鸿繃娓℃
-
- public PathSegment(Point start, Point end, boolean isMowing) {
- this.start = start;
- this.end = end;
- this.isMowing = isMowing;
- }
-
- @Override
- public String toString() {
- return String.format("[%s -> %s, isMowing=%b]", start, end, isMowing);
- }
- }
-
- /**
- * 鍧愭爣鐐圭被
- */
public static class Point {
public double x, y;
-
- public Point(double x, double y) {
- this.x = x;
- this.y = y;
- }
-
+ public Point(double x, double y) { this.x = x; this.y = y; }
@Override
- public String toString() {
- return String.format("(%.4f, %.4f)", x, y);
+ public String toString() { return String.format("%.6f,%.6f", x, y); }
+ }
+
+ public static class PathSegment {
+ public Point start, end;
+ public boolean isMowing;
+ public PathSegment(Point start, Point end, boolean isMowing) {
+ this.start = start; this.end = end; this.isMowing = isMowing;
}
}
/**
- * 瀵瑰鍏紑鐨勯潤鎬佽皟鐢ㄦ柟娉�
- *
- * @param boundaryCoordsStr 鍦板潡杈圭晫鍧愭爣瀛楃涓� "x1,y1;x2,y2;..."
- * @param mowingWidthStr 鏈夋晥鍓茶崏瀹藉害瀛楃涓� (宸插寘鍚噸鍙犵巼)锛屽 "0.30"
- * @param safetyMarginStr 瀹夊叏杈硅窛瀛楃涓诧紝濡� "0.2"
- * @return 璺緞娈靛垪琛�
+ * 瀵瑰涓绘帴鍙�
*/
public static List<PathSegment> planPath(String boundaryCoordsStr, String mowingWidthStr, String safetyMarginStr) {
- // 1. 瑙f瀽鍙傛暟
List<Point> originalPolygon = parseCoords(boundaryCoordsStr);
- double mowingWidth;
- double safetyMargin;
+ double width = Double.parseDouble(mowingWidthStr);
+ double margin = Double.parseDouble(safetyMarginStr);
- try {
- mowingWidth = Double.parseDouble(mowingWidthStr);
- safetyMargin = Double.parseDouble(safetyMarginStr);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("鍓茶崏瀹藉害鎴栧畨鍏ㄨ竟璺濇牸寮忛敊璇�");
- }
-
- // 2. 璋冪敤鏍稿績绠楁硶
- return planPathCore(originalPolygon, mowingWidth, safetyMargin);
+ return planPathCore(originalPolygon, width, margin);
}
- /**
- * 鏍稿績绠楁硶閫昏緫
- */
- private static List<PathSegment> planPathCore(List<Point> originalPolygon, double width, double safetyMargin) {
- if (originalPolygon == null || originalPolygon.size() < 3) {
- return new ArrayList<>(); // 鎴栨姏鍑哄紓甯革紝瑙嗕笟鍔¢渶姹傝�屽畾
- }
+ private static List<PathSegment> planPathCore(List<Point> originalPolygon, double width, double margin) {
+ if (originalPolygon.size() < 3) return new ArrayList<>();
- // 纭繚澶氳竟褰㈡槸閫嗘椂閽堟柟鍚�
+ // 1. 纭繚閫嗘椂閽堝苟杩涜瀹夊叏鍐呯缉
ensureCCW(originalPolygon);
+ List<Point> workArea = shrinkPolygon(originalPolygon, margin);
+ if (workArea.size() < 3) return new ArrayList<>();
- // 1. 鏍规嵁瀹夊叏杈硅窛鍐呯缉锛屽緱鍒板疄闄呬綔涓氬尯鍩�
- List<Point> workAreaPolygon = shrinkPolygon(originalPolygon, safetyMargin);
+ // 2. 棰勮绠楁渶浼樿搴﹀拰濉厖璺緞鐨勭涓�涓偣
+ double bestAngle = findOptimalScanAngle(workArea);
+ Point firstScanStart = getFirstScanStartPoint(workArea, bestAngle, width);
- // 濡傛灉鍐呯缉鍚庡尯鍩熷け鏁堬紙濡傚湴鍧楀お灏忥級锛岃繑鍥炵┖璺緞
- if (workAreaPolygon.size() < 3) {
- return new ArrayList<>();
- }
+ // 3. 瀵归綈鍥磋竟璧风偣锛氳鍥磋竟鐨勬渶鍚庝竴涓偣鍒氬ソ杩炴帴鎵弿濉厖鐨勮捣鐐�
+ List<Point> alignedWorkArea = alignBoundaryToStart(workArea, firstScanStart);
List<PathSegment> finalPath = new ArrayList<>();
- // 2. [浼樺寲] 浼樺厛鐢熸垚杞粨璺緞 (Contour Pass)
- // 娌夸綔涓氳竟鐣岃蛋涓�鍦堬紝纭繚杈圭紭鏁撮綈涓旀棤閬楁紡
- addContourPath(workAreaPolygon, finalPath);
-
- // 3. [浼樺寲] 璁$畻鏈�浣虫壂鎻忚搴�
- // 瀵绘壘璁╁杈瑰舰鎶曞奖楂樺害鏈�灏忕殑瑙掑害锛屼粠鑰屾渶灏忓寲杞集娆℃暟
- double bestAngle = findOptimalScanAngle(workAreaPolygon);
-
- // 4. 鐢熸垚鍐呴儴寮撳瓧褰㈣矾寰�
- // 鐩存帴浣跨敤浼犲叆鐨� width (宸插寘鍚噸鍙犵巼)
- List<PathSegment> zigZagPaths = generateClippedMowingLines(workAreaPolygon, bestAngle, width);
-
- // 5. 杩炴帴杞粨璺緞鍜屽紦瀛楀舰璺緞
- if (!finalPath.isEmpty() && !zigZagPaths.isEmpty()) {
- Point contourEnd = finalPath.get(finalPath.size() - 1).end;
- Point zigzagStart = zigZagPaths.get(0).start;
-
- // 濡傛灉杞粨缁堢偣涓庡紦瀛楀舰璧风偣涓嶉噸鍚堬紝娣诲姞杩囨浮娈�
- if (distanceSq(contourEnd, zigzagStart) > EPSILON) {
- finalPath.add(new PathSegment(contourEnd, zigzagStart, false));
- }
+ // 4. 銆愮涓�闃舵銆戞坊鍔犲洿杈瑰潗鏍囪矾寰�
+ for (int i = 0; i < alignedWorkArea.size(); i++) {
+ Point p1 = alignedWorkArea.get(i);
+ Point p2 = alignedWorkArea.get((i + 1) % alignedWorkArea.size());
+ finalPath.add(new PathSegment(p1, p2, true));
}
- // 6. 鍚堝苟寮撳瓧褰㈣矾寰�
- finalPath.addAll(connectPathSegments(zigZagPaths));
+ // 5. 銆愮浜岄樁娈点�戠敓鎴愬唴閮ㄥ紦瀛楀舰璺緞
+ // 浠庡洿杈归棴鍚堢偣锛坅lignedWorkArea.get(0)锛夊紑濮嬭繛鎺�
+ Point currentPos = alignedWorkArea.get(0);
+ List<PathSegment> zigZagLines = generateZigZagPath(workArea, bestAngle, width, currentPos);
+
+ finalPath.addAll(zigZagLines);
return finalPath;
}
- // ================= 鏍稿績閫昏緫杈呭姪鏂规硶 =================
-
/**
- * 娣诲姞杞粨璺緞 (鍥寸潃澶氳竟褰㈣蛋涓�鍦�)
+ * 瀵绘壘寮撳瓧褰㈢殑绗竴鏉$嚎鐨勮捣鐐�
*/
- private static void addContourPath(List<Point> polygon, List<PathSegment> path) {
- int n = polygon.size();
- for (int i = 0; i < n; i++) {
- Point p1 = polygon.get(i);
- Point p2 = polygon.get((i + 1) % n);
- path.add(new PathSegment(p1, p2, true));
- }
- }
-
- /**
- * 瀵绘壘鏈�浼樻壂鎻忚搴� (鏈�灏忔姇褰遍珮搴︽硶)
- */
- private static double findOptimalScanAngle(List<Point> polygon) {
- double minHeight = Double.MAX_VALUE;
- double bestAngle = 0;
- int n = polygon.size();
-
- // 閬嶅巻姣忎竴鏉¤竟锛岃绠椾互璇ヨ竟涓衡�滃簳鈥濇椂锛屽杈瑰舰鐨勯珮搴�
- for (int i = 0; i < n; i++) {
- Point p1 = polygon.get(i);
- Point p2 = polygon.get((i + 1) % n);
-
- // 褰撳墠杈圭殑瑙掑害
- double currentAngle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
-
- // 璁$畻鍦ㄨ繖涓搴︿笅鐨勬姇褰遍珮搴�
- double height = calculatePolygonHeightAtAngle(polygon, currentAngle);
-
- if (height < minHeight) {
- minHeight = height;
- bestAngle = currentAngle;
- }
- }
- return bestAngle;
- }
-
- /**
- * 璁$畻澶氳竟褰㈠湪鐗瑰畾鏃嬭浆瑙掑害涓嬬殑Y杞存姇褰遍珮搴�
- */
- private static double calculatePolygonHeightAtAngle(List<Point> poly, double angle) {
+ private static Point getFirstScanStartPoint(List<Point> polygon, double angle, double width) {
+ List<Point> rotated = rotatePolygon(polygon, -angle);
double minY = Double.MAX_VALUE;
- double maxY = -Double.MAX_VALUE;
+ for (Point p : rotated) minY = Math.min(minY, p.y);
- double cos = Math.cos(-angle);
- double sin = Math.sin(-angle);
-
- for (Point p : poly) {
- // 鍙渶璁$畻鏃嬭浆鍚庣殑Y鍧愭爣
- double rotatedY = p.x * sin + p.y * cos;
- if (rotatedY < minY) minY = rotatedY;
- if (rotatedY > maxY) maxY = rotatedY;
- }
- return maxY - minY;
+ double startY = minY + width + EPSILON;
+ List<Double> xIntersections = getXIntersections(rotated, startY);
+ if (xIntersections.isEmpty()) return polygon.get(0);
+
+ Collections.sort(xIntersections);
+ return rotatePoint(new Point(xIntersections.get(0), startY), angle);
}
- private static List<PathSegment> generateClippedMowingLines(List<Point> polygon, double angle, double width) {
- List<PathSegment> segments = new ArrayList<>();
-
- // 鏃嬭浆澶氳竟褰㈣嚦姘村钩
- List<Point> rotatedPoly = rotatePolygon(polygon, -angle);
-
- double minY = Double.MAX_VALUE;
- double maxY = -Double.MAX_VALUE;
- for (Point p : rotatedPoly) {
- if (p.y < minY) minY = p.y;
- if (p.y > maxY) maxY = p.y;
- }
-
- // 璧峰鎵弿绾夸綅缃細
- // 浠� minY + width/2 寮�濮嬶紝鍥犱负涔嬪墠宸茬粡璧颁簡杞粨绾�(Contour Pass)銆�
- // 杞粨绾胯礋璐f竻鐞嗚竟缂樺尯鍩燂紝鍐呴儴濉厖绾夸繚鎸� width 鐨勯棿璺濆嵆鍙��
- // 鍔犱笂 EPSILON 闃叉娴偣鏁板垰濂借惤鍦ㄨ竟鐣屼笂瀵艰嚧鐨勫垽鏂宸�
- double currentY = minY + width / 2.0 + EPSILON;
-
- while (currentY < maxY) {
- List<Double> xIntersections = new ArrayList<>();
- int n = rotatedPoly.size();
-
- for (int i = 0; i < n; i++) {
- Point p1 = rotatedPoly.get(i);
- Point p2 = rotatedPoly.get((i + 1) % n);
-
- // 蹇界暐姘村钩绾挎
- if (Math.abs(p1.y - p2.y) < EPSILON) continue;
-
- double minP = Math.min(p1.y, p2.y);
- double maxP = Math.max(p1.y, p2.y);
-
- if (currentY >= minP && currentY < maxP) {
- double x = p1.x + (currentY - p1.y) * (p2.x - p1.x) / (p2.y - p1.y);
- xIntersections.add(x);
- }
+ /**
+ * 閲嶇粍澶氳竟褰㈤《鐐癸紝浣垮緱绱㈠紩0鐨勭偣鏈�闈犺繎濉厖璧风偣
+ */
+ private static List<Point> alignBoundaryToStart(List<Point> polygon, Point target) {
+ int bestIdx = 0;
+ double minDist = Double.MAX_VALUE;
+ for (int i = 0; i < polygon.size(); i++) {
+ double d = Math.hypot(polygon.get(i).x - target.x, polygon.get(i).y - target.y);
+ if (d < minDist) {
+ minDist = d;
+ bestIdx = i;
}
-
- Collections.sort(xIntersections);
-
- if (xIntersections.size() >= 2) {
- // 鍙栨渶宸﹀拰鏈�鍙充氦鐐�
- double xStart = xIntersections.get(0);
- double xEnd = xIntersections.get(xIntersections.size() - 1);
-
- if (xEnd - xStart > EPSILON) {
- // 鍙嶅悜鏃嬭浆鍥炲師鍧愭爣绯�
- Point rStart = rotatePoint(new Point(xStart, currentY), angle);
- Point rEnd = rotatePoint(new Point(xEnd, currentY), angle);
- segments.add(new PathSegment(rStart, rEnd, true));
- }
- }
- // 姝ヨ繘
- currentY += width;
}
-
- return segments;
+ List<Point> aligned = new ArrayList<>();
+ for (int i = 0; i < polygon.size(); i++) {
+ aligned.add(polygon.get((bestIdx + i) % polygon.size()));
+ }
+ return aligned;
}
- private static List<PathSegment> connectPathSegments(List<PathSegment> lines) {
+ private static List<PathSegment> generateZigZagPath(List<Point> polygon, double angle, double width, Point startPoint) {
List<PathSegment> result = new ArrayList<>();
- if (lines.isEmpty()) return result;
+ List<Point> rotated = rotatePolygon(polygon, -angle);
- for (int i = 0; i < lines.size(); i++) {
- PathSegment currentLine = lines.get(i);
- Point actualStart, actualEnd;
+ double minY = Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
+ for (Point p : rotated) {
+ minY = Math.min(minY, p.y);
+ maxY = Math.max(maxY, p.y);
+ }
- // 寮撳瓧褰㈣鍒掞細鍋舵暟琛屾鍚戯紝濂囨暟琛屽弽鍚�
- if (i % 2 == 0) {
- actualStart = currentLine.start;
- actualEnd = currentLine.end;
- } else {
- actualStart = currentLine.end;
- actualEnd = currentLine.start;
+ Point currentPos = startPoint;
+ boolean leftToRight = true;
+ // 璧风偣浠� minY + width 寮�濮嬶紝鍥犱负杈圭紭宸茬粡鍥磋竟鍓茶繃
+ for (double y = minY + width; y < maxY - width / 2; y += width) {
+ List<Double> xInt = getXIntersections(rotated, y);
+ if (xInt.size() < 2) continue;
+ Collections.sort(xInt);
+
+ double xStart = leftToRight ? xInt.get(0) : xInt.get(xInt.size() - 1);
+ double xEnd = leftToRight ? xInt.get(xInt.size() - 1) : xInt.get(0);
+
+ Point pS = rotatePoint(new Point(xStart, y), angle);
+ Point pE = rotatePoint(new Point(xEnd, y), angle);
+
+ // 娣诲姞杩囨浮娈� (濡傛灉鏄粠鍥磋竟鍒囨崲杩囨潵鎴栬�呮崲琛�)
+ if (Math.hypot(currentPos.x - pS.x, currentPos.y - pS.y) > 0.05) {
+ result.add(new PathSegment(currentPos, pS, false));
}
-
- // 娣诲姞杩囨浮娈�
- if (i > 0) {
- Point prevEnd = result.get(result.size() - 1).end;
- if (distanceSq(prevEnd, actualStart) > EPSILON) {
- result.add(new PathSegment(prevEnd, actualStart, false));
- }
- }
-
- result.add(new PathSegment(actualStart, actualEnd, true));
+ result.add(new PathSegment(pS, pE, true));
+ currentPos = pE;
+ leftToRight = !leftToRight;
}
return result;
}
- // ================= 鍩虹鍑犱綍宸ュ叿 =================
-
- private static List<Point> parseCoords(String s) {
- List<Point> list = new ArrayList<>();
- if (s == null || s.trim().isEmpty()) return list;
-
- String[] parts = s.split(";");
- for (String part : parts) {
- String[] xy = part.split(",");
- if (xy.length >= 2) {
- try {
- double x = Double.parseDouble(xy[0].trim());
- double y = Double.parseDouble(xy[1].trim());
- list.add(new Point(x, y));
- } catch (NumberFormatException e) {
- // 蹇界暐鏍煎紡閿欒
- }
+ private static List<Double> getXIntersections(List<Point> rotatedPoly, double y) {
+ List<Double> xIntersections = new ArrayList<>();
+ int n = rotatedPoly.size();
+ for (int i = 0; i < n; i++) {
+ Point p1 = rotatedPoly.get(i);
+ Point p2 = rotatedPoly.get((i + 1) % n);
+ if ((p1.y <= y && p2.y > y) || (p2.y <= y && p1.y > y)) {
+ double x = p1.x + (y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y);
+ xIntersections.add(x);
}
}
- return list;
+ return xIntersections;
}
- private static void ensureCCW(List<Point> polygon) {
- double sum = 0;
- for (int i = 0; i < polygon.size(); i++) {
- Point p1 = polygon.get(i);
- Point p2 = polygon.get((i + 1) % polygon.size());
- sum += (p2.x - p1.x) * (p2.y + p1.y);
- }
- if (sum > 0) {
- Collections.reverse(polygon);
- }
- }
+ // --- 鍑犱綍鍩虹宸ュ叿 ---
private static List<Point> shrinkPolygon(List<Point> polygon, double margin) {
- List<Point> newPoints = new ArrayList<>();
+ List<Point> result = new ArrayList<>();
int n = polygon.size();
-
for (int i = 0; i < n; i++) {
- Point p1 = polygon.get(i);
- Point p2 = polygon.get((i + 1) % n);
- Point p0 = polygon.get((i - 1 + n) % n);
+ Point pPrev = polygon.get((i - 1 + n) % n);
+ Point pCurr = polygon.get(i);
+ Point pNext = polygon.get((i + 1) % n);
- Line line1 = offsetLine(p1, p2, margin);
- Line line0 = offsetLine(p0, p1, margin);
+ 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);
- Point intersection = getIntersection(line0, line1);
- if (intersection != null) {
- newPoints.add(intersection);
- }
+ double n1x = -d1y / l1, n1y = d1x / l1;
+ double n2x = -d2y / l2, n2y = d2x / l2;
+
+ double bx = n1x + n2x, by = n1y + n2y;
+ double bLen = Math.hypot(bx, by);
+ if (bLen < EPSILON) { bx = n1x; by = n1y; }
+ else { bx /= bLen; by /= bLen; }
+
+ double cosHalf = n1x * bx + n1y * by;
+ double d = margin / Math.max(cosHalf, 0.1);
+ result.add(new Point(pCurr.x + bx * d, pCurr.y + by * d));
}
- return newPoints;
+ return result;
}
- private static class Line {
- double a, b, c;
- public Line(double a, double b, double c) { this.a = a; this.b = b; this.c = c; }
+ private static double findOptimalScanAngle(List<Point> polygon) {
+ double minH = Double.MAX_VALUE;
+ double bestA = 0;
+ for (int i = 0; i < polygon.size(); i++) {
+ Point p1 = polygon.get(i), p2 = polygon.get((i + 1) % polygon.size());
+ double angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
+ double h = calculatePolygonHeightAtAngle(polygon, angle);
+ if (h < minH) { minH = h; bestA = angle; }
+ }
+ return bestA;
}
- private static Line offsetLine(Point p1, Point p2, double dist) {
- double dx = p2.x - p1.x;
- double dy = p2.y - p1.y;
- double len = Math.sqrt(dx * dx + dy * dy);
-
- if (len < EPSILON) return new Line(0, 0, 0);
-
- double nx = -dy / len;
- double ny = dx / len;
-
- // 鍚戝乏渚у钩绉伙紙鍋囪閫嗘椂閽堬級
- double newX = p1.x + nx * dist;
- double newY = p1.y + ny * dist;
-
- double a = -dy;
- double b = dx;
- double c = -a * newX - b * newY;
- return new Line(a, b, c);
- }
-
- private static Point getIntersection(Line l1, Line l2) {
- double det = l1.a * l2.b - l2.a * l1.b;
- if (Math.abs(det) < EPSILON) return null;
- double x = (l1.b * l2.c - l2.b * l1.c) / det;
- double y = (l2.a * l1.c - l1.a * l2.c) / det;
- return new Point(x, y);
+ private static double calculatePolygonHeightAtAngle(List<Point> poly, double angle) {
+ double minY = Double.MAX_VALUE, maxY = -Double.MAX_VALUE;
+ double sin = Math.sin(-angle), cos = Math.cos(-angle);
+ for (Point p : poly) {
+ double ry = p.x * sin + p.y * cos;
+ minY = Math.min(minY, ry); maxY = Math.max(maxY, ry);
+ }
+ return maxY - minY;
}
private static Point rotatePoint(Point p, double angle) {
- double cos = Math.cos(angle);
- double sin = Math.sin(angle);
- return new Point(p.x * cos - p.y * sin, p.x * sin + p.y * cos);
+ double c = Math.cos(angle), s = Math.sin(angle);
+ return new Point(p.x * c - p.y * s, p.x * s + p.y * c);
}
private static List<Point> rotatePolygon(List<Point> poly, double angle) {
List<Point> res = new ArrayList<>();
- for (Point p : poly) {
- res.add(rotatePoint(p, angle));
- }
+ for (Point p : poly) res.add(rotatePoint(p, angle));
return res;
}
- private static double distanceSq(Point p1, Point p2) {
- return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
+ private static void ensureCCW(List<Point> poly) {
+ double s = 0;
+ for (int i = 0; i < poly.size(); i++) {
+ Point p1 = poly.get(i), p2 = poly.get((i + 1) % poly.size());
+ s += (p2.x - p1.x) * (p2.y + p1.y);
+ }
+ if (s > 0) Collections.reverse(poly);
+ }
+
+ private static List<Point> parseCoords(String s) {
+ List<Point> list = new ArrayList<>();
+ for (String p : s.split(";")) {
+ String[] xy = p.split(",");
+ if (xy.length >= 2) list.add(new Point(Double.parseDouble(xy[0]), Double.parseDouble(xy[1])));
+ }
+ return list;
}
}
\ No newline at end of file
--
Gitblit v1.10.0