2012-12-15 17 views
15

Ho bisogno di un algoritmo per calcolare la distribuzione dei punti su un percorso a spirale.Disegna punti equidistanti su una spirale

I parametri di ingresso di questo algoritmo dovrebbe essere:

  • larghezza del loop (distanza dal ciclo più interno)
  • Fixed distanza tra i punti
  • Il numero di punti per disegnare

La spirale da disegnare è una spirale archimedeata ei punti ottenuti devono essere equidistanti l'uno dall'altro.

L'algoritmo dovrebbe stampare la sequenza delle coordinate cartesiane di singoli punti, ad esempio:

Punto 1: (0.0) Punto 2: (..., ...) .... .... Punto N (..., ...)

Il linguaggio di programmazione non è importante e tutti sono di grande aiuto!

EDIT:

ho già capito e modificare questo esempio da questo sito:

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

Ma la disposizione del punto è sbagliato, i punti non sono equidistanti tra loro.

Spiral with non equidistant distribution

L'esempio di distribuzione corretto è è l'immagine a sinistra:

Sirals

+0

Quando si dice equidistante, si intende una distanza costante seguendo un percorso diretto (linea retta) da un punto a quello successivo o si intende la distanza lungo il percorso della spirale? (Immagino che tu voglia il secondo, ma l'attuale frase sembra più vicina alla prima). –

+0

Ciao Jerry. Grazie in anticipo. Intendo la distanza costante lungo il percorso della spirale. Penso che entrambe le distanze siano simili, ma la distanza lungo la curva è più accurata. (FORSE!) –

+2

[Wolfram] (http://mathworld.wolfram.com/images/equations/ArchimedesSpiral/Inline3.gif) fornisce l'equazione per una lunghezza lungo la spirale. Almeno a prima vista, riordinare quello per ottenere un angolo per una data distanza sembra una manipolazione algebrica abbastanza semplice (anche se suppongo che avrei potuto perdere qualcosa quindi è più difficile di quanto sembri). –

risposta

14

In prima approssimazione - che è abbastanza probabilmente un bene per tracciare blocchi abbastanza vicino - la spirale è un cerchia e aumenta l'angolo in base al rapporto 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

Tuttavia, per una spirale perdente si dovrà risolvere la distanza percorso più accuratamente come spazi troppo ampia dove la differenza tra away per punti successivi è significativa rispetto chord: 1 coil spiral 1st approximation1 coil spiral 2nd approximation

La seconda versione sopra riportata utilizza un passo basato sulla risoluzione del delta in base all'utilizzo del raggio medio per theta e 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; 

Per risultati ancora migliori su una spirale libera, utilizzare una soluzione numerica iterativa per trovare il valore di delta in cui la distanza calcolata è all'interno di una tolleranza adeguata.

+0

Grazie mille, ragazzi. Questo algoritmo è perfetto per le mie esigenze! –

2

Contribuire a un generatore Python (l'OP non ha richiesto alcuna lingua specifica). Usa un'approssimazione a cerchio simile alla risposta di Pete Kirkham.

arc è la distanza punto richiesta lungo il percorso, separation è la separazione richiesta dei bracci a spirale.

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

In Swift (sulla base di liborm's risposta), prendendo i tre ingressi come OP richiesto:

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

ho trovato questo post utile, quindi sto aggiungendo una versione Matlab del codice di cui sopra .

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 
Problemi correlati