2012-12-15 51 views
15

Tôi cần một thuật toán để tính toán phân bố các điểm trên đường xoắn ốc.Vẽ các điểm cách đều nhau trên hình xoắn ốc

Các thông số đầu vào của thuật toán này sẽ là:

  • Chiều rộng của vòng lặp (khoảng cách từ vòng lặp trong cùng)
  • Cố định khoảng cách giữa các điểm
  • Số điểm để vẽ

Hình xoắn ốc để vẽ là xoắn ốc archimedean và các điểm thu được phải là cách đều nhau từ mỗi khác.

Thuật toán nên in ra một chuỗi các tọa độ Descartes của điểm duy nhất, ví dụ:

điểm 1: (0.0) điểm 2: (..., ...) .... .... Điểm N (..., ...)

Ngôn ngữ lập trình không quan trọng và tất cả giúp đánh giá cao!

EDIT:

Tôi đã có được và sửa đổi mẫu này từ trang web này:

// 
// 
// centerX-- X origin of the spiral. 
// centerY-- Y origin of the spiral. 
// radius--- Distance from origin to outer arm. 
// sides---- Number of points or sides along the spiral's arm. 
// coils---- Number of coils or full rotations. (Positive numbers spin clockwise, negative numbers spin counter-clockwise) 
// rotation- Overall rotation of the spiral. ('0'=no rotation, '1'=360 degrees, '180/360'=180 degrees) 
// 
void SetBlockDisposition(float centerX, float centerY, float radius, float sides, float coils, float rotation) 
{ 
    // 
    // How far to step away from center for each side. 
    var awayStep = radius/sides; 
    // 
    // How far to rotate around center for each side. 
    var aroundStep = coils/sides;// 0 to 1 based. 
    // 
    // Convert aroundStep to radians. 
    var aroundRadians = aroundStep * 2 * Mathf.PI; 
    // 
    // Convert rotation to radians. 
    rotation *= 2 * Mathf.PI; 
    // 
    // For every side, step around and away from center. 
    for(var i=1; i<=sides; i++){ 

     // 
     // How far away from center 
     var away = i * awayStep; 
     // 
     // How far around the center. 
     var around = i * aroundRadians + rotation; 
     // 
     // Convert 'around' and 'away' to X and Y. 
     var x = centerX + Mathf.Cos(around) * away; 
     var y = centerY + Mathf.Sin(around) * away; 
     // 
     // Now that you know it, do it. 

     DoSome(x,y); 
    } 
} 

Nhưng sự sắp xếp của điểm là sai, những điểm không cách đều nhau.

Spiral with non equidistant distribution

Ví dụ phân phối đúng là là hình ảnh bên trái:

Sirals

+0

Khi bạn nói cách đều, bạn có nghĩa là khoảng cách không đổi theo đường thẳng (đường thẳng) từ điểm này sang điểm tiếp theo hay ý bạn là khoảng cách dọc theo đường xoắn ốc? (Tôi đoán bạn có thể muốn sau này, nhưng các giai điệu hiện tại âm thanh gần gũi hơn với trước đây). –

+0

Xin chào Jerry. Cảm ơn trước. Tôi có nghĩa là khoảng cách không đổi dọc theo con đường xoắn ốc. Tôi nghĩ rằng cả hai khoảng cách đều giống nhau, nhưng khoảng cách dọc theo đường cong chính xác hơn. (MAYBE!) –

+2

[Wolfram] (http://mathworld.wolfram.com/images/equations/ArchimedesSpiral/Inline3.gif) đưa ra phương trình cho một chiều dài dọc theo hình xoắn ốc. Ít nhất là trong nháy mắt đầu tiên, sắp xếp lại để có được một góc cho một khoảng cách nhất định trông giống như thao tác đại số khá đơn giản (mặc dù tôi cho rằng tôi có thể đã bỏ lỡ một cái gì đó vì vậy nó khó hơn nó nhìn). –

Trả lời

14

Để một xấp xỉ đầu tiên - mà có lẽ là đủ tốt cho âm mưu khối đủ gần - xoắn ốc là một khoanh tròn và tăng góc theo tỷ lệ 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; 
} 

10 coil spiral

Tuy nhiên, đối với một xoắn ốc lỏng hơn bạn sẽ phải giải quyết khoảng cách con đường chính xác hơn là không gian quá rộng nơi sự khác biệt giữa away cho điểm liên tiếp có ý nghĩa so với chord: 1 coil spiral 1st approximation1 coil spiral 2nd approximation

Phiên bản thứ hai ở trên sử dụng một bước dựa trên việc giải quyết delta dựa trên việc sử dụng bán kính trung bình cho theta và 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; 

Để có kết quả tốt hơn trên hình xoắn ốc lỏng lẻo, hãy sử dụng một giải pháp lặp số để tìm giá trị của delta nơi khoảng cách được tính trong phạm vi dung sai phù hợp.

+0

Cảm ơn rất nhiều, các bạn. Thuật toán này là hoàn hảo cho nhu cầu của tôi! –

2

Đóng góp bộ tạo Python (OP không yêu cầu bất kỳ ngôn ngữ cụ thể nào). Nó sử dụng một xấp xỉ vòng tròn tương tự như câu trả lời của Pete Kirkham.

arc là khoảng cách điểm được yêu cầu dọc theo đường dẫn, separation là sự tách biệt bắt buộc của cánh tay xoắn ốc.

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 
3

Trong Swift (dựa trên câu trả lời liborm's), lấy ba đầu vào như OP yêu cầu:

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 
} 
1

tôi tìm thấy bài này hữu ích, vì vậy tôi đang bổ sung thêm một phiên bản Matlab của các mã trên .

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