Déplacement d'une particule autour d'une spirale archimédienne à vitesse constante


8

Je veux déplacer une particule en spirale à une vitesse constante. Notez que ce n'est pas une vitesse angulaire constante. Cela s'avère assez difficile, et je vais passer en revue ma méthode jusqu'à présent ci-dessous.

La spirale en question est une spirale archimédienne classique avec l'équation polaire r = ϑet les équations paramétriques x = t*cos(t), y = t*sin(t). Cela ressemble à ceci:entrez la description de l'image ici

Je veux déplacer une particule autour de la spirale, donc naïvement, je peux simplement donner la position des particules comme la valeur de t, et la vitesse comme l'augmentation de t. De cette façon, la particule se déplace autour de la spirale à une vitesse angulaire constante. Cependant, cela signifie que plus on s'éloigne du centre, plus sa vitesse (non angulaire) devient rapide.

Donc, au lieu d'avoir ma vitesse dans l'augmentation de t, je veux ma vitesse comme l'augmentation de la longueur de l'arc. Obtenir la longueur d'arc d'une spirale est le premier défi, mais étant donné que la spirale d'Archimède que j'utilise n'est pas trop folle, la fonction de longueur d'arc est , où a = 1. Cela me permet de convertir les valeurs thêta en longueur d'arc, mais c'est exactement le contraire de ce dont j'ai besoin. J'ai donc besoin de trouver l'inverse de la fonction de longueur d'arc, et à cet obstacle, Wolfram-Alpha m'a échoué.

Est-il donc possible de trouver l'inverse de la fonction de longueur d'arc? La fonction est un mappage un à un, si vous excluez les valeurs négatives de thêta.

Merci,

Laurie


1
Je pense que vous obtiendrez une réponse plus rapidement sur le débordement mathématique. Cela concerne cependant GameDev.
deceleratedcaviar

Ce serait plus facile s'il n'était pas paramétrique - doit-il l'être?
CiscoIPPhone

La spirale doit-elle être archimédienne?
Ingénieur

@Cisco Eh bien, j'ai donné l'équation polaire, et ils sont à peu près interchangeables
Blue Peppers

@ Nick Oui: P logarithmique et / ou lituus n'est pas ce que je veux
Blue Peppers

Réponses:


12

Compliquons votre spirale:

être p (t): = (cos (t) · f (t), sin (t) · f (t))

dans votre cas f (t): = t, dans le mien f (t): = 1 (donc je rembourse mes complications avec des simplifications :)

Si vous voulez aller à une certaine vitesse dans cette spirale dégénérée (un cercle), vous devez savoir combien de temps dure votre spirale dans un tour afin que vous puissiez dire combien de tours par seconde font pour être sûr que votre point voyage avec la vitesse désirée .

Nous savons maintenant que chaque tour complet dans un cercle est long de 2 · π · r : 2 · π · 1 dans notre cas; si ω est la vitesse de révolution (en tours par seconde) la vitesse V sera V = 2 · π · 1 · ω ou d'une manière plus générale:

V = 2 · π · r · ω

si r est le rayon général; cela nous dit que:

V / (2 · π · r) = ω

si r est fonction de t on peut dire:

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

dans mon cas "compliqué" cela peut être réécrit comme suit:

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

dans votre cas "simplifié" la réponse est:

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

Vous connaissez votre vitesse constante V souhaitée, vous savez: 2, π et t est votre variable: vous savez tout et vous êtes prêt à partir!

approximation du cercle pour le voisinage infinitésimal de la spirale en t

l'approximation du cercle pour le voisinage infinitésimal de la spirale en t

[AVERTISSEMENT]

Il ne s'agit pas d'un traitement mathématique rigoureux: il ne prend pas en compte la contribution du différentiel de f ni ne dit quels types de fonctions ne peuvent pas être utilisés.


Donc, en utilisant la dernière équation que vous résolvez pour w (t) et que vous mettez ensuite dans l'équation paramétrique d'origine pour obtenir la position de la particule, est-ce correct?
CiscoIPPhone

