如何使用很少坐标的 AffineTransform?
How to use AffineTransform with very little coordinates?
我有一组二维点。它们的X和Y大于-2小于2。这样的点可以是:(-0.00012 ; 1.2334 )
.
我想在图表上显示这些点,使用矩形(矩形表示一个点,并将其坐标设置为其点的坐标 - 此外,它的大小为 10*10)。
类似 (... ; Y) 的矩形应该显示在 上方 任何类似 (... ; Y-1) 的矩形(正 Y 方向向上)。因此,我必须将图形的原点设置在其他地方而不是左上角。
我正在尝试使用 Graphics2D
的 AffineTransform
来做到这一点。
- 我得到所有 X 坐标的最小值
- 我得到了所有 Y 坐标的最小值
- 我得到所有 X 坐标的最大值
- 我得到所有 Y 坐标的最大值
- 我得到距离
xmax-xmin
和 ymax-ymin
- 然后,我写了下面给你的代码。
截图
几天前,用我自己的方法缩放,我得到了这张图:
(正如我所解释的,Y 是倒置的,这不是一件好事)
目前,即我在下面给你的代码中,我只有一个点占据了图表的 all 位置!一点都不好。
我想要:
(没有线条,也没有图表的轴。这里重要的是根据坐标正确显示点)。
代码
获取最小和最大坐标值:
x_min = Double.parseDouble((String) list_all_points.get(0).get(0));
x_max = Double.parseDouble((String) list_all_points.get(0).get(0));
y_min = Double.parseDouble((String) list_all_points.get(0).get(1));
y_max = Double.parseDouble((String) list_all_points.get(0).get(1));
for(StorableData s : list_all_points) {
if(Double.parseDouble((String) s.get(0)) < x_min) {
x_min = Double.parseDouble((String) s.get(0));
}
if(Double.parseDouble((String) s.get(0)) > x_max) {
x_max = Double.parseDouble((String) s.get(0));
}
if(Double.parseDouble((String) s.get(1)) < y_min) {
y_min = Double.parseDouble((String) s.get(1));
}
if(Double.parseDouble((String) s.get(1)) > y_max) {
y_max = Double.parseDouble((String) s.get(1));
}
}
画点:
int x, y;
private void drawPoint(Cupple storable_data) {
//x = (int) (storable_data.getNumber(0) * scaling_coef + move_x);
//y = (int) (storable_data.getNumber(1) * scaling_coef + move_y);
x = storable_data.getNumber(0).intValue();
y = storable_data.getNumber(1).intValue();
graphics.fillRect(x, y, 10, 10);
graphics.drawString(storable_data.toString(), x - 5, y - 5);
}
绘制图形:
@Override
public void paint(Graphics graphics) {
this.graphics = graphics;
Graphics2D graphics_2d = ((Graphics2D) this.graphics);
AffineTransform affine_transform = graphics_2d.getTransform();
affine_transform.scale(getWidth()/(x_max - x_min), getHeight()/(y_max - y_min));
affine_transform.translate(x_min, y_min);
graphics_2d.transform(affine_transform);
for(StorableData storable_data : list_all_points) {
graphics_2d.setColor(Color.WHITE);
this.drawPoint((Cupple) storable_data);
}
我建议您将每个数据点映射到屏幕上的一个点,从而避免以下坐标系陷阱。获取您的点列表并从中创建要绘制的点列表。考虑到:
- 绘图是 pixel-based,因此您需要缩放点(或者您需要 1 到 4 像素宽的矩形...)。
- 您需要转换所有点,因为负值将超出您绘制的组件的边界。
y
轴的方向在绘图坐标中反转。
完成后,使用新的点列表进行绘图,并使用初始点列表进行计算。这是一个例子:
public class Graph extends JPanel {
private static int gridSize = 6;
private static int scale = 100;
private static int size = gridSize * scale;
private static int translate = size / 2;
private static int pointSize = 10;
List<Point> dataPoints, scaledPoints;
Graph() {
setBackground(Color.WHITE);
// points taken from your example
Point p1 = new Point(-1, -2);
Point p2 = new Point(-1, 0);
Point p3 = new Point(1, 0);
Point p4 = new Point(1, -2);
dataPoints = Arrays.asList(p1, p2, p3, p4);
scaledPoints = dataPoints.stream()
.map(p -> new Point(p.x * scale + translate, -p.y * scale + translate))
.collect(Collectors.toList());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(size, size);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// draw a grid
for (int i = 0; i < gridSize; i++) {
g2d.drawLine(i * scale, 0, i * scale, size);
g2d.drawLine(0, i * scale, size, i * scale);
}
// draw the rectangle
g2d.setPaint(Color.RED);
g2d.drawPolygon(scaledPoints.stream().mapToInt(p -> p.x).toArray(),
scaledPoints.stream().mapToInt(p -> p.y).toArray(),
scaledPoints.size());
// draw the points
g2d.setPaint(Color.BLUE);
// origin
g2d.fillRect(translate, translate, pointSize, pointSize);
g2d.drawString("(0, 0)", translate, translate);
// data
for (int i = 0; i < dataPoints.size(); i++) {
Point sp = scaledPoints.get(i);
Point dp = dataPoints.get(i);
g2d.fillRect(sp.x, sp.y, pointSize, pointSize);
g2d.drawString("(" + dp.x + ", " + dp.y + ")", sp.x, sp.y);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setContentPane(new Graph());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
还有一个:
您可能希望这些点在网格交叉点上对齐,而不是在它们的下方和右侧。我相信你会解决这个问题的。
此外,我对点进行了排序,以便 drawPolygon
以正确的顺序绘制线条。如果你的点是随意排列的,那就想办法找到轮廓。如果你想要像你的例子中的所有点之间的线,用 drawLine
.
迭代它们的所有组合
我有一组二维点。它们的X和Y大于-2小于2。这样的点可以是:(-0.00012 ; 1.2334 )
.
我想在图表上显示这些点,使用矩形(矩形表示一个点,并将其坐标设置为其点的坐标 - 此外,它的大小为 10*10)。
类似 (... ; Y) 的矩形应该显示在 上方 任何类似 (... ; Y-1) 的矩形(正 Y 方向向上)。因此,我必须将图形的原点设置在其他地方而不是左上角。
我正在尝试使用 Graphics2D
的 AffineTransform
来做到这一点。
- 我得到所有 X 坐标的最小值
- 我得到了所有 Y 坐标的最小值
- 我得到所有 X 坐标的最大值
- 我得到所有 Y 坐标的最大值
- 我得到距离
xmax-xmin
和ymax-ymin
- 然后,我写了下面给你的代码。
截图
几天前,用我自己的方法缩放,我得到了这张图:
(正如我所解释的,Y 是倒置的,这不是一件好事)
目前,即我在下面给你的代码中,我只有一个点占据了图表的 all 位置!一点都不好。
我想要:
(没有线条,也没有图表的轴。这里重要的是根据坐标正确显示点)。
代码
获取最小和最大坐标值:
x_min = Double.parseDouble((String) list_all_points.get(0).get(0));
x_max = Double.parseDouble((String) list_all_points.get(0).get(0));
y_min = Double.parseDouble((String) list_all_points.get(0).get(1));
y_max = Double.parseDouble((String) list_all_points.get(0).get(1));
for(StorableData s : list_all_points) {
if(Double.parseDouble((String) s.get(0)) < x_min) {
x_min = Double.parseDouble((String) s.get(0));
}
if(Double.parseDouble((String) s.get(0)) > x_max) {
x_max = Double.parseDouble((String) s.get(0));
}
if(Double.parseDouble((String) s.get(1)) < y_min) {
y_min = Double.parseDouble((String) s.get(1));
}
if(Double.parseDouble((String) s.get(1)) > y_max) {
y_max = Double.parseDouble((String) s.get(1));
}
}
画点:
int x, y;
private void drawPoint(Cupple storable_data) {
//x = (int) (storable_data.getNumber(0) * scaling_coef + move_x);
//y = (int) (storable_data.getNumber(1) * scaling_coef + move_y);
x = storable_data.getNumber(0).intValue();
y = storable_data.getNumber(1).intValue();
graphics.fillRect(x, y, 10, 10);
graphics.drawString(storable_data.toString(), x - 5, y - 5);
}
绘制图形:
@Override
public void paint(Graphics graphics) {
this.graphics = graphics;
Graphics2D graphics_2d = ((Graphics2D) this.graphics);
AffineTransform affine_transform = graphics_2d.getTransform();
affine_transform.scale(getWidth()/(x_max - x_min), getHeight()/(y_max - y_min));
affine_transform.translate(x_min, y_min);
graphics_2d.transform(affine_transform);
for(StorableData storable_data : list_all_points) {
graphics_2d.setColor(Color.WHITE);
this.drawPoint((Cupple) storable_data);
}
我建议您将每个数据点映射到屏幕上的一个点,从而避免以下坐标系陷阱。获取您的点列表并从中创建要绘制的点列表。考虑到:
- 绘图是 pixel-based,因此您需要缩放点(或者您需要 1 到 4 像素宽的矩形...)。
- 您需要转换所有点,因为负值将超出您绘制的组件的边界。
y
轴的方向在绘图坐标中反转。
完成后,使用新的点列表进行绘图,并使用初始点列表进行计算。这是一个例子:
public class Graph extends JPanel {
private static int gridSize = 6;
private static int scale = 100;
private static int size = gridSize * scale;
private static int translate = size / 2;
private static int pointSize = 10;
List<Point> dataPoints, scaledPoints;
Graph() {
setBackground(Color.WHITE);
// points taken from your example
Point p1 = new Point(-1, -2);
Point p2 = new Point(-1, 0);
Point p3 = new Point(1, 0);
Point p4 = new Point(1, -2);
dataPoints = Arrays.asList(p1, p2, p3, p4);
scaledPoints = dataPoints.stream()
.map(p -> new Point(p.x * scale + translate, -p.y * scale + translate))
.collect(Collectors.toList());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(size, size);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// draw a grid
for (int i = 0; i < gridSize; i++) {
g2d.drawLine(i * scale, 0, i * scale, size);
g2d.drawLine(0, i * scale, size, i * scale);
}
// draw the rectangle
g2d.setPaint(Color.RED);
g2d.drawPolygon(scaledPoints.stream().mapToInt(p -> p.x).toArray(),
scaledPoints.stream().mapToInt(p -> p.y).toArray(),
scaledPoints.size());
// draw the points
g2d.setPaint(Color.BLUE);
// origin
g2d.fillRect(translate, translate, pointSize, pointSize);
g2d.drawString("(0, 0)", translate, translate);
// data
for (int i = 0; i < dataPoints.size(); i++) {
Point sp = scaledPoints.get(i);
Point dp = dataPoints.get(i);
g2d.fillRect(sp.x, sp.y, pointSize, pointSize);
g2d.drawString("(" + dp.x + ", " + dp.y + ")", sp.x, sp.y);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setContentPane(new Graph());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
还有一个:
您可能希望这些点在网格交叉点上对齐,而不是在它们的下方和右侧。我相信你会解决这个问题的。
此外,我对点进行了排序,以便 drawPolygon
以正确的顺序绘制线条。如果你的点是随意排列的,那就想办法找到轮廓。如果你想要像你的例子中的所有点之间的线,用 drawLine
.