Swing中绘制超级拥挤的点
Drawing super crowded points in Swing
我需要能够通过 Swing 为图形绘制非常拥挤的点。例如:让我们看看以下几点:
p1=(35.19589389346247,32.10152879327731),
p2 = (35.20319591121872,32.10318254621849),
p3 = (35.20752617756255,32.1025646605042),
p4 = (35.21007339305892,32.10107446554622),
p5 = (35.21310882485876,32.104636394957986),
等...
我想画它们,但是可以看到,它们的坐标非常密集。另外,扩大比例也没有用,只是移动了框内的点。
下面是我的尝试:
private void Oval(Graphics2D g2, String id, int locationX, int locationY) {
AffineTransform old = g2.getTransform();
g2.scale(4,4);
g2.setPaint(Color.blue);
g2.fillOval(locationX - Radius, locationY - Radius, Radius * 2, Radius * 2);
g2.setPaint(Color.black);
g2.drawString(id, locationX + Radius, locationY - Radius);
g2.setTransform(old);
}
考虑到面板尺寸为(1000,1000),这是点绘制的代码。
这是点绘图的输出:
如您所见,它们相互覆盖,这显然不是我想要做的。我的目标是将它们分开,以便我们可以清楚地看到这些点。
因此,基本概念是对“虚拟”坐标(您的点)进行某种“转换”到(屏幕的)“物理”坐标
您确实尝试通过缩放图形上下文来做到这一点,但这样做的问题是它也会缩放球的大小,这并不是您真正想要做的。
以下是一种可能解决方案的基本示例。
它计算由点表示的区域的 min/max 范围,然后使用组件大小平移点,使它们适合可见 space
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GraphPoint {
private String id;
private Point2D point;
public GraphPoint(String id, Point2D point) {
this.id = id;
this.point = point;
}
public String getId() {
return id;
}
public Point2D getPoint() {
return point;
}
}
public class TestPane extends JPanel {
private List<GraphPoint> points;
private int radius = 10;
private double virtualScale = 1.0;
private Point2D minRange;
private Point2D maxRange;
public TestPane() {
points = new ArrayList<>(16);
points.add(new GraphPoint("1", new Point2D.Double(35.19589389346247, 32.10152879327731)));
points.add(new GraphPoint("2", new Point2D.Double(35.20319591121872, 32.10318254621849)));
points.add(new GraphPoint("3", new Point2D.Double(35.20752617756255, 32.1025646605042)));
points.add(new GraphPoint("4", new Point2D.Double(35.21007339305892, 32.10107446554622)));
points.add(new GraphPoint("5", new Point2D.Double(35.21310882485876, 32.104636394957986)));
double minX = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
double minY = Double.MAX_VALUE;
double maxY = Double.MIN_VALUE;
for (GraphPoint gp : points) {
minX = Math.min(minX, gp.getPoint().getX());
maxX = Math.max(maxX, gp.getPoint().getX());
minY = Math.min(minY, gp.getPoint().getY());
maxY = Math.max(maxY, gp.getPoint().getY());
}
minRange = new Point2D.Double(minX, minY);
maxRange = new Point2D.Double(maxX, maxY);
double xRange = maxRange.getX() - minRange.getX();
double yRange = maxRange.getY() - minRange.getY();
System.out.println(minRange.getX() + " - " + minRange.getY());
System.out.println(maxRange.getX() + " - " + maxRange.getY());
System.out.println(xRange + " - " + yRange);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (GraphPoint gp : points) {
paintPoint(g2d, gp);
}
g2d.dispose();
}
private void paintPoint(Graphics2D g2d, GraphPoint gp) {
Graphics2D g2 = (Graphics2D) g2d.create();
Point2D translated = translate(gp);
double xPos = translated.getX();
double yPos = translated.getY();
double offset = radius;
g2.translate(xPos - offset, yPos - offset);
g2.setPaint(Color.blue);
g2.fill(new Ellipse2D.Double(0, 0, offset * 2, offset * 2));
g2.dispose();
}
protected Point2D translate(GraphPoint gp) {
double xRange = maxRange.getX() - minRange.getX();
double yRange = maxRange.getY() - minRange.getY();
double offset = radius;
double width = getWidth() - (offset * 2);
double height = getHeight() - (offset * 2);
double xScale = width / xRange;
double yScale = height / yRange;
Point2D original = gp.getPoint();
double x = offset + ((original.getX() - minRange.getX()) * xScale);
double y = offset + ((original.getY() - minRange.getY()) * yScale);
System.out.println(gp.getId() + " " + x + " x " + y);
return new Point2D.Double(x, y);
}
}
}
我必须强调,这是一种可能的解决方案,您的实际要求可能会有所不同,但这应该为您提供一个起点,您可以从中定义自己的算法,例如,您可以定义自己的 min/max 范围(即 34x30 到 36x33)
the String I have tried now for 1 hour and I didn't get it I did edit your code already you help us a lot. the string above the points the id I mean point "0" this string above the point if u can help us or show us it will be appreciated a lot!
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GraphPoint {
private String id;
private Point2D point;
public GraphPoint(String id, Point2D point) {
this.id = id;
this.point = point;
}
public String getId() {
return id;
}
public Point2D getPoint() {
return point;
}
}
public class TestPane extends JPanel {
private List<GraphPoint> points;
private int radius = 10;
private double virtualScale = 1.0;
private Point2D minRange;
private Point2D maxRange;
public TestPane() {
points = new ArrayList<>(16);
points.add(new GraphPoint("1", new Point2D.Double(35.19589389346247, 32.10152879327731)));
points.add(new GraphPoint("2", new Point2D.Double(35.20319591121872, 32.10318254621849)));
points.add(new GraphPoint("3", new Point2D.Double(35.20752617756255, 32.1025646605042)));
points.add(new GraphPoint("4", new Point2D.Double(35.21007339305892, 32.10107446554622)));
points.add(new GraphPoint("5", new Point2D.Double(35.21310882485876, 32.104636394957986)));
double minX = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
double minY = Double.MAX_VALUE;
double maxY = Double.MIN_VALUE;
for (GraphPoint gp : points) {
minX = Math.min(minX, gp.getPoint().getX());
maxX = Math.max(maxX, gp.getPoint().getX());
minY = Math.min(minY, gp.getPoint().getY());
maxY = Math.max(maxY, gp.getPoint().getY());
}
minRange = new Point2D.Double(minX, minY);
maxRange = new Point2D.Double(maxX, maxY);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
FontMetrics fm = g2d.getFontMetrics();
double insets = fm.getHeight() + radius;
// I'm lazy, so I'm drawing the lines first, then painting
// the points over the top as I can't be bothered to workout
// a clever way to ensure the lines are always painted under
// the dots
GraphPoint lastPoint = null;
for (GraphPoint gp : points) {
if (lastPoint != null) {
paintLine(g2d, lastPoint, gp, insets);
}
lastPoint = gp;
}
for (GraphPoint gp : points) {
paintPoint(g2d, gp, insets);
}
g2d.dispose();
}
private void paintLine(Graphics2D g2d, GraphPoint from, GraphPoint to, double insets) {
Point2D fromPoint = translate(from, insets);
Point2D toPoint = translate(to, insets);
g2d.setColor(Color.RED);
g2d.draw(new Line2D.Double(fromPoint, toPoint));
}
private void paintPoint(Graphics2D g2d, GraphPoint gp, double insets) {
Graphics2D g2 = (Graphics2D) g2d.create();
Point2D translated = translate(gp, insets);
double xPos = translated.getX();
double yPos = translated.getY();
double offset = radius;
g2.translate(xPos - offset, yPos - offset);
g2.setPaint(Color.blue);
g2.fill(new Ellipse2D.Double(0, 0, offset * 2, offset * 2));
FontMetrics fm = g2d.getFontMetrics();
String text = gp.getId();
double x = xPos - (fm.stringWidth(text) / 2);
double y = (yPos - radius - fm.getHeight()) + fm.getAscent();
g2d.drawString(text, (float)x, (float)y);
g2.dispose();
}
protected Point2D translate(GraphPoint gp, double insets) {
double xRange = maxRange.getX() - minRange.getX();
double yRange = maxRange.getY() - minRange.getY();
double offset = insets;
double width = getWidth() - (offset * 2);
double height = getHeight() - (offset * 2);
double xScale = width / xRange;
double yScale = height / yRange;
Point2D original = gp.getPoint();
double x = offset + ((original.getX() - minRange.getX()) * xScale);
double y = offset + ((original.getY() - minRange.getY()) * yScale);
System.out.println(gp.getId() + " " + x + " x " + y);
return new Point2D.Double(x, y);
}
}
}
文本的技巧是理解我已经翻译了上下文的原点,所以 0x0 位置实际上是圆的中间,所以你需要从中减去文本偏移量。
我还进行了轻微更新以允许工作流传入一个 insets
值,这将减少可用的可见区域以“帮助”补偿文本
another question can make a line with an arrow in the tip
见...
- Java make a directed line and make it move
一些想法。请注意,这变得越来越复杂,因为箭头需要旋转到他们正在看的点, 之类的东西可能会有所帮助
我需要能够通过 Swing 为图形绘制非常拥挤的点。例如:让我们看看以下几点:
p1=(35.19589389346247,32.10152879327731),
p2 = (35.20319591121872,32.10318254621849),
p3 = (35.20752617756255,32.1025646605042),
p4 = (35.21007339305892,32.10107446554622),
p5 = (35.21310882485876,32.104636394957986),
等...
我想画它们,但是可以看到,它们的坐标非常密集。另外,扩大比例也没有用,只是移动了框内的点。
下面是我的尝试:
private void Oval(Graphics2D g2, String id, int locationX, int locationY) {
AffineTransform old = g2.getTransform();
g2.scale(4,4);
g2.setPaint(Color.blue);
g2.fillOval(locationX - Radius, locationY - Radius, Radius * 2, Radius * 2);
g2.setPaint(Color.black);
g2.drawString(id, locationX + Radius, locationY - Radius);
g2.setTransform(old);
}
考虑到面板尺寸为(1000,1000),这是点绘制的代码。
这是点绘图的输出:
如您所见,它们相互覆盖,这显然不是我想要做的。我的目标是将它们分开,以便我们可以清楚地看到这些点。
因此,基本概念是对“虚拟”坐标(您的点)进行某种“转换”到(屏幕的)“物理”坐标
您确实尝试通过缩放图形上下文来做到这一点,但这样做的问题是它也会缩放球的大小,这并不是您真正想要做的。
以下是一种可能解决方案的基本示例。
它计算由点表示的区域的 min/max 范围,然后使用组件大小平移点,使它们适合可见 space
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GraphPoint {
private String id;
private Point2D point;
public GraphPoint(String id, Point2D point) {
this.id = id;
this.point = point;
}
public String getId() {
return id;
}
public Point2D getPoint() {
return point;
}
}
public class TestPane extends JPanel {
private List<GraphPoint> points;
private int radius = 10;
private double virtualScale = 1.0;
private Point2D minRange;
private Point2D maxRange;
public TestPane() {
points = new ArrayList<>(16);
points.add(new GraphPoint("1", new Point2D.Double(35.19589389346247, 32.10152879327731)));
points.add(new GraphPoint("2", new Point2D.Double(35.20319591121872, 32.10318254621849)));
points.add(new GraphPoint("3", new Point2D.Double(35.20752617756255, 32.1025646605042)));
points.add(new GraphPoint("4", new Point2D.Double(35.21007339305892, 32.10107446554622)));
points.add(new GraphPoint("5", new Point2D.Double(35.21310882485876, 32.104636394957986)));
double minX = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
double minY = Double.MAX_VALUE;
double maxY = Double.MIN_VALUE;
for (GraphPoint gp : points) {
minX = Math.min(minX, gp.getPoint().getX());
maxX = Math.max(maxX, gp.getPoint().getX());
minY = Math.min(minY, gp.getPoint().getY());
maxY = Math.max(maxY, gp.getPoint().getY());
}
minRange = new Point2D.Double(minX, minY);
maxRange = new Point2D.Double(maxX, maxY);
double xRange = maxRange.getX() - minRange.getX();
double yRange = maxRange.getY() - minRange.getY();
System.out.println(minRange.getX() + " - " + minRange.getY());
System.out.println(maxRange.getX() + " - " + maxRange.getY());
System.out.println(xRange + " - " + yRange);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (GraphPoint gp : points) {
paintPoint(g2d, gp);
}
g2d.dispose();
}
private void paintPoint(Graphics2D g2d, GraphPoint gp) {
Graphics2D g2 = (Graphics2D) g2d.create();
Point2D translated = translate(gp);
double xPos = translated.getX();
double yPos = translated.getY();
double offset = radius;
g2.translate(xPos - offset, yPos - offset);
g2.setPaint(Color.blue);
g2.fill(new Ellipse2D.Double(0, 0, offset * 2, offset * 2));
g2.dispose();
}
protected Point2D translate(GraphPoint gp) {
double xRange = maxRange.getX() - minRange.getX();
double yRange = maxRange.getY() - minRange.getY();
double offset = radius;
double width = getWidth() - (offset * 2);
double height = getHeight() - (offset * 2);
double xScale = width / xRange;
double yScale = height / yRange;
Point2D original = gp.getPoint();
double x = offset + ((original.getX() - minRange.getX()) * xScale);
double y = offset + ((original.getY() - minRange.getY()) * yScale);
System.out.println(gp.getId() + " " + x + " x " + y);
return new Point2D.Double(x, y);
}
}
}
我必须强调,这是一种可能的解决方案,您的实际要求可能会有所不同,但这应该为您提供一个起点,您可以从中定义自己的算法,例如,您可以定义自己的 min/max 范围(即 34x30 到 36x33)
the String I have tried now for 1 hour and I didn't get it I did edit your code already you help us a lot. the string above the points the id I mean point "0" this string above the point if u can help us or show us it will be appreciated a lot!
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class GraphPoint {
private String id;
private Point2D point;
public GraphPoint(String id, Point2D point) {
this.id = id;
this.point = point;
}
public String getId() {
return id;
}
public Point2D getPoint() {
return point;
}
}
public class TestPane extends JPanel {
private List<GraphPoint> points;
private int radius = 10;
private double virtualScale = 1.0;
private Point2D minRange;
private Point2D maxRange;
public TestPane() {
points = new ArrayList<>(16);
points.add(new GraphPoint("1", new Point2D.Double(35.19589389346247, 32.10152879327731)));
points.add(new GraphPoint("2", new Point2D.Double(35.20319591121872, 32.10318254621849)));
points.add(new GraphPoint("3", new Point2D.Double(35.20752617756255, 32.1025646605042)));
points.add(new GraphPoint("4", new Point2D.Double(35.21007339305892, 32.10107446554622)));
points.add(new GraphPoint("5", new Point2D.Double(35.21310882485876, 32.104636394957986)));
double minX = Double.MAX_VALUE;
double maxX = Double.MIN_VALUE;
double minY = Double.MAX_VALUE;
double maxY = Double.MIN_VALUE;
for (GraphPoint gp : points) {
minX = Math.min(minX, gp.getPoint().getX());
maxX = Math.max(maxX, gp.getPoint().getX());
minY = Math.min(minY, gp.getPoint().getY());
maxY = Math.max(maxY, gp.getPoint().getY());
}
minRange = new Point2D.Double(minX, minY);
maxRange = new Point2D.Double(maxX, maxY);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
FontMetrics fm = g2d.getFontMetrics();
double insets = fm.getHeight() + radius;
// I'm lazy, so I'm drawing the lines first, then painting
// the points over the top as I can't be bothered to workout
// a clever way to ensure the lines are always painted under
// the dots
GraphPoint lastPoint = null;
for (GraphPoint gp : points) {
if (lastPoint != null) {
paintLine(g2d, lastPoint, gp, insets);
}
lastPoint = gp;
}
for (GraphPoint gp : points) {
paintPoint(g2d, gp, insets);
}
g2d.dispose();
}
private void paintLine(Graphics2D g2d, GraphPoint from, GraphPoint to, double insets) {
Point2D fromPoint = translate(from, insets);
Point2D toPoint = translate(to, insets);
g2d.setColor(Color.RED);
g2d.draw(new Line2D.Double(fromPoint, toPoint));
}
private void paintPoint(Graphics2D g2d, GraphPoint gp, double insets) {
Graphics2D g2 = (Graphics2D) g2d.create();
Point2D translated = translate(gp, insets);
double xPos = translated.getX();
double yPos = translated.getY();
double offset = radius;
g2.translate(xPos - offset, yPos - offset);
g2.setPaint(Color.blue);
g2.fill(new Ellipse2D.Double(0, 0, offset * 2, offset * 2));
FontMetrics fm = g2d.getFontMetrics();
String text = gp.getId();
double x = xPos - (fm.stringWidth(text) / 2);
double y = (yPos - radius - fm.getHeight()) + fm.getAscent();
g2d.drawString(text, (float)x, (float)y);
g2.dispose();
}
protected Point2D translate(GraphPoint gp, double insets) {
double xRange = maxRange.getX() - minRange.getX();
double yRange = maxRange.getY() - minRange.getY();
double offset = insets;
double width = getWidth() - (offset * 2);
double height = getHeight() - (offset * 2);
double xScale = width / xRange;
double yScale = height / yRange;
Point2D original = gp.getPoint();
double x = offset + ((original.getX() - minRange.getX()) * xScale);
double y = offset + ((original.getY() - minRange.getY()) * yScale);
System.out.println(gp.getId() + " " + x + " x " + y);
return new Point2D.Double(x, y);
}
}
}
文本的技巧是理解我已经翻译了上下文的原点,所以 0x0 位置实际上是圆的中间,所以你需要从中减去文本偏移量。
我还进行了轻微更新以允许工作流传入一个 insets
值,这将减少可用的可见区域以“帮助”补偿文本
another question can make a line with an arrow in the tip
见...
- Java make a directed line and make it move
一些想法。请注意,这变得越来越复杂,因为箭头需要旋转到他们正在看的点,