Bewegen eines Teilchens um eine archimedische Spirale mit konstanter Geschwindigkeit


8

Ich möchte ein Teilchen in einer Spirale mit konstanter Geschwindigkeit bewegen. Beachten Sie, dass dies keine konstante Winkelgeschwindigkeit ist. Dies erweist sich als ziemlich schwierig, und ich werde meine Methode so weit unten durchgehen.

Die fragliche Spirale ist eine klassische archimedische Spirale mit der polaren Gleichung r = ϑund den parametrischen Gleichungen x = t*cos(t), y = t*sin(t). Das sieht so aus:Geben Sie hier die Bildbeschreibung ein

Ich möchte ein Teilchen so naiv um die Spirale bewegen, dass ich einfach die Teilchenposition als Wert von t und die Geschwindigkeit als Zunahme von t angeben kann. Auf diese Weise bewegt sich das Teilchen mit einer konstanten Winkelgeschwindigkeit um die Spirale. Dies bedeutet jedoch, dass die (nicht eckige) Geschwindigkeit umso schneller wird, je weiter es von der Mitte entfernt ist.

Anstatt meine Geschwindigkeit in der Zunahme von t zu haben, möchte ich meine Geschwindigkeit als die Zunahme der Bogenlänge. Das Ermitteln der Bogenlänge einer Spirale ist die erste Herausforderung, aber aufgrund der Tatsache, dass die von mir verwendete archimedische Spirale nicht zu verrückt ist, ist die Bogenlängenfunktion wo a = 1. Dadurch kann ich Theta-Werte in die Bogenlänge umwandeln, aber das ist genau das Gegenteil von dem, was ich brauche. Ich muss also die Umkehrung der Bogenlängenfunktion finden, und an dieser Hürde hat Wolfram-Alpha mich im Stich gelassen.

Ist es also möglich, die Umkehrung der Bogenlängenfunktion zu finden? Die Funktion ist eine Eins-zu-Eins-Zuordnung, wenn Sie negative Theta-Werte ausschließen.

Vielen Dank,

Laurie


1
Ich denke, Sie werden schneller eine Antwort auf den mathematischen Überlauf erhalten. Es ist jedoch für GameDev relevant.
Verlangsamte

Das wäre einfacher, wenn es nicht parametrisch wäre - muss es sein?
CiscoIPPhone

Ist die Spirale müssen archimedische sein?
Ingenieur

@ Cisco Nun, ich gab die polare Gleichung, und sie sind ziemlich austauschbar
Blue Peppers

@ Nick Ja: P Logarithmisch und / oder Lituus ist nicht das, was ich will
Blue Peppers

Antworten:


12

Lassen Sie uns Ihre Spirale komplizieren:

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

in deinem Fall f (t): = t, in meinem f (t): = 1 (also zahle ich meine Komplikationen mit Vereinfachungen zurück :)

Wenn Sie in dieser entarteten Spirale (einem Kreis) mit einer bestimmten Geschwindigkeit fahren möchten, müssen Sie wissen, wie lang Ihre Spirale in einer Runde ist, damit Sie sagen können, wie viele Runden pro Sekunde Sie machen, um sicherzustellen, dass Ihr Punkt mit der gewünschten Geschwindigkeit fährt .

Jetzt wissen wir, dass jede vollständige Runde in einem Kreis 2 · π · r lang ist: 2 · π · 1 in unserem Fall; wenn ω die Drehgeschwindigkeit (in Umdrehungen pro Sekunde) , ist die Geschwindigkeit V wird V = 2 · π · 1 · ω oder in allgemeinerer Art und Weise:

V = 2 · π · r · ω

wenn r der allgemeine Radius ist; dies sagt uns, dass:

V / (2 · π · r) = ω

Wenn r eine Funktion von t ist, können wir sagen:

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

In meinem "komplizierten" Fall kann dies wie folgt umgeschrieben werden:

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

In Ihrem "vereinfachten" Fall lautet die Antwort:

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

Sie kennen Ihre gewünschte konstante Geschwindigkeit V, Sie wissen: 2, π und t ist Ihre Variable: Sie wissen alles und sind bereit zu gehen!

Kreisnäherung für die infinitesimale Nachbarschaft der Spirale in t

die Kreisnäherung für die infinitesimale Nachbarschaft der Spirale in t

[HAFTUNGSAUSSCHLUSS]

Dies soll keine strenge mathematische Behandlung sein: Sie berücksichtigt weder den Beitrag des Differentials von f noch sagt sie, welche Arten von Funktionen nicht verwendet werden können.


Verwenden Sie also die letzte Gleichung, die Sie für w (t) lösen, und fügen Sie diese dann in die ursprüngliche parametrische Gleichung ein, um die Position des Partikels zu ermitteln. Ist das richtig?
CiscoIPPhone

