package dikuai; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; import java.util.List; import bianjie.bianjieguihua2; import publicway.Fuzhibutton; import zhuye.Coordinate; import zhuye.Shouye; import java.text.SimpleDateFormat; import java.util.Date; /** * 地块边界管理页面 * 显示:原始边界坐标(经纬度、高程)、原始边界XY(相对于基准站)、以及可编辑的优化后边界坐标 */ public class Dikuanbianjipage extends JDialog { private static final long serialVersionUID = 1L; private static final int SCREEN_WIDTH = 400; private static final int SCREEN_HEIGHT = 800; private static final Color PRIMARY_COLOR = new Color(46, 139, 87); private static final Color PRIMARY_DARK = new Color(30, 107, 69); private static final Color TEXT_COLOR = new Color(51, 51, 51); private static final Color WHITE = Color.WHITE; private static final Color BORDER_COLOR = new Color(200, 200, 200); private static final Color BACKGROUND_COLOR = new Color(250, 250, 250); private String result = null; private Dikuai dikuai; public Dikuanbianjipage(Window owner, String title, String initialValue, Dikuai dikuai) { super(owner, title, Dialog.ModalityType.APPLICATION_MODAL); this.dikuai = dikuai; initializeUI(title, initialValue, dikuai); } public String getResult() { return result; } private void initializeUI(String title, String initialValue, Dikuai dikuai) { setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); getContentPane().setLayout(new BorderLayout()); getContentPane().setBackground(BACKGROUND_COLOR); JPanel contentPanel = new JPanel(); contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS)); contentPanel.setBackground(BACKGROUND_COLOR); contentPanel.setBorder(BorderFactory.createEmptyBorder(12, 16, 12, 16)); String landName = dikuai != null ? (dikuai.getLandName() != null ? dikuai.getLandName() : "未知地块") : "未知地块"; String landNumber = dikuai != null ? (dikuai.getLandNumber() != null ? dikuai.getLandNumber() : "未知编号") : "未知编号"; JLabel headerLabel = new JLabel(landName + " / " + landNumber); headerLabel.setFont(new Font("微软雅黑", Font.BOLD, 16)); headerLabel.setForeground(TEXT_COLOR); headerLabel.setAlignmentX(Component.LEFT_ALIGNMENT); contentPanel.add(headerLabel); contentPanel.add(Box.createVerticalStrut(12)); // 原始边界坐标(经纬度, 高程) String rawCoords = dikuai != null ? prepareCoordinateForEditor(dikuai.getBoundaryOriginalCoordinates()) : ""; int rawCount = 0; if (rawCoords != null && !rawCoords.isEmpty() && !"-1".equals(rawCoords)) { rawCount = rawCoords.split(";").length; } JTextArea rawTextArea = createInfoTextArea(rawCoords, false, 6); contentPanel.add(createTextAreaSection("原始边界坐标 (经度, 纬度, 高程) (" + rawCount + "点)", rawTextArea)); // 原始边界XY坐标(相对于基准站) String rawXY = dikuai != null ? prepareCoordinateForEditor(dikuai.getBoundaryOriginalXY()) : ""; int xyCount = 0; if (rawXY != null && !rawXY.isEmpty() && !"-1".equals(rawXY)) { xyCount = rawXY.split(";").length; } JTextArea rawXYArea = createInfoTextArea(rawXY, false, 6); contentPanel.add(createTextAreaSection("原始边界XY坐标(相对于基准站) (" + xyCount + "点)", rawXYArea)); // 优化后边界坐标(可编辑) String optCoords = prepareCoordinateForEditor(initialValue); int optCount = 0; if (optCoords != null && !optCoords.isEmpty() && !"-1".equals(optCoords)) { optCount = optCoords.split(";").length; } JTextArea optTextArea = createInfoTextArea(optCoords, true, 6); contentPanel.add(createTextAreaSection("优化后地块边界坐标 (" + optCount + "点)", optTextArea)); JScrollPane dialogScrollPane = new JScrollPane(contentPanel); dialogScrollPane.setBorder(BorderFactory.createEmptyBorder()); dialogScrollPane.getVerticalScrollBar().setUnitIncrement(16); add(dialogScrollPane, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 12, 12)); buttonPanel.setBackground(BACKGROUND_COLOR); JButton optimizeBtn = createPrimaryFooterButton("优化边界坐标"); JButton saveBtn = createPrimaryFooterButton("保存"); JButton previewBtn = createPrimaryFooterButton("预览"); JButton closeBtn = createPrimaryFooterButton("关闭"); optimizeBtn.addActionListener(e -> { if (dikuai == null) { JOptionPane.showMessageDialog(this, "未找到地块信息,无法优化", "错误", JOptionPane.ERROR_MESSAGE); return; } String baseStation = dikuai.getBaseStationCoordinates(); if (baseStation == null || baseStation.trim().isEmpty() || "-1".equals(baseStation)) { JOptionPane.showMessageDialog(this, "基站坐标未设置,无法优化", "错误", JOptionPane.ERROR_MESSAGE); return; } // 准备 Coordinate 列表 String originalCoords = dikuai.getBoundaryOriginalCoordinates(); if (originalCoords == null || originalCoords.trim().isEmpty() || "-1".equals(originalCoords)) { JOptionPane.showMessageDialog(this, "原始边界坐标为空,无法优化", "错误", JOptionPane.ERROR_MESSAGE); return; } try { // 解析原始坐标到 Coordinate.coordinates List coords = new ArrayList<>(); String[] points = originalCoords.split(";"); for (String point : points) { String[] parts = point.split(","); if (parts.length >= 2) { double lonDecimal = Double.parseDouble(parts[0].trim()); double latDecimal = Double.parseDouble(parts[1].trim()); double alt = parts.length > 2 ? Double.parseDouble(parts[2].trim()) : 0.0; // 将十进制度转换为度分格式字符串 String latDM = decimalToDegreeMinute(latDecimal); String lonDM = decimalToDegreeMinute(lonDecimal); String latDir = latDecimal >= 0 ? "N" : "S"; String lonDir = lonDecimal >= 0 ? "E" : "W"; coords.add(new Coordinate(latDM, latDir, lonDM, lonDir, alt)); } } Coordinate.coordinates = coords; // 调用优化算法 String optimized = bianjieguihua2.processCoordinateListAuto(baseStation); optTextArea.setText(optimized); JOptionPane.showMessageDialog(this, "边界优化完成", "提示", JOptionPane.INFORMATION_MESSAGE); } catch (Exception ex) { JOptionPane.showMessageDialog(this, "优化失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE); ex.printStackTrace(); } }); previewBtn.addActionListener(e -> { if (dikuai == null) { return; } // 关闭当前对话框 dispose(); // 获取当前优化后的边界 String currentOptimized = optTextArea.getText(); // 调用首页显示预览 SwingUtilities.invokeLater(() -> { Shouye.showBoundaryPreview(dikuai, currentOptimized, () -> { // 返回回调:重新打开此页面 new Dikuanbianjipage(getOwner(), getTitle(), currentOptimized, dikuai).setVisible(true); }); }); }); saveBtn.addActionListener(e -> { if (dikuai == null) { JOptionPane.showMessageDialog(this, "未找到地块信息,无法保存", "错误", JOptionPane.ERROR_MESSAGE); return; } String currentText = optTextArea.getText(); if (currentText == null || currentText.trim().isEmpty() || "-1".equals(currentText.trim())) { JOptionPane.showMessageDialog(this, "优化后地块边界为空,无法保存", "提示", JOptionPane.WARNING_MESSAGE); return; } String trimmed = currentText.trim(); // 保存到地块对象 if (!Dikuai.updateField(dikuai.getLandNumber(), "boundaryCoordinates", trimmed)) { JOptionPane.showMessageDialog(this, "无法更新地块边界坐标", "错误", JOptionPane.ERROR_MESSAGE); return; } Dikuai.updateField(dikuai.getLandNumber(), "updateTime", getCurrentTime()); Dikuai.saveToProperties(); this.result = trimmed; JOptionPane.showMessageDialog(this, "地块边界坐标已更新", "成功", JOptionPane.INFORMATION_MESSAGE); dispose(); }); closeBtn.addActionListener(e -> dispose()); // 按钮顺序:优化边界坐标、保存、预览、关闭 buttonPanel.add(optimizeBtn); buttonPanel.add(saveBtn); buttonPanel.add(previewBtn); buttonPanel.add(closeBtn); add(buttonPanel, BorderLayout.SOUTH); pack(); setSize(SCREEN_WIDTH, SCREEN_HEIGHT); setLocationRelativeTo(getOwner()); } private String prepareCoordinateForEditor(String value) { if (value == null) { return ""; } String trimmed = value.trim(); if (trimmed.isEmpty() || "-1".equals(trimmed)) { return ""; } return trimmed; } private JTextArea createInfoTextArea(String text, boolean editable, int rows) { JTextArea area = new JTextArea(text); area.setEditable(editable); area.setLineWrap(true); area.setWrapStyleWord(true); area.setFont(new Font("微软雅黑", Font.PLAIN, 13)); area.setRows(Math.max(rows, 2)); area.setCaretPosition(0); area.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); area.setBackground(editable ? WHITE : new Color(245, 245, 245)); return area; } private JPanel createTextAreaSection(String title, JTextArea textArea) { JPanel section = new JPanel(new BorderLayout(0, 6)); section.setBackground(BACKGROUND_COLOR); section.setAlignmentX(Component.LEFT_ALIGNMENT); JPanel titlePanel = new JPanel(new BorderLayout()); titlePanel.setBackground(BACKGROUND_COLOR); titlePanel.setOpaque(false); JLabel titleLabel = new JLabel(title); titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 14)); titleLabel.setForeground(TEXT_COLOR); titlePanel.add(titleLabel, BorderLayout.WEST); JButton copyButton = Fuzhibutton.createCopyButton( () -> { String text = textArea.getText(); if (text == null || text.trim().isEmpty() || "-1".equals(text.trim())) { return null; } return text; }, "复制", new Color(230, 250, 240) ); copyButton.setFont(new Font("微软雅黑", Font.PLAIN, 12)); copyButton.setPreferredSize(new Dimension(50, 24)); copyButton.setMargin(new Insets(0,0,0,0)); titlePanel.add(copyButton, BorderLayout.EAST); section.add(titlePanel, BorderLayout.NORTH); JScrollPane scrollPane = new JScrollPane(textArea); scrollPane.setBorder(BorderFactory.createLineBorder(BORDER_COLOR)); scrollPane.getVerticalScrollBar().setUnitIncrement(12); section.add(scrollPane, BorderLayout.CENTER); section.setBorder(BorderFactory.createEmptyBorder(4, 0, 12, 0)); return section; } private JButton createPrimaryFooterButton(String text) { JButton button = new JButton(text); button.setFont(new Font("微软雅黑", Font.PLAIN, 12)); button.setBackground(PRIMARY_COLOR); button.setForeground(WHITE); button.setBorder(BorderFactory.createEmptyBorder(6, 12, 6, 12)); button.setFocusPainted(false); button.setCursor(new Cursor(Cursor.HAND_CURSOR)); button.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseEntered(java.awt.event.MouseEvent e) { button.setBackground(PRIMARY_DARK); } public void mouseExited(java.awt.event.MouseEvent e) { button.setBackground(PRIMARY_COLOR); } }); return button; } private String getCurrentTime() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(new Date()); } /** * 将十进制度转换为度分格式字符串 * 例如:39.831468 -> "3949.888080" (39度49.888080分) * * @param decimalDegrees 十进制度 * @return 度分格式字符串 */ private String decimalToDegreeMinute(double decimalDegrees) { double absDecimal = Math.abs(decimalDegrees); int degrees = (int) Math.floor(absDecimal); double minutes = (absDecimal - degrees) * 60.0; double degreeMinutes = degrees * 100.0 + minutes; return String.format(java.util.Locale.US, "%.8f", degreeMinutes); } }