| | |
| | | import java.util.List; |
| | | import java.util.Locale; |
| | | import java.util.Set; |
| | | import java.util.function.Consumer; |
| | | import java.io.File; |
| | | import set.Setsys; |
| | | import gecaoji.Device; |
| | |
| | | * 添加导航预览轨迹点 |
| | | */ |
| | | public void addNavigationPreviewTrackPoint(Point2D.Double point) { |
| | | if (point != null && Double.isFinite(point.x) && Double.isFinite(point.y)) { |
| | | if (point != null && isFinite(point.x) && isFinite(point.y)) { |
| | | navigationPreviewTrack.add(new Point2D.Double(point.x, point.y)); |
| | | if (visualizationPanel != null) { |
| | | visualizationPanel.repaint(); |
| | |
| | | return; |
| | | } |
| | | Point2D.Double position = mower.getPosition(); |
| | | if (position == null || !Double.isFinite(position.x) || !Double.isFinite(position.y)) { |
| | | if (position == null || !isFinite(position.x) || !isFinite(position.y)) { |
| | | pendingTrackBreak = true; |
| | | return; |
| | | } |
| | |
| | | } |
| | | |
| | | realtimeMowingTrack.add(candidate); |
| | | if (!pendingTrackBreak && lastPoint != null && Double.isFinite(distance)) { |
| | | if (!pendingTrackBreak && lastPoint != null && isFinite(distance)) { |
| | | trackLengthMeters += distance; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | Point2D.Double position = mower.getPosition(); |
| | | if (position == null || !Double.isFinite(position.x) || !Double.isFinite(position.y)) { |
| | | if (position == null || !isFinite(position.x) || !isFinite(position.y)) { |
| | | return; |
| | | } |
| | | |
| | |
| | | // 刷新mower位置,使用最新的Device数据 |
| | | mower.refreshFromDevice(); |
| | | Point2D.Double position = mower.getPosition(); |
| | | if (position == null || !Double.isFinite(position.x) || !Double.isFinite(position.y)) { |
| | | if (position == null || !isFinite(position.x) || !isFinite(position.y)) { |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | private String formatTrackCoordinate(double value) { |
| | | if (!Double.isFinite(value)) { |
| | | if (!isFinite(value)) { |
| | | return "0"; |
| | | } |
| | | return String.format(Locale.US, "%.3f", value); |
| | |
| | | try { |
| | | double x = Double.parseDouble(parts[0].trim()); |
| | | double y = Double.parseDouble(parts[1].trim()); |
| | | if (!Double.isFinite(x) || !Double.isFinite(y)) { |
| | | if (!isFinite(x) || !isFinite(y)) { |
| | | continue; |
| | | } |
| | | Point2D.Double current = new Point2D.Double(x, y); |
| | |
| | | String safetyDistance = null; |
| | | String obstaclesCoords = null; |
| | | String mowingPattern = null; |
| | | String plannedPathStr = null; |
| | | |
| | | // 从当前地块编号获取地块信息 |
| | | if (currentBoundaryLandNumber != null) { |
| | |
| | | mowingWidth = landData.getMowingWidth(); |
| | | safetyDistance = landData.getMowingSafetyDistance(); |
| | | mowingPattern = landData.getMowingPattern(); |
| | | // 从地块获取plannedPath属性值作为路径 |
| | | plannedPathStr = landData.getPlannedPath(); |
| | | |
| | | // 获取障碍物坐标 |
| | | try { |
| | |
| | | } |
| | | } |
| | | |
| | | // 如果从地块获取到了路径,使用地块的路径;否则使用currentPlannedPath |
| | | List<Point2D.Double> pathToDraw = currentPlannedPath; |
| | | if (plannedPathStr != null && !plannedPathStr.trim().isEmpty() && !"-1".equals(plannedPathStr.trim())) { |
| | | // 从地块获取的路径 |
| | | pathToDraw = lujingdraw.parsePlannedPath(plannedPathStr); |
| | | } |
| | | |
| | | // 调用带地块信息的绘制方法 |
| | | lujingdraw.drawPlannedPath(g2d, currentPlannedPath, scale, arrowScale, |
| | | if (pathToDraw != null && pathToDraw.size() >= 2) { |
| | | lujingdraw.drawPlannedPath(g2d, pathToDraw, scale, arrowScale, |
| | | boundaryCoords, mowingWidth, safetyDistance, obstaclesCoords, mowingPattern); |
| | | } |
| | | } |
| | | |
| | | private void drawCircleSampleMarkers(Graphics2D g2d, List<double[]> markers, double scale) { |
| | |
| | | FontMetrics metrics = g2d.getFontMetrics(labelFont); |
| | | |
| | | for (double[] pt : markers) { |
| | | if (pt == null || pt.length < 2 || !Double.isFinite(pt[0]) || !Double.isFinite(pt[1])) { |
| | | if (pt == null || pt.length < 2 || !isFinite(pt[0]) || !isFinite(pt[1])) { |
| | | continue; |
| | | } |
| | | double x = pt[0]; |
| | |
| | | } |
| | | double x = pt[0]; |
| | | double y = pt[1]; |
| | | if (!Double.isFinite(x) || !Double.isFinite(y)) { |
| | | if (!isFinite(x) || !isFinite(y)) { |
| | | continue; |
| | | } |
| | | circleSampleMarkers.add(new double[]{x, y}); |
| | |
| | | private double computeSelectionThresholdPixels() { |
| | | double scaleFactor = Math.max(0.5, scale); |
| | | double diameterScale = boundaryPointSizeScale * (previewSizingEnabled ? PREVIEW_BOUNDARY_MARKER_SCALE : 1.0d); |
| | | if (!Double.isFinite(diameterScale) || diameterScale <= 0.0d) { |
| | | if (!isFinite(diameterScale) || diameterScale <= 0.0d) { |
| | | diameterScale = 1.0d; |
| | | } |
| | | double markerDiameterWorld = Math.max(1.0, (10.0 / scaleFactor) * 0.2 * diameterScale); |
| | |
| | | } |
| | | |
| | | private boolean isPointInsideActiveBoundary(Point2D.Double point) { |
| | | if (point == null || !Double.isFinite(point.x) || !Double.isFinite(point.y)) { |
| | | if (point == null || !isFinite(point.x) || !isFinite(point.y)) { |
| | | return false; |
| | | } |
| | | if (realtimeTrackLandNumber == null) { |
| | |
| | | } |
| | | |
| | | private boolean isPointInsideBoundary(Point2D.Double point, Path2D.Double path) { |
| | | if (point == null || path == null || !Double.isFinite(point.x) || !Double.isFinite(point.y)) { |
| | | if (point == null || path == null || !isFinite(point.x) || !isFinite(point.y)) { |
| | | return false; |
| | | } |
| | | if (path.contains(point.x, point.y)) { |
| | |
| | | Path2D.Double path = new Path2D.Double(); |
| | | boolean started = false; |
| | | for (Point2D.Double point : boundary) { |
| | | if (point == null || !Double.isFinite(point.x) || !Double.isFinite(point.y)) { |
| | | if (point == null || !isFinite(point.x) || !isFinite(point.y)) { |
| | | continue; |
| | | } |
| | | if (!started) { |
| | |
| | | // 设置点的大小(随缩放变化) |
| | | double scaleFactor = Math.max(0.5, scale); |
| | | double clampedScale = boundaryPointSizeScale * (previewSizingEnabled ? PREVIEW_BOUNDARY_MARKER_SCALE : 1.0d); |
| | | if (!Double.isFinite(clampedScale) || clampedScale <= 0.0d) { |
| | | if (!isFinite(clampedScale) || clampedScale <= 0.0d) { |
| | | clampedScale = 1.0d; |
| | | } |
| | | double minimumDiameter = clampedScale < 1.0 ? 0.5 : 1.0; |
| | |
| | | } |
| | | double x = coord.getX(); |
| | | double y = coord.getY(); |
| | | if (!Double.isFinite(x) || !Double.isFinite(y)) { |
| | | if (!isFinite(x) || !isFinite(y)) { |
| | | continue; |
| | | } |
| | | copy.add(new Obstacledge.XYCoordinate(x, y)); |
| | |
| | | } |
| | | |
| | | public void setBoundaryPointSizeScale(double sizeScale) { |
| | | double normalized = (Double.isFinite(sizeScale) && sizeScale > 0.0d) ? sizeScale : 1.0d; |
| | | double normalized = (isFinite(sizeScale) && sizeScale > 0.0d) ? sizeScale : 1.0d; |
| | | if (Math.abs(boundaryPointSizeScale - normalized) < 1e-6) { |
| | | return; |
| | | } |
| | |
| | | } |
| | | |
| | | public void setBoundaryPreviewMarkerScale(double markerScale) { |
| | | double normalized = Double.isFinite(markerScale) && markerScale > 0.0d ? markerScale : 1.0d; |
| | | double normalized = isFinite(markerScale) && markerScale > 0.0d ? markerScale : 1.0d; |
| | | if (Math.abs(boundaryPreviewMarkerScale - normalized) < 1e-6) { |
| | | return; |
| | | } |
| | |
| | | } |
| | | |
| | | public void addHandheldBoundaryPoint(double x, double y) { |
| | | if (!Double.isFinite(x) || !Double.isFinite(y)) { |
| | | if (!isFinite(x) || !isFinite(y)) { |
| | | return; |
| | | } |
| | | if (!handheldBoundaryPreviewActive) { |
| | |
| | | |
| | | Point2D.Double mowerPosition = mower.getPosition(); |
| | | if (mowerPosition == null |
| | | || !Double.isFinite(mowerPosition.x) |
| | | || !Double.isFinite(mowerPosition.y)) { |
| | | || !isFinite(mowerPosition.x) |
| | | || !isFinite(mowerPosition.y)) { |
| | | return expanded; |
| | | } |
| | | |
| | |
| | | /** |
| | | * 设置边界预览更新回调 |
| | | */ |
| | | private java.util.function.Consumer<String> boundaryPreviewUpdateCallback; |
| | | private Consumer<String> boundaryPreviewUpdateCallback; |
| | | |
| | | public void setBoundaryPreviewUpdateCallback(java.util.function.Consumer<String> callback) { |
| | | public void setBoundaryPreviewUpdateCallback(Consumer<String> callback) { |
| | | this.boundaryPreviewUpdateCallback = callback; |
| | | } |
| | | |
| | |
| | | fitBoundsToView(bounds); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 检查double值是否有限(不是NaN或无穷大) |
| | | * 兼容低版本Java |
| | | */ |
| | | private static boolean isFinite(double value) { |
| | | return !Double.isNaN(value) && !Double.isInfinite(value); |
| | | } |
| | | } |