package bianjie; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.text.DecimalFormat; import java.util.List; /** * 边界长度绘制器 * 用于在地图上显示地块边界相邻两点之间的距离 */ public class BoundaryLengthDrawer { private static final Color LENGTH_TEXT_COLOR = new Color(80, 80, 80); // 灰色文字,与缩放文字颜色一致 // 不设置字体,使用Graphics2D的默认字体(与缩放文字一致) private static final DecimalFormat DISTANCE_FORMAT = new DecimalFormat("0.00"); /** * 计算两点之间的距离(米) * * @param p1 第一个点 * @param p2 第二个点 * @return 距离(米),保留2位小数 */ public static double calculateDistance(Point2D.Double p1, Point2D.Double p2) { if (p1 == null || p2 == null) { return 0.0; } double dx = p2.x - p1.x; double dy = p2.y - p1.y; double distance = Math.sqrt(dx * dx + dy * dy); return distance; } /** * 在地图上绘制边界长度 * 在相邻两个边界点的中点位置显示距离 * * @param g2d Graphics2D对象 * @param boundary 边界点列表 * @param scale 当前缩放比例 * @param panelWidth 面板宽度 * @param panelHeight 面板高度 * @param translateX X方向平移量 * @param translateY Y方向平移量 */ public static void drawBoundaryLengths(Graphics2D g2d, List boundary, double scale, int panelWidth, int panelHeight, double translateX, double translateY) { if (boundary == null || boundary.size() < 2) { return; } // 保存原始变换 AffineTransform savedTransform = g2d.getTransform(); // 保存当前字体(使用默认字体,与缩放文字一致) Font originalFont = g2d.getFont(); FontMetrics fontMetrics = g2d.getFontMetrics(originalFont); g2d.setColor(LENGTH_TEXT_COLOR); // 判断边界是否闭合 int totalPoints = boundary.size(); boolean closed = totalPoints > 2 && arePointsClose( boundary.get(0), boundary.get(totalPoints - 1) ); int effectiveCount = closed ? totalPoints - 1 : totalPoints; // 绘制每相邻两点之间的距离 for (int i = 0; i < effectiveCount; i++) { int nextIndex = (i + 1) % totalPoints; Point2D.Double p1 = boundary.get(i); Point2D.Double p2 = boundary.get(nextIndex); // 计算距离(米) double distance = calculateDistance(p1, p2); if (distance <= 0) { continue; // 跳过距离为0的点 } String distanceText = DISTANCE_FORMAT.format(distance) + "m"; // 计算中点位置(世界坐标) double midX = (p1.x + p2.x) / 2.0; double midY = (p1.y + p2.y) / 2.0; // 将世界坐标转换为屏幕坐标(使用与MapRenderer相同的转换公式) double screenX = (midX + translateX) * scale + panelWidth / 2.0; double screenY = (midY + translateY) * scale + panelHeight / 2.0; Point2D.Double screenPoint = new Point2D.Double(screenX, screenY); // 保存当前变换(此时g2d已经是原始变换,不包含视图变换) AffineTransform currentTransform = g2d.getTransform(); // 确保使用屏幕坐标系统(不随缩放变化) g2d.setTransform(new AffineTransform()); // 计算文字位置(居中显示) int textWidth = fontMetrics.stringWidth(distanceText); int textHeight = fontMetrics.getHeight(); int textX = (int)(screenPoint.x - textWidth / 2.0); int textY = (int)(screenPoint.y + textHeight / 4.0); // 绘制距离文字 g2d.drawString(distanceText, textX, textY); // 恢复变换 g2d.setTransform(currentTransform); } // 恢复原始变换 g2d.setTransform(savedTransform); } /** * 检查两个点是否接近(用于判断边界是否闭合) * * @param a 第一个点 * @param b 第二个点 * @return 如果两点距离小于阈值则返回true */ private static boolean arePointsClose(Point2D.Double a, Point2D.Double b) { if (a == null || b == null) { return false; } double dx = a.x - b.x; double dy = a.y - b.y; double threshold = 0.05; // 5厘米的阈值 return Math.hypot(dx, dy) <= threshold; } }