Movendo uma partícula em torno de uma espiral arquimediana a uma velocidade constante


8

Eu quero mover uma partícula em espiral a uma velocidade constante. Observe que essa não é uma velocidade angular constante. Isso está se mostrando um pouco difícil, e vou seguir meu método até agora.

A espiral em questão é uma espiral arquimediana clássica com a equação polar r = ϑe as equações paramétricas x = t*cos(t), y = t*sin(t). É assim:insira a descrição da imagem aqui

Eu quero mover uma partícula ao redor da espiral, de forma tão ingênua, que eu possa apenas dar a posição da partícula como o valor de t, e a velocidade como o aumento em t. Dessa forma, a partícula se move em volta da espiral a uma velocidade angular constante. No entanto, isso significa que, quanto mais distante fica do centro, mais rápida se torna sua velocidade (não angular).

Então, em vez de ter minha velocidade no aumento em t, quero minha velocidade como o aumento no comprimento do arco. Conseguir o comprimento do arco de uma espiral é o primeiro desafio, mas devido ao fato de que a espiral arquimediana que estou usando não é muito insana, a função de comprimento do arco é onde a = 1. Isso me permite converter valores teta no comprimento do arco, mas esse é exatamente o oposto do que eu preciso. Então, preciso encontrar a inversa da função de comprimento do arco e, nesse obstáculo, o Wolfram-Alpha falhou comigo.

Então, é possível encontrar o inverso da função de comprimento do arco? A função é um mapeamento individual, se você excluir valores negativos de teta.

Obrigado,

Laurie


11
Eu acho que você obterá uma resposta mais rápida em excesso de matemática. É relevante para o GameDev.
Deceleratedcaviar

Isso seria mais fácil se não fosse paramétrico - precisa ser?
CiscoIPPhone

A espiral precisa ser arquimediana?
coordenador

@Cisco Bem, eu dei a equação polar, e eles são praticamente intercambiáveis
Azul Pimentas

@ Nick Sim: P logarítmica e / ou lituus não é o que eu quero
Azul Pimentas

Respostas:


12

Vamos complicar sua espiral:

estar p (t): = (cos (t) · f (t), sen (t) · f (t))

no seu caso f (t): = t, no meu f (t): = 1 (então eu pago minhas complicações com simplificações :)

Se você deseja ir a uma certa velocidade nesta espiral degenerada (um círculo), você precisa saber quanto tempo dura sua espiral em uma rodada, para poder dizer quantas rodadas por segundo fazem para ter certeza de que seu ponto viaja com a velocidade desejada .

Agora sabemos que cada rodada completa em um círculo tem 2 · π · r long: 2 · π · 1 no nosso caso; se ω é a velocidade de rotação (em rodadas por segundo), a velocidade V será V = 2 · π · 1 · ω ou de uma maneira mais geral:

V = 2 · π · r · ω

se r é o raio geral; isso nos diz que:

V / (2 · π · r) = ω

se r é uma função de t, podemos dizer:

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

no meu caso "complicado", isso pode ser reescrito da seguinte maneira:

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

no seu caso "simplificado", a resposta é:

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

Você sabe que sua velocidade constante desidered V, você sabe: 2, π e t é a variável: você sabe tudo e você está pronto para ir!

aproximação do círculo para a vizinhança infinitesimal da espiral em t

a aproximação do círculo para a vizinhança infinitesimal da espiral em t

[AVISO LEGAL]

Não se pretende que este seja um tratamento matemático rigoroso: não leva em consideração a contribuição do diferencial de f nem diz que tipos de função não podem ser utilizados.


Então, usando a última equação que você resolve para w (t) e a coloca na equação paramétrica original para obter a posição da partícula, está correto?
CiscoIPPhone

Oh, esta é realmente uma excelente resposta. E devido ao uso de f (t) em vez de t, podemos modificar nossa espiral com esta solução ainda funcionando. Muito obrigado.
Blue Peppers

O @CiscoIPPhone w (t) é a velocidade de rotação, informa quanto aumenta o seu t com o passar do tempo e, em seguida, use t para obter a posição.
FxIII 03/09/11

Pimentas @Blue como eu disse na declaração não é verdade para todos os f (t), ele funciona se f (t) se move lentamente (e é diferenciável)
FXIII

2

Se você não se importa com uma suposição que é bastante precisa rapidamente, esta solução simples funciona muito bem:

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

Isso é paramétrico no tempo, o que é bastante útil. No entanto, para conseguir isso, eu precisava assumir que o movimento é aproximadamente circular - ie. a velocidade linear instantânea é proporcional ao raio vezes a velocidade angular:

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

Para mostrar que a solução funciona, conecte-o 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.

Em {time}=1, isso coloca um ponto à distância sqrt(2)da origem. Depois disso, a aproximação melhora significativamente: a separação (linear, não ao longo do caminho) entre os pontos subsequentes é 1,13, 1,08, 1,06. Após 100 pontos, a separação é menor que 1,0023.


0

Enquanto procurava uma solução para calcular o ângulo que corresponde a um determinado comprimento de arco, deparei-me com esta pergunta e a resposta atual. Infelizmente, nem essa resposta nem qualquer outro recurso que eu encontrei na Web podem ser usados ​​diretamente para uma implementação.

Obviamente, calcular a inversa da função de comprimento do arco (que também foi fornecida na pergunta) é muito difícil. Mas uma aproximação deste inverso usando o Método Iterativo de Newton é possível. A seguir, é uma classe que oferece principalmente dois métodos:

  • computeArcLength(double alpha, double angleRad): Calcula o comprimento do arco de um ponto na Espiral Arquimediana, onde alphaestá a distância entre rotações sucessivas e angleRadé o ângulo em radianos
  • computeAngle(double alpha, double arcLength, double epsilon): Calcula o ângulo no qual o ponto para o comprimento de arco especificado está localizado na Espiral Arquimediana, onde alphaestá a distância entre as rotações sucessivas e epsiloné o limiar de aproximação para a Iteração de Newton

O código é implementado aqui em Java, mas esses métodos principais devem ser bastante independentes da linguagem:

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

Um exemplo de como usar isso para o objetivo descrito na pergunta é dado neste trecho: ele gera um certo número de pontos na espiral, com uma distância desejada (comprimento do arco!) Entre os pontos:

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

A distância real do comprimento do arco dos pontos computados é impressa e pode-se ver que eles são de fato equidistantes, com a distância desejada do comprimento do arco.


0

Também estou lutando com isso.

O que estou fazendo é manter a velocidade constante e mudar a direção do objeto.

Se eu fizer assim o ângulo (em graus) é igual à distância da origem, vezes uma constante, recebo uma espiral arquimediana perfeita e agradável. constantes maiores obtêm menos espaço entre as linhas. O único problema é que, se a velocidade for muito alta, ela pula a pista e atrapalha. espirais mais apertadas requerem uma velocidade mais lenta para serem rastreadas com segurança.

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

Onde current_distance é o raio traçado do local para o ponto de desova em pixels, agarrado por uma função de mecanismo que me fornece isso.

O que está me levando até a parede é o inverso. colocando o objeto no lado de fora e traçando a espiral arquimediana para dentro. Mover a partícula para o lado oposto não funciona. que apenas gira a espiral em 180 graus. inverter a direção dá uma no sentido horário.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.