From f05cc1a5f3f0aee782aeb6547f0416e9e07b6cd0 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:46:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0=E5=96=B7=E5=A4=B4?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E8=B7=AF=E5=BE=84=E7=AE=97=E6=B3=95=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/qyft/ms/app/service/WebSocketService.java | 2 +- .../com/qyft/ms/test/PathGenerator/MainFrame.java | 47 +++++ .../qyft/ms/test/PathGenerator/PathGenerator.java | 208 +++++++++++++++++++++ .../ms/test/PathGenerator/PathPanelJPanel.java | 114 +++++++++++ 4 files changed, 370 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java create mode 100644 src/main/java/com/qyft/ms/test/PathGenerator/PathGenerator.java create mode 100644 src/main/java/com/qyft/ms/test/PathGenerator/PathPanelJPanel.java diff --git a/src/main/java/com/qyft/ms/app/service/WebSocketService.java b/src/main/java/com/qyft/ms/app/service/WebSocketService.java index 7f7d051..bbe8c7a 100644 --- a/src/main/java/com/qyft/ms/app/service/WebSocketService.java +++ b/src/main/java/com/qyft/ms/app/service/WebSocketService.java @@ -20,7 +20,7 @@ public class WebSocketService { @PostConstruct public void init() { // 设置 WebSocketService 实例到 WebSocketServer - WebSocketServer.setWebSocketService(this); +// WebSocketServer.setWebSocketService(this); } // 新增方法:处理接收到的消息 diff --git a/src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java b/src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java new file mode 100644 index 0000000..2bc069b --- /dev/null +++ b/src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java @@ -0,0 +1,47 @@ +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 new file mode 100644 index 0000000..ebb6143 --- /dev/null +++ b/src/main/java/com/qyft/ms/test/PathGenerator/PathGenerator.java @@ -0,0 +1,208 @@ +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 new file mode 100644 index 0000000..a044cf7 --- /dev/null +++ b/src/main/java/com/qyft/ms/test/PathGenerator/PathPanelJPanel.java @@ -0,0 +1,114 @@ +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; + } +}