Created
June 18, 2024 15:02
-
-
Save pozitron57/d3b26ab870051e5b3def72233c4756f6 to your computer and use it in GitHub Desktop.
Animation for kinematics constraints problem https://phys.pro/problems/1189.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
from matplotlib import pyplot as plt | |
from matplotlib import rc, rcParams | |
# Parameters {{{ | |
alpha = 30/np.pi | |
alpha = np.degrees(alpha) | |
dt = 0.7 | |
v1 = 1.6 | |
## Неверный, но веселый результат | |
#v2x = v1 * np.cos(alpha) | |
#v2y = v1 * (np.sin(alpha) + np.tan(alpha)) | |
v2x = v1 * (np.cos(alpha) - 1) | |
v2y = v1 * np.sin(alpha) | |
#}}} | |
# Клин общие настройки | |
base_length = 1 | |
A = (0, 0) # Левый угол | |
B = (-base_length, 0) # Правый угол | |
height = base_length * np.tan(alpha) | |
C = (0, height) # Верхний угол | |
# Брусок (прямоугольник) общие настройки | |
rect_width = base_length / 6 | |
rect_height = base_length / 8 | |
# Блок (круг) общие настройки | |
r = rect_height / 2 | |
times = np.linspace(0, (base_length/np.cos(alpha) - rect_width - r) / v1, 300) | |
ccc = '#555555' | |
# Общие настройки для стрелок | |
ct = '#3344BB' | |
arrow_lw=1.5 | |
start_time = np.amax(times) * 0.19 | |
scale = 10 | |
for idx, dt in enumerate(times): | |
# Plot setup | |
rcParams['font.size'] = 15 | |
fig, ax = plt.subplots(figsize=(7.63, 2.42)) | |
fig.subplots_adjust(left=.15, bottom=.15, right=.95, top=.95) | |
plt.rcParams.update({ | |
"text.usetex": False, | |
"mathtext.fontset": "custom", | |
"mathtext.it": "STIX Two Text:italic", | |
"mathtext.rm": "STIX Two Text", | |
"mathtext.sf": "STIX Two Text", | |
"font.sans-serif": "STIX Two Text", | |
}) | |
### Клин | |
x = [A[0] - v1*dt, B[0] - v1*dt, C[0] - v1*dt, A[0] - v1*dt] | |
y = [A[1], B[1], C[1], A[1]] | |
plt.plot(x, y, color=ccc, linewidth=2) | |
plt.fill(x, y, 'white', edgecolor=ccc, zorder=20) | |
### Пунктиром начальное положение клина | |
x = [A[0], B[0], C[0], A[0]] | |
y = [A[1], B[1], C[1], A[1]] | |
plt.plot(x, y, color=ccc, ls='--', linewidth=1) | |
#plt.fill(x, y, 'white', edgecolor=ccc) | |
# Матрица поворота для прямоугольника | |
origin = np.array([0, 0]) | |
rotation_matrix = np.array([[np.cos(alpha), np.sin(alpha)], [-np.sin(alpha), np.cos(alpha)]]) | |
rect_points = np.array([[0, 0], | |
[rect_width, 0], | |
[rect_width, rect_height], | |
[0, rect_height]]) | |
# Поворот | |
rect_rotated = np.dot(rect_points, rotation_matrix) | |
# Смещение прямоугольника в левый угол треугольника (координаты -1, 0) | |
rect_rotated[:, 0] -= base_length | |
rect_rotated[:, 0] += v2x * dt | |
rect_rotated[:, 1] += v2y * dt | |
# Координаты для построения | |
rect_x_rotated = rect_rotated[:, 0].tolist() + [rect_rotated[0, 0]] | |
rect_y_rotated = rect_rotated[:, 1].tolist() + [rect_rotated[0, 1]] | |
# Координаты середины правой стороны прямоугольника | |
midpoint_x = (rect_rotated[1, 0] + rect_rotated[2, 0]) / 2 | |
midpoint_y = (rect_rotated[1, 1] + rect_rotated[2, 1]) / 2 | |
# Построение прямоугольника | |
plt.plot(rect_x_rotated, rect_y_rotated, color=ccc, linewidth=2) | |
# Блок (круг) | |
circle = plt.Circle((C[0] - v1*dt, C[1]), r, color=ccc, fill=False, linewidth=2) | |
plt.gca().add_patch(circle) | |
# Наклонная нить до сдвига | |
line_x = [C[0] - v1*dt - r * np.sin(alpha), midpoint_x] | |
line_y = [C[1] + r * np.cos(alpha), midpoint_y] | |
plt.plot(line_x, line_y, color=ccc, linewidth=1) | |
# Горизонтальная нить до сдвига | |
line_x = [0.35, C[0]-v1*dt] | |
line_y = [height + r, height + r] | |
plt.plot(line_x, line_y, color=ccc, linewidth=1) | |
# Смещение подписей Δx | |
offset = -0.01 * base_length/np.sin(alpha) | |
# Стрелка Δx от начального положения клина | |
if dt>start_time: | |
plt.annotate( | |
'', # Пустая строка для текста | |
xy=(C[0]-v1*dt, height/2), # Конечная точка стрелки | |
xytext=(C[0], height/2), # Начальная точка стрелки | |
arrowprops=dict( | |
arrowstyle='<->', # Двусторонняя стрелка | |
lw=arrow_lw, # Толщина линии | |
color=ct, # Цвет стрелки | |
shrinkA=0, # Убрать отступ в начальной точке | |
shrinkB=0, # Убрать отступ в конечной точке | |
mutation_scale=scale # Масштаб головки стрелки | |
) | |
) | |
plt.text(-v1*dt/2, height/2 - offset, r'$\Delta x$', color=ct, ha='center') | |
# Стрелка Δx текущего положения угла клина к бруску | |
start = (B[0] + v2x * dt, B[1] + v2y * dt) | |
end = (B[0] - v1 * dt, B[1]) | |
# Координаты середины стрелки | |
mid_x = (start[0] + end[0]) / 2 | |
mid_y = (start[1] + end[1]) / 2 | |
# Вектор стрелки | |
arrow_vector = np.array([end[0] - start[0], end[1] - start[1]]) | |
# Нормализация вектора стрелки | |
norm_arrow_vector = arrow_vector / np.linalg.norm(arrow_vector) | |
# Вектор, перпендикулярный стрелке | |
perpendicular_vector = np.array([-norm_arrow_vector[1], norm_arrow_vector[0]]) | |
# Смещение текста перпендикулярно стрелке | |
text_x = mid_x + offset * perpendicular_vector[0] | |
text_y = mid_y + offset * perpendicular_vector[1] | |
if dt>start_time: | |
plt.annotate( | |
'', # Пустая строка для текста | |
xy=end, # Конечная точка стрелки | |
xytext=start, # Начальная точка стрелки | |
zorder=21, | |
arrowprops=dict( | |
arrowstyle='<->', # Двусторонняя стрелка | |
lw=arrow_lw, # Толщина линии | |
color=ct, # Цвет стрелки | |
shrinkA=0, # Убрать отступ в начальной точке | |
shrinkB=0, # Убрать отступ в конечной точке | |
mutation_scale=scale # Масштаб головки стрелки | |
) | |
) | |
plt.text(text_x, text_y, r'$\Delta x$', color=ct, | |
ha='center', rotation=np.degrees(alpha)) | |
# СТЕНА И ПОЛ | |
wall_x = [0.35, 0.35] | |
wall_y = [-0.01, height + r * 1.5] | |
plt.plot(wall_x, wall_y, 'k-', linewidth=8) | |
# Построение пола floor | |
plt.plot([0.40, -v1*np.amax(times) - base_length*1.1], [-0.02, -0.02], 'k-', linewidth=6) | |
plt.gca().set_aspect('equal', adjustable='box') | |
plt.xlim([-v1*np.amax(times) - base_length*1.01, 0.4]) | |
#plt.ylim([-0.03, 0.75]) | |
plt.axis('off') | |
plt.xticks([]) | |
plt.yticks([]) | |
plt.savefig(f'/Users/slisakov/Yandex.disk.localized/documents/scripts/1514_school/1189/{idx:03d}.png', | |
dpi=200, bbox_inches='tight') | |
plt.close() | |
# Create animation with ffmpeg: | |
# ffmpeg -framerate 30 -i %03d.png -c:v libx264 -pix_fmt yuv420p 1189.mp4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment