Random points inside a circle

2019-08-13 07:31发布

So I got a circle in a Windows Forms Application and have to place 20 random points in this circle. My idea was to split the circle into 4 parts to make it more balanced. My problem is that the points are all generated around the middle and I have no idea how to fix this...

    Graphics g;
    Pen p;
    Random r = new Random();
    int[] KegelX = new int[20];
    int[] KegelY = new int[20];
    private void Form1_Load(object sender, EventArgs e)
    {

    }

    private void button1_Click(object sender, EventArgs e)
    {
        Kegelplatzierung();
        p = new Pen(Color.Black);
        g = this.CreateGraphics();
        g.DrawEllipse(p, new Rectangle(50, 50, 400, 400));
        for (int i = 0; i < 20; i++)
        {
            g.DrawEllipse(p, new Rectangle(KegelX[i], KegelY[i], 1, 1));
        }
        p.Dispose();
        g.Dispose();
    }

    private void Kegelplatzierung() {
        for (int i = 0; i < 5; i++)
        {
            bool Kriterium = false;
            while (!Kriterium)
            {
                KegelX[i] = r.Next(50, 250);
                KegelY[i] = r.Next(50, 250);
                if (Math.Sqrt((250 - KegelX[i]) ^ 2 + (KegelY[i] - 250) ^ 2) < 200)
                {
                    Kriterium = true;
                }
            }
        }
        for (int i = 5; i < 10; i++)
        {
            bool Kriterium = false;
            while (!Kriterium)
            {
                KegelX[i] = r.Next(250, 450);
                KegelY[i] = r.Next(50, 250);
                if (Math.Sqrt((KegelX[i] - 250) ^ 2 + (KegelY[i] - 250) ^ 2) < 200)
                {
                    Kriterium = true;
                }
            }
        }
        for (int i = 10; i < 15; i++)
        {
            bool Kriterium = false;
            while (!Kriterium)
            {
                KegelX[i] = r.Next(50, 250);
                KegelY[i] = r.Next(250, 450);
                if (Math.Sqrt((250 - KegelX[i]) ^ 2 + (250 - KegelY[i]) ^ 2) < 200)
                {
                    Kriterium = true;
                }
            }
        }
        for (int i = 15; i < 20; i++)
        {
            bool Kriterium = false;
            while (!Kriterium)
            {
                KegelX[i] = r.Next(250, 450);
                KegelY[i] = r.Next(250, 450);
                if (Math.Sqrt((KegelX[i] - 250) ^ 2 + (250 - KegelY[i]) ^ 2) < 200)
                {
                    Kriterium = true;
                }
            }
        }

    }

Examples: http://puu.sh/gB6Dg/e81f8c3486.png http://puu.sh/gB6Ec/306f61424c.png

Thanks for help!

4条回答
你好瞎i
2楼-- · 2019-08-13 07:57

The problem is that in C#, ^ is the logical xor operator. You need to use Math.Pow instead. So...

if (Math.Sqrt(Math.Pow(250 - KegelX[i], 2) + Math.Pow(KegelY[i] - 250, 2)) < 200)

and so on.

查看更多
对你真心纯属浪费
3楼-- · 2019-08-13 07:58

This will do it as you planned it. Note however, that the symmetry between the four quadrants is only necessary if you really need it to balance very few points. For greater numbers it is not necessary and you could reduce the code to around half of its lines..!

private void panel2_Paint(object sender, PaintEventArgs e)
{
    int dotsPerQuadrant = 666;
    Random R = new Random();
    Size s1x1 = new System.Drawing.Size(2, 2);
    int radius = 200;
    int rad2 = radius / 2;
    int off = 20;
    Rectangle bounds = new Rectangle(off, off, radius, radius);
    GraphicsPath gp = new GraphicsPath();
    gp.AddEllipse(bounds);
    Rectangle rectQ1 = new Rectangle(off, off, rad2, rad2);
    Rectangle rectQ2 = new Rectangle(off + rad2, off, rad2, rad2);
    Rectangle rectQ3 = new Rectangle(off, off + rad2, rad2, rad2);
    Rectangle rectQ4 = new Rectangle(off + rad2, off + rad2, rad2, rad2);
    List<Rectangle> quadrants = new List<Rectangle> { rectQ1, rectQ2, rectQ3, rectQ4 };
    e.Graphics.Clear(Color.AntiqueWhite);
    e.Graphics.DrawEllipse(Pens.Black, bounds);

    foreach (Rectangle rect in quadrants)
    {
        int count = 0;
        do
        {
            Point p = new Point(rect.X + R.Next(rad2), rect.Y + R.Next(rad2));
            if (gp.IsVisible(p))
            {
                e.Graphics.FillEllipse(Brushes.Red, new Rectangle(p, s1x1));
                count++;
            }
        } while (count < dotsPerQuadrant);
    }

}

