k.asgari
k.asgari

Reputation: 1

is there a method in java for drawing a circle with double variables for its center?

here i'm trying to draw a circle using drawOval method and I want to move it on the screen with a specific velocity. but i have a problem with double variables for the velocity.for example when vx=0.25 and vy=0 the circle is just stuck on its place. sorry for my bad English though.

here is the java code that i'm using

 int x=0 , y=0;
 @Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    move();
    g.drawOval(x, y, 10, 10);
    repaint();
}
public void move() {
    x+=0.25;
    y+=0.25;
}

Upvotes: 0

Views: 705

Answers (2)

Marco13
Marco13

Reputation: 54659

  • You should not call move from the paintComponent method! You never know when this method will be called, and thus, you cannot control the movement speed properly.
  • You should not call repaint from the paintComponent method! Never. This will send the painting system into an endless cycle of repaint operations!

Regarding the question:

There is a method for drawing arbitrary shapes based on double coordinates. This is also covered and explained extensively in the 2D Graphics Tutorial. The key is to use the Shape interface. For your particular example, the relevant part of the code is this:

private double x = 0;
private double y = 0;

@Override
public void paintComponent(Graphics gr)
{
    super.paintComponent(gr);
    Graphics2D g = (Graphics2D)gr;

    double radius = 5;
    g.draw(new Ellipse2D.Double(
        x - radius, y - radius, radius * 2, radius * 2));
}

That is, you create an Ellipse2D instance, and then just draw it.

Here is an MVCE, showing what you're probably trying to accomplish:

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;

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

public class PaintWithDouble
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        PaintWithDoublePanel p = new PaintWithDoublePanel();
        f.getContentPane().add(p);
        startMoveThread(p);

        f.setSize(500, 500);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static void startMoveThread(PaintWithDoublePanel p)
    {
        Thread t = new Thread(() -> {
            while (true)
            {
                p.move();
                p.repaint();
                try
                {
                    Thread.sleep(20);
                }
                catch (InterruptedException e)
                {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        });
        t.setDaemon(true);
        t.start();
    }
}

class PaintWithDoublePanel extends JPanel
{
    private double x = 0;
    private double y = 0;

    @Override
    public void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D) gr;
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        double radius = 5;
        g.draw(new Ellipse2D.Double(
            x - radius, y - radius, radius * 2, radius * 2));

        g.drawString("At " + x + ", " + y, 10, 30);
    }

    public void move()
    {
        x += 0.05;
        y += 0.05;
    }

}

Edited in response to the comment (and to clarify some things that have been said in other answers) :

While it is technically correct to say that there are "only whole pixels", and there "is no pixel with coordinates (0.3, 1.8)", this does not mean that fractional coordinates will not affect the final appearance of the rendered output. Every topic becomes a science when you're studying it long enough. Particularly, a lot of research went into the question of how to improve the visual appearance of rendered output, going beyond what you can achieve with a trivial Bresenham or so. An entry point for further research could be the article about subpixel rendering.

In many cases, as usual, there are trade-offs between the appearance and the drawing performance. As for Java and its 2D drawing capabilities, these trade-offs are mostly controlled via the RenderingHints class. For example, there is the RenderingHints#VALUE_STROKE_PURE that enables subpixel rendering. The effect is shown in this screen capture:

Subpixel

The slider is used to change the y-offset of the rightmost point of a horizontal line by -3 to +3 pixels. In the upper left, you see a line, rendered as-it-is. In the middle, you see the line magnified by a factor of 8, to better show the effect: The pixels are filled with different opacities, depending on how much of the pixel is covered by an idealized, 1 pixel wide line.

While it's certainly the case that this is not relevant for most application cases, it might be worth noting here.

The following is an MCVE that was used for the screen capture:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;

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

