张世豪
10 小时以前 13d032241e1a2938a8be4f64c9171e1240e9ea1e
src/dikuai/ObstacleManagementPage.java
@@ -20,6 +20,8 @@
/**
 * 障碍物管理页面 - UI优化版
 */
import publicway.Gpstoxuzuobiao;
public class ObstacleManagementPage extends JDialog {
    private static final long serialVersionUID = 1L;
    
@@ -299,7 +301,17 @@
        JTextArea xyArea = createDataTextArea(genCoords, 3); // 引用以便更新
        JScrollPane scrollXY = new JScrollPane(xyArea);
        scrollXY.setBorder(BorderFactory.createEmptyBorder()); // 外部由Panel提供边框
        // 设置滚动条策略:需要时显示垂直滚动条,不使用水平滚动条(因为启用了自动换行)
        scrollXY.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollXY.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        // 设置滚动条单位增量,使滚动更流畅
        scrollXY.getVerticalScrollBar().setUnitIncrement(16);
        // 设置滚动面板的首选大小,确保在内容超出时显示滚动条
        int lineHeight = xyArea.getFontMetrics(xyArea.getFont()).getHeight();
        int preferredHeight = 3 * lineHeight + 10; // 3行的高度
        scrollXY.setPreferredSize(new Dimension(Integer.MAX_VALUE, preferredHeight));
        scrollXY.setMaximumSize(new Dimension(Integer.MAX_VALUE, 200)); // 最大高度200像素
        JPanel xyWrapper = createWrapperPanel("生成坐标 (XY米)", scrollXY);
        card.add(xyWrapper);
        card.add(Box.createVerticalStrut(15));
@@ -338,6 +350,16 @@
        JTextArea area = createDataTextArea(content, rows);
        JScrollPane scroll = new JScrollPane(area);
        scroll.setBorder(BorderFactory.createEmptyBorder());
        // 设置滚动条策略:需要时显示垂直滚动条,不使用水平滚动条(因为启用了自动换行)
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        // 设置滚动条单位增量,使滚动更流畅
        scroll.getVerticalScrollBar().setUnitIncrement(16);
        // 设置滚动面板的首选大小,确保在内容超出时显示滚动条
        int lineHeight = area.getFontMetrics(area.getFont()).getHeight();
        int preferredHeight = rows * lineHeight + 10; // 根据行数计算首选高度
        scroll.setPreferredSize(new Dimension(Integer.MAX_VALUE, preferredHeight));
        scroll.setMaximumSize(new Dimension(Integer.MAX_VALUE, 200)); // 最大高度200像素
        return createWrapperPanel(title, scroll);
    }
@@ -366,12 +388,13 @@
        JTextArea area = new JTextArea(text);
        area.setRows(rows);
        area.setEditable(false);
        // 启用自动换行
        area.setLineWrap(true);
        area.setWrapStyleWord(true);
        area.setBackground(BG_INPUT);
        area.setForeground(new Color(50, 50, 50));
        // 使用等宽字体显示数据,看起来更专业
        area.setFont(new Font("Monospaced", Font.PLAIN, 12));
        area.setFont(new Font("Monospaced", Font.PLAIN, 12));
        return area;
    }
@@ -545,6 +568,9 @@
            return;
        }
        
        // 计算障碍物的中心点坐标
        double[] centerCoords = calculateObstacleCenter(obstacle);
        List<Obstacledge.Obstacle> allObstacles = loadObstacles();
        String allObstaclesCoords = buildAllObstaclesCoordinates(allObstacles);
        
