#!/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 = 600, 600
name = "Ballistic-trajectories-planet"
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 = 140, 530
R = 440
lw = 5
dash = "4,10"
c1, c2 = "#0072bd", "#d95319"
vx, vy = 0.5, 0.5 # 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.8, 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.2*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, 0.25*R, -0.03*R, 0.2*R, 0, 0.25*R, 0.03*R, 0.2*R)
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.87*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.87*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(0.56*R,-0.63*R), stroke="none", fill="black"))
doc.save(pretty=True)