gpt4 book ai didi

java - 如何在 Java 中制作 "Pixelated"行

转载 作者:搜寻专家 更新时间:2023-11-01 02:58:33 24 4
gpt4 key购买 nike

我想用 Java 画一条“像素化”的线。这是我所说的“像素化”行的示例:

Pixelated line

这就是我的代码试图做的事情。假设该行从 (x1, y1)(x2, y2) 并且我想要它们之间有 10 个“ block ”长度的行(我会调用它们是像素,但它们将使用许多像素显示):

  1. (x1, y1) 制作一个矩形作为 (0, 0) 并且宽度 x2 - x1 和高度 y2 - y1.
  2. 计算由该矩形形成的三角形的斜边。称其为 cOriginal
  3. 重新缩放矩形,使斜边长度为 10。
  4. 创建一个大小为重新缩放的矩形的二维 boolean 数组。调用那个网格
  5. 在该网格上从右上角运行 Bresenham 线算法,即 (0, 0) 到左下角,将属于该线的网格空间标记为 true 。我确信我的 Bresenham 算法适用于所有象限和所有情况。
  6. 这是我有点模糊的部分。目前,我首先定义了 2 个“放大”网格的变量。这些定义如下:

    float widthScalingFactor = (float) widthOriginal/(float) newWidth;float heightScalingFactor = (float) heightOriginal/(float) newHeight;

(我不知道为什么那不是格式化......)接下来我遍历 grid 并且如果 grid[i][j] (是 true ),我在 (x1 + (i * widthScalingFactor), yOffset + (j * heightScalingFactor)) 处绘制了一个宽度和高度为 10 的矩形。

这是当前的方法:

public static void drawPixelatedLine(Graphics g, int x1, int y1, int x2, int y2) {

int widthOriginal = x2 - x1;
int heightOriginal = y2 - y1;

if(widthOriginal <= 0 && heightOriginal <= 0){

int temp = x2;
x2 = x1;
x1 = temp;

temp = y2;
y2 = y1;
y1 = temp;

}

double cOriginal = Math.sqrt(widthOriginal * widthOriginal + heightOriginal * heightOriginal);

double shrinkingFactor = 10d / cOriginal;

int newWidth = (int) Math.round(shrinkingFactor * widthOriginal);
int newHeight = (int) Math.round(shrinkingFactor * heightOriginal);

newWidth = (newWidth <= 0 ? 1 : newWidth);
newHeight = (newHeight <= 0 ? 1 : newHeight);

boolean[][] grid = new boolean[newWidth][newHeight];

int rescaledX1 = 0;
int rescaledY1 = 0;

int rescaledX2 = newWidth - 1;
int rescaledY2 = newHeight - 1;

int x = rescaledX1;
int y = rescaledY1;

int dx = Math.abs(rescaledX2 - rescaledX1);
int dy = Math.abs(rescaledY2 - rescaledY1);

int s1 = Utils.sign(rescaledX2 - rescaledX1);
int s2 = Utils.sign(rescaledY2 - rescaledY1);

boolean swap = false;

if (dy > dx) {

int temp = dx;
dx = dy;
dy = temp;

swap = true;

}

int D = 2 * dy - dx;

for (int i = 0; i < dx; i += 1) {

grid[x][y] = true;

while (D >= 0) {

D = D - 2 * dx;

if (swap) {

x += s1;

}

else {

y += s2;

}

}

D = D + 2 * dy;

if (swap) {

y += s2;

}

else {

x += s1;

}

}

int xOffset = x1;
int yOffset = y1;

float widthScalingFactor = (float) widthOriginal / (float) newWidth;
float heightScalingFactor = (float) heightOriginal / (float) newHeight;

for(int i = 0; i < grid.length; i++){

for(int j = 0; j < grid[0].length; j++){

if(grid[i][j]){

g.fillRect((int) (xOffset + (i * widthScalingFactor)), (int) (yOffset + (j * heightScalingFactor)), 10, 10);

}

}

}

现在这段代码在任何主要方向以及西北和东南方向绘制时部分起作用,尽管我绘制的矩形的大小似乎是错误的(这可能是因为我试图在一个平面上绘制 10 个大小为 10 的正方形距离可能超过 ~140 像素。但是,当我尝试向东北方向或西南方向绘制一条线时,它只会绘制一条水平线。以下是一些示例。

这是一条向西北方向行驶的线路,运行正常(我可以解决整个拉伸(stretch)/间隙问题)。 Example 1

这是一条向东北方向的线,如您所见,它只是一条从原点向东到目的地 x 位置的直线。向西南画线时会发生类似的事情,只是它向南走并停在目的地的 y 位置。 Example 2

目前您可以看到该线是否向西北方向移动,我只是翻转 2 个点,使其向东南方向移动。但是,我觉得我目前的方法不太正确,需要进行大量修改才能适应最后两种情况。

我如何修改我当前的算法或创建一个新算法来绘制“像素化”线条?

最佳答案

此代码演示了一种方法,其中所有坐标都缩放到较低的分辨率,然后以较低的分辨率绘制线,同时在 plot(x, y) 函数中再次放大。

明显的副作用是线条端点会四舍五入(实际上是截断)到较低的分辨率。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class BresenhamBlocky {

static class TestPanel extends JPanel {
public TestPanel() {
setPreferredSize(new Dimension(800, 800));
}

@Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
int w = getWidth();
int h = getHeight();
g.setColor(Color.GRAY);
g.fillRect(0, 0, w, h);
g.setColor(Color.BLUE);
drawLine(g, w >> 1, h >> 1, targetX, targetY, 10);
}
}

public static void main(String[] argv) {
SwingUtilities.invokeLater(() -> { showTest(); });
}

static int targetX, targetY;

static void showTest() {
JFrame frame = new JFrame("Test");
JComponent test = new TestPanel();
test.setFocusable(true);
test.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
targetX = e.getX();
targetY = e.getY();
e.getComponent().repaint();
}
});
frame.setLayout(new BorderLayout());
frame.add(test, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}

public static void drawLine(Graphics g, int x0, int y0, int x1, int y1, int blockSize) {
int scaledX0 = x0 / blockSize;
int scaledY0 = y0 / blockSize;
int scaledX1 = x1 / blockSize;
int scaledY1 = y1 / blockSize;
int dx = scaledX1 - scaledX0;
int dy = scaledY1 - scaledY0;
int stepX = Integer.signum(dx);
int stepY = Integer.signum(dy);
dx = Math.abs(dx);
dy = Math.abs(dy);
int dx2 = dx << 1;
int dy2 = dy << 1;
int x = scaledX0;
int y = scaledY0;
int error;
if (dx >= dy) {
error = dy2 - dx;
do {
plot(g, x, y, blockSize);
if (error > 0) {
y += stepY;
error -= dx2;
}
error += dy2;
x += stepX;
} while (x != scaledX1);
} else {
error = dx2 - dy;
do {
plot(g, x, y, blockSize);
if (error > 0) {
x += stepX;
error -= dy2;
}
error += dx2;
y += stepY;
} while (y != scaledY1);
}
}

static void plot(Graphics g, int x, int y, int blockSize) {
int x0 = x * blockSize;
int y0 = y * blockSize;
int w = blockSize;
int h = blockSize;
g.fillRect(x0, y0, w, h);
}

}

(用鼠标点击移动直线的一个端点)

关于java - 如何在 Java 中制作 "Pixelated"行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44417784/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com