Memindahkan partikel di sekitar spiral Archimedean dengan kecepatan konstan


8

Saya ingin memindahkan partikel dalam spiral dengan kecepatan konstan. Perhatikan bahwa itu bukan kecepatan sudut konstan. Ini terbukti agak sulit, dan saya akan melewati metode saya sejauh ini di bawah.

Spiral yang dimaksud adalah spiral Archimedean klasik dengan persamaan kutub r = ϑ, dan persamaan parametrik x = t*cos(t), y = t*sin(t). Ini terlihat seperti ini:masukkan deskripsi gambar di sini

Saya ingin memindahkan partikel di sekitar spiral, dengan sangat naif, saya hanya bisa memberikan posisi partikel sebagai nilai t, dan kecepatan seiring peningkatan t. Dengan begitu partikel bergerak mengelilingi spiral dengan kecepatan sudut konstan. Namun, ini berarti bahwa semakin jauh dari pusatnya, semakin cepat (non-sudut) kecepatannya.

Jadi, alih-alih memiliki kecepatan saya dalam peningkatan t, saya ingin kecepatan saya sebagai peningkatan panjang busur. Mendapatkan panjang busur spiral adalah tantangan pertama, tetapi karena fakta bahwa spiral Archimedean yang saya gunakan tidak terlalu gila, fungsi panjang arc adalah , di mana a = 1. Ini memungkinkan saya untuk mengkonversi nilai theta ke panjang busur, tetapi itu adalah kebalikan dari apa yang saya butuhkan. Jadi saya perlu menemukan kebalikan dari fungsi panjang busur, dan pada rintangan itu, Wolfram-Alpha telah mengecewakan saya.

Jadi apakah mungkin untuk menemukan kebalikan dari fungsi panjang busur? Fungsi ini pemetaan satu ke satu, jika Anda mengecualikan nilai negatif theta.

Terima kasih,

Laurie


1
Saya pikir Anda akan mendapatkan jawaban lebih cepat pada matematika overflow. Ini relevan untuk GameDev.
decaviatedcaviar

Ini akan lebih mudah jika bukan parametrik - haruskah demikian?
CiscoIPPhone

Apakah spiral harus menjadi Archimedean?
Insinyur

@Cisco Yah saya memberikan persamaan kutub, dan mereka cukup banyak dipertukarkan
Blue Peppers

@Nick Ya: P Logaritmik dan / atau lituus bukan yang saya inginkan
Blue Peppers

Jawaban:


12

Mari menyulitkan spiral Anda:

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

dalam kasus Anda f (t): = t, di tambang f (t): = 1 (jadi saya membayar kembali komplikasinya dengan penyederhanaan :)

Jika Anda ingin melaju pada kecepatan tertentu dalam spiral degenerasi ini (sebuah lingkaran), Anda harus tahu berapa lama spiral Anda dalam satu putaran sehingga Anda dapat mengatakan berapa putaran per detik yang dilakukan untuk memastikan bahwa titik Anda bergerak dengan kecepatan yang diinginkan .

Sekarang kita tahu bahwa setiap putaran lengkap dalam lingkaran adalah 2 · π · r panjang: 2 · π · 1 dalam kasus kami; jika ω adalah kecepatan revolusi (dalam putaran per detik) kecepatan V akan menjadi V = 2 · π · 1 · ω atau dengan cara yang lebih umum:

V = 2 · π · r · ω

jika r adalah jari-jari umum; ini memberitahu kita bahwa:

V / (2 · π · r) = ω

jika r adalah fungsi dari t kita dapat mengatakan:

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

dalam kasus "rumit" saya ini dapat ditulis ulang sebagai berikut:

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

dalam kasus "disederhanakan" jawabannya adalah:

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

Anda tahu kecepatan konstan V yang ditentukan, Anda tahu: 2, π dan t adalah variabel Anda: Anda tahu segalanya dan Anda siap untuk pergi!

perkiraan lingkaran untuk lingkungan sangat kecil dari spiral di t

perkiraan lingkaran untuk lingkungan sangat kecil dari spiral di t

[PENOLAKAN]

Ini tidak dimaksudkan untuk menjadi perlakuan matematika yang ketat: tidak memperhitungkan kontribusi perbedaan f atau mengatakan jenis fungsi apa yang tidak dapat digunakan.


Jadi menggunakan persamaan terakhir yang Anda selesaikan untuk w (t) dan kemudian memasukkannya ke dalam persamaan parametrik asli untuk mendapatkan posisi partikel, apakah itu benar?
CiscoIPPhone

