1
votes

I have an interesting problem. Using Java graphics, I'd like to draw a circle with parallel lines in the circle that are spaced with some pre defined gap constant. The circle has a known x and y position and a radius. The lines should start from the center of the circle and should move outward thereof. For example,

enter image description here

I'd imaging it would be easiest to first draw the lines to fill up the whole square as follows:

enter image description here

and then perhaps draw 4 polygons and fill them in white white. The 4 polygons are labeled as follows:

enter image description here

As you can see, a polygon in this case is defined by a left top point (x,y), edges of width and height defined by the radius of the circle, and then an arc from (x+radius, y+radius).

Feedback needed:

  1. Is it even possible to draw such a polygon in Java?
  2. Is this logic making sense? Does this seem easier to you?
  3. The alternative is to somehow determine the pixels that make up the circle and draw lines using those. But this seems messy to me. Do you agree?
  4. Can you think of an alternative way of doing this?

IMPORTANT: note that while this solution has vertical lines, the lines should be defined in terms of some angle theta. That is, they can be angled (but all parallel to each other).

If someone could provide code that actually draws this, I would be forever thankful!! :)

public void draw(Graphics g, int x, int y, int radius, int lineGap, int lineThickness, int theta) {
   //g = the graphics object
   //x,y = the top left coordinate of the square
   //radius = the radius of the circle, the width of the rectangle, the height of the rectangle
   //lineGap = the gap in between each of the lines
   //lineThickness = the thickness of the lines in pixels
   //theta = the angle that the lines should be at, relative to the y axis
}
3
I don't think polygons are the way to go. Instead, use a bit of math (trigonometry) to find the height required for each line, based on its radius from the centerAnti Earth
So you mean for all x points that I know my line falls on, determine the y position using the equation of the circle?CodeGuy
Set a circular clip when drawing the lines.Andrew Thompson
That would be another reasonable solution.SJuan76

3 Answers

3
votes

Simple change the graphics clipping...

enter image description here

public class SimplePaint02 {

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

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

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }

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

            int radius = Math.min(getWidth(), getHeight());
            int x = (getWidth() - radius) / 2;
            int y = (getHeight()- radius) / 2;

            BufferedImage buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = buffer.createGraphics();

            Ellipse2D circle = new Ellipse2D.Float(0, 0, radius, radius);
            Shape clip = g2d.getClip();
            g2d.setClip(circle);
            int gap = getWidth() / 10;
            g2d.setColor(Color.RED);
            for (int index = 0; index < 10; index++) {

                g2d.drawLine(index * gap, 0, index * gap, radius);

            }
            g2d.setClip(clip);
            g2d.setColor(Color.BLUE);
            g2d.draw(circle);
            g2d.dispose();
            g.drawImage(buffer, x, y, this);
        }

    }

}

Update

I should point out that you should NEVER modify any graphics context's clipping that is rendering to the screen, this can seriously screw up the screen rendering ;)

Updated #2

Example showing the use of an AffinTransformation to support rotation...

enter image description here

public class CirlceDraw {

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

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

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class TestPane extends JPanel {

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }

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

            int radius = Math.min(getWidth(), getHeight());
            int x = (getWidth() - radius) / 2;
            int y = (getHeight() - radius) / 2;

            BufferedImage buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = buffer.createGraphics();

            Ellipse2D circle = new Ellipse2D.Float(0, 0, radius, radius);
            Shape clip = g2d.getClip();
            g2d.setClip(circle);
            AffineTransform at = g2d.getTransform();
            g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(33), radius / 2, radius / 2));
            int gap = getWidth() / 10;
            g2d.setColor(Color.RED);
            for (int index = 0; index < 10; index++) {

                g2d.drawLine(index * gap, 0, index * gap, radius);

            }
            g2d.setTransform(at);
            g2d.setClip(clip);
            g2d.setColor(Color.BLUE);
            g2d.draw(circle);
            g2d.dispose();
            g.drawImage(buffer, x, y, this);
        }

    }

}
5
votes

Using the ol' Pythagorean Thereom, this simple bit of algebra follows... y in terms of x and r

r is the radius of the circle.
x is a variable you'll make iterate through the circle, in increments you can easily work out from knowing the radius and the spacing.

Knowing the height of each line (and their x position), it won't be a challenge centering the verticle lines parallel to the cirlce center (if your placement coordinates specify the top left corner as they usually do, you'll want to place it at y = circle_center - (line_length / 2)

Note also, that if you do specify the coordinates of the vertical lines via the top left corner, you'll need to consider how thick they are when calculating the x coordinate.
This is extremely simple, using the x value suggested by the circle.
true_x = suggested_x - (line_width / 2)

Refer to other more sensible answers for dealing with angled lines

This procedure remains as a demonstration of the sensibility of using a clip over finding the exact domain/range of each line (and because I wasted so much of my life on it).

enter image description hereenter image description hereenter image description hereenter image description here Here's where the fun ended for me. enter image description here

Oomph! Replace that last m with 'tan(theta)'

1
votes

I would use trigonometry.

The x of your line is given by the cosinus of the angle from origin (center of the circle). So, arccos(x) would give you which is the angle.

Once you have the angle, you can have its maxim height by using the sinus sin function.

Of course, all java trig functions work with radians (360 degrees = 2*PI radians).