grand-theft-arena/docs/figures.py

116 lines
3.1 KiB
Python

import math
import drawsvg as draw
import os
from pathlib import Path
images_path = Path(os.path.realpath(__file__)).parent.joinpath('src').joinpath('images')
# Define arrowhead marker
arrow = draw.Marker(0,0,10,10, refX="10", refY="5", markerWidth="6", markerHeight="6", orient='auto-start-reverse')
arrow.append(draw.Path(d='M 0 0 L 10 5 L 0 10 z', fill='black'))
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def force_diagram():
d = draw.Drawing(600, 600, origin='center')
# Outline drawing area
d.append(draw.Rectangle(-300,-300,600,600, fill='white'))
# Coordinate system
c = translate(coordinate_system(), -230, -230)
d.append(c)
# Define group
g = draw.Group(fill='black', stroke='black', stroke_width=1.5)
A = Point(0, -200)
B = Point(0, 200)
steering_angle = 20
w = 300
g.append(draw.Rectangle(-w/2,-280, w, 560, fill='none', stroke_width=1))
wheel = draw.Rectangle(-15,-40, 30, 80, fill='none', stroke_width=1)
g.append(translate(rotate(wheel, steering_angle), -w/2, A.y))
g.append(translate(rotate(wheel, steering_angle), w/2, A.y))
g.append(translate(wheel, -w/2, B.y))
g.append(translate(wheel, w/2, B.y))
# Center of Mass
g.append(draw.Circle(0, 0, 3))
g.append(text("CM", 0, 0, angle=180))
# Velocity vector
g.append(draw.Line(0, 0, -50, -160, marker_end=arrow))
g.append(text("v", -50, -160, angle=-110))
# Point A
g.append(text("A", A.x, A.y, angle=180))
g.append(draw.Circle(A.x, A.y, 3))
g.append(draw.Line(A.x, A.y, 80, -170, marker_end=arrow))
g.append(text("F_A", 80, -170))
# Point B
g.append(text("B", B.x, B.y, angle=180))
g.append(draw.Circle(B.x, B.y, 3))
g.append(draw.Line(B.x, B.y, 70, 200, marker_end=arrow))
g.append(text("F_B", 70, 200))
d.append(translate(g, 100, 0))
d.save_svg(f'{images_path}/force_diagram.svg')
def coordinate_system():
g = draw.Group(stroke='black', stroke_width=1.5)
g.append(draw.Line(0, 0, 50, 0, marker_end=arrow))
g.append(text("x", 50, 0))
g.append(draw.Line(0, 0, 0, 50, marker_end=arrow))
g.append(text("y", 0, 50, angle=90))
# Arc
cx = 0
cy = 0
r = 50
start = 120
end = -30
start_angle = math.radians(start)
end_angle = math.radians(end)
x0 = cx + r * math.cos(start_angle)
y0 = cy + r * math.sin(start_angle)
x1 = cx + r * math.cos(end_angle)
y1 = cy + r * math.sin(end_angle)
# SVG arc path from (x0, y0) to (x1, y1) around center
path_d = f'M {x0} {y0} A {r} {r} 0 1 1 {x1} {y1}'
arc = draw.Path(d=path_d, fill='none', marker_end=arrow)
g.append(arc)
return g
# Wrap in translated group
def translate(t, x, y):
g = draw.Group(transform=f"translate({x},{y})")
g.append(t)
return g
# Wrap in rotated group
def rotate(t, a):
g = draw.Group(transform=f"rotate({a})")
g.append(t)
return g
def text(text, x, y, offset=20, angle=0):
angle = math.radians(angle)
x = x + offset * math.cos(angle)
y = y + offset * math.sin(angle)
return draw.Text(text, 18, x, y, stroke_width=1, center=True)
force_diagram()