Oh, ini benar-benar jawaban yang bagus. Dan karena penggunaan f (t) alih-alih t, kita dapat memodifikasi spiral kita dengan solusi ini masih berfungsi. Terima kasih banyak.
Blue Peppers

@CiscoIPPhone w (t) adalah kecepatan rotasi, ia memberi tahu Anda berapa banyak t yang ditambahkan saat waktu berlalu, lalu gunakan t untuk mendapatkan posisi.
FxIII

@Blue Peppers seperti yang saya katakan di disclaimer tidak benar untuk setiap f (t), itu bekerja jika f (t) bergerak perlahan (dan dapat dibedakan)
FxIII

2

Jika Anda tidak keberatan dengan asumsi yang menjadi cukup akurat dengan cepat, solusi sederhana ini berfungsi dengan baik:

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

Ini adalah parametrik dalam waktu, yang cukup berguna. Namun, untuk mendapatkan ini, saya perlu mengasumsikan bahwa gerakan itu kira-kira melingkar - yaitu. kecepatan linear sesaat sebanding dengan jari-jari kali kecepatan sudut:

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

Untuk menunjukkan bahwa solusinya berfungsi, hubungkan ke 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.

Pada {time}=1, ini menempatkan titik pada jarak sqrt(2)dari asal. Setelah ini, perkiraan meningkat secara signifikan: pemisahan (linier, tidak di sepanjang jalan) antara titik-titik berikutnya adalah 1,13, 1,08, 1,06. Setelah 100 poin pemisahannya kurang dari 1,0023.


0

Sambil mencari solusi menghitung sudut yang sesuai dengan panjang busur tertentu, saya menemukan pertanyaan ini dan jawaban saat ini. Sayangnya, baik jawaban ini maupun sumber daya lain yang saya temukan di web tidak dapat langsung digunakan untuk implementasi.

Jelas, menghitung kebalikan dari fungsi panjang busur (yang juga disediakan dalam pertanyaan) sangat sulit. Tetapi perkiraan inversi ini menggunakan Metode Iteratif Newton dimungkinkan. Berikut ini adalah kelas yang terutama menawarkan dua metode:

  • computeArcLength(double alpha, double angleRad): Menghitung panjang busur titik pada Archimedean Spiral di mana alphajarak antara putaran yang berurutan, dan angleRadmerupakan sudut dalam radian
  • computeAngle(double alpha, double arcLength, double epsilon): Menghitung sudut di mana titik untuk panjang busur yang diberikan terletak pada Archimedean Spiral, di mana alphajarak antara putaran yang berurutan, dan epsilonmerupakan ambang perkiraan untuk Iterasi Newton

Kode ini diterapkan di sini di Jawa, tetapi metode inti ini harus cukup agnostik-bahasa:

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

Contoh cara menggunakan ini untuk tujuan yang dijelaskan dalam pertanyaan diberikan dalam cuplikan ini: Ini menghasilkan sejumlah titik pada spiral, dengan jarak yang diinginkan (panjang busur!) Antara titik-titik:

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

The aktual panjang busur jarak poin dihitung dicetak, dan satu dapat melihat bahwa mereka sebenarnya berjarak sama, dengan yang diinginkan panjang busur kejauhan.


0

Saya berjuang dengan ini juga.

Apa yang saya lakukan adalah menjaga kecepatan konstan, dan mengubah arah objek.

Jika saya membuatnya sudut (dalam derajat) sama dengan jarak dari titik asal, kali konstan, saya mendapatkan spiral archimedean sempurna yang bagus. konstanta yang lebih besar mendapatkan lebih sedikit ruang di antara garis. Satu-satunya masalah adalah jika kecepatannya terlalu tinggi, maka lompatan trek dan mengacaukan. jadi spiral yang lebih rapat membutuhkan kecepatan yang lebih lambat untuk dapat diandalkan.

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

Di mana current_distance adalah jari-jari yang digambar dari lokasi ke titik spawn dalam piksel, diraih oleh fungsi mesin yang memberikannya kepada saya.

Apa yang mendorong saya ke atas tembok adalah kebalikannya. menempatkan objek di luar dan setelah itu menelusuri spiral Archimedean INWARDS. Memindahkan partikel dengan cara sebaliknya tidak bekerja. yang hanya memutar spiral 180 derajat. membalikkan arah memberi arah searah jarum jam.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.