在Java中创建斜坡

11

我正在尝试在 Java 中创建斜坡。我可以使用 DrawLine 函数来创建完美的斜坡,但我不想使用它,而是要创建自己的函数。问题在于点之间存在间隙。

import java.applet.Applet;
import java.awt.Graphics;

public class slope extends Applet{



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

        double m = (y2 - y1) / (double)(x2-x1);
        double y = y1;
        for (int x =x1; x < x2; x++) {

            drawPoint(x,(int)y,g);
            y +=m;
        }
    }


    public void paint(Graphics g) {
        drawLine(20, 10, 300, 700, g); //has spaces between the dots 
        g.drawLine(20, 10, 300, 700); //this is perfect


    }

    private void drawPoint(int x, int y, Graphics g) {

        g.drawLine(x, y, x, y);

    }
}

enter image description here


3
根据角度不同,您应迭代 xy - Maarten Bodewes
6
它没有“点之间的间隙”。它仅仅不是一条线。你画出个别的点,为什么期望它们连接在一起呢? - f1sh
10
布雷森汉姆线算法是一种用于在计算机图形学中绘制直线的算法。它以低存储器需求和高效率而著称,因此在计算机图形学中得到广泛应用。该算法由Jack E. Bresenham于1962年开发。 - Steve Smith
4
他想知道如何在没有间隔的情况下完成这个任务。所有行都相当于点,只是没有间隔而已。 - Steve Smith
2
如果m大于1,那么显然会有间隙,因此您需要在y上添加1/mx。如果您注意到还需要处理负值,则可以获得额外的分数。 - Maarten Bodewes
显示剩余14条评论
3个回答

2
通常这是通过使用一种算法来实现的,该算法不仅沿x轴或y轴步进,而且通过可变量调整更新增量,使得每个点之间最多相距sqrt(2)
因此,如果您认为您有一个在x值上的点,但当您计算它时,您发现它离它非常陡峭的斜率有3.5像素的距离,那么您就会进入一个计算(通常是递归)中间像素的例程。
(x, y)
(0, 0) to (1, 5) distance 5.09
-> fill routine
   (0, 0) to (0.5, 2.5) distance 2.69
   -> fill routine
      (0, 0) to (0.25, 1.25) distance 1.34 < 1.41 
      (0.25, 1.25) to (0.5, 2.5) distance 1.34 < 1.41
      (0.5, 2.5) to (0.75, 3.75) distance 1.34 < 1.41
      (0.75, 3.75) to (1, 5) distance 1.34 < 1.41
(1, 5) to (2, 10) etc...

使用1.41(sqrt(2))作为允许的最大距离的原因是,屏幕底部45度角处的像素仍然会显示连接。
现在,在您的绘图中,您需要将值四舍五入以对齐到精确的像素。有许多方法可以做到这一点。最简单的方法就是将其四舍五入到下一个有效值,这在大多数情况下都有效。它有一个不幸的副作用,即您的线条将呈现出锯齿状步进(舍入移动像素更多时,步进将呈现出更加锯齿状)。这种锯齿状被称为“混叠”,因为真实点通过非真实点的表示(别名)呈现出来。
第二种方法是根据点的接近程度成比例地交替变暗两个像素。在x轴上为(0.5)的点会使两个像素变暗50%,而在(0.25)的点会使0像素变暗75%,1像素变暗25%。这就是反混叠,可能会导致线条略微模糊,但看起来更直。这种模糊可以通过绘制较粗的线条来抵消。
希望这能让您了解许多高质量绘图例程背后的数学原理,当然,还有比我刚刚介绍的更复杂的方法。

当然,我和user2023577的方法都存在一些问题,例如当有垂直线时。但是如果你遵循其中任何一种方法,很可能可以轻松处理这些问题。通常的做法是通过伪造一个无限小的斜率来解决,这个斜率在屏幕上不会被察觉,但足够大以避免除以零的错误。 - Edwin Buck

2
两个循环:只有当deltaX > deltaY时,您才会循环x ++。否则,您只循环y ++。
在同一个循环中双步x和y,并决定哪个应该增加(假设您也将x作为y的函数)可能会导致绘图变慢,因为需要额外的测试,相邻的像素可能看起来像线条中的点。您需要手动调整颜色强度以进行抗锯齿处理(金色镀层)。两个循环更简单。
顺便说一下,您正在尝试生成图像,您还可以在矩阵中设置int并制作屏幕外原始图像(BufferedImage及其.setRGB()方法),然后再绘制。这可能会更快,并避免可见的绘画延迟。
最初的回答

1
基于Bresenham算法,这是一个Java实现,假设x2>x1和y2>y1,并使用整数算术。
import java.applet.Applet;
import java.awt.*;

public class Slope extends Applet{

    private int x1 = 20, y1 = 10;
    private int x2 = 300, y2 = 700;

    @Override
    public void paint(Graphics g) {

        drawLine(x1, y1, x2, y2, g);
        //g.drawLine(x1, y1, x2, y2, g);  

    }

    private void drawPoint(int x, int y, Graphics g) {
        g.drawLine(x,y,x,y);
   }

   @Override
    public void init(){
        this.setSize(500,700);
   }

    private void drawLine(int x1,int y1,int x2,int y2,Graphics g){

        int dx = x2 - x1;
        int dy = y2 - y1;
        int xi = 1;
        int D = 2*dx - dy;
        int x = x1;

        for(int y = y1; y <y2; y++) {
            drawPoint(x,y,g);
            if(D > 0) {
                x = x + xi;
                D = D - 2 * dy;
            }
                D = D + 2 * dx;
            }
        }
}

Image Output


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接