Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw ring with given thickness, position, and radius. (Java2D)

I need to draw a ring, with given thickness, that looks something like this:

enter image description here

The center must be transparent, so that it doesn't cover previously drawn shapes. (or other rings) I've tried something like this:

//g is a Graphics2D object
g.setColor(Color.RED);
g.drawOval(x,y,width,height);
g.setColor(Color.WHITE);
g.drawOval(x+thickness,y+thickness,width-2*thickness,height-2*thickness);

which draws a satisfactory ring, but it covers other shapes; the interior is white, not transparent. How can I modify/rewrite my code so that it doesn't do that?

like image 394
ostrichofevil Avatar asked Feb 20 '16 14:02

ostrichofevil


People also ask

How to draw a point in Java 2D?

In this part of the Java 2D tutorial, we do some basic drawing. The most simple graphics primitive is a point. It is a single dot on the window. There is a Point class for representing a point in a coordinate space, but there is no method to to draw a point.

How to draw a point randomly in Java?

To draw a point, we used the drawLine () method, where we supplied one point for the both arguments of the method. The example draws randomly 2000 points on the window. A timer is used to draw points in a cycle. A javax.swing.Timer is used to create animation. It fires ActionEvents at the specified interval. The points are painted in blue color.

How to draw points in a cycle in Java?

A timer is used to draw points in a cycle. A javax.swing.Timer is used to create animation. It fires ActionEvents at the specified interval. The points are painted in blue color. We get the width and height of the component.

How to draw a point in a coordinate space in Java?

There is a Point class for representing a point in a coordinate space, but there is no method to to draw a point. To draw a point, we used the drawLine () method, where we supplied one point for the both arguments of the method. The example draws randomly 2000 points on the window. A timer is used to draw points in a cycle.


2 Answers

You can create an Area from an Ellipse2D that describes the outer circle, and subtract the ellipse that describes the inner circle. This way, you will obtain an actual Shape that can either be drawn or filled (and this will only refer to the area that is actually covered by the ring!).

The advantage is that you really have the geometry of the ring available. This allows you, for example, to check whether the ring shape contains a certain point, or to fill it with a Paint that is more than a single color:

RingPaint01

Here is an example, the relevant part is the createRingShape method:

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class RingPaintTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        RingPaintTestPanel p = new RingPaintTestPanel();
        f.getContentPane().add(p);
        f.setSize(800,800);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}


class RingPaintTestPanel extends JPanel
{
    @Override
    protected void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D)gr;

        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        g.setColor(Color.RED);
        g.drawString("Text", 100, 100);
        g.drawString("Text", 300, 100);

        Shape ring = createRingShape(100, 100, 80, 20); 
        g.setColor(Color.CYAN);
        g.fill(ring);
        g.setColor(Color.BLACK);
        g.draw(ring);

        Shape otherRing = createRingShape(300, 100, 80, 20); 
        g.setPaint(new GradientPaint(
            new Point(250, 40), Color.RED, 
            new Point(350, 200), Color.GREEN));
        g.fill(otherRing);
        g.setColor(Color.BLACK);
        g.draw(otherRing);

    }

    private static Shape createRingShape(
        double centerX, double centerY, double outerRadius, double thickness)
    {
        Ellipse2D outer = new Ellipse2D.Double(
            centerX - outerRadius, 
            centerY - outerRadius,
            outerRadius + outerRadius, 
            outerRadius + outerRadius);
        Ellipse2D inner = new Ellipse2D.Double(
            centerX - outerRadius + thickness, 
            centerY - outerRadius + thickness,
            outerRadius + outerRadius - thickness - thickness, 
            outerRadius + outerRadius - thickness - thickness);
        Area area = new Area(outer);
        area.subtract(new Area(inner));
        return area;
    }

}
like image 98
Marco13 Avatar answered Sep 16 '22 22:09

Marco13


You can use the Shape and Area classes to create interesting effects:

import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.net.*;

public class Subtract extends JPanel
{
    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        int size = 100;
        int thickness = 10;
        int innerSize = size - (2 * thickness);

        Shape outer = new Ellipse2D.Double(0, 0, size, size);
        Shape inner = new Ellipse2D.Double(thickness, thickness, innerSize, innerSize);

        Area circle = new Area( outer );
        circle.subtract( new Area(inner) );

        int x = (getSize().width - size) / 2;
        int y = (getSize().height - size) / 2;
        g2d.translate(x, y);

        g2d.setColor(Color.CYAN);
        g2d.fill(circle);
        g2d.setColor(Color.BLACK);
        g2d.draw(circle);

        g2d.dispose();
     }


    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("Subtract");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new Subtract());
        frame.setLocationByPlatform( true );
        frame.setSize(200, 200);
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
/*
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
*/
    }
}

Using an Area you can also add multiple Shapes together or get the intersection of multiple Shapes.

like image 44
camickr Avatar answered Sep 19 '22 22:09

camickr