祝贺比赛获胜者 Stanislav Volodarskiy!
他的解决方案很有趣、原创且非常专业。
他们100%满足比赛条件。
除了他的解决方案之外,还发布了几个非常可靠的答案。给他们打高分是公平的,但一场比赛只能产生一名获胜者。
因此,我呼吁潜在的赞助商:请分享你的萝卜并重新启动,这里有一个新的比赛。
我有一张军刀凸轮机构的照片。
有*.gif 机构动画
我为凸轮机构创建了一个 svg 代码:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400" viewBox="0 0 500 500">
<!-- Шарнир -->
<path fill="grey" stroke="black" stroke-width="3" d="M344.3 197.6a49.6 49.6 0 0 1 34.4 13A57 57 0 0 1 396 251a54 54 0 0 1-17.4 36.8c-9 8.2-22 13.1-34.2 13a54.4 54.4 0 0 1-36.8-15.4A51.4 51.4 0 0 1 294 251a55.4 55.4 0 0 1 13.7-37.6 53.7 53.7 0 0 1 36.6-16z"/>
<!-- Вертикальный стержень -->
<path fill="grey" stroke="black" stroke-width="3" d="M387.3 13.1h30v440.5h-30z"/>
<!-- Ось кулачка -->
<path fill="#626262" stroke="black" stroke-width="2" d="M344.3 223.5c8.9 0 18 5.5 23.7 12.3 3.4 4.1 4.9 10 4.5 15.3-.4 6.7-3.2 13.9-8.2 18.4a27 27 0 0 1-20 6.5c-7.1-.8-13.8-5.4-18.6-10.6a24.4 24.4 0 0 1-1-31.8c4.7-5.7 12.2-10.1 19.6-10z"/>
<!-- Кулачок -->
<path fill="grey" stroke="black" stroke-width="3" d="M41.3 153c32.7 0 78.5 3.3 117.6 7 35 3.2 69.9 6.8 104.3 13.2 16.8 3.1 33.3 7.7 49.8 12.2 13 3.5 43.8 11.3 38.7 11.6-20 1.4-39.1 7.2-48.7 22.3-20.3 31.8-.9 54.9-7 41.8-5.4-11.8-18.1-18-29-24.3-13.4-7.9-28.7-11.9-43.5-16.5-19-5.9-38.9-9.2-58.2-14.3-21.5-5.5-42.7-12-64.1-17.4-14-3.5-26.3-5.5-41.9-9.6a25 25 0 0 1-13.2-10.6c-3-4.4-10.1-15.3-4.8-15.3z"/>
<!-- Цилиндр -->
<path fill="black" d="M377.5 54.3c3.8-.7 50.6-.4 50.6-.4l9.3 10.5v88.8h-66.6V64.4Z"/>
<!-- Линия фаски -->
<path stroke="white" d="m370.8 64 66.6.4"/>
<!-- Верхний рычаг -->
<path fill="grey" stroke="black" stroke-width="3" d="M21.2 153c-3.1 0 1.1-6.2 2.6-9 1.4-2.4 3-5.7 5.9-6.3a17587 17587 0 0 1 341-65.7v81H21.3z"/>
</svg>
如何根据给定的.gif 文件创建凸轮机构的动画?
更新
解决问题时出现问题时提供额外数据。
希望这有帮助。
Inkscape 源代码,创建了该机制的静态 SVG 文件。
SVG 画布大小 500x500 px
可以通过在矢量编辑器中运行 inkscape 源代码来获取部件的尺寸 下面的代码
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="500"
height="500"
viewBox="0 0 500 500"
version="1.1"
id="svg4"
sodipodi:docname="Заготовка-ink2.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1440"
inkscape:window-height="837"
id="namedview6"
showgrid="false"
inkscape:zoom="0.944"
inkscape:cx="295.12041"
inkscape:cy="242.72973"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
showguides="true"
inkscape:guide-bbox="true">
<sodipodi:guide
position="436.69836,486.88497"
orientation="0,1"
id="guide4520"
inkscape:locked="false" />
<sodipodi:guide
position="387.26081,395.5004"
orientation="1,0"
id="guide4522"
inkscape:locked="false" />
<sodipodi:guide
position="417.22296,388.75892"
orientation="1,0"
id="guide4524"
inkscape:locked="false" />
<sodipodi:guide
position="448.68322,46.441335"
orientation="0,1"
id="guide4526"
inkscape:locked="false" />
<sodipodi:guide
position="370.78163,381.26838"
orientation="1,0"
id="guide4532"
inkscape:locked="false" />
<sodipodi:guide
position="437.44742,370.03257"
orientation="1,0"
id="guide4534"
inkscape:locked="false" />
<sodipodi:guide
position="489.88118,471.15484"
orientation="0,1"
id="guide4536"
inkscape:locked="false" />
<sodipodi:guide
position="489.13213,416.47391"
orientation="0,1"
id="guide4538"
inkscape:locked="false" />
<sodipodi:guide
position="411.97959,435.94931"
orientation="0,1"
id="guide4546"
inkscape:locked="false" />
<sodipodi:guide
position="288.66525,346.92797"
orientation="0,1"
id="guide4550"
inkscape:locked="false" />
<sodipodi:guide
position="344.27966,512.1822"
orientation="1,0"
id="guide4554"
inkscape:locked="false" />
<sodipodi:guide
position="370.78163,248.94068"
orientation="0,1"
id="guide4556"
inkscape:locked="false" />
</sodipodi:namedview>
<image
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 387.26081,13.11503 h 29.96215 v 440.44364 h -17.97729 -11.98486 z"
id="path4528"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#0000f7;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 387.26081,13.11503 h 29.96215 v 440.44364 h -29.96215 z"
id="path4530"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#e50000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 377.52311,54.312992 c 3.74527,-0.749054 50.56113,-0.374527 50.56113,-0.374527 l 9.36318,10.486753 V 153.18809 H 370.78163 V 64.425218 Z"
id="path4544"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#570400;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 370.78163,64.05069 66.66579,0.374528"
id="path4548"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#008800;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 21.186441,153.07203 c -3.12854,0 1.110117,-6.27995 2.648305,-9.00423 1.413084,-2.50271 3.015439,-5.75628 5.826271,-6.35594 C 135.51425,115.12916 370.78163,72.033898 370.78163,72.033898 v 81.038132 c 0,0 -212.74111,0 -349.595189,0 z"
id="path4552"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sasccs" />
<path
style="fill:none;stroke:#0000e7;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 344.27966,223.51695 c 8.90907,0.0198 18.05228,5.44187 23.72125,12.31462 3.36808,4.08327 4.85373,9.94633 4.50212,15.22775 -0.44642,6.70562 -3.23009,13.91363 -8.22867,18.40572 -5.21172,4.68364 -13.02457,7.20658 -19.9947,6.48835 -7.07962,-0.72951 -13.76582,-5.31323 -18.53813,-10.59322 -3.49791,-3.87002 -6.03275,-9.09431 -6.35594,-14.30085 -0.37718,-6.07621 1.39653,-12.80421 5.29661,-17.47881 4.70441,-5.63868 12.25403,-10.07987 19.59746,-10.06356 z"
id="path4558"
inkscape:connector-curvature="0"
sodipodi:nodetypes="aaaaaaaaa" />
<path
style="fill:none;stroke:#0000ed;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 344.27966,197.56356 c 12.26035,-0.30456 25.5788,4.48545 34.42797,12.97669 10.5885,10.16022 17.51589,25.8475 17.21398,40.51907 -0.2794,13.57787 -7.48027,27.60038 -17.4599,36.81145 -8.95578,8.26607 -21.9962,13.17457 -34.18205,12.97669 -13.2941,-0.21588 -27.5112,-5.85832 -36.81144,-15.36017 -8.6229,-8.80982 -13.36567,-22.10127 -13.50636,-34.42797 -0.15236,-13.3485 4.61476,-27.89174 13.77119,-37.60593 9.11148,-9.66649 23.26688,-15.55995 36.54661,-15.88983 z"
id="path4560"
inkscape:connector-curvature="0"
sodipodi:nodetypes="aaaaaaaaa" />
<path
style="fill:none;stroke:#00aa40;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 41.313559,153.07203 c 32.676369,0 78.490031,3.2645 117.584751,6.8856 34.91059,3.23355 69.86925,6.85792 104.34322,13.24152 16.80002,3.11088 33.30494,7.68524 49.78813,12.18221 12.98636,3.54296 43.73855,11.29999 38.66526,11.65254 -19.95701,1.38685 -39.13749,7.18503 -48.72882,22.24576 -20.23867,31.77966 -0.83862,54.89455 -6.88559,41.84322 -5.46997,-11.80596 -18.20255,-17.97596 -29.13136,-24.3644 -13.36198,-7.81076 -28.65095,-11.82981 -43.4322,-16.4195 -19.0979,-5.93004 -38.9043,-9.28613 -58.26271,-14.30084 -21.4357,-5.55283 -42.60775,-12.10487 -64.08899,-17.47882 -13.877535,-3.47173 -26.30999,-5.43823 -41.843216,-9.5339 -5.465675,-1.44114 -10.056956,-5.92321 -13.241525,-10.59322 -3.020329,-4.42916 -10.127906,-15.36017 -4.76695,-15.36017 z"
id="path4562"
inkscape:connector-curvature="0"
sodipodi:nodetypes="saaasssaaaasas" />
</svg>
矢量编辑器的屏幕截图
笔记:
设计凸轮旋转动画时,请注意旋转的不均匀性:大旋转角度与小角度交替!
相关主题:
比赛将在截止日期后的最后几个小时内结束。
还有很多时间,继续,寻找解决方案!
SVG + JS 选项。使用该方法通过对几个点进行两阶段搜索来找到拳头的顶点
SVGGeometryElement.getPointAtLength()
。点沿着该方法获得的路径长度分布SVGGeometryElement.getTotalLength()
。首先,我们粗略地找到 1 个最小y
(最高)的点,然后我们再次划分两个相邻点之间的区域,并以更高的精度找到最高点。不幸的是,上述方法对路径旋转一无所知。因此,搜索时必须旋转点。为此目的的功能
rotatePoint()
。UPD。为了不深入研究 JS 和实现细节,我添加了一个带有 Web 组件的选项。该属性
data-anim
包含拳头的旋转角度,格式为:время начала вращения, длительность вращения, начальный угол, конечный угол
。单独的动画由符号 分隔|
,它们在时间和旋转角度上应该接近(有些冗余)。您只需将其添加到标记中
<kulak-svg data-anim="0,1600,0,-40|1600,1600,-40,0|3200,1000,0,-20|4200,1000,-20,0"></kulak-svg>
即可获得所需的动画。没有 JS,代码片段中的代码被写入,例如,kulak-svg.js
您可以将<kulak-svg></kulak-svg>
带有必要动画数据的标签插入到页面上。例如,插入了 4 个具有不同动画的元素;如果扩展到整个页面,它们将可见。从物理学的角度来看,前两个动画是完全合法的。最后两个将拳头旋转一整圈,因此活塞杆的位置在 -90 到 0 度的位置(以右侧水平面为 0 而言)不合理。这个“错误”是因为我们只是简单地找到了拳头的上点,并用它来设置活塞杆的下边缘,而不管实际的“物体接触”。这样可以更好地展示该方法的优点和缺点。
还添加了更改的能力
viewBox
,width
并且height
对于每个单独的元素,这会覆盖设置为默认值<kulak-svg>
的相应属性。<svg>
<template>
正如所承诺的。
SVG+CSS解决方案
不幸的是,我无法在动画中使用多个变量(我尝试了一个和不同的变量)。由于某种原因,在动画中,要么一个变量起作用,要么根本不起作用。变量不再接收每 FPS 的平滑值,而是随机接收起始值或结束值。
使用变量来减少计算量会很棒。不幸的是,所有数学都必须写入 style="..." 参数中,否则您将无法读取动画内定义的值。
这样我们就得到了剪切变换的计算结果。
其中两列 (
86.8deg
,305.5px
) 是预先计算的常数。从半圆表面取5个点。86.8deg
- 这是从旋转轴到选定点的矢量相对于 X 轴(即活塞被抬起的部分的下边界)形成的角度。 A305.5px
是这个向量的长度,即旋转点到所选点的距离。这些值可以在JS中计算出来。但你可以不用 JS。我们以坐标为
45,223
、110,218.5
、和 的165,210
点为例。226,203
350,200
坐标样本可以从 inkscape 中获取。
让我们列出变量中的坐标值...
然后我们会做这样的事情:
CSS 公式看起来有点生硬。为了解决这个问题,使用了 CSS 函数:
cos()
,atan2()
,hypot()
。使用了可变动画@property
。我会说实话。当我第一次了解到 CSS 中几何函数的存在时,我想我一生中永远找不到在实际操作中使用它们的理由。但它可能是 JS 的一个很好的替代品。
我差点忘了。
有一个 SVG 动画与 GIF 的比较。
这可能不是最新版本。
我没有检查过文字。可能会出现恼人的错误。如果您发现错误,请在不发出警告的情况下更正它。
将原来的“铰链”、“凸轮轴”、“凸轮”
svg
组装成一组driver
。该组通过绕轴中心旋转来设置动画。中心是通过眼睛选择的。“垂直杆”、“圆柱体”、“倒角线”和“上杠杆”组合成一组
drivee
,通过脚本垂直移动。 “上臂”标有标识符lever
。该组
driver
使用 进行动画处理svg
。该函数垂直drive
移动组drivee
,使底部点lever
与顶部点重合drivee
。这看起来不错,因为底部边缘lever
在屏幕坐标中是水平的。如果杠杆倾斜,则需要进行额外的调整。如果杠杆的工作边缘是弯曲的,则有必要完全改变算法。浏览器提供用于计算所描述的矩形的标准工具。但它们工作得不够整齐。该规范并未在任何地方表明所描述的矩形必须是最小的。 Firefox 和 Chrome 都以不同的方式计算它们,并有一定的余量。
该调用
getExtreme([0, -1], driver)
计算屏幕坐标中组的顶点driver
。计算屏幕坐标中的getExtreme([0, 1], lever)
底部点。lever
getExtreme
迭代所有类型为 的节点path
。该属性d
被解析为其组件命令(函数parsePathD
)。为了解决这个问题,您需要能够处理椭圆弧、三次贝塞尔曲线和线段的命令。所有命令都被翻译成可以使用矩阵进行转换的形式。例如,椭圆由其中心和半轴的末端表示。贝塞尔曲线本身由四个点定义。曲线片段显示在屏幕坐标系中(调用node.getScreenCTM()
和part.map(matrix)
)。对于每个片段,计算方向上的极值
dir
。每种片段类型都以自己的方式解决这个问题:dir
对于椭圆弧,如果落在弧内,则取圆弧两端和椭圆的两个点(方向上的“上”和“下”)处的值的最大值;在工程程序中,我们获得了拳头和杠杆的配合边缘的布局。在拳头旋转的极限位置,我们设置与活塞杆的相切。
给定的臂总长度为 120 毫米,活塞冲程为 40 毫米,我们获得了 180 毫米的转向节边缘半径和一个有用的旋转角度(在这种情况下,程序中的灰色表示从其他尺寸导出的相关尺寸)参数)。
根据获得的参数,我们在画布上绘制拳头的弧线和活塞杆的水平线。我们建立了对拳头角度变化的依赖,将其限制在 39 度,超过该角度杠杆的位置不会改变。
杠杆旋转角度变化的依赖性如下:
Высота перемещения рычага = (угол вращения/общий полезный угол)² * общий ход поршня
UPD。我添加了一个土豆形的拳头 - 没有凸起的复杂曲线。通过简单的搜索,我从上到下、从左到右搜索与拳头形状一致的第一个点。块(“活塞”)被拉至此高度。