在JavaScript中挑战矢量数学

时间:2012-10-26 09:50:56

标签: javascript math vector raphael

我有一个有趣的开发/数学问题,我无法解决问题。

请参阅下图。

End result

我有两个圆点;一个小而一个大。

我想:

  • 从外圈中的任何给定点绘制一条线到内圈中的任何给定点(完成)
  • 线条应该是弧线,不应越过内圈的边界或外圈的边界。 (我需要你的帮助!)

拨弄!

我创建了一个用RaphaelJS编写的jsFiddle,我创建点并在它们之间绘制线条。见http://jsfiddle.net/KATT/xZVnx/9/

它基本上在drawLine函数中我需要你的帮助,以便绘制一个漂亮的弧,而不是一条直线。

我添加了一些辅助工具来处理矢量,se MathHelpers.Vector

请继续分叉并尝试实施一个解决方案,其中线条围绕着。使用实际看起来很好的Béziers的解决方案也非常受欢迎。

是的,我猜矢量几何最适合计算。

非常,非常,非常感谢任何帮助。我花了很多时间试图解决它,但我生锈的高中数学技能还不够。

4 个答案:

答案 0 :(得分:2)

简单地通过绘制一个螺旋形来开始。

螺旋半径从起始角到终止角,螺旋半径从内圆半径到外圆半径。

为了让您了解我的意思,请选择多个部分(n)

var n = 20, // The number of lines in the spiral
    rStep = (outerRadius - innerRadius)/n, // the radius increase between points
    aStep = (outerAngle - innerAngle)/n,  // the angle change between points
    points = [];

// compute the cartesian coordinates (x, y) from polar coordinates (r, a)
function cartesian(r, a) {
    return [
        r * Math.cos(a),
        r * Math.sin(a)
    ];
}

for (i = 0; i <= n; i += 1) {
   points.push(cartesian(innerRadius + (i * rStep), innerAngle + (i * aStep));
}

我使用极坐标演示了基本的分段螺旋:

http://jsfiddle.net/xmDx8/

尝试更改n以查看碎片的构建方式。

drawLine(innerCircleIndex, outerCircleIndex, 1); // This is what you did

drawLine(innerCircleIndex, outerCircleIndex, 100); // 100 lines in the example

drawLine(innerCircleIndex, outerCircleIndex, n); // Choose n to see how it grows

答案 1 :(得分:2)

One option是使用椭圆弧。这看起来并不太令人敬畏,但满足了约束条件,我认为可以通过仔细选择圆半径来改进(这里我使用的是固定的)。

var angleDiff = MathHelpers.getAngleInCircle(innerCircleIndex, numberOfDotsInInnerCircle) - MathHelpers.getAngleInCircle(outerCircleIndex, numberOfDotsInOuterCircle);
while (angleDiff > Math.PI) {
    angleDiff -= 2 * Math.PI;
}
while (angleDiff < -Math.PI) {
    angleDiff += 2 * Math.PI;
}

from = addOffsetAndRound(from);
to = addOffsetAndRound(to);
r = (0.5 * innerCircleRadius + 0.5 * outerCircleRadius);

var pathStr = "";
pathStr += "M" + [from.x, from.y].join(' '); // MOVE to
pathStr += "A" + [r, r, 0, 0, angleDiff >= 0 ? 1 : 0, to.x, to.y].join(' '); // Draw line to
var path = paper.path(pathStr);

P.S。当然,应该记住,真正的螺旋不是椭圆弧。

答案 2 :(得分:1)

如果你确实想要避免使用数学,那么你可以使用一系列简单的线段来近似螺旋线,除了连接的两个点的坐标以及它们各自相对于原点的角度或原点的坐标(显然可以从另一个推断)。给定(ix,iy,i_angle)描述内点的坐标和相对角度以及(ox,oy,o_angle)描述外部点的坐标和相对角度,

        var generatePath = function( ix, iy, i_angle, ox, oy, o_angle )
        {
            var path = [ "M", ox, oy ];
            var slices = 100;

            var cur_angle = o_angle;
            var cur_r = cr_outer;
            var delta_r = ( cr_inner - cr_outer ) / slices;
            var delta_angle = ( i_angle - o_angle );
            if ( delta_angle > Math.PI )
                delta_angle -= Math.PI * 2;
            else if ( delta_angle < Math.PI * -1 )
                delta_angle += Math.PI * 2;
            delta_angle = delta_angle / slices;

            for ( var i = 0; i < slices; i++ )
            {
                cur_angle += delta_angle;
                cur_r += delta_r;
                path.push( "L", cx + Math.cos( cur_angle ) * cur_r, cy + Math.sin( cur_angle ) * cur_r );
            }
            return path;
        }

逻辑非常简单,即使在高分辨率下看起来也很好,并且可能比“真正的”弧段或一系列二次贝塞尔曲线更具性能。每段的切片数量可能会根据长度和大小进行调整,以平衡性能与美学效果。

我有这个功能(控制点计算)暂存here

答案 3 :(得分:0)

尝试一种没有花哨数学的方法:

  • 找到要连接的点之间的外点和内点。
  • 找到由这些中间点形成的段的中间部分。

绘制你的曲线。