アルキメデスのらせんの周りを一定の速度で粒子を移動する


8

粒子をらせん状に一定速度で動かしたい。これは一定の角速度ではないことに注意してください。これはかなり困難であることがわかっているので、ここでは自分の方法について説明します。

問題のスパイラルは、極方程式r = ϑとパラメトリック方程式を使用した古典的なアルキメデスのスパイラルx = t*cos(t), y = t*sin(t)です。これは次のようになります。ここに画像の説明を入力してください

粒子をらせんの周りに移動したいので、単純に、粒子の位置をtの値として、速度をtの増加として与えることができます。このようにして、粒子は一定の角速度でらせんの周りを動きます。ただし、これは、中心から離れるほど、その(非角)速度が速くなることを意味します。

したがって、tの増加に速度を持たせる代わりに、弧の長さの増加として速度を求めます。スパイラルの弧の長さを取得する最初の課題ですが、原因私は使用していアルキメデスの螺旋があまりにも非常識ではないという事実に、弧の長さの関数である。ここでa = 1。これにより、シータ値を円弧長に変換できますが、これは私が必要としているものとは正反対です。したがって、弧長関数の逆を見つける必要があります。そのハードルで、Wolfram-Alphaは失敗しました。

それで、弧長関数の逆を見つけることは可能ですか?シータの負の値を除外する場合、関数は1対1のマッピングです。

おかげで、

ローリー


1
数学のオーバーフローの方が早く答えが得られると思います。GameDevにも関係があります。
deceleratedcaviar

パラメトリックでなければ、これは簡単です。そうでなければなりませんか?
CiscoIPPhone

スパイラルアルキメデスでなければなりませんか?
エンジニア

@Ciscoよく私は極方程式を与えました、そしてそれらはかなり交換可能です
Blue Peppers

@Nickはい:P対数またはリタスは私が望んでいるものではありません
Blue Peppers

回答:


12

あなたのスパイラルを複雑にしましょう:

なる p(t):=(cos(t)・f(t)、sin(t)・f(t))

あなたの場合f(t):= t、私の場合f(t):= 1(だから私は単純化で私の複雑さを返済します:)

この縮退したスパイラル(円)で特定の速度で移動したい場合、1ラウンドのスパイラルの長さを知っておく必要があります。これにより、ポイントが目的の速度で移動することを確実にするために、1秒あたりのラウンド数がわかります。 。

これで、円の完全な各ラウンドが2・π・rの長さであることがわかりました。この場合は2・π・1です。場合ωは回転速度である(秒あたりのラウンドで)速度Vは、あろうV = 2・π・1・ω以上の一般的な方法で。

V = 2・π・r・ω

もしrが一般的半径です。これは私たちにそれを伝えます:

V /(2・π・r)=ω

rがtの関数である場合、次のように言えます。

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

私の「複雑な」ケースでは、これは次のように書き換えることができます。

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

あなたの「単純化された」ケースでは、答えは:

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

あなたはあなたの望まれる一定の速度Vを知っています、あなたは知っています:2、πtはあなたの変数です:あなたはすべてを知っていて、あなたは行く準備ができています!

tのスパイラルの微小近傍の円近似

tにおけるスパイラルの微小近傍の円近似

[免責事項]

これは厳密な数学的処理を意図したものではありません。fの微分の寄与を考慮に入れておらず、使用できない関数のタイプについても述べていません。


したがって、最後の方程式を使用してw(t)を解いてから、それを元のパラメトリック方程式に入れて、粒子の位置を取得します。それは正しいですか。
CiscoIPPhone

ああ、これは本当に素晴らしい答えです。また、tの代わりにf(t)を使用しているため、このソリューションが機能している状態でスパイラルを変更できます。どうもありがとうございました。
ブルーペッパー

@CiscoIPPhone w(t)は回転速度であり、時間の経過とともにtにどれだけ加算されるかを示し、tを使用して位置を取得します。
FxIII

免責事項で述べた@Blue Peppersはすべてのf(t)に当てはまるわけではなく、f(t)がゆっくりと移動する場合(そして微分可能)に機能します
FxIII

2

かなり正確になる仮定が気にならない場合は、この単純なソリューションが非常にうまく機能します。

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

これは時間的にパラメトリックであり、非常に便利です。ただし、これを取得するには、モーションがほぼ円形であると想定する必要がありました。瞬時線速度は、半径と角速度の積に比例します。

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

ソリューションが機能することを示すには、次のようにプラグインします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、これsqrt(2)は原点から離れた位置にポイントを配置します。この後、近似は大幅に改善されます。後続のポイント間の分離(パスに沿ってではなく線形)は1.13、1.08、1.06です。100ポイント後、分離は1.0023未満になります。


0

特定の弧の長さに対応する角度を計算するソリューションを探しているときに、私はこの質問と現在の答えに出会いました。残念ながら、この回答も、ウェブ上で見つけた他のリソースも、実装に直接使用することはできませんでした。

明らかに、(質問でも提供された)弧長関数の逆を計算することは非常に困難です。しかし、ニュートン反復法を使用してこの逆数の近似が可能です。以下は、主に2つのメソッドを提供するクラスです。

  • computeArcLength(double alpha, double angleRad)alpha連続する方向転換の間の距離であるアルキメデスのらせん上の点の弧の長さを計算します。angleRadする回転はラジアン単位の角度です
  • computeAngle(double alpha, double arcLength, double epsilon):指定された弧の長さの点がアルキメデスのらせん上にある角度を計算します。ここalphaで、は連続する回転間の距離epsilonであり、ニュートン反復の近似しきい値です

コードはここでJavaで実装されていますが、これらのコアメソッドは言語にとらわれないものである必要があります。

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

質問で説明されている目標にこれを使用する方法の例は、次のスニペットに示されています。これは、スパイラル上に特定の数のポイントを生成し、ポイント間の望ましい(アーク長!)距離を指定します。

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

計算された点の実際の弧長距離が出力され、実際には、それらが望ましい弧長距離で等距離にあることがわかります。


0

私もこれで苦労しています。

私がやっていることは、速度を一定に保ち、オブジェクトの方向を変えることです。

角度(度単位)が原点からの距離に定数を掛けたものに等しい場合、私は素晴らしい完璧なアルキメデスのらせんを作成します。定数が大きいほど、行間のスペースが少なくなります。唯一の問題は、速度が速すぎると、トラックをジャンプしてめちゃくちゃになることです。スパイラルがきつくなると、トレースを確実に行うために低速が必要になります。

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

ここで、current_distanceは、ロケーションからスポーンポイントまで描画された半径(ピクセル単位)であり、これを取得するエンジン関数によって取得されます。

私を壁に押し上げているのはその逆です。オブジェクトを外側に配置し、アルキメデスの螺旋の内側をトレースします。パーティクルを反対方向に移動しても機能しません。スパイラルを180度回転させるだけです。方向を反転すると時計回りになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.