Draw equidistant points on a spiral

谁说我不能喝 提交于 2019-11-27 18:23:30

To a first approximation - which is probably good enough for plotting blocks close enough - the spiral is a circle and increment the angle by the ratio chord / radius.

// value of theta corresponding to end of last coil
final double thetaMax = coils * 2 * Math.PI;

// How far to step away from center for each side.
final double awayStep = radius / thetaMax;

// distance between points to plot
final double chord = 10;

DoSome ( centerX, centerY );

// For every side, step around and away from center.
// start at the angle corresponding to a distance of chord
// away from centre.
for ( double theta = chord / awayStep; theta <= thetaMax; ) {
    //
    // How far away from center
    double away = awayStep * theta;
    //
    // How far around the center.
    double around = theta + rotation;
    //
    // Convert 'around' and 'away' to X and Y.
    double x = centerX + Math.cos ( around ) * away;
    double y = centerY + Math.sin ( around ) * away;
    //
    // Now that you know it, do it.
    DoSome ( x, y );

    // to a first approximation, the points are on a circle
    // so the angle between them is chord/radius
    theta += chord / away;
}

However, for a looser spiral you will have to solve the path distance more accurately as spaces too wide where the difference between away for successive points is significant compared with chord:

The second version above uses a step based on solving for delta based on using the average radius for theta and theta+delta:

// take theta2 = theta + delta and use average value of away
// away2 = away + awayStep * delta 
// delta = 2 * chord / ( away + away2 )
// delta = 2 * chord / ( 2*away + awayStep * delta )
// ( 2*away + awayStep * delta ) * delta = 2 * chord 
// awayStep * delta ** 2 + 2*away * delta - 2 * chord = 0
// plug into quadratic formula
// a= awayStep; b = 2*away; c = -2*chord

double delta = ( -2 * away + Math.sqrt ( 4 * away * away + 8 * awayStep * chord ) ) / ( 2 * awayStep );

theta += delta;

For even better results on a loose spiral, use a numeric iterative solution to find the value of delta where the calculated distance is within a suitable tolerance.

Contributing a Python generator (OP did not request any specific language). It uses a similar circle approximation as Pete Kirkham's answer.

arc is the required point distance along the path, separation is the required separation of the spiral arms.

def spiral_points(arc=1, separation=1):
    """generate points on an Archimedes' spiral
    with `arc` giving the length of arc between two points
    and `separation` giving the distance between consecutive 
    turnings
    - approximate arc length with circle arc at given distance
    - use a spiral equation r = b * phi
    """
    def p2c(r, phi):
        """polar to cartesian
        """
        return (r * math.cos(phi), r * math.sin(phi))

    # yield a point at origin
    yield (0, 0)

    # initialize the next point in the required distance
    r = arc
    b = separation / (2 * math.pi)
    # find the first phi to satisfy distance of `arc` to the second point
    phi = float(r) / b
    while True:
        yield p2c(r, phi)
        # advance the variables
        # calculate phi that will give desired arc length at current radius
        # (approximating with circle)
        phi += float(arc) / r
        r = b * phi

In Swift (based on liborm´s answer), taking the three inputs as OP requested:

func drawSpiral(arc: Double, separation: Double, var numPoints: Int) -> [(Double,Double)] {

    func p2c(r:Double, phi: Double) -> (Double,Double) {
        return (r * cos(phi), r * sin(phi))
    }

    var result = [(Double(0),Double(0))]

    var r = arc
    let b = separation / (2 * M_PI)
    var phi = r / b

    while numPoints > 0 {
        result.append(p2c(r, phi: phi))
        phi += arc / r
        r = b * phi
        numPoints -= 1
    }

    return result
}

I found this post useful, so I am adding a Matlab version of the above code.

function [sx, sy] = spiralpoints(arc, separation, numpoints)

    %polar to cartesian
    function [ rx,ry ] = p2c(rr, phi)
        rx = rr * cos(phi);
        ry = rr * sin(phi);
    end

    sx = zeros(numpoints);
    sy = zeros(numpoints);

    r = arc;
    b = separation / (2 * pi());
    phi = r / b;

    while numpoints > 0
        [ sx(numpoints), sy(numpoints) ] = p2c(r, phi);
        phi = phi + (arc / r);
        r = b * phi;
        numpoints = numpoints - 1;
    end

end
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!