Oh, c'est vraiment une excellente réponse. Et en raison de l'utilisation de f (t) au lieu de t, nous pouvons modifier notre spirale avec cette solution qui fonctionne toujours. Merci beaucoup.
Blue Peppers

@CiscoIPPhone w (t) est la vitesse de rotation, il vous indique combien ajouter à votre t au fil du temps, puis utilisez t pour obtenir la position.
FxIII

@Blue Peppers comme je l'ai dit dans l'avertissement n'est pas vrai pour chaque f (t), cela fonctionne si f (t) se déplace lentement (et est différenciable)
FxIII

2

Si cela ne vous dérange pas une hypothèse qui devient assez précise assez rapidement, cette solution simple fonctionne assez bien:

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

C'est paramétrique dans le temps, ce qui est assez pratique. Cependant, pour obtenir cela, je devais supposer que la motion était à peu près circulaire - c'est-à-dire. la vitesse linéaire instantanée est proportionnelle au rayon multiplié par la vitesse angulaire:

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

Pour montrer que la solution fonctionne, branchez-la sur 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.

À {time}=1, cela place un point à distance sqrt(2)de l'origine. Après cela, l'approximation s'améliore considérablement: la séparation (linéaire, pas le long du chemin) entre les points suivants est de 1,13, 1,08, 1,06. Après 100 points, la séparation est inférieure à 1,0023.


0

En cherchant une solution de calcul de l'angle qui correspond à une certaine longueur d'arc, je suis tombé sur cette question et la réponse actuelle. Malheureusement, ni cette réponse ni aucune autre ressource que j'ai trouvée sur le Web n'ont pu être directement utilisées pour une implémentation.

De toute évidence, le calcul de l'inverse de la fonction de longueur d'arc (qui était également fourni dans la question) est très difficile. Mais une approximation de cet inverse en utilisant la méthode itérative de Newton est possible. Ce qui suit est une classe qui propose principalement deux méthodes:

  • computeArcLength(double alpha, double angleRad): Calcule la longueur d'arc d'un point sur la spirale d'Archimède où alphaest la distance entre les virages successifs et angleRadl'angle en radians
  • computeAngle(double alpha, double arcLength, double epsilon): Calcule l'angle auquel le point pour la longueur d'arc donnée est situé sur la spirale d'Archimède, où alphaest la distance entre les virages successifs, et epsilonest le seuil d'approximation pour l'itération de Newton

Le code est implémenté ici en Java, mais ces méthodes de base doivent être assez indépendantes du langage:

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 exemple de la façon de l'utiliser pour l'objectif décrit dans la question est donné dans cet extrait: il génère un certain nombre de points sur la spirale, avec une distance souhaitée (longueur d'arc!) Entre les points:

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

La distance de longueur d'arc réelle des points calculés est imprimée, et on peut voir qu'ils sont en fait équidistants, avec la distance de longueur d'arc souhaitée.


0

Je lutte aussi avec ça.

Ce que je fais, c'est maintenir la vitesse constante et changer la direction de l'objet.

Si je fais est si l'angle (en degrés) est égal à la distance de l'origine, multiplié par une constante, j'obtiens une belle spirale archimédienne parfaite. les constantes plus grandes obtiennent moins d'espace entre les lignes. Le seul problème est que si la vitesse est trop élevée, elle saute la piste et gâche. les spirales plus serrées nécessitent donc une vitesse plus lente pour tracer de manière fiable.

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

Où current_distance est le rayon dessiné de l'emplacement au point d'apparition en pixels, saisi par une fonction de moteur qui me le donne.

Ce qui me fait monter le mur, c'est l'inverse. placer l'objet à L'EXTÉRIEUR et le faire tracer la spirale archimédienne INTÉRIEURE. Déplacer la particule dans l'autre sens ne fonctionne pas. qui fait simplement pivoter la spirale de 180 degrés. inverser la direction en donne une dans le sens horaire.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.