12

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

请参见下图。

最终结果

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

我想要:

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

小提琴!

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

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

我还添加了一些用于处理向量的助手 se MathHelpers.Vector

请继续分叉,并尝试实施一个解决方案,使线路弯曲。使用实际上看起来不错的 Béziers 的解决方案也非常受欢迎。

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

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

4

4 回答 4

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
于 2012-10-26T10:23:07.037 回答
2

一种选择是使用椭圆弧。这看起来不太棒,但满足了约束,我认为可以通过仔细选择圆半径来改进它(这里我使用了一个固定的)。

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);

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

于 2012-10-26T12:05:05.617 回答
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;
        }

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

我有这个功能(带有控制点计算)在这里上演。

于 2012-10-26T18:55:22.303 回答
0

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

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

画出经过这一点的曲线。

于 2012-10-26T10:28:53.943 回答