diff --git a/gurpsspace/output/latexout.py b/gurpsspace/output/latexout.py index 8be3daf..f8a9fa3 100644 --- a/gurpsspace/output/latexout.py +++ b/gurpsspace/output/latexout.py @@ -4,6 +4,9 @@ processing towards a nicely formatted PDF file. """ +import subprocess +import os + # from ..starsystem import StarSystem from ..tables import AtmCompAbbr @@ -13,6 +16,36 @@ def __init__(self, starsystem, filename='starsystem.tex'): self.starsystem = starsystem self.filename = filename + def make_pdf(self) -> str: + self.write() + base_name = os.path.splitext(self.filename)[0] + pdf_name = base_name + ".pdf" + + cmd = ['pdflatex', '-interaction', 'nonstopmode', self.filename] + proc = subprocess.Popen(cmd) + proc.communicate() + + retcode = proc.returncode + if not retcode == 0: + os.unlink(pdf_name) + raise ValueError('Error {} executing command: {}'.format(retcode, ' '.join(cmd))) + # PDFLaTeX has to be run twice to properly generate the ToC + cmd = ['pdflatex', '-interaction', 'nonstopmode', self.filename] + proc = subprocess.Popen(cmd) + proc.communicate() + + retcode = proc.returncode + if not retcode == 0: + os.unlink(pdf_name) + raise ValueError('Error {} executing command: {}'.format(retcode, ' '.join(cmd))) + + os.unlink(base_name + '.log') + os.unlink(base_name + '.aux') + os.unlink(base_name + '.toc') + os.unlink(base_name + '.out') + + return os.path.abspath(pdf_name) + def write(self): # Open the file file = open(self.filename, 'w') diff --git a/gurpsspace/starsystem.py b/gurpsspace/starsystem.py index 54985b5..8058c06 100644 --- a/gurpsspace/starsystem.py +++ b/gurpsspace/starsystem.py @@ -364,6 +364,15 @@ def write_latex(self, filename='starsystem.tex') -> None: writer = LW(self, filename) writer.write() + def make_pdf(self, filename='starsystem.tex'): + """ + Create a PDF document with all the information about the starsystem. + :return: Path to the PDF. + """ + + writer = LW(self, filename) + return writer.make_pdf() + def get_age(self) -> int: """Return star system age in billion years""" return self.age diff --git a/server.py b/server.py index 1deacfe..ffb865b 100644 --- a/server.py +++ b/server.py @@ -7,6 +7,7 @@ from gurpsspace import starsystem as starsys from namegenerator import namegenerator +from cherrypy.lib.static import serve_file from jinja2 import Environment, FileSystemLoader env = Environment(loader=FileSystemLoader('webgui/templates')) @@ -68,6 +69,22 @@ def starsystem(self, must_have_garden="False", open_cluster=None, num_stars=0, a else: mysys = starsys.StarSystem(**arguments) + for star in mysys.stars: + for key, v in star.planetsystem.get_orbitcontents().items(): + if namegen is not None: + simple_name = v.get_name().replace("-", "") + if cherrypy.session.get('name_of_' + simple_name) is None: + name = namegen.get_random_name() + star.planetsystem.get_orbitcontents()[key].set_name(name) + # For some reason, using simple_name here leads to storing stuff improperly and + # generating new names every time. No idea why. + cherrypy.session['name_of_' + v.get_name().replace("-", "")] = name + else: + name = cherrypy.session.get('name_of_' + simple_name) + star.planetsystem.get_orbitcontents()[key].set_name(name) + + cherrypy.session.save() + tmpl = env.get_template('overview.html') cherrypy.session['starsystem'] = mysys cherrypy.response.cookie['names'] = {} @@ -83,34 +100,20 @@ def planetsystem(self, star_id=""): else: star_id = int(star_id) - namegen = cherrypy.session.get('namegen') - tmpl = env.get_template('planetsystem.html') env.globals['translate_row'] = self.translate_row t_count = 0 a_count = 0 g_count = 0 - for key, v in starsystem.stars[star_id].planetsystem.get_orbitcontents().items(): + for key, _ in starsystem.stars[star_id].planetsystem.get_orbitcontents().items(): if starsystem.stars[star_id].planetsystem.get_orbitcontents()[key].type() == 'Terrestrial': t_count += 1 if starsystem.stars[star_id].planetsystem.get_orbitcontents()[key].type() == 'Ast. Belt': a_count += 1 if starsystem.stars[star_id].planetsystem.get_orbitcontents()[key].type() == 'Gas Giant': g_count += 1 - if namegen is not None: - simple_name = v.get_name().replace("-", "") - if cherrypy.session.get('name_of_' + simple_name) is None: - name = namegen.get_random_name() - starsystem.stars[star_id].planetsystem.get_orbitcontents()[key].set_name(name) - # For some reason, using simple_name here leads to storing stuff improperly and - # generating new names every time. No idea why. - cherrypy.session['name_of_' + v.get_name().replace("-", "")] = name - else: - name = cherrypy.session.get('name_of_' + simple_name) - starsystem.stars[star_id].planetsystem.get_orbitcontents()[key].set_name(name) - cherrypy.session.save() cherrypy.session['planetsystem'] = starsystem.stars[star_id].planetsystem return tmpl.render(planetsystem=starsystem.stars[star_id].planetsystem, terrestrial_count=t_count, asteroid_count=a_count, gas_giant_count=g_count) @@ -140,6 +143,30 @@ def satellites(self, planet_id=""): tmpl = env.get_template('moons.html') return tmpl.render(moons=moons, planet_name=planet.get_name()) + @cherrypy.expose + def printable(self): + try: + starsystem = cherrypy.session['starsystem'] + except KeyError: + raise cherrypy.HTTPError(404) + + t_count = 0 + a_count = 0 + g_count = 0 + for star in starsystem.stars: + for key, _ in star.planetsystem.get_orbitcontents().items(): + if star.planetsystem.get_orbitcontents()[key].type() == 'Terrestrial': + t_count += 1 + if star.planetsystem.get_orbitcontents()[key].type() == 'Ast. Belt': + a_count += 1 + if star.planetsystem.get_orbitcontents()[key].type() == 'Gas Giant': + g_count += 1 + + tmpl = env.get_template('printable.html') + env.globals['translate_row'] = self.translate_row + + return tmpl.render(starsystem=starsystem, seed=self.random_seed, terrestrial_count=t_count, asteroid_count=a_count, gas_giant_count=g_count) + def translate_row(self, planet, row): """ It is difficult in HTML and Jinja to make a table where each column is a single item, rather than each row. diff --git a/webgui/templates/overview.html b/webgui/templates/overview.html index 5eb2b62..caa04e3 100644 --- a/webgui/templates/overview.html +++ b/webgui/templates/overview.html @@ -14,6 +14,7 @@

