2012-12-15 20 views
15

Potrzebuję algorytmu do obliczenia rozkładu punktów na spiralnej ścieżce.Rysuj równoodległe punkty na spirali

parametrów wejściowych tego algorytm powinien być:

  • szerokość pętli (odległość od wewnętrznej pętli)
  • stałej odległości pomiędzy punktami
  • Liczba punktów zwrócić

Spirala do rysowania to spirala archimedesa, a uzyskane punkty muszą być równe od siebie.

Algorytm powinien wypisać kolejność współrzędnych kartezjańskich pojedynczych punktach, na przykład:

Punkt 1: (0,0) Punkt 2: (..., ...) .... ... Punkt N (..., ...)

Język programowania nie jest ważny, a wszystkie są mile widziane!

EDIT:

już dostać i modyfikować ten przykład z tej strony:

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

Ale rozmieszczenie punktu jest źle, punkty nie są w równej odległości od siebie.

Spiral with non equidistant distribution

Prawidłowe przykład dystrybucja jest to obraz po lewej stronie:

Sirals

+0

Kiedy mówisz w jednakowej odległości, masz na myśli stałą odległość po bezpośredniej (prostej linii) ścieżce z jednego punktu do następnego, czy też masz na myśli odległość wzdłuż ścieżki spirali? (Domyślam się, że prawdopodobnie chcesz to drugie, ale obecne brzmienie brzmi bliższe temu pierwszemu). –

+0

Witaj Jerry. Z góry dziękuję. Mam na myśli stałą odległość wzdłuż ścieżki spiralnej. Myślę, że obie odległości są podobne, ale odległość wzdłuż krzywej jest dokładniejsza. (MAYBE!) –

+2

[Wolfram] (http://mathworld.wolfram.com/images/equations/ArchimedesSpiral/Inline3.gif) podaje równanie dla długości wzdłuż spirali. Przynajmniej na pierwszy rzut oka zmiana aranżacji, aby uzyskać kąt dla danej odległości, wygląda na dość prostą manipulację algebraiczną (choć przypuszczam, że mogłem coś przeoczyć, więc jest to trudniejsze niż to wygląda). –

Odpowiedz

14

do pierwszego zbliżenia - co jest prawdopodobnie wystarczająco dobre dla kreślenia bloki wystarczająco blisko - spirala jest okrąg i zwiększ kąt o współczynnik 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

Jednak dla luźniejszej spirali trzeba będzie rozwiązać odległość ścieżki dokładniej jako przestrzenie zbyt szeroko, gdy różnica między away dla kolejnych punktów jest znacząca w porównaniu z chord: 1 coil spiral 1st approximation1 coil spiral 2nd approximation

Druga wersja powyżej wykorzystuje krok oparty na rozwiązaniu dla delty w oparciu o użycie średniego promienia dla theta i 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; 

Aby uzyskać jeszcze lepsze wyniki na luźnej spirali, użyj numerycznego, iteracyjnego rozwiązania, aby znaleźć wartość delty, gdy obliczona odległość mieści się w odpowiedniej tolerancji.

+0

Wielkie dzięki, chłopaki. Ten algorytm jest idealny do moich potrzeb! –

2

Współtworzenie generatora Pythona (OP nie wymagał określonego języka). Używa podobnego zbliżenia do koła, jak odpowiedź Pete'a Kirkhama.

arc to wymagana odległość punktu wzdłuż ścieżki, separation to wymagane oddzielenie ramion spiralnych.

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

w Swift (na podstawie liborm's odpowiedzi), przy trzech wejść jako OP o:

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

znalazłem ten post użyteczne, więc dodaję wersję Matlab powyższego kodu .

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