Java Applets:绘制不相互重叠的圆圈?

时间:2014-04-13 11:08:43

标签: java applet geometry

该程序绘制10个圆圈,随机位置随机直径。如果圆的直径小于25,则将其填充为黄色,超过50,将其填充为绿色,否则将其填充为红色。

我的问题是我无法弄清楚如何阻止圆圈相互重叠。

这是我到目前为止所做的:

import java.util.Random;
import java.awt.*;
import javax.swing.JApplet;

public class Circles extends JApplet{   

public void paint(Graphics g) {

    Random rand = new Random();
    int diameter = 0;
    int posX = 0;
    int posY = 0;

    setBackground(Color.CYAN);

    for(int i=1; i <= 5 ; i++ )
    {
        posX = rand.nextInt(500);
        posY = rand.nextInt(500);
        diameter = rand.nextInt(75)+1;

        if (diameter < 25)
        {
            g.setColor(Color.YELLOW);
            g.fillOval(posX, posY,diameter,diameter);
        }

        else if(diameter > 50)
        {
            g.setColor(Color.GREEN);
            g.fillOval(posX, posY,diameter,diameter);
        }
        else
        {
            g.setColor(Color.RED);
            g.drawOval(posX, posY,diameter,diameter);
        }


    }
}
}

另外如果你注意到我的for循环只计数到5但我得到10个圆圈。我只是想知道为什么会这样?

2 个答案:

答案 0 :(得分:4)

这里有几个问题。

  • 不要在paint方法中调用setBackground(Color)。此方法仅用于绘画。其他修改应在构造函数或init方法
  • 中完成
  • super.paint(g)作为被覆盖的paint方法的第一行。这将清除背景
  • (轻微:让变量的范围尽可能小。所以只在{em>需要的地方声明posX等)

关于圈子的位置:

目前,每次重新绘制小程序时,您都会计算圈子的新位置和直径。因此,当您调整applet查看器的窗口大小时,随机放置的新圆圈将会四处闪烁。您应该只创建一次一次(可能在构造函数中)。在paint方法中,您应该只绘制它们。

更重要的是:如何知道可能放置圆圈没有重叠?最后,这会导致复杂的Circle Packing世界,您可以在其中使用一些真正复杂的技术,以确保尽可能紧密地放置圆圈。

但是现在,您可以使用非常简单的方法:每次创建新的圆圈时,您都可以尝试(多次)指定新的位置和直径,直到找到与现有圆圈不重叠的配置。虽然使用像

这样的方法似乎很诱人
while (existingCircles.size() < 5)
{
    Circle circle = newRandomCircle();
    if (!circle.overlapsAny(existingCircles))
    {
        existingCircles.add(circle);
    }
}

这里的问题是,当无法放置圆圈时,此算法不会终止! (注意:这是伪代码。但是......你应该考虑以某种方式编写代码,使它看起来像上面的代码。也就是说,考虑创建一个Circle类。)

然而,这是一个非常务实的解决方案,它只试图放置一个新的圆圈10次,并且当它没有成功时根本不放置它。虽然这不是很优雅,但它至少可以保证终止。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.JApplet;

public class Circles extends JApplet
{   
    private final List<Point> positions;
    private final List<Integer> diameters;

    public Circles()
    {
        positions = new ArrayList<Point>();
        diameters = new ArrayList<Integer>();

        Random rand = new Random();

        for(int i=1; i <= 5 ; i++ )
        {
            int tries = 10;
            for (int t=0; t<tries; t++)
            {
                int diameter = rand.nextInt(75)+1;
                int posX = rand.nextInt(500);;
                int posY = rand.nextInt(500);
                Point position = new Point(posX, posY);

                if (!overlapsOther(position, diameter))
                {
                    positions.add(new Point(posX, posY));
                    diameters.add(diameter);
                    break;
                }
            }
        }
    }

    private boolean overlapsOther(Point position, int diameter)
    {
        int radius = diameter/2;
        int centerX = position.x + radius;
        int centerY = position.y + radius;

        for (int i=0; i<positions.size(); i++)
        {
            Point otherPosition = positions.get(i);
            int otherDiameter = diameters.get(i);
            int otherRadius = otherDiameter/2;
            int otherCenterX = otherPosition.x + otherRadius;
            int otherCenterY = otherPosition.y + otherRadius;

            int dx = centerX - otherCenterX;
            int dy = centerY - otherCenterY;
            double distance = Math.hypot(dx, dy);
            if (distance < radius + otherRadius)
            {
                return true;
            }
        }
        return false;
    }

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

        for(int i=0; i<positions.size(); i++)
        {
            int posX = positions.get(i).x;
            int posY = positions.get(i).y;
            int diameter = diameters.get(i);

            if (diameter < 25)
            {
                g.setColor(Color.YELLOW);
                g.fillOval(posX, posY,diameter,diameter);
            }

            else if(diameter > 50)
            {
                g.setColor(Color.GREEN);
                g.fillOval(posX, posY,diameter,diameter);
            }
            else
            {
                g.setColor(Color.RED);
                g.drawOval(posX, posY,diameter,diameter);
            }

            System.out.println(diameter);
        }
    }
}

答案 1 :(得分:1)

要绘制不重叠的圆圈,您需要检查新圆圈是否会与已定义的圆圈相交。

  1. 初始化空堆栈
  2. 随机选择x,y和半径(直径的1/2)。
  3. 循环堆栈并使用(简单!)数学来计算到其他每个圆圈中心的距离。如果此距离小于其半径+新半径,则不会触及。
  4. 如果是,请转到2.
  5. 如果它没有触及任何其他圈子,请将其添加到堆栈中。
  6. 如果堆叠长度小于5,请转到2.
  7. 循环堆叠并绘制每个圆圈。
  8. 您可能想要将#Tries计数器添加到#2/3 - 例如,如果它找不到第四个或第五个圆圈的好位置,它可能会永远循环。如果#Tries计数器超过某个限制,请转到#1;基本上,从头开始。