Snap.svg 通过点差的斜率获取旋转角度

3

我正在制作一段动画,需要让这架飞机沿着给定的路径移动,并呈现“环绕”地球的效果。这里是CodePen链接,正如您所看到的,代码非常简单。

Picture

我的问题与角度有关,我试图通过计算两个点的斜率并将其转化为度数来确定平面在通过路径时应旋转多少。尽管我已经添加了一个epsilon来安全检查点之间的差异和其他每个安全检查,但当它接近+-90度时,它会改变符号,而不是通过到另一个象限120度等。
我可以理解这是因为formula,唯一的y在区间[-π/2;π/2]中,满足tan(y)=x。您可以在控制台中看到这种情况发生在正中间(显示:slope,反正切,度数)。

Console

为了解决这个问题,我使用Math.atan2()函数,将newPoint.x - firstPoint.x, newPoint.y - firstPoint.y作为参数传入。它开始时具有正确的值(CodePen here)。但是它仍然进行了奇怪的旋转。
以下是代码(我不会发布SVG图像,因为它非常大): JS
        var snap = Snap('#Globe_1_');

        // Trail 1
        var trail1 = snap.path('M354.3,707.9c13.9,14.5,27.9,27.2,41.7,38c13.9,10.9,27.2,19.3,39.3,25.4 c12.6,6.1,24.8,9,35.7,10.3c10.9,1.2,21.1-1.2,30.2-5.4c17-7.8,29-24.8,35.7-48.3c7.2-23.5,9-55,5.4-91.8 c-3.7-36.8-12-77.9-24.8-120.9c-12.6-43-30.2-87.6-51.9-131.7c-21.1-44.1-45.2-85.8-70.7-122.7s-50.8-69.5-77.3-95.5 c-27.2-26-52.5-43.6-75.6-53.2c-22.9-9.7-43.6-10.3-60.4-2.5c-16.3,7.8-27.9,24.2-35.1,47.7c-7.2,23.5-9.7,53.8-6.6,88.8')
            .attr({
                id: 'trail1',
                fill:'none', 
                stroke: '#C25353',
                strokeMiterLimit: 10
            });

        var len = trail1.getTotalLength();

        var plane1 = snap.path('M375.7,708.4c0.1,0.8-0.7,1.8-1.6,1.9l-10.4,0.2l-8.4,15.1l-4,0l4.1-14.6l-7.8-0.2l-2.7,3.2L342,714 l1.6-4.9l-1.7-5.4l3.1,0.1l2.5,3.6l7.8,0.2l-4.3-14.6l4,0l8.3,14.7l10.4-0.2C375.5,706.7,376,707.1,375.7,708.4z') .attr({fill: '#CDCCCC' });


        var initPoint = trail1.getPointAtLength( 1 ),
            lastPoint,
            slope = 0,
            lastLen = 0;

        Snap.animate(0, len, function( value ) {

            movePoint = trail1.getPointAtLength( value );

            if (lastPoint && ( Math.abs(lastPoint.y - movePoint.y) > 1 || Math.abs(lastPoint.x - movePoint.x) > 1 )) {

                var slope_val = (lastPoint.y - movePoint.y) / (lastPoint.x - movePoint.x),
                    slope_atan = Math.atan2(movePoint.x - initPoint.x, movePoint.y - initPoint.y),
                    slope_deg = Snap.deg(slope_atan);

                slope = slope_deg;
                console.log('Capturing rotation', slope_val, slope_atan, slope_deg);
                lastLen = value; 

            }

            plane1.transform( 't' + parseInt(movePoint.x - 350) + ',' + parseInt( movePoint.y - 700) + 'r' + slope);

            lastPoint = movePoint;

        }, 5000, mina.linear);

你能帮我一下吗,谢谢


为什么atan()调用使用movePoint - initPoint而不是movePoint - lastPoint - Paul LeBeau
1个回答

3

我不确定你想要的完整效果是什么,如果只是二维角度的话,Snap已经内置了这个功能(从点沿线返回角度),所以不需要太费力...

element.getPointAtLength() 返回一个角度 alpha,因此可以使用 movePoint.alpha...

下面是相关行,其他计算行已被删除。

plane1.transform( 't' + parseInt(movePoint.x - 350) + ',' + parseInt( movePoint.y - 700) + 'r' + (180 + movePoint.alpha));

codepen


看起来你真的很了解这个话题。你知道为什么我必须将(-350,-700)的平移应用到路径中吗?我已经尝试过对SVG进行不同的定位了@Ian - Alain Jacomet Forte
如果您想给我一些提示如何在此基础上添加3D旋转,我将不胜感激。 - Alain Jacomet Forte
你需要翻译路径,因为路径的第一部分是“M375.7,708.4”,所以它从该坐标开始。为了使其出现在线上方,您需要将其移回到0,0。另一种选择是让路径从0,0(或者也许是-10,-10或者任何一半宽度)开始,并且还有其他相关的绝对坐标,这样它就可以围绕中心旋转而不需要任何变换。不过这并不太重要,只要在某个编辑器中有这个选项就行了。 - Ian
我不知道如何在SVG中进行3D旋转(因为SVG只是2D的,所以你必须自己计算一些东西,你可能可以通过某种方式来伪造其中的一些内容)。你可以将其明确地作为一个新问题提出,因为有时会有重新计算3D路径的示例,但关于这方面的内容并不多。你之前用CSS的例子做了透视,但不确定在IE10或更低版本中是否有效。或者如果你将透视应用于整个SVG(即将不同的SVG图层重叠在彼此上面,这可能很有趣),你也许可以使用透视。 - Ian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接