Не в состоянии нарисовать круг, несмотря на использование логического способа - PullRequest
0 голосов
/ 01 февраля 2019

Я попытался построить круг, используя java awt, в результате я получаю лишь несколько маленьких, которые разделены друг от друга большим расстоянием и не выглядят как круг в целом.Код указан ниже:

class DrawFrame extends JFrame {
    int хс, yc, r, x, y;
    float p;
    DrawFrame(int rr, int c1, int c2) {
        setSize(1000, 1000);
        setTitle("circle drawing algo");
        r = rr;
        xc = c1;
        yc = c2;
    }
    public void paint(Graphics g) {
        Circl(g);
    }
    public void Circl(Graphics g) {
        x = xc - r;
        while (x <= (xc + r)) {
            for (y = yc - r; y <= (yc + r); y++) {
                p = x * x + y * y - r * r;
                if (p == 0.0)
                    g.drawOval(x, y, 2, 2);
            }
            x++;
        }
    }

Ответы [ 4 ]

0 голосов
/ 01 февраля 2019

Вы устанавливаете начальное значение x как x = xc - r, y как y = yc - r.И преобразование декартовой в полярную координату, как p = x * x + y * y - r * r.Предположим, что если xc = 500 и yc = 500, r = 50, «p» никогда не будет 0. Поэтому я думаю, что вы забыли вычислить xc, yc при рисовании.Я немного изменил ваш код и прикрепил результат.

package testProject;
import java.awt.*;
import javax.swing.*;

public class DrawFrame extends JPanel {
    int xc=500, yc=500, r=150, x, y;
    int real_x, real_y;
    float p;

    public static void main(String[] args) {
        JFrame.setDefaultLookAndFeelDecorated(true);
        JFrame frame = new JFrame("circle drawing algo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBackground(Color.white);
        frame.setSize(1000, 1000);
        DrawFrame panel = new DrawFrame();
        frame.add(panel);
        frame.setVisible(true);
    }



    public void paint(Graphics g) {
        Circl(g);
    }
    public void Circl(Graphics g) {
        x = -r;
        while (x <= r) {
            y = -r;
            while (y <= r) {
                p = x * x + y * y - r * r;
                // here is the change
                if (p>=0 && p<= xc) {
                    g.drawOval(x+xc, y+yc, 3, 3);
                }
                y++;
            }
            x++;
        }
    }
}

Result

0 голосов
/ 01 февраля 2019

Вы должны начать с чтения Выполнение пользовательской рисования и Рисование в AWT и Swing , чтобы лучше понять, как работает система рисования и как с ней работать..

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

JRootPane and it's many layers

Это означает, чтовозможно, что то, что вы нарисовали на поверхности фрейма, будет проигнорировано, так как содержимое поверх него закрашивает его.

Вы также игнорируете сложность процесса рисования, если только вы неготовый взять на себя ответственность за метод paint самостоятельно, вы всегда должны вызывать его метод super.

Лучше всего начать с JPanel (что проще) и переопределить его paintComponent метод

Example

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane(100, 100, 100));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        int xc, yc, r;

        public TestPane(int rr, int c1, int c2) {
            r = rr;
            xc = c1;
            yc = c2;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(r * 2, r * 2);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            circle(g);
        }

        public void circle(Graphics g) {
            // Credit to LAD for the algorithm updates
            int x = xc - r;
            while (x <= (xc + r)) {
                for (int y = yc - r; y <= (yc + r); y++) {
                    float p = (x - xc) * (x - xc) + (y - yc) * (y - yc) - (r * r);
                    if (p <= 0.0f)
                    {
                        g.drawOval(x, y, 2, 2);
                    }
                }
                x++;
            }


        }
    }

}

Кредит LAD за обновления алгоритма

0 голосов
/ 01 февраля 2019

Первое, что нужно изменить, это сделать JFrame видимым, добавив setVisible(true); в его конструктор.Рекомендуется использовать имена, которые имеют четкое значение, чтобы сделать код более читабельным.Сделайте область действия полей максимально ограниченной, в этом случае сделайте их приватными:

