116 lines
3.1 KiB
Python
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()
|
|
|