Muovere una particella attorno a una spirale di Archimede a velocità costante


8

Voglio spostare una particella in una spirale a velocità costante. Si noti che questa non è una velocità angolare costante. Questo si sta rivelando piuttosto difficile, e seguirò il mio metodo molto più avanti.

La spirale in questione è una classica spirale di Archimede con l'equazione polare r = ϑe le equazioni parametriche x = t*cos(t), y = t*sin(t). Questo assomiglia a questo:inserisci qui la descrizione dell'immagine

Voglio spostare una particella attorno alla spirale, così ingenuamente, posso solo dare la posizione della particella come il valore di t, e la velocità come l'aumento di t. In questo modo la particella si muove attorno alla spirale a una velocità angolare costante. Tuttavia, ciò significa che più si allontana dal centro, più veloce diventa la sua velocità (non angolare).

Quindi, invece di avere la mia velocità nell'aumento di t, voglio la mia velocità come aumento della lunghezza dell'arco. Ottenere la lunghezza dell'arco di una spirale è la prima sfida, ma a causa del fatto che la spirale di Archimede che sto usando non è troppo folle, la funzione della lunghezza dell'arco è , dove a = 1. Questo mi permette di convertire i valori theta nella lunghezza dell'arco, ma è esattamente l'opposto di ciò di cui ho bisogno. Quindi ho bisogno di trovare l'inverso della funzione lunghezza d'arco, e in quel ostacolo, Wolfram-Alpha mi ha deluso.

Quindi è possibile trovare l'inverso della funzione di lunghezza dell'arco? La funzione è un mapping uno a uno, se si escludono valori negativi di theta.

Grazie,

Laurie


1
Penso che otterrai una risposta più rapidamente sull'overflow della matematica. È rilevante per GameDev però.
deceleratedcaviar

Sarebbe più facile se non fosse parametrico - deve essere?
CiscoIPPhone

La spirale deve essere archimedea?
Ingegnere

@Cisco Beh, ho dato l'equazione polare, e sono praticamente intercambiabili
Blue Peppers

@Nick Sì: P Logarithmic e / o lituus non è quello che voglio
Blue Peppers

Risposte:


12

Compliciamo la tua spirale:

essere p (t): = (cos (t) · f (t), sin (t) · f (t))

nel tuo caso f (t): = t, nel mio f (t): = 1 (quindi ripagherò le mie complicazioni con le semplificazioni :)

Se vuoi andare ad una certa velocità in questa spirale degenerata (un cerchio) devi sapere quanto è lunga la tua spirale in un round in modo da poter dire quanti round al secondo fanno per essere sicuro che il tuo punto viaggi con la velocità desiderata .

Ora sappiamo che ogni round completo in un cerchio è lungo 2 · π · r : 2 · π · 1 nel nostro caso; se ω è la velocità di rivoluzione (in round al secondo) la velocità V sarà V = 2 · π · 1 · ω o in modo più generale:

V = 2 · π · r · ω

se r è il raggio generale; questo ci dice che:

V / (2 · π · r) = ω

se r è una funzione di t possiamo dire:

ω (t) = V / (2 · π · r (t))

nel mio caso "complicato" questo può essere riscritto come segue:

ω (t) = V / (2 · π · f (t))

nel tuo caso "semplificato" la risposta è:

ω (t) = V / (2 · π · t)

Tu conosci il tuo costante la velocità desiderata V, si sa: 2, π e t è la variabile: si sa tutto e si è pronti a partire!

approssimazione del cerchio per il vicinato infinitesimale della spirale in t

l'approssimazione del cerchio per il vicinato infinitesimale della spirale in t

[Disclaimer]

Questo non intende essere un rigoroso trattamento matematico: non tiene conto del contributo del differenziale di f né indica quali tipi di funzioni non possono essere utilizzati.


Quindi usando l'ultima equazione che risolvi per w (t) e poi inseriscila nell'equazione parametrica originale per ottenere la posizione della particella, è corretto?
CiscoIPPhone

Oh, questa è davvero una risposta eccellente. E grazie all'uso di f (t) invece di t, possiamo modificare la nostra spirale con questa soluzione ancora funzionante. Grazie mille.
Blue Peppers

@CiscoIPPhone w (t) è la velocità di rotazione, ti dice quanto aggiungi alla tua t col passare del tempo, quindi usa t per ottenere la posizione.
FxIII,

@Blue Peppers come ho detto nel disclaimer non è vero per ogni f (t), funziona se f (t) si muove lentamente (ed è differenziabile)
FxIII

2

Se non ti dispiace un presupposto che diventa abbastanza preciso abbastanza rapidamente, questa semplice soluzione funziona abbastanza bene:

theta = r = sqrt(2) . sqrt({time})

Questo è parametrico nel tempo, il che è abbastanza utile. Tuttavia, per ottenere questo ho dovuto supporre che il movimento sia approssimativamente circolare - cioè. la velocità lineare istantanea è proporzionale al raggio moltiplicata per la velocità angolare:

{velocity} ~= {radius} . d{theta} / d{time}

Per mostrare che la soluzione funziona, collegala a d{theta} / d{time}:

d{theta} / d{time} = d(sqrt(2).{time}^(1/2)) / d{time}
                   = (sqrt(2) / 2) . {time}^(-1/2))
                   = 1 / {theta}
                   = 1 / {radius}
=> {velocity} = {radius} / {radius} = 1, as required.

A {time}=1, questo pone un punto a distanza sqrt(2)dall'origine. Successivamente, l'approssimazione migliora in modo significativo: la separazione (lineare, non lungo il percorso) tra i punti successivi è 1,13, 1,08, 1,06. Dopo 100 punti la separazione è inferiore a 1.0023.


0

Mentre cercavo una soluzione per calcolare l'angolo che corrisponde a una certa lunghezza dell'arco, mi sono imbattuto in questa domanda e nella risposta attuale. Sfortunatamente, né questa risposta né altre risorse che ho trovato sul web potrebbero essere utilizzate direttamente per un'implementazione.

Ovviamente, calcolare l'inverso della funzione di lunghezza dell'arco (che è stata fornita anche nella domanda) è molto difficile. Ma è possibile un'approssimazione di questo inverso usando il metodo iterativo di Newton. Di seguito è una classe che offre principalmente due metodi:

  • computeArcLength(double alpha, double angleRad): Calcola la lunghezza dell'arco di un punto sulla spirale di Archimede in cui si alphatrova la distanza tra le svolte successive e angleRadl'angolo in radianti
  • computeAngle(double alpha, double arcLength, double epsilon): Calcola l'angolo in cui si trova il punto per la lunghezza dell'arco data sulla spirale di Archimede, dove si alphatrova la distanza tra le torniture successive ed epsilonè la soglia di approssimazione per la Iterazione di Newton

Il codice è implementato qui in Java, ma questi metodi di base dovrebbero essere abbastanza indipendenti dal linguaggio:

import java.awt.geom.Point2D;

/**
 * A class for computations related to an Archimedean Spiral
 */
class ArchimedeanSpiral
{
    /**
     * Computes an approximation of the angle at which an Archimedean Spiral
     * with the given distance between successive turnings has the given 
     * arc length.<br>
     * <br>
     * Note that the result is computed using an approximation, and not
     * analytically. 
     * 
     * @param alpha The distance between successive turnings
     * @param arcLength The desired arc length
     * @param epsilon A value greater than 0 indicating the precision
     * of the approximation 
     * @return The angle at which the desired arc length is achieved
     * @throws IllegalArgumentException If the given arc length is negative
     * or the given epsilon is not positive
     */
    static double computeAngle(
        double alpha, double arcLength, double epsilon)
    {
        if (arcLength < 0)
        {
            throw new IllegalArgumentException(
                "Arc length may not be negative, but is "+arcLength);
        }
        if (epsilon <= 0)
        {
            throw new IllegalArgumentException(
                "Epsilon must be positive, but is "+epsilon);
        }
        double angleRad = Math.PI + Math.PI;
        while (true)
        {
            double d = computeArcLength(alpha, angleRad) - arcLength;
            if (Math.abs(d) <= epsilon)
            {
                return angleRad;
            }
            double da = alpha * Math.sqrt(angleRad * angleRad + 1);
            angleRad -= d / da;
        }
    }