Star System Generator for GURPS 4th Edition

Click here if you want to change the settings.

Seed: {{seed}}

+

Printable view here.

You have successfully generated the following star system:

Star system properties

diff --git a/webgui/templates/printable.html b/webgui/templates/printable.html new file mode 100644 index 0000000..861b4cb --- /dev/null +++ b/webgui/templates/printable.html @@ -0,0 +1,264 @@ + + + + + Starsystem Generator for GURPS + + + + + +

Star System Generator for GURPS 4th Edition

+

Seed: {{seed}}

+

Star system properties

+ + {% if starsystem.is_open_cluster() %} +

The star system is located in an open cluster.

+ {% endif %} + {% if starsystem.stars|count == 1 %} +
+ There is a single star in the system.
+ {% else %} +
+ There are {{ starsystem.stars|count }} stars in the system.
+ {% endif %} + {% if starsystem.get_age() < 1 %} + The stars in this system are {{starsystem.get_age()|round(2)}} billion years old.
+ {% else %} + The stars in this system are {{starsystem.get_age() * 1000}} million years old.
+ {% endif %} +
+ + + + {% if starsystem.stars|count > 1 %} + + + {% endif %} + + + + + + + + + {% if starsystem.stars|count > 1 %} + + {% endif %} + + + {% for star in starsystem.stars %} + + + {% if star.get_letter() == 'A' and starsystem.stars|count > 1 %} + + + {% elif star.get_letter() != 'A' %} + + + {% endif %} + + + + + + + + + {% if star.get_letter() == 'A' and starsystem.stars|count > 1 %} + + {% elif star.get_letter() != 'A' %} + + {% endif %} + {% if star.planetsystem.get_orbitcontents()|count > 0 %} + + {% else %} + + {% endif %} + + {% endfor %} +
NameOrbital RadiusOrbital PeriodSequenceMass*Avg. Temp.Luminosity*Radius*Inner LimitOuter LimitSnow LineForbidden ZonePlanetary System
{{star.get_letter()}}--{{starsystem.get_orbits()[loop.index0 - 1][0]|round(2)}} AU{{starsystem.get_period()[loop.index0 - 1]|round(1, 'common')}} days{{star.get_sequence()}}{{star.get_mass()|round(2)}}{{star.get_temp()|round(2)}} K{{star.get_luminosity()|round(4)}}{{(star.get_radius() * 214.93) | round(2)}}{{star.get_orbit_limits()[0]|round(2)}} AU{{star.get_orbit_limits()[1]|round(2)}} AU{{star.get_snowline()|round(2)}} AU-{{star.get_forbidden_zone()[0]|round(2)}} AU - {{star.get_forbidden_zone()[1]|round(2)}} AU + {{star.planetsystem.get_orbitcontents()|count }} Planets in System + No Planetary System
+