@@ -568,11 +594,85 @@
                        newPage.setVisible(true);
                    })
                );
                // 将地图视图中心设置为障碍物的中心位置
                if (centerCoords != null && shouye.getMapRenderer() != null) {
                    double currentScale = shouye.getMapRenderer().getScale();
                    // 将视图中心设置为障碍物中心(使用负值,因为translate是相对于原点的偏移)
                    shouye.getMapRenderer().setViewTransform(currentScale, -centerCoords[0], -centerCoords[1]);
                }
            } else {
                JOptionPane.showMessageDialog(null, "无法打开主页面进行预览", "提示", JOptionPane.WARNING_MESSAGE);
            }
        });
    }
    /**
     * 计算障碍物的中心点坐标
     * @param obstacle 障碍物
     * @return 中心点坐标 [centerX, centerY],如果无法计算则返回null
     */
    private double[] calculateObstacleCenter(Obstacledge.Obstacle obstacle) {
        if (obstacle == null) {
            return null;
        }
        List<Obstacledge.XYCoordinate> xyCoords = obstacle.getXyCoordinates();
        if (xyCoords == null || xyCoords.isEmpty()) {
            return null;
        }
        Obstacledge.ObstacleShape shape = obstacle.getShape();
        double centerX, centerY;
        if (shape == Obstacledge.ObstacleShape.CIRCLE) {
            // 圆形障碍物:第一个坐标点就是圆心
            if (xyCoords.size() < 1) {
                return null;
            }
            Obstacledge.XYCoordinate centerCoord = xyCoords.get(0);
            centerX = centerCoord.getX();
            centerY = centerCoord.getY();
        } else if (shape == Obstacledge.ObstacleShape.POLYGON) {
            // 多边形障碍物:计算重心
            centerX = 0.0;
            centerY = 0.0;
            double area = 0.0;
            int n = xyCoords.size();
            for (int i = 0; i < n; i++) {
                Obstacledge.XYCoordinate current = xyCoords.get(i);
                Obstacledge.XYCoordinate next = xyCoords.get((i + 1) % n);
                double x0 = current.getX();
                double y0 = current.getY();
                double x1 = next.getX();
                double y1 = next.getY();
                double cross = x0 * y1 - x1 * y0;
                area += cross;
                centerX += (x0 + x1) * cross;
                centerY += (y0 + y1) * cross;
            }
            double areaFactor = area * 0.5;
            if (Math.abs(areaFactor) < 1e-9) {
                // 如果面积为0或接近0,使用简单平均
                for (Obstacledge.XYCoordinate coord : xyCoords) {
                    centerX += coord.getX();
                    centerY += coord.getY();
                }
                int size = Math.max(1, xyCoords.size());
                centerX /= size;
                centerY /= size;
            } else {
                centerX = centerX / (6.0 * areaFactor);
                centerY = centerY / (6.0 * areaFactor);
            }
        } else {
            return null;
        }
        return new double[]{centerX, centerY};
    }
    private String buildAllObstaclesCoordinates(List<Obstacledge.Obstacle> obstacles) {
        if (obstacles == null || obstacles.isEmpty()) return null;
@@ -806,29 +906,11 @@
    }
    private double parseDMToDecimal(String dmm, String direction) {
        if (dmm == null || dmm.trim().isEmpty()) return Double.NaN;
        try {
            String trimmed = dmm.trim();
            int dotIndex = trimmed.indexOf('.');
            if (dotIndex < 2) return Double.NaN;
            int degrees = Integer.parseInt(trimmed.substring(0, dotIndex - 2));
            double minutes = Double.parseDouble(trimmed.substring(dotIndex - 2));
            double decimal = degrees + minutes / 60.0;
            if ("S".equalsIgnoreCase(direction) || "W".equalsIgnoreCase(direction)) decimal = -decimal;
            return decimal;
        } catch (NumberFormatException ex) {
            return Double.NaN;
        }
        return Gpstoxuzuobiao.parseDMToDecimal(dmm, direction);
    }
    
    private double[] convertLatLonToLocal(double lat, double lon, double baseLat, double baseLon) {
        double deltaLat = lat - baseLat;
        double deltaLon = lon - baseLon;
        double meanLatRad = Math.toRadians((baseLat + lat) / 2.0);
        double METERS_PER_DEGREE_LAT = 111320.0;
        double eastMeters = deltaLon * METERS_PER_DEGREE_LAT * Math.cos(meanLatRad);
        double northMeters = deltaLat * METERS_PER_DEGREE_LAT;
        return new double[]{eastMeters, northMeters};
        return Gpstoxuzuobiao.convertLatLonToLocal(lat, lon, baseLat, baseLon);
    }
    
    private void deleteObstacle(Obstacledge.Obstacle obstacle) {
@@ -897,3 +979,10 @@
        return value != null && !value.trim().isEmpty() && !"-1".equals(value.trim());
    }
}