Mover una partícula alrededor de una espiral de Arquímedes a una velocidad constante

8

Quiero mover una partícula en espiral a una velocidad constante. Tenga en cuenta que esa no es una velocidad angular constante. Esto está resultando bastante difícil, y pasaré por mi método hasta ahora a continuación.

La espiral en cuestión es una espiral clásica de Arquímedes con la ecuación polar r = ϑy las ecuaciones paramétricas x = t*cos(t), y = t*sin(t). Esto se ve así:ingrese la descripción de la imagen aquí

Quiero mover una partícula alrededor de la espiral, tan ingenuamente, solo puedo dar la posición de la partícula como el valor de t, y la velocidad como el aumento de t. De esa manera, la partícula se mueve alrededor de la espiral a una velocidad angular constante. Sin embargo, esto significa que cuanto más se aleja del centro, más rápida se vuelve su velocidad (no angular).

Entonces, en lugar de tener mi velocidad en el aumento de t, quiero mi velocidad como el aumento en la longitud del arco. Obtener la longitud del arco de una espiral es el primer desafío, pero debido al hecho de que la espiral de Arquímedes que estoy usando no es una locura, la función de longitud del arco es dónde a = 1. Esto me permite convertir los valores theta a la longitud del arco, pero eso es exactamente lo contrario de lo que necesito. Así que necesito encontrar el inverso de la función de longitud de arco, y en ese obstáculo, Wolfram-Alpha me ha fallado.

Entonces, ¿es posible encontrar la inversa de la función de longitud de arco? La función es un mapeo uno a uno, si excluye los valores negativos de theta.

Gracias,

Laurie

Pimientos azules
fuente
1
Creo que obtendrá una respuesta más rápida sobre el desbordamiento matemático. Sin embargo, es relevante para GameDev.
desaceleratedcaviar
Esto sería más fácil si no fuera paramétrico, ¿tiene que serlo?
CiscoIPPhone
¿La espiral tiene que ser Archimedean?
Ingeniero
@Cisco Bueno, di la ecuación polar, y son prácticamente intercambiables
Blue Peppers el
@Nick Sí: P Logarítmico y / o lituus no es lo que quiero
Blue Peppers

Respuestas:

12

Vamos a complicar tu espiral:

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

en su caso f (t): = t, en el mío f (t): = 1 (así que pago mis complicaciones con simplificaciones :)

Si desea ir a cierta velocidad en esta espiral degenerada (un círculo), debe saber cuánto dura su espiral en una ronda para poder decir cuántas rondas por segundo hace para asegurarse de que su punto viaja con la velocidad deseada .

Ahora sabemos que cada ronda completa en un círculo es 2 · π · r de largo: 2 · π · 1 en nuestro caso; si ω es la velocidad de revolución (en rondas por segundo) la velocidad V será V = 2 · π · 1 · ω o de una manera más general:

V = 2 · π · r · ω

si r es el radio general; esto nos dice que:

V / (2 · π · r) = ω

si r es una función de t podemos decir:

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

en mi caso "complicado" esto se puede reescribir de la siguiente manera:

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

en su caso "simplificado" la respuesta es:

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

Conoces tu velocidad constante deseada V, sabes: 2, π y t es tu variable: ¡lo sabes todo y estás listo para comenzar!

aproximación circular para la vecindad infinitesimal de la espiral en t

la aproximación circular para la vecindad infinitesimal de la espiral en t

[DESCARGO DE RESPONSABILIDAD]

Esto no pretende ser un tratamiento matemático riguroso: no tiene en cuenta la contribución del diferencial de f ni dice qué tipos de funciones no se pueden utilizar.

FxIII
fuente
Entonces, utilizando la última ecuación que resuelve para w (t) y luego la coloca en la ecuación paramétrica original para obtener la posición de la partícula, ¿es correcto?
CiscoIPPhone
Oh, esta es realmente una excelente respuesta. Y debido al uso de f (t) en lugar de t, podemos modificar nuestra espiral con esta solución aún funcionando. Muchas gracias.
Blue Peppers
@CiscoIPPhone w (t) es la velocidad de rotación, le indica cuánto agregar a su t a medida que pasa el tiempo, luego use t para obtener la posición.
FxIII
@Blue Peppers como dije en el descargo de responsabilidad no es cierto para cada f (t), funciona si f (t) se mueve lentamente (y es diferenciable)
FxIII
2

Si no le importa una suposición que se vuelve bastante precisa con bastante rapidez, esta solución simple funciona bastante bien:

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

Esto es paramétrico en el tiempo, lo cual es bastante útil. Sin embargo, para obtener esto, necesitaba suponer que el movimiento es aproximadamente circular, es decir. La velocidad lineal instantánea es proporcional al radio multiplicado por la velocidad angular:

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

Para mostrar que la solución funciona, conéctela 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.

En {time}=1, esto coloca un punto a distancia sqrt(2)del origen. Después de esto, la aproximación mejora significativamente: la separación (lineal, no a lo largo del camino) entre los puntos subsiguientes es 1.13, 1.08, 1.06. Después de 100 puntos, la separación es inferior a 1.0023.

Andrew The Bolt
fuente
0

Mientras buscaba una solución para calcular el ángulo que corresponde a una cierta longitud de arco, me topé con esta pregunta y la respuesta actual. Desafortunadamente, ni esta respuesta ni ningún otro recurso que encontré en la web podrían usarse directamente para una implementación.

Obviamente, calcular la inversa de la función de longitud de arco (que también se proporcionó en la pregunta) es muy difícil. Pero es posible una aproximación de este inverso utilizando el método iterativo de Newton. La siguiente es una clase que ofrece principalmente dos métodos:

  • computeArcLength(double alpha, double angleRad): Calcula la longitud del arco de un punto en la espiral de Arquímedes donde alphaes la distancia entre giros sucesivos y angleRadel ángulo en radianes
  • computeAngle(double alpha, double arcLength, double epsilon): Calcula el ángulo en el que el punto para la longitud de arco dada se encuentra en la Espiral de Arquímedes, donde alphaestá la distancia entre giros sucesivos y epsilones el umbral de aproximación para la iteración de Newton

El código se implementa aquí en Java, pero estos métodos principales deberían ser bastante independientes del lenguaje:

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

En este fragmento se proporciona un ejemplo de cómo usar esto para el objetivo descrito en la pregunta: genera un cierto número de puntos en la espiral, con una distancia deseada (¡longitud del arco!) Entre los puntos:

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

Se imprime la distancia real de la longitud del arco de los puntos calculados, y se puede ver que de hecho son equidistantes, con la distancia deseada de la longitud del arco.

Marco13
fuente
0

Estoy luchando con esto también.

Lo que estoy haciendo es mantener constante la velocidad y cambiar la dirección del objeto.

Si hago es que el ángulo (en grados) es igual a la distancia desde el origen, multiplicado por una constante, obtengo una espiral arquímedeca perfecta y agradable. Las constantes más grandes obtienen menos espacio entre las líneas. El único problema es si la velocidad es demasiado alta, entonces salta la pista y se equivoca. así que las espirales más apretadas requieren una velocidad más lenta para trazar de manera confiable.

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

Donde current_distance es el radio dibujado desde la ubicación hasta el punto de generación en píxeles, agarrado por una función del motor que me lo da.

Lo que me está volviendo loco es lo contrario. colocando el objeto en el EXTERIOR y haciéndolo trazar la espiral de Arquímedes HACIA ADENTRO. Mover la partícula de la manera opuesta no funciona. eso solo gira la espiral 180 grados. invertir la dirección da una en sentido horario.

Arrojar
fuente