*: Mass, Luminosity and Radius are given relative to the Sun: 1.0 is equal to the Sun.

+
+
+ {% for star in starsystem.stars %} + {% set planetsystem = star.planetsystem %} + +

Properties of Planet System {{planetsystem.parentstar.get_letter()}}

+ +

+ This planetary system orbits star {{planetsystem.parentstar.get_letter()}} of the star system. +

+

+ +
+

Overview

+

This planetary system contains the following planets and other astronomical objects:

+ + + + + + + + + + + + + + + {% for key, planet in planetsystem.get_orbitcontents().items()|sort %} + {% set astro_body = planetsystem.get_orbitcontents()[key] %} + + + + + + + + + + + + + + {% endfor %} +
NameTypeSizeWorldOrbital RadiusOrbital PeriodOrbital EccentricityMinimum RadiusMaximum RadiusMoonsMoonlets
{{astro_body.get_name()|e}}{{astro_body.type()}}{% if astro_body.get_size() != '' %}{{astro_body.get_size()}}{% else %} N/A {% endif %}{% if astro_body.get_type() != '' %}{{astro_body.get_type()}}{% else %} N/A {% endif %}{{astro_body.get_orbit()|round(2)}} AU{{(astro_body.get_period() * 365)|round(2)}} days{{astro_body.get_eccentricity()}}{{astro_body.get_min_max()[0]|round(2)}} AU{{astro_body.get_min_max()[1]|round(2)}} AU + {% if astro_body.num_moons() != '' %} + {{astro_body.num_moons()|round(2)}} + {% else %} + N/A + {% endif %} + {% if astro_body.num_moonlets() != '' %}{{astro_body.num_moonlets()|round(2)}}{% else %} N/A {% endif %}
+
+ {% for key, planet in planetsystem.get_orbitcontents().items()|sort %} + {% if planetsystem.get_orbitcontents()[key].num_moons()|int > 0 %} + {% set planet_name = planet.get_name() %} + {% if planet.type() == 'Terrestrial' %} + {% set moons = planet.get_satellites() %} + {% else %} + {% set moons = planet.get_moons() %} + {% endif %} +

Satellites of Planet {{planet_name}}

