如何制作一个像素化的" Java中的行

时间:2017-06-07 16:08:19

标签: java algorithm swing graphics

我想画一个"像素化" Java中的一行。这是我的意思的一个例子"像素化"行:

Pixelated line

这是我的代码试图做的。假设该行从(x1, y1)(x2, y2)并且我想要一行10"块"它们之间的长度(我称之为像素,但它们将使用许多像素显示):

  1. 制作一个(x1, y1)(0, 0)且宽度为x2 - x1且高度为y2 - y1的矩形。
  2. 计算该矩形形成的三角形的斜边。拨打cOriginal
  3. 重新缩放矩形,使斜边长度为10长。
  4. 创建一个重新缩放的矩形大小的2D布尔数组。拨打grid
  5. 在该网格上从右上角运行Bresenham线算法,(0, 0)到左下角,标记作为行的一部分的网格空间为true。我确信我的Bresenham算法适用于所有象限和所有情况。
  6. 这是我有点模糊的部分。目前,我首先定义了2个"向上扩展"网格。这些定义如下:

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

  7. (我不知道为什么不格式化...)接下来我循环grid如果grid[i][j](是true),我绘制一个宽度和高度为的矩形10 (x1 + (i * widthScalingFactor), yOffset + (j * heightScalingFactor))

    这是目前的方法:

    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像素。但是,当我尝试画一条东北或西南的线时,它只画一条水平线。这里有一些例子。

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

    这是一条向东北方向行的线路,你可以看到它只是一条直线,从原点到目的地的x位置。当向西南方向绘制线条时会发生类似的事情,除非它向南移动并停在目的地的y位置。 Example 2

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

    如何修改我当前的算法或创建一个新的算法来绘制像素化的#34;线吗

1 个答案:

答案 0 :(得分:3)

此代码演示了一种方法,其中所有坐标都缩放到较低的分辨率,然后以较低的分辨率绘制线,同时在绘图(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);
    }

}

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