private int сenterX, centerY, radius; 

(x, y и p являются переменными метода и не должны быть полями)Избегайте использования магических чисел .Вместо этого используйте константы:

private static final int W = 1000, H = 1000, DOT_SIZE =2 ;

Соберите их вместе, используя правильные Соглашения об именах Java и исправьте алгоритм:

import java.awt.Graphics; //add imports to make tour code mcve
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

class DrawFrame extends JFrame {

    private final int сenterX, centerY, radius;
    private static final int W = 1000, H = 1000, DOT_SIZE =2 ;

    DrawFrame(int radius, int centerX, int centerY) {
        setSize(W, H);
        setTitle("circle drawing algo");
        this.radius = radius;
        сenterX = centerX;
        this.centerY = centerY;
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//make program stop when closing frame
        setVisible(true); //make frame visible
    }

    @Override
    public void paint(Graphics g) {
       super.paint(g); 
       circl(g);
    }

    public void circl(Graphics g) {
        int x, y;
        x = сenterX - radius;
        while (x <= сenterX + radius) {
           //calculate x 
           y = (int)Math.sqrt(radius*radius - (сenterX -x)*(сenterX -x ));
           g.drawOval(x, centerY-y, 2, 2); // 2 y values for every x 
           g.drawOval(x, centerY+y, 2, 2);
           x++;
       }
    }

    // add main to make your code mcve 
    public static void main(String[] args) {
        SwingUtilities.invokeLater(()-> new DrawFrame(100, 400, 400));
    }
}

Следующим улучшением может стать рефакторинг, такрисование выполняется на JPanel, а не на JFrame, используя Graphics.drawOval:

class DrawFrame extends JFrame {

    DrawFrame(int radius, int centerX, int centerY) {
        setTitle("circle drawing algo");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//make program stop when closing frame
        add(new DrawingPane(radius, centerX, centerY));
        pack();
        setVisible(true); //make frame visible
    }

    // add main to make your code mcve
    public static void main(String[] args) {
        SwingUtilities.invokeLater(()-> new DrawFrame(100, 400, 400));
    }
}

class DrawingPane extends JPanel{

    private final int сenterX, centerY, radius;
    private static final int W = 1000, H = 1000, DOT_SIZE =2 ;

    DrawingPane(int radius, int centerX, int centerY) {
        setPreferredSize(new Dimension(W, H));
        this.radius = radius;
        сenterX = centerX;
        this.centerY = centerY;
    }

    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawOval(сenterX, centerY, radius, radius);
    }
}
0 голосов
/ 01 февраля 2019

Я немного отредактировал ваш код и немного изменил алгоритм отрисовки, чтобы полностью нарисовать круг.Вот измененный код:

class DrawFrame extends JFrame {
    int xc, yc, r, x, y;
    float p;
    DrawFrame(int rr, int c1, int c2) {
        setSize(1000, 1000);
        setTitle("circle drawing algo");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Handles the window being closed
        setVisible(true); // Makes the window visible
        r = rr;
        xc = c1;
        yc = c2;
    }
    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D)g;
        GradientPaint gp = new GradientPaint(0f,0f,Color.blue,0f,30f,Color.green); // Just sets a color for the paint
        g2.setPaint(gp);
        Circl(g2); 
    }
    public void Circl(Graphics g) {
        x = xc-r;
        while (x <= (xc+r)) {
            for (y = yc-r; y <= (yc+r); y++) {
                p = (x-xc)*(x-xc)+(y-yc)*(y-yc)-(r*r); // Edited this line so that it’s now the correct circle formula
                if (p <= 0.0f) // If the point is 0 or less, then the point is within the circle bounds
                    g.drawOval(x, y, 2, 2);
            }
            x++;
        }
    }
    public static void main(String[] args) {
        new DrawFrame(100, 500, 500);
    }
}

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

g.drawOval(x, y, 200, 200);
g.fillOval(x, y, 200, 200);
...