Here is the result. The dots spread over the whole circle uniformly, not clustering in the middle:

4x666 random dots

The direct code, sans quadrants;

private void panel2_Paint(object sender, PaintEventArgs e)
{
    int dotstoDraw = 666*4;
    Random R = new Random();
    Size s1x1 = new System.Drawing.Size(2, 2);
    int radius = 200;
    int off = 20;
    Rectangle bounds = new Rectangle(off, off, radius, radius);
    GraphicsPath gp = new GraphicsPath();
    gp.AddEllipse(bounds);

    e.Graphics.Clear(Color.AntiqueWhite);
    e.Graphics.DrawEllipse(Pens.Black, bounds);

    int count = 0;
    do
    {
        Point p = new Point(off + R.Next(radius), off + R.Next(radius));
        if (gp.IsVisible(p))
        {
            e.Graphics.FillEllipse(Brushes.Red, new Rectangle(p, s1x1));
            count++;
        }
    } while (count < dotstoDraw);
 }
查看更多
做自己的国王
4楼-- · 2019-08-13 08:08

You can do this by choosing a random radius and angle for each point.

To avoid noticeable quantisation of the angle component into radial spokes, I use (double)rand.Next() / int.MaxValue to get a random number between 0 and 1 and multiply that by 2π.

To avoid the points being bunched up near the centre of the circle, I used Chris A.'s formula (at Generate a random point within a circle (uniformly)) to generate the radius:

Random rand = new Random();

private List<Point> GetRandomPoints(double rMax, int nPoints)
{
    var randPoints = new List<Point>();
    for (int i = 0; i < nPoints; i++)
    {
        var r = Math.Sqrt((double)rand.Next() / int.MaxValue) * rMax;
        var theta = (double)rand.Next() / int.MaxValue * 2 * Math.PI;
        randPoints.Add(new Point((int)(r * Math.Cos(theta)), (int)(r * Math.Sin(theta))));
    }
    return randPoints;
}

private void button1_Click(object sender, EventArgs e)
{
    using (Graphics g = this.CreateGraphics())
    {
        using (Pen p = new Pen(Color.Black))
        {
            var left = 50;
            var top = 50;
            var r = 200;
            g.DrawEllipse(p, new Rectangle(left, top, r * 2, r * 2));

            int nPoints = 20;
            var randomPoints = GetRandomPoints(r - 1, nPoints);

            for (int i = 0; i < nPoints; i++)
            {
                g.DrawEllipse(p, new Rectangle(randomPoints[i].X + left + r, randomPoints[i].Y + top + r, 1, 1));
            }
        }
    }
}

To make sure objects are disposed of cleanly, you can use the using construct - it makes sure you don't accidentally forget.

It's usually better to assign things like the radius of the circle to a variable as then you can easily change it in one place, and it makes the code easier to read if you use meaningful variable names.

Here's an example of the output, but with the radius set to 100 and generating 200 points:

Sample output

查看更多
爷、活的狠高调
5楼-- · 2019-08-13 08:18

Generates a random set of points inside a circle of a given radius...

 private void button1_Click(object sender, EventArgs e)
            {
                int radius = 100;
                var p = new Pen(Color.Black);
                var g = this.CreateGraphics();
                g.DrawEllipse(p, 0,0,radius*2, radius*2);
                var pointGen = new RandomPointGenerator();
                var randomPoints = pointGen.GetPointsInACircle(radius, 20);
                p.Color = Color.Red;
                foreach (var point in randomPoints)
                {

                    g.DrawEllipse(p, point.X + radius, point.Y+radius, 2, 2);
                }
            }



public class RandomPointGenerator
    {
        private Random _randy = new Random();
        public List<Point> GetPointsInACircle(int radius, int numberOfPoints)
        {
            List<Point> points = new List<Point>();
            for (int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++)
            {
                int distance = _randy.Next(radius);
                double angleInRadians = _randy.Next(360)/(2 * Math.PI) ;

                int x = (int)(distance * Math.Cos(angleInRadians));
                int y = (int)(distance * Math.Sin(angleInRadians));
                Point randomPoint = new Point(x, y);
                points.Add(randomPoint);
            }
            return points;
        }
    }
查看更多
登录 后发表回答