我把格点改成double之后为什么选不出点也画不出图来了,画图的时候可以直接舍入到int,package com.smics.apps;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class BfsFindShot extends JFrame {
public static void main(String[] args) {
List<String> list1 = calcAllShot();
System.out.println("===========");
List<String> list2 = new BfsFindShot().selectPoints(list1,11);
SwingUtilities.invokeLater(() -> {
BfsFindShot visualizer = new BfsFindShot();
visualizer.addPoints(list1, list2);
visualizer.setVisible(true);
});
}
private final List<Point> pointsList1 = new ArrayList<>();
private final List<Point> pointsList2 = new ArrayList<>();
public BfsFindShot() {
setTitle("点分布预览");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public void addPoints(List<String> list1, List<String> list2) {
pointsList1.clear();
pointsList2.clear();
for (String s : list1) pointsList1.add(parsePointAwt(s));
for (String s : list2) pointsList2.add(parsePointAwt(s));
DrawingPanel panel = new DrawingPanel();
panel.setSiteCount(list2.size());
add(panel);
}
private Point parsePointAwt(String s) {
s = s.replaceAll("[{} ]", "");
String[] coords = s.split(",");
return new Point(
(int) Math.round(Double.parseDouble(coords[0])),
(int) Math.round(Double.parseDouble(coords[1]))
);
}
class DrawingPanel extends JPanel {
private int siteCount; // 新增:存储选点数
// 新增:设置选点数
public void setSiteCount(int count) {
this.siteCount = count;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
// 1. 动态获取并绘制同心圆
g.setColor(Color.BLUE);
ZoneConfig config = CONFIG_MAP.get(siteCount); // 直接从常量配置获取
if (config != null) {
for (double radius : config.radiusBounds) {
int diameter = (int)(radius * 2);
g.drawOval(centerX - (int)radius, centerY - (int)radius, diameter, diameter);
}
}
// 2. 绘制坐标轴(保持不变)
g.setColor(Color.LIGHT_GRAY);
g.drawLine(0, centerY, getWidth(), centerY);
g.drawLine(centerX, 0, centerX, getHeight());
// 3. 绘制点集(保持不变)
g.setColor(Color.BLACK);
for (Point p : pointsList1) {
drawPoint(g, centerX + p.x, centerY - p.y);
}
g.setColor(Color.RED);
for (Point p : pointsList2) {
drawPoint(g, centerX + p.x, centerY - p.y);
}
}
private void drawPoint(Graphics g, int x, int y) {
g.fillOval(x - 3, y - 3, 6, 6);
}
}
private static List<String> calcAllShot() {
double radius = 150;
double w = 24;
double h = 28;
double x0 = 0;
double y0 = 0;
List<String> rectangles = new ArrayList<>();
Set<String> visited = new HashSet<>();
Queue<double[]> queue = new LinkedList<>();
double startX = x0 - w / 2;
double startY = y0 - h / 2;
queue.offer(new double[]{startX, startY});
visited.add(formatKey(startX) + "," + formatKey(startY));
while (!queue.isEmpty()) {
double[] current = queue.poll();
double x = current[0];
double y = current[1];
// 四个角坐标
boolean allInCircle = isInCircle(x, y, radius) ||
isInCircle(x + w, y, radius) ||
isInCircle(x, y + h, radius) ||
isInCircle(x + w, y + h, radius);
if (allInCircle) {
rectangles.add("{" + format(x) + "," + format(y) + "}");
double[][] directions = {
{-w, 0}, {w, 0}, {0, -h}, {0, h}
};
for (double[] dir : directions) {
double nx = x + dir[0];
double ny = y + dir[1];
String key = formatKey(nx) + "," + formatKey(ny);
if (!visited.contains(key)) {
visited.add(key);
queue.offer(new double[]{nx, ny});
}
}
}
}
rectangles.sort((a, b) -> {
double x1 = parseX(a);
double y1 = parseY(a);
double x2 = parseX(b);
double y2 = parseY(b);
if (x1 != x2) {
return Double.compare(x1, x2);
} else {
return Double.compare(y1, y2);
}
});
for (String rect : rectangles) {
System.out.println(rect);
}
return rectangles;
}
private static double parseX(String s) {
int commaIndex = s.indexOf(',');
return Double.parseDouble(s.substring(1, commaIndex));
}
private static double parseY(String s) {
int commaIndex = s.indexOf(',');
int endIndex = s.length() - 1;
return Double.parseDouble(s.substring(commaIndex + 1, endIndex));
}
public static boolean isInCircle(double x, double y, double radius) {
return x * x + y * y <= radius * radius;
}
private static String format(double value) {
return String.format("%.6f", value);
}
private static String formatKey(double value) {
return String.format("%.6f", value).replaceAll("0*$", "").replaceAll("\\.$", "");
}
// 配置定义(选点数 -> [圈半径边界, 圈选点数])
private static final Map<Integer, ZoneConfig> CONFIG_MAP = new HashMap<>();
static {
// 13点:5圈(30/60/90/120/140) → 1/2/2/4/4
CONFIG_MAP.put(13, new ZoneConfig(
new double[]{30, 60, 90, 120, 140},
new int[]{1, 2, 2, 4, 4}
));
// 11点:5圈(30/60/90/120/140) → 1/1/3/4/2
CONFIG_MAP.put(11, new ZoneConfig(
new double[]{30, 60, 90, 120, 140},
new int[]{1, 1, 3, 4, 2}
));
// 9点:3圈(45/95/140) → 1/4/4
CONFIG_MAP.put(9, new ZoneConfig(
new double[]{45, 95, 140},
new int[]{1, 4, 4}
));
// 5点:3圈(45/95/140) → 1/2/2
CONFIG_MAP.put(5, new ZoneConfig(
new double[]{45, 95, 140},
new int[]{1, 2, 2}
));
}
public List<String> selectPoints(List<String> pointStrings, int siteCount) {
ZoneConfig config = CONFIG_MAP.get(siteCount);
if (config == null) throw new IllegalArgumentException("不支持的点数配置");
// 解析点数据
List<ShotPoint> allPoints = pointStrings.stream()
.map(this::parsePoint)
.filter(Objects::nonNull)
.filter(p -> p.radius <= config.outerRadius())
.collect(Collectors.toList());
// 生成半径分区
List<RadiusRing> rings = createRings(config, allPoints);
// 计算动态角度偏移(自动交错)
double[] angleOffsets = calculateAngleOffsets(rings);
// 分层选点
return selectPointsFromRings(rings, angleOffsets);
}
//======================== 核心算法 ========================//
private List<RadiusRing> createRings(ZoneConfig config, List<ShotPoint> points) {
List<RadiusRing> rings = new ArrayList<>();
double prevBoundary = 0;
for (int i = 0; i < config.radiusBounds.length; i++) {
double lower = prevBoundary;
double upper = config.radiusBounds[i];
double target = (lower + upper) / 2; // 目标半径(相邻圈平均值)
List<ShotPoint> ringPoints = points.stream()
.filter(p -> p.radius >= lower && p.radius <= upper)
.collect(Collectors.toList());
rings.add(new RadiusRing(
ringPoints, config.pointCounts[i], target
));
prevBoundary = upper;
}
return rings;
}
private double[] calculateAngleOffsets(List<RadiusRing> rings) {
double[] offsets = new double[rings.size()];
int prevStep = 0;
int step = 0;
for (int i = 0; i < rings.size(); i++) {
step = rings.get(i).targetCount;
if (i == 0) {
offsets[i] = 0; // 最内层不偏移
} else {
// 自动计算偏移量:内层角度步长的一半
if(prevStep == 1) {
if(step == 1) {
offsets[i] = 180;
}else if (step == 2) {
offsets[i] = 90;
}else if (step == 3) {
offsets[i] = 60;
}else if (step == 4) {
offsets[i] = 45;
}
}else if (prevStep == 2) {
if(step == 2) {
offsets[i] = 90;
}else if (step == 4) {
offsets[i] = 45;
}
}else if (prevStep == 3) {
if(step == 4) {
offsets[i] = 15;
}
}else if (prevStep == 4) {
if(step == 2) {
offsets[i] = 45;
}else if (step == 4) {
offsets[i] = 45;
}
}
offsets[i] += offsets[i-1];
}
prevStep = step;
}
return offsets;
}
private List<String> selectPointsFromRings(List<RadiusRing> rings, double[] angleOffsets) {
List<String> result = new ArrayList<>();
for (int i = 0; i < rings.size(); i++) {
RadiusRing ring = rings.get(i);
if (ring.points.isEmpty()) continue;
// 特殊处理:最内环选中心点
if (i == 0 && ring.targetCount == 1) {
ShotPoint center = ring.points.stream()
.min(Comparator.comparingDouble(p -> p.radius))
.orElse(ring.points.get(0));
result.add(center.original);
continue;
}
// 通用环形选点
result.addAll(selectRingWithOffset(
ring.points,
ring.targetCount,
angleOffsets[i],
ring.targetRadius
));
}
return result;
}
private List<String> selectRingWithOffset(
List<ShotPoint> points, int count, double offset, double targetRadius
) {
List<String> selected = new ArrayList<>();
List<ShotPoint> candidates = new ArrayList<>(points);
double angleStep = 360.0 / count;
for (int i = 0; i < count; i++) {
if (candidates.isEmpty()) break;
double targetAngle = (i * angleStep + offset) % 360;
// 角度优先级高于半径
ShotPoint best = candidates.stream()
.min(Comparator.<ShotPoint>comparingDouble(p ->
circularDistance(p.angle, targetAngle) // 第一优先级:角度匹配
).thenComparingDouble(p ->
Math.abs(p.radius - targetRadius) // 第二优先级:半径匹配
))
.orElse(null);
if (best != null) {
selected.add(best.original);
candidates.remove(best);
}
}
return selected;
}
//======================== 工具方法 ========================//
private ShotPoint parsePoint(String s) {
try {
String clean = s.replaceAll("[{}]", "");
String[] coords = clean.split(",");
int x = Integer.parseInt(coords[0].trim());
int y = Integer.parseInt(coords[1].trim());
return new ShotPoint(x, y, s);
} catch (Exception e) {
return null;
}
}
private double circularDistance(double a, double b) {
double diff = Math.abs(a - b) % 360;
return Math.min(diff, 360 - diff);
}
//======================== 数据结构 ========================//
static class ZoneConfig {
final double[] radiusBounds; // 圈半径边界
final int[] pointCounts; // 每圈选点数
final double outerRadius; // 最大半径
ZoneConfig(double[] radiusBounds, int[] pointCounts) {
this.radiusBounds = radiusBounds;
this.pointCounts = pointCounts;
this.outerRadius = radiusBounds[radiusBounds.length - 1];
}
double outerRadius() {
return outerRadius;
}
}
static class RadiusRing {
final List<ShotPoint> points;
final int targetCount;
final double targetRadius;
RadiusRing(List<ShotPoint> points, int targetCount, double targetRadius) {
this.points = points;
this.targetCount = targetCount;
this.targetRadius = targetRadius;
}
}
static class ShotPoint {
final int x, y;
final double radius;
final double angle;
final String original;
ShotPoint(int x, int y, String original) {
this.x = x;
this.y = y;
this.original = original;
this.radius = Math.sqrt(x*x + y*y);
this.angle = (Math.toDegrees(Math.atan2(y, x)) + 360) % 360;
}
}
}
最新发布