    /**
     * Computes the arc length of an Archimedean Spiral with the given
     * parameters
     * 
     * @param alpha The distance between successive turnings
     * @param angleRad The angle, in radians
     * @return The arc length
     * @throws IllegalArgumentException If the given alpha is negative
     */
    static double computeArcLength(
        double alpha, double angleRad)
    {
        if (alpha < 0)
        {
            throw new IllegalArgumentException(
                "Alpha may not be negative, but is "+alpha);
        }
        double u = Math.sqrt(1 + angleRad * angleRad);
        double v = Math.log(angleRad + u);
        return 0.5 * alpha * (angleRad * u + v);
    }

    /**
     * Compute the point on the Archimedean Spiral for the given parameters.<br>
     * <br>
     * If the given result point is <code>null</code>, then a new point will
     * be created and returned.
     * 
     * @param alpha The distance between successive turnings
     * @param angleRad The angle, in radians
     * @param result The result point
     * @return The result point
     * @throws IllegalArgumentException If the given alpha is negative
     */
    static Point2D computePoint(
        double alpha, double angleRad, Point2D result)
    {
        if (alpha < 0)
        {
            throw new IllegalArgumentException(
                "Alpha may not be negative, but is "+alpha);
        }
        double distance = angleRad * alpha;
        double x = Math.sin(angleRad) * distance;
        double y = Math.cos(angleRad) * distance;
        if (result == null)
        {
            result = new Point2D.Double();
        }
        result.setLocation(x, y);
        return result;
    }

    /**
     * Private constructor to prevent instantiation
     */
    private ArchimedeanSpiral()
    {
        // Private constructor to prevent instantiation
    }
}

Un esempio di come utilizzarlo per l'obiettivo descritto nella domanda è riportato in questo frammento: genera un certo numero di punti sulla spirale, con una distanza desiderata (lunghezza dell'arco!) Tra i punti:

import java.awt.geom.Point2D;
import java.util.Locale;

public class ArchimedeanSpiralExample
{
    public static void main(String[] args)
    {
        final int numPoints = 50;
        final double pointArcDistance = 0.1;
        final double alpha = 0.5;
        final double epsilon = 1e-5;

        double totalArcLength = 0.0;
        double previousAngleRad = 0.0; 
        for (int i=0; i<numPoints; i++)
        {
            double angleRad = 
                ArchimedeanSpiral.computeAngle(alpha, totalArcLength, epsilon);
            Point2D point = 
                ArchimedeanSpiral.computePoint(alpha, angleRad, null);
            totalArcLength += pointArcDistance;

            // Compute and print the arc lengths, for validation:
            double currentArcLength = 
                ArchimedeanSpiral.computeArcLength(alpha, angleRad);
            double previousArcLength = 
                ArchimedeanSpiral.computeArcLength(alpha, previousAngleRad);
            double arcDistance = (currentArcLength - previousArcLength);
            System.out.printf(Locale.ENGLISH,
                "Point (%6.2f, %6.2f  distance in arc "
                + "length from previous is %6.2f\n",
                point.getX(), point.getY(), arcDistance);

            previousAngleRad = angleRad;
        }
    }
}

L' effettiva distanza lunghezza d'arco dei punti calcolati viene stampato, e si può vedere che in realtà sono equidistanti, con la distanza desiderata lunghezza d'arco.


0

Sto lottando anche con questo.

Quello che sto facendo è mantenere costante la velocità e cambiare la direzione dell'oggetto.

Se faccio così l'angolo (in gradi) è uguale alla distanza dall'origine, volte una costante, ottengo una bella spirale archimedea perfetta. le costanti più grandi ottengono meno spazio tra le linee. L'unico problema è se la velocità è troppo alta, quindi salta la traccia e incasina. spirali così più strette richiedono una velocità più bassa per tracciare in modo affidabile.

direction = ((spiral_factor*(current_distance) mod 360);

Dove current_distance è il raggio disegnato dalla posizione al punto di spawn in pixel, afferrato da una funzione del motore che me lo dà.

Ciò che mi sta spingendo verso il muro è l'inverso. posizionando l'oggetto ESTERNO e facendolo rintracciare la spirale di Archimede. Spostare la particella nella direzione opposta non funziona. che ruota solo la spirale di 180 gradi. invertendo la direzione si ottiene una direzione in senso orario.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.