0

I'm trying to generate a nebula cloud in a specified radius around a Vector2 (Point).

Currently I'm using this code

public static Vector2 GeneratePosition(Vector2 position, float radius)
{
    float X = GenerateScaleFloat() * (GenerateInt(2) == 1 ? 1 : -1);
    float Y = GenerateInt((int)(radius * -(1 - Math.Abs(X))),
                          (int)(radius *  (1 - Math.Abs(X)))) / radius;

    X *= radius;
    Y *= radius;
        
    return new Vector2(X, Y);
}

which gives me this result:

(Origin: 0;0, Radius: 300, Particles: 5000) Filled non-circle

It looks to me like my code is generating a rotated square. How can I make it generate the positions of the particles in (and within) a more circular pattern?

GenerateScaleFloat: Returns a value between 0.0 and 1.0

GenerateInt: The standard rand.Next

EDIT: This post has now been flagged as duplicate, which was not my intention. I will however leave my answer here for other googlers to find since I know how helpful it is:

New code:

public static Vector2 GeneratePosition(Vector2 position, float radius)
{
    float X = GenerateScaleFloat() * (GenerateInt(2) == 1 ? 1 : -1) * radius;
    float Y = float.PositiveInfinity;

    while(Y > Math.Sqrt(Math.Pow(radius, 2) - Math.Pow(X, 2))
        || Y < -Math.Sqrt(Math.Pow(radius, 2) - Math.Pow(X, 2)))
    {
        Y = GenerateScaleFloat() * (GenerateInt(2) == 1 ? 1 : -1) * radius;
    }
                                
    return new Vector2(X, Y) + position;
}

New output: (Origin: 0;0, Radius 100, Particles: 5000) Circular nebula

Hope it'll help somebody else

Community
  • 1
  • 1
Felix ZY
  • 674
  • 6
  • 14

1 Answers1

2

The formula for a circle area is

x^2 + y^2 <= r^2

Given a x you can calculate y like this

y <= +/-sqrt( r^2 - x^2 )

By applying different scaling factors to the axis you can create an ellipse.


Another possibility is to generate points in a rectangle and look if they are within the ellipse:

a = width / 2
b = height / 2
(x/a)^2 + (y/b)^2 <= 1    Where the ellipse will be centered on
                          the origin of the coordinate system.

This might generate more evenly distributed points.


EDIT: You can improve your new code. Instead of comparing ...

y > Sqrt(r^2 - x^2) OR y < -Sqrt(r^2 - x^2)

... you can compare

y^2 > r^2 - x^2

y^2 is always positive since minus times minus is plus. It is often worth transforming an otherwise correct mathematical correct formula in order to make it more efficient for the computer. Calculating a square root is expensive, Math.Pow as well.

Also the generation of Y values between -1 and plus +1 can be achieved in an easier way by first generating a random number between 0 and 1, multiplying it by twice the radius and finally subtracting the radius.

float y2max = radius * radius - X * X;
do { 
    Y = 2 * radius * GenerateScaleFloat() - radius;
} while (Y * Y > y2max);
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188