Browse Source

feat:添加喷头移动路径算法测试类

master
白凤吉 5 months ago
parent
commit
f05cc1a5f3
  1. 2
      src/main/java/com/qyft/ms/app/service/WebSocketService.java
  2. 47
      src/main/java/com/qyft/ms/test/PathGenerator/MainFrame.java
  3. 208
      src/main/java/com/qyft/ms/test/PathGenerator/PathGenerator.java
  4. 114
      src/main/java/com/qyft/ms/test/PathGenerator/PathPanelJPanel.java

2
src/main/java/com/qyft/ms/app/service/WebSocketService.java

@ -20,7 +20,7 @@ public class WebSocketService {
@PostConstruct @PostConstruct
public void init() { public void init() {
// 设置 WebSocketService 实例到 WebSocketServer // 设置 WebSocketService 实例到 WebSocketServer
WebSocketServer.setWebSocketService(this);
// WebSocketServer.setWebSocketService(this);
} }
// 新增方法处理接收到的消息 // 新增方法处理接收到的消息

47
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<Point> 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); // 居中显示
}
}

208
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<Point> 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<Point> generateHorizontalZigzagTopDown(
int effLeft,
int effRight,
int effBottom,
int effTop,
int spacing
) {
List<Point> 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<Point> generateVerticalZigzagLeftRight(
int effLeft,
int effRight,
int effBottom,
int effTop,
int spacing
) {
List<Point> 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<Point> 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<Point> verticalPath = generatePathPoints(
left, right, bottom, top, spacing, MoveMode.VERTICAL_ZIGZAG_LEFT_RIGHT
);
for (Point p : verticalPath) {
System.out.println(p);
}
}
}

114
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..topGUI需翻转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<Point> pathPoints;
// 每单位1点对应多少像素可自行调节
private static final int CELL_SIZE = 20;
public PathPanelJPanel(int left, int right, int bottom, int top, List<Point> 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;
}
}
Loading…
Cancel
Save