feat(sim-builder): фаза 1 — графики (plot), drag-ручки, readout, векторы origin+dx/dy

This commit is contained in:
Maxim Dolgolyov
2026-06-13 11:30:37 +03:00
parent 4dd92f83a0
commit e51b57d9c7
6 changed files with 423 additions and 34 deletions
+38 -10
View File
@@ -25,30 +25,49 @@
return false;
}
// Спека v1: бросок тела. g фиксирован 10 -> y = v*sin(θ)*t - 5*t^2.
// Спека v1+ (Фаза 1): бросок тела. g фиксирован 10 -> y = y0 + v*sin(θ)*t - 5*t^2.
// Старт (x0,y0) — перетаскиваемая ручка (drag). plot — статическая параболическая
// траектория y(x); readout — дальность и макс. высота. Вектор v0 — origin+dx/dy.
var PROJECTILE_DEMO = {
id: 'customdemo',
cat: 'phys',
meta: { title: 'Демо: бросок тела', desc: 'Спек-симуляция (Фаза 0). Угол и скорость — слайдеры.' },
meta: { title: 'Демо: бросок тела', desc: 'Спек-симуляция (Фаза 1): слайдеры, drag-старт, график, readout.' },
viewport: { xmin: 0, xmax: 60, ymin: 0, ymax: 30, grid: true, axes: true, bg: '#0D0D1A' },
time: { autoplay: false, loop: true, duration: 8, speed: 1 },
params: [
{ name: 'theta', label: 'Угол θ', min: 0, max: 90, step: 1, value: 45, unit: '°' },
{ name: 'v', label: 'Скорость v', min: 0, max: 30, step: 0.5, value: 20, unit: 'м/с' }
{ name: 'v', label: 'Скорость v', min: 0, max: 30, step: 0.5, value: 20, unit: 'м/с' },
{ name: 'x0', label: 'Старт X', min: 0, max: 20, step: 0.5, value: 2, unit: 'м' },
{ name: 'y0', label: 'Старт Y', min: 0, max: 25, step: 0.5, value: 0, unit: 'м' }
],
objects: [
// снаряд: x = v*cos(θ)*t, y = v*sin(θ)*t - 5 t^2 (но не ниже 0)
// снаряд: x = x0 + v*cos(θ)*t, y = y0 + v*sin(θ)*t - 5 t^2 (но не ниже 0)
{
id: 'ball', type: 'point',
x: 'v*cos(theta*pi/180)*t',
y: 'max(0, v*sin(theta*pi/180)*t - 5*t^2)',
x: 'x0 + v*cos(theta*pi/180)*t',
y: 'max(0, y0 + v*sin(theta*pi/180)*t - 5*t^2)',
r: 7, color: '#06D6E0', trail: true, trailColor: '#9B5DE5'
},
// вектор начальной скорости из старта
// график траектории y(x): парабола броска, var=x на [x0, x0+дальность].
// y(x) = y0 + tan(θ)(x-x0) - g(x-x0)^2/(2 v^2 cos^2θ), g=10.
{
type: 'vector', x1: 0, y1: 0,
x2: 'cos(theta*pi/180)*v*0.4',
y2: 'sin(theta*pi/180)*v*0.4',
type: 'plot', color: '#FFD166', width: 1.6,
var: 'x', range: ['x0', 'x0 + v*v*sin(2*theta*pi/180)/10 + 0.001'],
samples: 200,
expr: 'max(0, y0 + tan(theta*pi/180)*(x-x0) - 10*(x-x0)^2/(2*v*v*cos(theta*pi/180)^2))'
},
// перетаскиваемая ручка старта (drag по обеим осям -> x0/y0)
{
id: 'start', type: 'point',
x: 'x0', y: 'y0', r: 8, color: '#EF476F',
drag: { axis: 'xy', param: 'x0', paramY: 'y0', min: 0, max: 25 }
},
// вектор начальной скорости из старта (origin + dx/dy)
{
type: 'vector',
origin: ['x0', 'y0'],
dx: 'cos(theta*pi/180)*v*0.4',
dy: 'sin(theta*pi/180)*v*0.4',
color: '#FFD166', width: 3
},
// земля
@@ -58,6 +77,15 @@
type: 'label', latex: true,
x: 'ball.x', y: 'ball.y + 2.5',
text: 'v_0', color: '#06D6E0', size: 15
},
// readout: дальность полёта R = v^2 sin(2θ)/g (для y0=0) и макс. высота H
{
type: 'readout', label: 'R', unit: 'м', precision: 1, color: '#FFD166',
expr: 'x0 + v*v*sin(2*theta*pi/180)/10'
},
{
type: 'readout', label: 'H', unit: 'м', precision: 1, color: '#06D6E0',
expr: 'y0 + (v*sin(theta*pi/180))^2/20'
}
]
};