Galaxy: A few more tweaks to the Radius generation
[GalaxyGenerator.git] / Galaxy.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using System;
using System.Collections.Generic;
using System.IO;
 
namespace GalaxyGenerator
{
        public class Galaxy
        {
                public Galaxy ()
                {
                        Stars = new Dictionary<UInt64, Star>();
                }
                
                public void Populate()
                {
                        Random rand = GlobalParameters.rand;
                                                
                        uint NumStars = GlobalParameters.NumStars;
                        uint DiskRadius = GlobalParameters.DiskRadius;
                        uint HubRadius = GlobalParameters.HubRadius;
                        uint NumArms = GlobalParameters.NumArms;
                        double ArmRotations = GlobalParameters.ArmRotations;
                        double ArmWidth = GlobalParameters.ArmWidth;
                        double Fuzz = GlobalParameters.Fuzz;
                        
                        uint GalaxyRadius = HubRadius + DiskRadius;
                        
                        double TwoPi = 2d*Math.PI;
                        
                        double Omega;
                        if (NumArms != 0)
                        {
                                Omega = TwoPi / (double)NumArms;
                        }
                        else
                        {
                                Omega = 0d;
                        }
                        
                        for (int i = 1; i <= NumStars; ++i)
                        {
                                double Radius = (double)GalaxyRadius * rand.NextDouble() * rand.NextDouble();
 
//                              Ziggy is using this method to get a better-looking distribution in the hub, but it doesn't translate well to the whole galaxy.
//
//                              double Radius = (double)HubRadius;
//                              while (true)
//                              {
//                                      Radius *= 1.618 * rand.NextDouble();
//                                      if (rand.NextDouble() > 0.8 || (Radius > (double)GalaxyRadius)) { break; }
//                              }
//                              Radius += (2d * rand.NextDouble() - 1d) * GalaxyRadius * .1;
 
                                double Phi, Theta;  // Rotational angles for some spherical coordinates.
                                double x, y, z;  // Cartesian coordinates, maybe?
                                
                                // If the radius puts the star outside the Hub (be fuzzy), we need to align it in an arm.
                                if (Radius > (HubRadius + rand.NextDouble() * ( rand.NextDouble() * 2 - 1 ) * ( DiskRadius - HubRadius)))
                                {
                                        // This spiral algorithm was taken from the python Galaxy Generator found here: http://www.ailis.de/~k/archives/29-Galaxy-Generator.html
                                        // Rotate the star by the specified number of rotations, then
                                        // multiply by the proportional distance from center to give
                                        // curvature.
                                        Phi = ((TwoPi * (double)ArmRotations * Radius / (double)GalaxyRadius)
                                                     // Then move the point further around by a random factor up to ArmWidth
                                                     + rand.NextDouble() * (double)ArmWidth
                                                     // Then add a factor of omega, putting the point into one of the arms.
                                                     + Omega * (double)(int)rand.Next(0, (int)NumArms)
                                                     // Then add some extra "fuzz".
                                                     + (rand.NextDouble() * 2d - 1d) * (double)Fuzz);
                                        
                                        z = (2d * rand.NextDouble() - 1d) * (double)HubRadius * ( Math.Pow (( 1 - (Radius / (double)GalaxyRadius) ), 4 ) 
                                                + (rand.NextDouble() * 2d - 1d) * (double)Fuzz);
                                        Theta = Math.Acos (z / Radius);
 
                                        // Find the x, y cartesians from r and phi.
                                        x = Math.Cos(Phi) * Radius;
                                        y = Math.Sin(Phi) * Radius;
                                }
                                // If the star is not in an arm, the distribution should be spherical.
                                else
                                {
                                        Phi = rand.NextDouble() * TwoPi;
                                        Theta = Math.Asin(2d * rand.NextDouble() -1) + Math.PI / 2;
 
                                        z = Math.Cos(Theta) * Radius;
                                        x = Math.Sin(Theta) * Math.Cos(Phi) * Radius;
                                        y = Math.Sin(Theta) * Math.Sin(Phi) * Radius;
                                }
 
                                AddStar(new Star(x, y, z));
                        }
                }
                
                public void AddStar(Star star,UInt64 id)
                {
                        CartesianCoords starCoords = star.getCoords();
                        int maxCoord = (int) Math.Max (Math.Max (starCoords.getX (), starCoords.getY()), starCoords.getZ());
                        if (Extents < maxCoord)
                        {
                                Extents = maxCoord;
                        }
                        
                        Stars.Add(id, star);
                }
                public void AddStar(Star star)
                {
                        star.setID(NewID());
                        AddStar(star, star.getID());
                }
                
                public void RemoveStar(UInt64 id)
                {
                        Stars.Remove(id);
                }
                
                public int getExtents()
                {
                        return Extents;
                }
                
                public Dictionary<UInt64, Star> getStars()
                {
                        return Stars;
                }
                
                public void Save(FileStream stream)
                {
                        stream.Write(BitConverter.GetBytes(SaveCode), 0, sizeof(UInt16));
                        foreach (Star star in Stars.Values)
                        {
                                star.Save(stream);
                        }
                }
                
                public void Load(byte[] stream)
                {
                        int offset = 0;
                        UInt16 ReadCode = BitConverter.ToUInt16(stream, offset);
                        if (ReadCode != SaveCode) { throw new Exception("File not a valid galaxy blob." + ReadCode); }
                        offset += sizeof(UInt16);
                        while (offset < stream.Length)
                        {
                                Star star = Star.Load(stream, ref offset);
                                this.AddStar(star, star.getID());
                        }
                }
                
                private UInt64 NewID()
                {
                        return GalacticallyUniqueIdentifier.NewID();
                }
                
                private Dictionary<UInt64, Star> Stars;
                private int Extents = 0;
                private static UInt16 SaveCode = GlobalParameters.SaveCodes["Galaxy"];
        }
}