Как сделать анимацию кулачкового механизма?
У меня есть гифка работы кулачкового механизма:
Эта иллюстрация показывает, что при равномерном вращении вала с насаженным на него кулачком, толкатель получает неравномерные возвратно-поступательные движения толкателя, который скользит по поверхности кулачка.
Я воспроизвел основные контуры этого механизма.
Вот мой код статичного механизма:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" preserveAspectRatio="xMinYMin meet" id="svg4" width="390" height="700" viewBox="0 0 390 700">
<!-- Верхняя скоба -->
<g stroke="#717171" stroke-width="2" fill="none" >
<path d="M149 124h87v31h-87z" />
<path d="M175 124v31" />
<path d="M210 124v31" />
<path d="M161 134c3 0 6 3 6 6s-3 6-6 6c-2 0-5-4-5-6 0-3 3-6 5-6z"/>
<path d="M221 134c3 0 6 3 6 6s-3 6-6 6c-2 0-5-4-5-6 0-3 3-6 5-6z" />
</g>
<!-- Нижняя скоба -->
<g stroke="#717171" stroke-width="2" fill="none" >
<path id="circ910" d="M221 278c3 0 6 3 6 6s-3 6-6 6c-2 0-5-4-5-6 0-3 3-6 5-6z"/>
<path id="circ912" d="M161 278c3 0 6 3 6 6s-3 6-6 6c-2 0-5-4-5-6 0-3 3-6 5-6z"/>
<path d="M149 267h87v31h-87z" />
<path d="M175 267v31" id="path916" />
<path d="M210 267v31" id="path918" />
</g>
<!-- Кулачок -->
<g ig="gr1" stroke-width="2" >
<path id="cam" fill="#8080B1" stroke="black" fill-opacity="0.5" d="M83 493c1-7 19-23 32-30 10-6 34-10 34-10 6-5 35-42 59-48 21-5 60-15 65-10 11 15 21 57 10 93-4 12-10 27-18 39-5 8-14 14-20 22l-5 9s-4 12-4 19c0 20-9 36-20 49-10 12-32 26-39 24-6-1-21-18-28-30-13-21-22-38-24-69 0-4-19-14-26-23-7-10-17-27-16-35z" />
<circle id="path866" cx="192" cy="514.6" r="36" fill="#5F5F5F" stroke="black" stroke-width="2" />
<circle id="spindle" cx="192" cy="514.6" r="20" fill="#4A4A4A" stroke="black" stroke-width="2" />
<!-- Шпонка -->
<path id="key" fill="#151515" stroke="black" d="M189 491h6v10h-6v-10h6" />
</g>
<!-- Толкатель -->
<path id="kernel" d="M184 60v340l8 14 7-14V59z" fill="none" stroke="red" stroke-width="2" >
</path>
<circle id="path868" cx="192" cy="514.4" r="144.7" opacity=".5" fill="none" fill-opacity="1" stroke="#1515B1" stroke-width="2" />
</svg>
Попробовал сделать анимацию кулачкового механизма:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" preserveAspectRatio="xMinYMin meet" id="svg4" width="390" height="700" viewBox="0 0 390 700">
<!-- Верхняя скоба -->
<g stroke="#717171" stroke-width="2" fill="none" >
<path d="M149 124h87v31h-87z" />
<path d="M175 124v31" />
<path d="M210 124v31" />
<path d="M161 134c3 0 6 3 6 6s-3 6-6 6c-2 0-5-4-5-6 0-3 3-6 5-6z"/>
<path d="M221 134c3 0 6 3 6 6s-3 6-6 6c-2 0-5-4-5-6 0-3 3-6 5-6z" />
</g>
<!-- Нижняя скоба -->
<g stroke="#717171" stroke-width="2" fill="none" >
<path id="circ910" d="M221 278c3 0 6 3 6 6s-3 6-6 6c-2 0-5-4-5-6 0-3 3-6 5-6z"/>
<path id="circ912" d="M161 278c3 0 6 3 6 6s-3 6-6 6c-2 0-5-4-5-6 0-3 3-6 5-6z"/>
<path d="M149 267h87v31h-87z" />
<path d="M175 267v31" id="path916" />
<path d="M210 267v31" id="path918" />
</g>
<g ig="gr1" stroke-width="2" >
<!-- Кулачок -->
<path id="cam" fill="#8080B1" stroke="black" fill-opacity="0.5" d="M83 493c1-7 19-23 32-30 10-6 34-10 34-10 6-5 35-42 59-48 21-5 60-15 65-10 11 15 21 57 10 93-4 12-10 27-18 39-5 8-14 14-20 22l-5 9s-4 12-4 19c0 20-9 36-20 49-10 12-32 26-39 24-6-1-21-18-28-30-13-21-22-38-24-69 0-4-19-14-26-23-7-10-17-27-16-35z" />
<!-- Вал -->
<circle id="path866" cx="192" cy="514.6" r="36" fill="#5F5F5F" stroke="black" stroke-width="2" />
<circle id="spindle" cx="192" cy="514.6" r="20" fill="#4A4A4A" stroke="black" stroke-width="2" />
<path id="key" fill="#151515" stroke="black" d="M189 491h6v10h-6v-10h6" />
<!-- Анимация вращения вала с кулачком -->
<animateTransform attributeName="transform" type="rotate" begin="0s" dur="2s" values="0 192 514.6;360 192 514.6" repeatCount="indefinite" />
</g>
<!-- Толкатель -->
<path id="kernel" d="M184 60v340l8 14 7-14V59z" fill="none" stroke="red" stroke-width="2" >
<!-- Анимация перемещения толкателя -->
<animateTransform attributeName="transform" type="translate" begin="0s" dur="2s" calcMode="linear"
values="0 0;0 30;0 0" repeatCount="indefinite" />
</path>
<circle id="path868" cx="192" cy="514.4" r="144.7" fill="none" fill-opacity="1" stroke="#1515B1" stroke-width="2" />
</svg>
Из работы программы видно, что хоть время начала анимаций и их продолжительность совпадает, но не получается добиться согласованной работы вращения кулачка и возвратно-поступательного движения толкателя.
Как согласовать анимацию вращения кулачка и неравномерное движение толкателя, которое зависит от профиля поверхности кулачка.
Ответы (1 шт):
Отобразил только ключевые элементы. Пути переделал так, чтобы ось вращения диска с кулачками была на [0,0]. Для толкателя нулевой точкой сделал нижний кончик.
После отрисовки кулачка находим точку пересечения перебором координат y (при неизменной x равной центру вращения) пока эта точка не совпадет с контуром пути: ctx.isPointInStroke(cam,x,y).
render();
function render(){
// Описание путей диска с кулачками (cam) и игольчатого толкателя (kernel)
const cam_path = 'M-39.89 -11.27c0.39,-2.73 7.4,-8.97 12.47,-11.7 3.9,-2.33 13.25,-3.89 13.25,-3.89 2.34,-1.95 13.64,-16.37 23,-18.71 8.18,-1.95 23.38,-5.85 25.33,-3.9 4.29,5.85 8.19,22.22 3.9,36.25 -1.56,4.68 -3.9,10.52 -7.01,15.2 -1.95,3.12 -5.46,5.46 -7.8,8.58l-1.95 3.5c0,0 -1.56,4.68 -1.56,7.41 0,7.8 -3.51,14.03 -7.79,19.1 -3.9,4.68 -12.48,10.13 -15.21,9.35 -2.33,-0.39 -8.18,-7.01 -10.91,-11.69 -5.07,-8.18 -8.57,-14.81 -9.35,-26.89 0,-1.56 -7.41,-5.46 -10.14,-8.97 -2.73,-3.9 -6.62,-10.52 -6.23,-13.64l0 0z';
const kernel_path = 'M-4 -70c2.67,0 5.33,0 8,0 0,21.54 0,43.08 0,64.62 -1.34,1.79 -2.67,3.58 -4,5.38 -1.33,-1.8 -2.67,-3.59 -4,-5.38 0,-21.54 0,-43.08 0,-64.62z';
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const w = canvas.width = 600;
const h = canvas.height = 190;
const cam = new Path2D(cam_path); // Путь кулачка
const kernel = new Path2D(kernel_path); // Путь толкателя
let angle = 0; // Угол вращения сцены (для кулачка)
animate(); // Функция будет вызывать сама себя на каждом кадре (помещать в очередь на отрисовку)
function animate(){
ctx.clearRect(0,0,w,h); // Очистка холста
ctx.save(); // Сохраняем настройки контекста
ctx.translate(w/2, 129); // Центр вращения
ctx.rotate(angle * Math.PI/180); // Вращаем полотно
ctx.fillStyle = 'rgb(128, 128, 177)'; // Указываем стиль заливки
ctx.fill(cam); // Заливаем путь кулачка
ctx.stroke(cam); // Контур кулачка
ctx.beginPath(); // Внешняя окружность (вал?)
ctx.arc(0,0,60,0,Math.PI*2,true);
ctx.strokeStyle = 'rgb(100,0,180)';
ctx.stroke();
ctx.beginPath(); // Шток (ось)
ctx.arc(0,0,16,0,Math.PI*2,true);
ctx.fillStyle = 'grey';
ctx.strokeStyle = 'black';
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(0,0,10,0,Math.PI*2,true);
ctx.stroke();
ctx.fillStyle = 'black'; // Шпонка
ctx.fillRect(7,-2,6,4);
angle = angle%360 + 2; // Изменение угла за кадр
let kernel_position = 0 // Позиция кончика толкателя (инициализируем 0)
while(!ctx.isPointInStroke(cam,w/2,kernel_position)){ // Пока точка не совпадет с контуром кулачка
kernel_position++; // Добавляем к позиции по Y
}
ctx.restore(); // Возвращаем настройки контекста (translate, rotate, fillStyle, strokeStyle)
ctx.save();
ctx.translate(w/2, kernel_position); // Позиция кончика толкателя
ctx.fillStyle = 'red';
ctx.fill(kernel); // Заливка толкателя
ctx.stroke(kernel); // Контур толкателя
ctx.restore();
requestAnimationFrame(animate); // Помещаем в очередь на отрисовку на следующем кадре
}
}
<canvas></canvas>

