java中有没有一种方法可以绘制一个以双变量为中心的圆?

时间:2019-01-25 16:45:06

标签: java jframe

在这里,我尝试使用drawOval方法绘制一个圆,我想以特定的速度在屏幕上移动它。但是我有一个关于速度的双变量的问题。例如,当vx = 0.25和vy = 0时,圆刚好卡在其位置上。 抱歉,我的英语不好。

这是我正在使用的Java代码

 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;
}

2 个答案:

答案 0 :(得分:3)

  • 您不应通过move方法调用paintComponent!您永远都不知道何时调用此方法,因此无法正确控制移动速度。
  • 您不应通过repaint方法调用paintComponent从不。这将使绘画系统进入无休止的重画操作周期!

关于这个问题:

有一种方法可以根据double坐标绘制任意形状。 2D Graphics Tutorial中也对此进行了详细介绍和解释。关键是使用Shape界面。对于您的特定示例,代码的相关部分是这样的:

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));
}

也就是说,您创建一个Ellipse2D实例,然后将其绘制。

这是MVCE,显示您可能要完成的工作:

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;
    }

}

根据评论进行了编辑(并澄清了其他答案中已经提到的一些内容):

虽然说“只有整个像素”而没有“坐标(0.3,1.8)的像素”在技术上是正确的,但这并不意味着分数坐标不会影响渲染的最终外观输出。您学习足够长的时间后,每个主题都会变成一门科学。特别地,很多研究涉及到如何改善渲染输出的视觉外观的问题,这超出了用平凡的Bresenham所能达到的范围。进一步研究的切入点可以是关于subpixel rendering的文章。

在许多情况下,与往常一样,外观和绘图性能之间需要权衡取舍。对于Java及其2D绘图功能,这些权衡主要是通过RenderingHints类控制的。例如,有RenderingHints#VALUE_STROKE_PURE用于启用子像素渲染。该效果如下图所示:

Subpixel

滑块用于将水平线最右边点的y偏移更改为-3到+3像素。在左上方,您会看到一条按原样呈现的线。在中间,您会看到线条被放大了8倍,以更好地显示效果:像素充满了不同的不透明度,具体取决于理想化的1像素宽的线条覆盖了多少像素< / em>。

虽然这确实与大多数应用程序情况无关,但在这里可能值得注意。

以下是用于屏幕截图的MCVE:

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;
    }

}

答案 1 :(得分:0)

首先请注意,渲染系统正在将int用作每个像素的参数。
因此,如果p1在x轴上靠近p2,则 p1(x,y)p2(x+1,y)
例如:(0,0)和(1,0) 由于没有像素,因此中间没有(0.5,1)之类的东西。
这就是为什么Graphics api将int用于(x,y)坐标。 Graphics api

如果还要考虑使用double,则必须调整默认坐标系以适应您的需要。(不能在单个像素中渲染所有double,需要将它们分组在类别中)


例如说要放置x_points:0, 0.5, 1
所以0->00.5(double)->1(int)1->2
其他像素可以映射为0.2->10.7->2-0.9->0
一个规则图将所有范围都考虑在内(最好说in (-0.5,1]) 可以为
-0.5<d<=0 -> 00<d<=0.5 -> 10.5<d<=1 -> 2,其中d=input_x(双精度)
这意味着您可以根据自己的需要调整坐标系

  

java中是否有一种方法可以绘制一个以双变量为中心的圆?


否(使用标准Graphics api)。拥有提供的api,但是您可以通过调整坐标系来呈现所需的任何输入(即使基于double)。

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;
}
}