создание склона в 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

Ответ 1

Основанный на алгоритме Брезенхэма, вот реализация Java, которая предполагает x2 > x1 and 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

Ответ 2

Два цикла: вы пересекаете x++ только тогда, когда deltaX> deltaY. иначе вы перебираете только y++.

Двойной шаг x и y в одном и том же цикле, решение которого должно быть увеличено (при условии, что у вас также есть x как функция y), может привести к более медленному рисованию из-за дополнительных тестов, и смежные пиксели могут выглядеть как точка на линии. Вам нужно будет поиграть с интенсивностью цвета, чтобы сделать сглаживание вручную (позолота). Две циклы намного проще.

К вашему сведению, вы пытаетесь сгенерировать изображение, вы также можете просто установить целые числа в матрице и создать неэкранное необработанное изображение (BufferedImage и метод .setRGB()), которое вы рисуете позже. Это, вероятно, будет быстрее и позволит избежать видимых задержек покраски.

Ответ 3

Обычно это делается с помощью алгоритма, который не шагает только вдоль оси 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 градусов от нижней части экрана все еще будут выглядеть подключенными.

Теперь при построении графика вам необходимо округлить значения, чтобы выровнять их по точным пикселям. Есть несколько способов сделать это. Самое простое - просто округлить до следующего действительного значения, и это работает большую часть времени. У него есть один неприятный побочный эффект: ваша линия будет иметь ступенчатые ступени (если при округлении смещается пиксель больше, ступенька будет выглядеть более неровной). Эта зазубренность называется "псевдонимом", поскольку истинная точка представлена через неверное представление точки (псевдоним).

Второй подход заключается в пропорциональном затемнении обоих пикселей пропорционально, исходя из того, насколько близка точка. Точка, которая находится в точке (0,5) на оси x, будет затемнять оба пикселя на 50%, а точка, которая находится в точке (0,25), будет затемнять пиксель 0 на 75%, а 1 пиксель - на 25%. Это сглаживание и может привести к получению линии, которая будет немного более размытой, но выглядит более прямой. С этой нечеткостью можно немного бороться, рисуя более толстую линию.

Я надеюсь, что это даст вам некоторое представление о математике, лежащей в основе многих из высококачественных процедур рисования, и, конечно, есть подходы, которые даже более сложные, чем тот, который я только что представил.