Oh, das ist wirklich eine ausgezeichnete Antwort. Und aufgrund der Verwendung von f (t) anstelle von t können wir unsere Spirale modifizieren, während diese Lösung noch funktioniert. Vielen Dank.
Blue Peppers

@CiscoIPPhone w (t) ist die Drehzahl. Sie gibt an, wie viel Sie im Laufe der Zeit zu Ihrem t hinzufügen, und verwenden Sie dann t, um die Position zu ermitteln.
FxIII

@ Blue Peppers, wie ich im Haftungsausschluss sagte, gilt nicht für jedes f (t), es funktioniert, wenn sich f (t) langsam bewegt (und differenzierbar ist)
FxIII

2

Wenn Ihnen eine Annahme nichts ausmacht, die ziemlich schnell ziemlich genau wird, funktioniert diese einfache Lösung recht gut:

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

Dies ist zeitlich parametrisch, was sehr praktisch ist. Um dies zu erreichen, musste ich jedoch davon ausgehen, dass die Bewegung ungefähr kreisförmig ist - dh. Die momentane Lineargeschwindigkeit ist proportional zum Radius multipliziert mit der Winkelgeschwindigkeit:

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

Um zu zeigen, dass die Lösung funktioniert, schließen Sie sie an 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.

Bei platziert {time}=1dies einen Punkt in der Entfernung sqrt(2)vom Ursprung. Danach verbessert sich die Approximation erheblich: Der Abstand (linear, nicht entlang des Pfades) zwischen nachfolgenden Punkten beträgt 1,13, 1,08, 1,06. Nach 100 Punkten beträgt der Abstand weniger als 1,0023.


0

Auf der Suche nach einer Lösung zur Berechnung des Winkels, der einer bestimmten Bogenlänge entspricht, bin ich auf diese Frage und die aktuelle Antwort gestoßen. Leider konnten weder diese Antwort noch eine andere Ressource, die ich im Web gefunden habe, direkt für eine Implementierung verwendet werden.

Offensichtlich ist die Berechnung der Umkehrung der Bogenlängenfunktion (die auch in der Frage angegeben wurde) sehr schwierig. Eine Annäherung dieser Umkehrung unter Verwendung der Newtonschen iterativen Methode ist jedoch möglich. Die folgende Klasse bietet hauptsächlich zwei Methoden:

  • computeArcLength(double alpha, double angleRad): Berechnet die Bogenlänge eines Punktes auf der archimedischen Spirale, wobei alphader Abstand zwischen aufeinanderfolgenden Drehungen und angleRadder Winkel im Bogenmaß ist
  • computeAngle(double alpha, double arcLength, double epsilon): Berechnet den Winkel, in dem sich der Punkt für die angegebene Bogenlänge auf der archimedischen Spirale befindet, wobei alphader Abstand zwischen aufeinanderfolgenden Drehungen und epsilondie Näherungsschwelle für die Newton-Iteration ist

Der Code ist hier in Java implementiert, aber diese Kernmethoden sollten ziemlich sprachunabhängig sein:

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

Ein Beispiel dafür, wie dies für das in der Frage beschriebene Ziel verwendet werden kann, finden Sie in diesem Snippet: Es wird eine bestimmte Anzahl von Punkten auf der Spirale mit einem gewünschten Abstand (Bogenlänge!) Zwischen den Punkten generiert:

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

Der tatsächliche Bogenlängenabstand der berechneten Punkte wird gedruckt, und man kann sehen, dass sie tatsächlich äquidistant mit dem gewünschten Bogenlängenabstand sind.


0

Ich kämpfe auch damit.

Ich halte die Geschwindigkeit konstant und ändere die Richtung des Objekts.

Wenn ich mache, ist der Winkel (in Grad) gleich dem Abstand vom Ursprung, mal eine Konstante, ich bekomme eine schöne perfekte archimedische Spirale. Größere Konstanten erhalten weniger Platz zwischen den Linien. Das einzige Problem ist, wenn die Geschwindigkeit zu hoch ist, dann springt es die Strecke und bringt es durcheinander. Engere Spiralen erfordern daher eine langsamere Geschwindigkeit, um zuverlässig verfolgt zu werden.

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

Wobei current_distance der Radius ist, der von der Position zum Spawnpunkt in Pixel gezeichnet wird und von einer Engine-Funktion erfasst wird, die ihn mir gibt.

Was mich die Wand hoch treibt, ist das Gegenteil. Platzieren Sie das Objekt AUSSEN und lassen Sie es die archimedische Spirale INWARDS verfolgen. Das Gegenteil zu bewegen, funktioniert nicht. das dreht nur die Spirale um 180 Grad. Das Umkehren der Richtung ergibt eine im Uhrzeigersinn.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.