9

I'm trying to generate a set of points (represented by a Vector struct) that roughly models a spiral galaxy.

The C# code I've been playing with is below; but I can only seem to get it to generate a single 'arm' of the galaxy.

    public Vector3[] GenerateArm(int numOfStars, int numOfArms, float rotation)
    {
        Vector3[] result = new Vector3[numOfStars];
        Random r = new Random();

        float fArmAngle = (float)((360 / numOfArms) % 360);
        float fAngularSpread = 180 / (numOfArms * 2);

        for (int i = 0; i < numOfStars; i++)
        {

            float fR = (float)r.NextDouble() * 64.0f;
            float fQ = ((float)r.NextDouble() * fAngularSpread) * 1;
            float fK = 1;

            float fA = ((float)r.NextDouble() % numOfArms) * fArmAngle;


            float fX = fR * (float)Math.Cos((MathHelper.DegreesToRadians(fA + fR * fK + fQ)));
            float fY = fR * (float)Math.Sin((MathHelper.DegreesToRadians(fA + fR * fK + fQ)));

            float resultX = (float)(fX * Math.Cos(rotation) - fY * Math.Sin(rotation));
            float resultY = (float)(fY * Math.Cos(rotation) - fX * Math.Sin(rotation));

            result[i] = new Vector3(resultX, resultY, 1.0f);
        }

        return result;
    }
Icemanind
  • 47,519
  • 50
  • 171
  • 296
Chris Bampton
  • 199
  • 1
  • 8

3 Answers3

5

Check this. It's a simulation of galaxy using density wave theory. Code is available. http://beltoforion.de/galaxy/galaxy_en.html

sveco
  • 51
  • 1
  • 3
  • the link is dead, but for all of those that still want to read it use the following link https://web.archive.org/web/20140119101505/http://beltoforion.de/galaxy/galaxy_en.html – Peter Dec 29 '14 at 21:22
  • The reports of the links death are greatly exaggerated ;) And this article is great. Thanks! – ndreisg Jan 11 '19 at 19:17
  • To me the link also looks very alive and the article is awesome. Here the two github repos from the link for your convenience :) https://github.com/beltoforion/Galaxy-Renderer (C++) https://github.com/beltoforion/Galaxy-Renderer-Typescript – ndreisg Apr 08 '22 at 14:55
5

I liked this idea so much i had to play around with it on my own and here is my result. Note that i used PointF instead of Vector3, but you should be able to search and replace and add , 0) in a few places.

PointF[] points;

private void Render(Graphics g, int width, int height)
{
    using (Brush brush = new SolidBrush(Color.FromArgb(20, 150, 200, 255)))
    {
        g.Clear(Color.Black);
        foreach (PointF point in points)
        {
            Point screenPoint = new Point((int)(point.X * (float)width), (int)(point.Y * (float)height));
            screenPoint.Offset(new Point(-2, -2));
            g.FillRectangle(brush, new Rectangle(screenPoint, new Size(4, 4)));
        }
        g.Flush();
    }
}

public PointF[] GenerateGalaxy(int numOfStars, int numOfArms, float spin, double armSpread, double starsAtCenterRatio)
{
    List<PointF> result = new List<PointF>(numOfStars);
    for (int i = 0; i < numOfArms; i++)
    {
        result.AddRange(GenerateArm(numOfStars / numOfArms, (float)i / (float)numOfArms, spin, armSpread, starsAtCenterRatio));
    }
    return result.ToArray();
}

public PointF[] GenerateArm(int numOfStars, float rotation, float spin, double armSpread, double starsAtCenterRatio)
{
    PointF[] result = new PointF[numOfStars];
    Random r = new Random();

    for (int i = 0; i < numOfStars; i++)
    {
        double part = (double)i / (double)numOfStars;
        part = Math.Pow(part, starsAtCenterRatio);

        float distanceFromCenter = (float)part;
        double position = (part * spin + rotation) * Math.PI * 2;

        double xFluctuation = (Pow3Constrained(r.NextDouble()) - Pow3Constrained(r.NextDouble())) * armSpread;
        double yFluctuation = (Pow3Constrained(r.NextDouble()) - Pow3Constrained(r.NextDouble())) * armSpread;

        float resultX = (float)Math.Cos(position) * distanceFromCenter / 2 + 0.5f + (float)xFluctuation;
        float resultY = (float)Math.Sin(position) * distanceFromCenter / 2 + 0.5f + (float)yFluctuation;

        result[i] = new PointF(resultX, resultY);
    }

    return result;
}

public static double Pow3Constrained(double x)
{
    double value = Math.Pow(x - 0.5, 3) * 4 + 0.5d;
    return Math.Max(Math.Min(1, value), 0);
}

Example:

points = GenerateGalaxy(80000, 2, 3f, 0.1d, 3);

Result: Galaxy

Peter
  • 37,042
  • 39
  • 142
  • 198
2

I would abstract that function out into a createArm function.

Then you can store each arm as its own galaxy (temporarily).

So if you want 2 arms, do 2 galaxies of 5000. Then, rotate one of them 0 degrees around the origin (so doesn't move) and the other 180 degrees around the origin.

With this you can do an arbitrary number of arms by using different rotation amounts. You could even add some "naturalization" to it by making the rotation distance more random, like with a range instead of straight (360 / n). For example, 5 arms would be 0, 72, 144, 216, 288. But with some randomization you could make it 0, 70, 146, 225, 301.

Edit:

Some quick google-fu tells me (source)

q = initial angle, f  = angle of rotation.

x = r cos q
y = r sin q

x' = r cos ( q + f ) = r cos q cos f - r sin q sin f
y' = r sin ( q + w ) = r sin q cos f + r cos q sin f

hence:
x' = x cos f - y sin f
y' = y cos f + x sin f 
corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • Any ideas how I might go about changing the algorithm to 'rotate' all the values around 0.0? I could do it with a rotation matrix on each point, but it would be better to be able to pass in an 'rotation offset' value into the createArm function, and have the points rotated on generation. – Chris Bampton Sep 06 '11 at 18:05
  • are there any spiral galaxies with a number of arms other than two? i don't think it happens unless perhaps it's a transient feature due to disruption in some way (merger / collision). – andrew cooke Sep 06 '11 at 18:14
  • @Chris I added some formulas shameless ripped from siggraph. – corsiKa Sep 06 '11 at 18:17
  • @andrew the Milky Way has 2 primary arms, and 4 smaller ones. – corsiKa Sep 06 '11 at 18:18
  • really? huh. how embarassing. i was once an astronomer...! – andrew cooke Sep 06 '11 at 19:07
  • I updated the function above to include the rotation, but it doesn't seem to be rotating correctly... any ideas? – Chris Bampton Sep 06 '11 at 19:11
  • Your y should be `+` not `-`. Review the equations carefully. – corsiKa Sep 06 '11 at 21:16
  • 1
    Damn that cut + paste coding! – Chris Bampton Sep 07 '11 at 00:43
  • 1
    @Chris too true. Too too true. Whenever I'm copying and pasting, I know one of two thing is happening: I'm about to forget to change a subtle difference between the copied code and the pasted code, or I'm duplicating code that really should be refactored into a function. Copy/paste is a prototype programmer's best friend, and a maintenance programmer's nightmare! – corsiKa Sep 07 '11 at 05:32