public class PaintWithDoubleMagnified
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().setLayout(new BorderLayout());

        PaintWithDoubleMagnifiedPanel p = new PaintWithDoubleMagnifiedPanel();
        f.getContentPane().add(p, BorderLayout.CENTER);

        JSlider slider = new JSlider(0, 100, 50);
        slider.addChangeListener(e -> {
            int value = slider.getValue();
            double relative = -0.5 + value / 100.0;
            p.setY(relative * 6);
        });
        f.getContentPane().add(slider, BorderLayout.SOUTH);

        f.setSize(500, 500);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

class PaintWithDoubleMagnifiedPanel extends JPanel
{
    private double y = 0;

    @Override
    public void paintComponent(Graphics gr)
    {
        super.paintComponent(gr);
        Graphics2D g = (Graphics2D) gr;

        g.drawString("At " + y, 10, 20);
        paintLine(g);

        BufferedImage image = paintIntoImage();
        g.setRenderingHint(
            RenderingHints.KEY_INTERPOLATION,
            RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
        g.scale(8.0, 8.0);
        g.drawImage(image, 0, 0, null);

    }

    public void setY(double y)
    {
        this.y = y;
        repaint();
    }

    private void paintLine(Graphics2D g)
    {
        g.setColor(Color.BLACK);
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(
            RenderingHints.KEY_STROKE_CONTROL,
            RenderingHints.VALUE_STROKE_PURE);

        Line2D line = new Line2D.Double(
            10, 30, 50, 30 + y);
        g.draw(line);

    }

    private BufferedImage paintIntoImage()
    {
        BufferedImage image = new BufferedImage(
            100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        paintLine(g);
        g.dispose();
        return image;
    }

}

Upvotes: 3

Traian GEICU
Traian GEICU

Reputation: 1786

First notice that rendering system is using int as arguments for each pixel.
So if p1 is near p2 on x axis then p1(x,y) and p2(x+1,y)
eg:(0,0) and (1,0) You do not have something in the middle like (0.5,1) since no pixels.
That why Graphics api is using int for (x,y) coordinates. Graphics api

If you wanted to consider also double you have to adapt the default coordinates systems to fit your needs.(cannot render all double there in individual pixels, need to group them in categories)


Eg. say want to place x_points : 0, 0.5, 1
So 0->0, 0.5(double)->1(int) , 1->2
Other pixels could map as 0.2->1, 0.7->2 , -0.9->0
One rule map consider all double range (better say in (-0.5,1]) can be
-0.5<d<=0 -> 0,0<d<=0.5 -> 1, 0.5<d<=1 -> 2 where d=input_x(double)
That means you adjust the coordinates systems to fit your needs

is there a method in java for drawing a circle with double variables for its center?


NO(using standard Graphics api). Have just what api is provided, but you could render what ever input you wanted (even based on double) by adjusting coordinates system.

class MyPaint extends JPanel
{

private double x = 0, y=0;
private int width = 30, height = 30;

//adjust coordinates system
//for x in [0,1] have [0,0.1,0.2,0.3 ..] 
//from no pixel between (0,1) to 9 pixels (0,0.1, ..,1)
//0->0,0.1->1,0.2->2,0.9->9,1->10
//in that way you have full control of rendering
private double scale_x = 0.1;
//same on y as x 
private double scale_y = 0.1;
//pixel scaled on x,y
//drawing with
private int xs,ys;

@Override
public void paintComponent(Graphics g)
{
    super.paintComponent(g);
    xs = (int) (x/scale_x);
    ys = (int) (y/scale_y);
    g.drawString("Draw At: " + xs + ", " + ys + " From:" + x+","+y, 10, 30);
    g.drawOval(xs, ys, (int) (width/scale_x), (int) (height/scale_y));
}

public void move()
{
     //adjustments is better to be >= then scale(x or y) seen as absolute value
     //if need 0.01 to be display on individual pixel on x 
     //then modify scale_x = 0.01 (or even 0.001)
     x+=0.1;
     y+=0.5;
}
}

Upvotes: 0

Related Questions