From 8e70ec23b3d306ebd17f57736debfb702c764190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=87=A4=E5=90=89?= Date: Sat, 1 Mar 2025 15:58:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0PathGenerator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ms/app/common/generator/PathGenerator.java | 207 ++++++++++++++++++++ .../com/qyft/ms/test/PathGenerator/MainFrame.java | 47 ----- .../qyft/ms/test/PathGenerator/PathGenerator.java | 208 --------------------- .../ms/test/PathGenerator/PathPanelJPanel.java | 114 ----------- 4 files changed, 207 insertions(+), 369 deletions(-) create mode 100644 src/main/java/com/qyft/ms/app/common/generator/PathGenerator.java delete mode 100644 src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java delete mode 100644 src/main/java/com/qyft/ms/test/PathGenerator/PathGenerator.java delete mode 100644 src/main/java/com/qyft/ms/test/PathGenerator/PathPanelJPanel.java diff --git a/src/main/java/com/qyft/ms/app/common/generator/PathGenerator.java b/src/main/java/com/qyft/ms/app/common/generator/PathGenerator.java new file mode 100644 index 0000000..ead0ce0 --- /dev/null +++ b/src/main/java/com/qyft/ms/app/common/generator/PathGenerator.java @@ -0,0 +1,207 @@ +package com.qyft.ms.app.common.generator; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** + * 路径生成器:可选择水平之字形(从上往下) 或 垂直之字形(从左往右), + * 并考虑画笔spacing,向内收缩以避免越出外部边界。 + */ +public class PathGenerator { + + /** + * 路径移动模式 + */ + public enum MoveMode { + /** + * 水平之字形,从上往下。 + * 例如:先在(左上) -> (右上),向下spacing -> (右下) -> (左下) -> ... + */ + HORIZONTAL_ZIGZAG_TOP_DOWN, + + /** + * 垂直之字形,从左往右。 + * 例如:先在(左上)->(左下),向右spacing->(右下)->(右上)-> ... + */ + VERTICAL_ZIGZAG_LEFT_RIGHT + } + + /** + * 在 [left, right] x [bottom, top] 范围内生成“之字形”路径, + * 并考虑画笔 spacing(内缩以防越界)。 + * + * @param left 矩形左边界 (数学坐标: 左下角为原点) + * @param right 矩形右边界 + * @param bottom 矩形下边界 + * @param top 矩形上边界 + * @param spacing 画笔粗细/间距 (>0) + * @param mode HORIZONTAL_ZIGZAG_TOP_DOWN 或 VERTICAL_ZIGZAG_LEFT_RIGHT + * @return 之字形路径拐点列表 (每个拐点是 (x,y) 的int坐标) + */ + public static List generatePathPoints( + int left, + int right, + int bottom, + int top, + int spacing, + MoveMode mode + ) { + // 基本校验 + if (left >= right || bottom >= top) { + throw new IllegalArgumentException("无效矩形边界: left>=right 或 bottom>=top"); + } + if (spacing <= 0) { + throw new IllegalArgumentException("spacing必须>0"); + } + + // 1) 内缩,以防画笔越界 + // 留出 spacing 宽度,可改成 spacing/2 (半个笔刷) + int effLeft = left + spacing; + int effRight = right - spacing; + int effBottom = bottom + spacing; + int effTop = top - spacing; + + // 若收缩后无空间,则返回空集合 + if (effLeft > effRight || effBottom > effTop) { + System.out.println("内缩后无有效空间,返回空路径"); + return new ArrayList<>(); + } + + // 2) 根据mode选择不同的之字形算法 + return switch (mode) { + case HORIZONTAL_ZIGZAG_TOP_DOWN -> generateHorizontalZigzagTopDown( + effLeft, effRight, effBottom, effTop, spacing + ); + case VERTICAL_ZIGZAG_LEFT_RIGHT -> generateVerticalZigzagLeftRight( + effLeft, effRight, effBottom, effTop, spacing + ); + default -> + // 预留给更多模式扩展 + new ArrayList<>(); + }; + } + + /** + * [effLeft..effRight] x [effBottom..effTop] 区域内, + * 从(左上)开始水平之字形向下扫描。 + * 流程: + * 1) 第1行: (effLeft, effTop) -> (effRight, effTop) + * 2) 下移 spacing + * 3) 第2行: (effRight, effTop - spacing) -> (effLeft, effTop - spacing) + * 4) 下移 spacing + * 重复,直到无法再下移。 + */ + private static List generateHorizontalZigzagTopDown( + int effLeft, + int effRight, + int effBottom, + int effTop, + int spacing + ) { + List result = new ArrayList<>(); + int currentX = effLeft; + int currentY = effTop; + boolean goingRight = true; + + // 起点 + result.add(new Point(currentX, currentY)); + + while (true) { + // 水平移动到对侧 + if (goingRight) { + currentX = effRight; + } else { + currentX = effLeft; + } + result.add(new Point(currentX, currentY)); + + // 往下移动 spacing + int nextY = currentY - spacing; + if (nextY < effBottom) { + break; // 无法再往下 + } + currentY = nextY; + result.add(new Point(currentX, currentY)); + + // 反转方向 + goingRight = !goingRight; + } + return result; + } + + /** + * [effLeft..effRight] x [effBottom..effTop] 区域内, + * 从(左上)开始垂直之字形向右扫描。 + *

+ * 流程: + * 1) 第1列: (effLeft, effTop) -> (effLeft, effBottom) + * 2) 右移 spacing + * 3) 第2列: (effLeft+spacing, effBottom) -> (effLeft+spacing, effTop) + * 4) 右移 spacing + * 重复,直到无法再右移。 + */ + private static List generateVerticalZigzagLeftRight( + int effLeft, + int effRight, + int effBottom, + int effTop, + int spacing + ) { + List result = new ArrayList<>(); + int currentX = effLeft; + int currentY = effTop; + boolean goingDown = true; // 第一列先从上往下 + + // 起点 + result.add(new Point(currentX, currentY)); + + while (true) { + // 垂直移动到对侧 + if (goingDown) { + currentY = effBottom; + } else { + currentY = effTop; + } + result.add(new Point(currentX, currentY)); + + // 向右移动 spacing + int nextX = currentX + spacing; + if (nextX > effRight) { + break; // 无法再右移 + } + currentX = nextX; + result.add(new Point(currentX, currentY)); + + // 反转 + goingDown = !goingDown; + } + return result; + } + + // ============= 简单测试 ============= + public static void main(String[] args) { + int left = 0, right = 10; + int bottom = 0, top = 6; + int spacing = 2; + + // 1) 测试水平之字形(从上往下) + System.out.println("=== HORIZONTAL_ZIGZAG_TOP_DOWN ==="); + List horizontalPath = generatePathPoints( + left, right, bottom, top, spacing, MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN + ); + for (Point p : horizontalPath) { + System.out.println(p); + } + + // 2) 测试垂直之字形(从左往右) + System.out.println("\n=== VERTICAL_ZIGZAG_LEFT_RIGHT ==="); + List verticalPath = generatePathPoints( + left, right, bottom, top, spacing, MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT + ); + for (Point p : verticalPath) { + System.out.println(p); + } + } +} + diff --git a/src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java b/src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java deleted file mode 100644 index 2bc069b..0000000 --- a/src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.qyft.ms.test.PathGenerator; - -import javax.swing.*; -import java.awt.*; -import java.util.List; - -/** - * 主窗口,包含main方法。创建面板PathPanel,加载进JFrame展示。 - */ -public class MainFrame extends JFrame { - - public static void main(String[] args) { - SwingUtilities.invokeLater(() -> { - MainFrame frame = new MainFrame(); - frame.setVisible(true); - }); - } - - public MainFrame() { - super("Zigzag Path Demo (No Inner Classes)"); - - setDefaultCloseOperation(EXIT_ON_CLOSE); - - // 1. 定义边界 - int left = 0; - int right = 20; - int bottom = 0; - int top = 50; - int spacing = 2; - - // 2. 生成路径(从“左上角”往下的水平之字形) - List path = PathGenerator.generatePathPoints( - left, right, bottom, top, - spacing, - PathGenerator.MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN - ); - - // 3. 创建面板并设置大小 - PathPanelJPanel panel = new PathPanelJPanel(left, right, bottom, top, path); - panel.setPreferredSize(new Dimension((right - left + 1) * 20, - (top - bottom + 1) * 20)); - getContentPane().add(panel); - - pack(); - setLocationRelativeTo(null); // 居中显示 - } -} diff --git a/src/main/java/com/qyft/ms/test/PathGenerator/PathGenerator.java b/src/main/java/com/qyft/ms/test/PathGenerator/PathGenerator.java deleted file mode 100644 index ebb6143..0000000 --- a/src/main/java/com/qyft/ms/test/PathGenerator/PathGenerator.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.qyft.ms.test.PathGenerator; - -import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -/** - * 路径生成器:可选择水平之字形(从上往下) 或 垂直之字形(从左往右), - * 并考虑画笔spacing,向内收缩以避免越出外部边界。 - */ -public class PathGenerator { - - /** 路径移动模式 */ - public enum MoveMode { - /** - * 水平之字形,从上往下。 - * 例如:先在(左上) -> (右上),向下spacing -> (右下) -> (左下) -> ... - */ - HORIZONTAL_ZIGZAG_TOP_DOWN, - - /** - * 垂直之字形,从左往右。 - * 例如:先在(左上)->(左下),向右spacing->(右下)->(右上)-> ... - */ - VERTICAL_ZIGZAG_LEFT_RIGHT - } - - /** - * 在 [left, right] x [bottom, top] 范围内生成“之字形”路径, - * 并考虑画笔 spacing(内缩以防越界)。 - * - * @param left 矩形左边界 (数学坐标: 左下角为原点) - * @param right 矩形右边界 - * @param bottom 矩形下边界 - * @param top 矩形上边界 - * @param spacing 画笔粗细/间距 (>0) - * @param mode HORIZONTAL_ZIGZAG_TOP_DOWN 或 VERTICAL_ZIGZAG_LEFT_RIGHT - * @return 之字形路径拐点列表 (每个拐点是 (x,y) 的int坐标) - */ - public static List generatePathPoints( - int left, - int right, - int bottom, - int top, - int spacing, - MoveMode mode - ) { - // 基本校验 - if (left >= right || bottom >= top) { - throw new IllegalArgumentException("无效矩形边界: left>=right 或 bottom>=top"); - } - if (spacing <= 0) { - throw new IllegalArgumentException("spacing必须>0"); - } - - // 1) 内缩,以防画笔越界 - int margin = spacing; // 留出 spacing 宽度,可改成 spacing/2 (半个笔刷) - int effLeft = left + margin; - int effRight = right - margin; - int effBottom = bottom + margin; - int effTop = top - margin; - - // 若收缩后无空间,则返回空集合 - if (effLeft > effRight || effBottom > effTop) { - System.out.println("内缩后无有效空间,返回空路径"); - return new ArrayList<>(); - } - - // 2) 根据mode选择不同的之字形算法 - switch (mode) { - case HORIZONTAL_ZIGZAG_TOP_DOWN: - return generateHorizontalZigzagTopDown( - effLeft, effRight, effBottom, effTop, spacing - ); - case VERTICAL_ZIGZAG_LEFT_RIGHT: - return generateVerticalZigzagLeftRight( - effLeft, effRight, effBottom, effTop, spacing - ); - default: - // 预留给更多模式扩展 - return new ArrayList<>(); - } - } - - /** - * [effLeft..effRight] x [effBottom..effTop] 区域内, - * 从(左上)开始水平之字形向下扫描。 - * - * 流程: - * 1) 第1行: (effLeft, effTop) -> (effRight, effTop) - * 2) 下移 spacing - * 3) 第2行: (effRight, effTop - spacing) -> (effLeft, effTop - spacing) - * 4) 下移 spacing - * 重复,直到无法再下移。 - */ - private static List generateHorizontalZigzagTopDown( - int effLeft, - int effRight, - int effBottom, - int effTop, - int spacing - ) { - List result = new ArrayList<>(); - int currentX = effLeft; - int currentY = effTop; - boolean goingRight = true; - - // 起点 - result.add(new Point(currentX, currentY)); - - while (true) { - // 水平移动到对侧 - if (goingRight) { - currentX = effRight; - } else { - currentX = effLeft; - } - result.add(new Point(currentX, currentY)); - - // 往下移动 spacing - int nextY = currentY - spacing; - if (nextY < effBottom) { - break; // 无法再往下 - } - currentY = nextY; - result.add(new Point(currentX, currentY)); - - // 反转方向 - goingRight = !goingRight; - } - return result; - } - - /** - * [effLeft..effRight] x [effBottom..effTop] 区域内, - * 从(左上)开始垂直之字形向右扫描。 - * - * 流程: - * 1) 第1列: (effLeft, effTop) -> (effLeft, effBottom) - * 2) 右移 spacing - * 3) 第2列: (effLeft+spacing, effBottom) -> (effLeft+spacing, effTop) - * 4) 右移 spacing - * 重复,直到无法再右移。 - */ - private static List generateVerticalZigzagLeftRight( - int effLeft, - int effRight, - int effBottom, - int effTop, - int spacing - ) { - List result = new ArrayList<>(); - int currentX = effLeft; - int currentY = effTop; - boolean goingDown = true; // 第一列先从上往下 - - // 起点 - result.add(new Point(currentX, currentY)); - - while (true) { - // 垂直移动到对侧 - if (goingDown) { - currentY = effBottom; - } else { - currentY = effTop; - } - result.add(new Point(currentX, currentY)); - - // 向右移动 spacing - int nextX = currentX + spacing; - if (nextX > effRight) { - break; // 无法再右移 - } - currentX = nextX; - result.add(new Point(currentX, currentY)); - - // 反转 - goingDown = !goingDown; - } - return result; - } - - // ============= 简单测试 ============= - public static void main(String[] args) { - int left = 0, right = 10; - int bottom = 0, top = 6; - int spacing = 2; - - // 1) 测试水平之字形(从上往下) - System.out.println("=== HORIZONTAL_ZIGZAG_TOP_DOWN ==="); - List horizontalPath = generatePathPoints( - left, right, bottom, top, spacing, MoveMode.HORIZONTAL_ZIGZAG_TOP_DOWN - ); - for (Point p : horizontalPath) { - System.out.println(p); - } - - // 2) 测试垂直之字形(从左往右) - System.out.println("\n=== VERTICAL_ZIGZAG_LEFT_RIGHT ==="); - List verticalPath = generatePathPoints( - left, right, bottom, top, spacing, MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT - ); - for (Point p : verticalPath) { - System.out.println(p); - } - } -} - diff --git a/src/main/java/com/qyft/ms/test/PathGenerator/PathPanelJPanel.java b/src/main/java/com/qyft/ms/test/PathGenerator/PathPanelJPanel.java deleted file mode 100644 index a044cf7..0000000 --- a/src/main/java/com/qyft/ms/test/PathGenerator/PathPanelJPanel.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.qyft.ms.test.PathGenerator; - -import javax.swing.*; -import java.awt.*; -import java.util.List; - -/** - * 自定义面板:绘制网格和路径。 - * 坐标系:数学上left..right, bottom..top;GUI需翻转y轴。 - */ -public class PathPanelJPanel extends JPanel { - - private final int left; - private final int right; - private final int bottom; - private final int top; - private final List pathPoints; - - // 每单位1点对应多少像素,可自行调节 - private static final int CELL_SIZE = 20; - - public PathPanelJPanel(int left, int right, int bottom, int top, List pathPoints) { - this.left = left; - this.right = right; - this.bottom = bottom; - this.top = top; - this.pathPoints = pathPoints; - } - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - - Graphics2D g2d = (Graphics2D) g.create(); - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - - // 1) 画网格 - drawGrid(g2d); - // 2) 画路径 - drawPath(g2d); - - g2d.dispose(); - } - - /** 绘制网格线和坐标标签 */ - private void drawGrid(Graphics2D g2d) { - g2d.setColor(Color.LIGHT_GRAY); - - // 画垂直线 - for (int x = left; x <= right; x++) { - int px = worldToPanelX(x); - g2d.drawLine(px, worldToPanelY(bottom), px, worldToPanelY(top)); - } - // 画水平线 - for (int y = bottom; y <= top; y++) { - int py = worldToPanelY(y); - g2d.drawLine(worldToPanelX(left), py, worldToPanelX(right), py); - } - - // 坐标文本标注(可选) -// g2d.setColor(Color.BLACK); -// for (int x = left; x <= right; x++) { -// for (int y = bottom; y <= top; y++) { -// int px = worldToPanelX(x) + 2; -// int py = worldToPanelY(y) - 2; -// g2d.drawString(x + "," + y, px, py); -// } -// } - } - - /** 绘制之字形路径及每个拐点小圆,边绘制边输出坐标 */ - private void drawPath(Graphics2D g2d) { - // 先用红色线段连接拐点 - g2d.setColor(Color.RED); - g2d.setStroke(new BasicStroke(2f)); - - for (int i = 0; i < pathPoints.size() - 1; i++) { - Point p1 = pathPoints.get(i); - Point p2 = pathPoints.get(i + 1); - - int x1 = worldToPanelX(p1.x); - int y1 = worldToPanelY(p1.y); - int x2 = worldToPanelX(p2.x); - int y2 = worldToPanelY(p2.y); - - g2d.drawLine(x1, y1, x2, y2); - } - - // 再用蓝色在拐点上画小圆点 - g2d.setColor(Color.BLUE); - for (Point p : pathPoints) { - int cx = worldToPanelX(p.x); - int cy = worldToPanelY(p.y); - - // 同时打印到控制台,说明“已经画到了这个点” - System.out.println("画点: (" + p.x + ", " + p.y + ")"); - - g2d.fillOval(cx - 4, cy - 4, 8, 8); - } - } - - /** 坐标转换:世界X -> 面板像素X */ - private int worldToPanelX(int worldX) { - return (worldX - left) * CELL_SIZE; - } - - /** 坐标转换:世界Y -> 面板像素Y(翻转y) */ - private int worldToPanelY(int worldY) { - // 矩形整体高度(像素) - int totalHeight = (top - bottom) * CELL_SIZE; - // 自下而上 -> GUI坐标需自上而下翻转 - return totalHeight - (worldY - bottom) * CELL_SIZE; - } -}