Skip to content

Commit c22de88

Browse files
authored
All files updated. Automatic files created.
1 parent e83b967 commit c22de88

10 files changed

+2025
-146
lines changed
+233
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
#
2+
# This script generates a 3D galaxy from a number of parameters and stores
3+
# it in an array. You can modify this script to store the data in a database
4+
# or whatever your purpose is. THIS script uses the data only to generate a
5+
# PNG with a 2D view from top of the galaxy.
6+
#
7+
# The algorithm used to generate the galaxy is borrowed from Ben Motz
8+
# <[email protected]>. The original C source code for DOS (including a 3D
9+
# viewer) can be downloaded here:
10+
#
11+
# http://bits.bristol.ac.uk/motz/tep/galaxy.html
12+
#
13+
# Unfortunately, the original python code has been lost to time and a lack of wanting-to- search-through-several-hundred-webpages-for-one-webarchive-page. Sorry, original python guy.
14+
#
15+
# A fair portion of the revisions and code is from /u/_Foxtrot_ on reddit. They are much better with the python-fu than I!
16+
#
17+
18+
from PIL import Image
19+
from PIL import ImageDraw
20+
import random
21+
import math
22+
import sys
23+
24+
# Generation parameters:
25+
26+
# raw_input the user's desired values
27+
# Background color of the created PNG
28+
PNGBGCOLOR = (0, 0, 0)
29+
30+
# Quick Filename
31+
RAND = random.randrange(0, 108000000000)
32+
33+
# ---------------------------------------------------------------------------
34+
NAME = raw_input('Galaxy Name:')
35+
36+
HSB = int(raw_input('Galaxy Size Bracket <0 = 1-100, 1 = 100-1000, 2 = 1000-100000, 3 = 100000-1000000, 4 = 1000000-2000000>:'))
37+
38+
NUMC = (random.randint(0,12))
39+
40+
if HSB == 0: NUMSTR = random.randrange(1, 100)
41+
elif HSB == 1: NUMSTR = random.randrange(100, 1000)
42+
elif HSB == 2: NUMSTR = random.randrange(1000, 100000)
43+
elif HSB == 3: NUMSTR = random.randrange(100000, 1000000)
44+
elif HSB == 4: NUMSTR = random.randrange(1000000, 2000000)
45+
46+
print NUMSTR
47+
48+
NUMCLUS = NUMSTR / 70
49+
50+
DISCLUS = NUMCLUS / 4
51+
52+
GALX = int(NUMSTR / (random.randrange(8,20)))
53+
54+
GALY = int(NUMSTR / (random.randrange(6,28)))
55+
56+
GALZ = int(NUMSTR / (random.randrange(10,40)))
57+
58+
CLUSRAD = NUMCLUS / 5
59+
60+
DISCLRAD = CLUSRAD / 5
61+
62+
PNGSIZEA = GALX / 5
63+
64+
PNGFRAMEA = PNGSIZEA / 10
65+
66+
PNGSIZE = float(raw_input('X and Y Size of PNG <Default:Bad Idea>:') or str(PNGSIZEA))
67+
68+
PNGFRAME = float(raw_input('PNG Frame Size <Default:Bad Idea>:') or str(PNGFRAMEA))
69+
70+
stars = []
71+
clusters = []
72+
73+
star_color_dict = {
74+
0: (229, 30, 30),
75+
1: (203, 30, 26),
76+
2: (181, 18, 6),
77+
3: (200, 39, 13),
78+
4: (200, 63, 21),
79+
5: (222, 75, 10),
80+
6: (222, 102, 10),
81+
7: (222, 137, 10),
82+
8: (212, 178, 42),
83+
9: (210, 188, 38),
84+
10: (217, 207, 66),
85+
11: (217, 207, 66),
86+
12: (222, 226, 125),
87+
13: (222, 226, 125),
88+
14: (255, 255, 253),
89+
15: (255, 255, 255),
90+
16: (253, 255, 255),
91+
17: (222, 243, 255),
92+
18: (222, 243, 255),
93+
19: (140, 176, 225)
94+
}
95+
96+
SGX = GALX * 0.1
97+
SGY = GALY * 0.1
98+
SCRAD = CLUSRAD * 0.06
99+
NUMCLUSA = NUMCLUS - DISCLUS
100+
NUMCLUSB = NUMCLUS + DISCLUS
101+
CLUSRADA = CLUSRAD - DISCLRAD
102+
CLUSRADB = CLUSRAD + DISCLRAD
103+
NUMCB = NUMC + 1
104+
105+
def generateClusters():
106+
c = 0
107+
cx = 0
108+
cy = 0
109+
cz = 0
110+
rad = random.uniform(CLUSRADA, CLUSRADB)
111+
num = random.uniform(NUMCLUSA, NUMCLUSB)
112+
clusters.append((cx, cy, cz, rad, num))
113+
c = 1
114+
while c < NUMCB:
115+
# random distance from centre
116+
dist = random.uniform(CLUSRAD, GALX)
117+
# any rotation- clusters can be anywhere
118+
theta = random.random() * 360
119+
cx = math.cos(theta * math.pi / 180.0) * dist
120+
cy = math.sin(theta * math.pi / 180.0) * dist
121+
cz = random.random() * GALZ * 2.0 - GALZ
122+
rad = random.uniform(CLUSRADA, CLUSRADB)
123+
num = random.uniform(NUMCLUSA, NUMCLUSB)
124+
# add cluster to clusters array
125+
clusters.append((cx, cy, cz, rad, num))
126+
# process next
127+
c = c+1
128+
sran = 0
129+
cran = 0
130+
131+
def generateStars():
132+
133+
# Now generate the Hub. This places a point on or under the curve
134+
# maxHubZ - s d^2 where s is a scale factor calculated so that z = 0 is
135+
# at maxHubR (s = maxHubZ / maxHubR^2) AND so that minimum hub Z is at
136+
# maximum disk Z. (Avoids edge of hub being below edge of disk)
137+
138+
scale = GALZ / (GALX * GALY)
139+
i = 0
140+
while i < NUMSTR:
141+
142+
# Choose a random distance from center
143+
distX = random.random() * GALX
144+
distY = random.random() * GALY
145+
distXb = distX + random.uniform(0,SGX)
146+
distYb = distY + random.uniform(0,SGY)
147+
148+
# Any rotation (points are not on arms)
149+
theta = random.random() * 360
150+
151+
# Convert to cartesian
152+
x = math.cos(theta * math.pi / 180.0) * distXb
153+
y = math.sin(theta * math.pi / 180.0) * distYb
154+
z = (random.random() * 2 - 1) * (GALZ - scale * distXb * distYb)
155+
156+
# Replaces the if/elif logic with a simple lookup. Faster and
157+
# and easier to read.
158+
scol = star_color_dict[random.randrange(0,19)]
159+
160+
# Add star to the stars array
161+
stars.append((x, y, z, scol))
162+
163+
# Process next star
164+
i = i + 1
165+
sran = 0
166+
167+
c = 0
168+
while c < NUMCB:
169+
for (cx, cy, cz, rad, num) in clusters:
170+
scale = rad / (rad * rad)
171+
i = 0
172+
while i < num:
173+
dist = random.uniform(-rad,rad)
174+
distb = dist + random.uniform(0,SCRAD)
175+
theta = random.random() * 360
176+
# Cartesian!
177+
x = cx + (math.cos(theta * math.pi / 180) * distb)
178+
y = cy + (math.sin(theta * math.pi / 180) * distb)
179+
z = (random.random() * 2 - 1) * ((cz + rad) - scale * distb * distb)
180+
scol = star_color_dict[random.randrange(0,19)]
181+
stars.append((x, y, z, scol))
182+
i = i + 1
183+
sran = 0
184+
c = c+1
185+
186+
187+
188+
189+
def drawToPNG(filename):
190+
image = Image.new("RGB", (int(PNGSIZE), int(PNGSIZE)), PNGBGCOLOR)
191+
draw = ImageDraw.Draw(image)
192+
193+
# Find maximal star distance
194+
max = 0
195+
for (x, y, z, scol) in stars:
196+
if abs(x) > max: max = x
197+
if abs(y) > max: max = y
198+
if abs(z) > max: max = z
199+
200+
# Calculate zoom factor to fit the galaxy to the PNG size
201+
factor = float(PNGSIZE - PNGFRAME * 2) / (max * 2)
202+
for (x, y, z, scol) in stars:
203+
sx = factor * x + PNGSIZE / 2
204+
sy = factor * y + PNGSIZE / 2
205+
draw.point((sx, sy), fill=scol)
206+
207+
# Save the PNG
208+
image.save(filename)
209+
print filename
210+
211+
212+
# Generate the galaxy
213+
generateClusters()
214+
generateStars()
215+
216+
# Save the galaxy as PNG to galaxy.png
217+
drawToPNG("ellipticalgalaxy" + str(RAND) + "-" + str(NAME) + ".png")
218+
219+
# Create the galaxy's data galaxy.txt
220+
with open("ellipticalgalaxy" + str(RAND) + "-" + str(NAME) + ".txt", "w") as text_file:
221+
text_file.write("Galaxy Number: {}".format(RAND))
222+
text_file.write("Galaxy Name: {}".format(NAME))
223+
text_file.write("Number of Clusters: {}".format(NUMC))
224+
text_file.write("Stars: {}".format(NUMSTR))
225+
text_file.write("Number of Stars per Cluster {}".format(NUMCLUS))
226+
text_file.write("Star Number Distribution per Cluster {}".format(DISCLUS))
227+
text_file.write("Galaxy X Length: {}".format(GALX))
228+
text_file.write("Galaxy Y Length: {}".format(GALY))
229+
text_file.write("Galaxy Z Length: {}".format(GALZ))
230+
text_file.write("Cluster Radius: {}".format(CLUSRAD))
231+
text_file.write("Cluster Radius Distribution: {}".format(DISCLRAD))
232+
text_file.write("Image Size: {}".format(PNGSIZE))
233+
text_file.write("Frame Size: {}".format(PNGFRAME))

0 commit comments

Comments
 (0)