#!/usr/bin/python3
# -*- coding: utf8 -*-
try:
import svgwrite
except ImportError:
print("requires svgwrite library: https://pypi.org/project/svgwrite/")
# documentation at https://svgwrite.readthedocs.io/
exit(1)
from math import *
# document
size = 720, 440
name = "Ballistic-trajectories-planet2"
doc = svgwrite.Drawing(name + ".svg", profile="full", size=size)
doc.set_desc(name, name + """.svg
https://commons.wikimedia.org/wiki/File:""" + name + """.svg
rights: Creative Commons Attribution-Share Alike 4.0 International license""")
# background
doc.add(doc.rect(id="background", insert=(0, 0), size=size, fill="white", stroke="none"))
cx, cy = 72, 1720
R = 1500
lw = 5
dash = "5,9"
c1, c2 = "#0072bd", "#d95319"
vx, vy = 0.4, 0.4 # in units of sqrt(R*g)
# gradients
rgrad = doc.defs.add(doc.radialGradient(id='rgrad', center=(0.5,0.5), r=0.5, gradientUnits='objectBoundingBox'))
rgrad.add_stop_color(offset=0.93, color='#ffffff')
rgrad.add_stop_color(offset=1, color='#ddc099')
lgrad = doc.defs.add(doc.linearGradient(id='lgrad', start=(0,0), end=(0,1), gradientUnits='objectBoundingBox'))
lgrad.add_stop_color(offset=0, color='#ddc099')
lgrad.add_stop_color(offset=1, color='#ffffff')
g = doc.add(doc.g(transform="translate({:.1f}, {:.1f})".format(cx, cy), fill="none"))
g.add(doc.rect(insert=(-cx, -R), size=(size[0], 0.07*R), fill="url(#lgrad)", stroke="none"))
g.add(doc.path(d="M {:.1f},{:.1f}h{:.1f}".format(-cx, -R, size[0]), stroke="black", stroke_width="3"))
g.add(doc.circle(r=str(R), center=(0,0), fill="url(#rgrad)", stroke="black", stroke_width="3"))
# trajectories
def parabola(x1, x2, abc): # using a quadratic Bezier curve
a, b, c = abc
y1 = a + b * x1 + c * x1**2
y2 = a + b * x2 + c * x2**2
txt = "M {:.1f},{:.1f}Q{:.1f},{:.1f} {:.1f},{:.1f}"
return txt.format(x1, y1, (x1+x2)/2, (y1+y2)/2 - c/2*(x2-x1)**2, x2, y2)
def ellipse(p1, p2, abphi, l): # using arc
a, b, phi = abphi
c = 1
if (pi/2-phi) % (2 * pi) > pi:
c = 1 - c
txt = "M {:.1f},{:.1f}A{:.1f},{:.1f} {:.1f} {:} {:} {:.1f},{:.1f}"
return txt.format(p1[0], p1[1], a, b, degrees(phi), l, c, p2[0], p2[1])
p0 = (0, -R)
p1 = (2 * R * vx * vy, -R)
abc = -R, -vy / vx, 0.5 / R / vx**2
E2 = 2 - vx**2 - vy**2
a = R / E2
b = R * fabs(vx) / sqrt(E2)
phi = asin(vx / sqrt(E2) * sqrt((2 * a * R - b**2 - R**2) / (a**2 - b**2))) - pi/2
p2 = (-R * sin(2 * phi), R * cos(2 * phi))
abphi = a, b, phi
g.add(doc.path(d=ellipse(p2, p0, abphi, 1),
stroke=c2, stroke_width=lw, stroke_dasharray=dash))
g.add(doc.path(d=parabola(-cx, 0, abc) + " " + parabola(2*R*vx*vy, size[0]-cx, abc),
stroke=c1, stroke_width=lw, stroke_dasharray=dash))
g.add(doc.path(d=ellipse(p0, p2, abphi, 0), stroke=c2, stroke_width=lw))
g.add(doc.path(d=parabola(p0[0], p1[0], abc), stroke=c1, stroke_width=lw))
# arrows
arrowd = "M {:.1f},{:.1f}V{:.1f}M{:.1f},{:.1f}L{:.1f},{:.1f}L{:.1f},{:.1f}".format(
0, 0, 110, -13, 88, 0, 110, 13, 88)
g.add(doc.path(transform="translate(0, {:.1f})".format(-R), d=arrowd,
stroke="#777777", stroke_width="7", fill="none", stroke_linecap="butt"))
g.add(doc.path(transform="translate({:.1f}, {:.1f})".format(*p1), d=arrowd,
stroke="#777777", stroke_width="7", fill="none", stroke_linecap="butt"))
g.add(doc.path(transform="rotate({:.2f}) translate(0, {:.1f})".format(degrees(2*phi-pi), -R), d=arrowd,
stroke="#777777", stroke_width="7", fill="none", stroke_linecap="butt"))
g.add(doc.circle(r="6", center=(0,0), fill="black", stroke="none"))
g.add(doc.circle(r="6", center=p0, fill="black", stroke="none"))
g.add(doc.circle(r="6", center=p1, fill="black", stroke="none"))
g.add(doc.circle(r="6", center=p2, fill="black", stroke="none"))
# text
g.add(doc.text("g", font_size="30px", font_family="Bitstream Vera Sans",
text_anchor="middle", transform="translate({:.1f}, {:.1f})".format(19, -0.955*R), stroke="none", fill="black"))
g.add(doc.text("g", font_size="30px", font_family="Bitstream Vera Sans",
text_anchor="middle", transform="translate({:.1f}, {:.1f})".format(19+p1[0], -0.955*R), stroke="none", fill="black"))
g.add(doc.text("g'", font_size="30px", font_family="Bitstream Vera Sans",
text_anchor="middle", transform="translate({:.1f}, {:.1f})".format(550, -1322), stroke="none", fill="black"))
legend = doc.add(doc.g(transform="translate({:.1f}, {:.1f})".format(510, 20), fill="none"))
legend.add(doc.rect(insert=(0, 0), size=(190, 100), fill="white", stroke="black", stroke_width="3"))
legend.add(doc.path(d="M {:.1f},{:.1f}h{:.1f}".format(20, 30, 40), stroke=c1, stroke_width=lw))
legend.add(doc.path(d="M {:.1f},{:.1f}h{:.1f}".format(20, 70, 40), stroke=c2, stroke_width=lw))
legend.add(doc.text("flat", font_size="30px", font_family="Bitstream Vera Sans",
text_anchor="start", transform="translate({:.1f}, {:.1f})".format(76, 39), stroke="none", fill="black"))
legend.add(doc.text("planet", font_size="30px", font_family="Bitstream Vera Sans",
text_anchor="start", transform="translate({:.1f}, {:.1f})".format(76, 79), stroke="none", fill="black"))
doc.save(pretty=True)