+ +
+ + {% set list_of_rows = ["", "World Size", "World Type", "Atm. Mass*", "Atm. Composition", "Hydr. Coverage", "Avg. Surface Temperature", "Climate Type", "Density*", "Diameter*", "Surface Gravity", "Mass*", "Atm. Pressure", "Pressure Category", "Volcanics", "Tectonics", "Resource Value Modifier", "Habitability", "Affinity", "Rotational Period*"] %} + {% for row in list_of_rows %} + + {% if row == "" %} + {% else %} + {% endif %} + + {% for astro_body in moons%} + {% if row == "" %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endfor %} +
{{row}}{{translate_row(astro_body, row)}}{{translate_row(astro_body, row)}}
+

*: Atmospheric mass, density, diameter, and mass are all relative to Earth dimensions; 1.0 is what you'd expect on Earth. The rotation of the body is prograde by default, negative rotational period values indicate retrograde rotation.

+
+ {% endif %} + {% endfor %} + {% if asteroid_count > 0 %} +
+ {% if asteroid_count == 1 %} +

Asteroid Belt Details

+ {% else %} +

Details of the Asteroid Belts

+ {% endif %} + + + + + + + + + {% for key, _ in planetsystem.get_orbitcontents().items()|sort if planetsystem.get_orbitcontents()[key].type() == 'Ast. Belt'%} + {% set astro_body = planetsystem.get_orbitcontents()[key] %} + + + + + + + + {% endfor %} +
NameAvg. Surface TemperatureClimate TypeResource Value ModifierAffinity
{{astro_body.get_name()|e}}{{astro_body.get_average_surface_temp()|round(2)}} K / {{(astro_body.get_average_surface_temp()-273.15)|round(2)}}°C{{astro_body.get_climate()}}{{astro_body.get_rvm()}}{{astro_body.get_affinity()}}
+
+ {% endif %} + {% if terrestrial_count > 0 %} +
+ {% if terrestrial_count == 1 %} +

Planet Details

+ {% else %} +

Details of the Planets

+ {% endif %} + + {% set list_of_rows = ["", "World Size", "World Type", "Atm. Mass*", "Atm. Composition", "Hydr. Coverage", "Avg. Surface Temperature", "Climate Type", "Axial Tilt", "Density*", "Diameter*", "Surface Gravity", "Mass*", "Atm. Pressure", "Pressure Category", "Volcanics", "Tectonics", "Resource Value Modifier", "Habitability", "Affinity", "Rotational Period*"] %} + {% for row in list_of_rows %} + + {% if row == "" %} + {% else %} + {% endif %} + + {% for key, _ in planetsystem.get_orbitcontents().items()|sort if planetsystem.get_orbitcontents()[key].type() == 'Terrestrial'%} + {% set astro_body = planetsystem.get_orbitcontents()[key] %} + + {% if row == "" %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endfor %} +
{{row}}{{translate_row(astro_body, row)}}{{translate_row(astro_body, row)}}
+ +

*: Atmospheric mass, density, diameter, and mass are all relative to Earth dimensions; 1.0 is what you'd expect on Earth. The rotation of the body is prograde by default, negative rotational period values indicate retrograde rotation.

+
+ {% endif %} + {% if gas_giant_count > 0 %} +
+ {% if gas_giant_count == 1%} +

Gas Giant Details

+ {% else %} +

Details of the Gas Giants

+ {% endif %} + + {% set list_of_rows = ["", "World Size", "Density*", "Diameter*", "Mass*", "Cloudtop Gravity", "Blackbody Temperature"] %} + {% for row in list_of_rows %} + + {% if row == "" %} + {% else %} + {% endif %} + + {% for key, _ in planetsystem.get_orbitcontents().items()|sort if planetsystem.get_orbitcontents()[key].type() == 'Gas Giant'%} + {% set astro_body = planetsystem.get_orbitcontents()[key] %} + + {% if row == "" %} + + {% else %} + + {% endif %} + {% endfor %} + + {% endfor %} +
{{row}}{{translate_row(astro_body, row)}}{{translate_row(astro_body, row)}}
+ +

*: Atmospheric mass, density, diameter, and mass are all relative to Earth dimensions; 1.0 is what you'd expect on Earth.

+
+ {% endif %} + {% endfor %} +
+ +