Zufällige 3D Vektoren innerhalb einer Kugel



  • Ich habe jetzt nicht alle Post gelesen daher könnte es sein, dass mein Vorschlag schon gesagt wurde.

    Man kann doch jedem Punkt in einer Kugel mit 2 Winkeln und einem Skalar genau beschreiben. Daher müsste man doch nur 2 Zufallszahlen zwischen 0 und 360 erstellen und eine Zufallszahl zwischen 0 und r und damit wäre man fertig.



  • bliblablid schrieb:

    Ich habe jetzt nicht alle Post gelesen daher könnte es sein, dass mein Vorschlag schon gesagt wurde.

    Ja, gleich als erste Antwort.



  • Ich habe dein Verfahren, SeppJ, leider nicht verstanden, denn wir haben Integralrechnung in der Schule auch noch nicht gemacht. Es wäre schön, wenn mir das jemand programmieren könnte.

    Grüße



  • pumuckl schrieb:

    KLar, nur wirfst du beim vorliegenden Fall, wo der innenradius = 1/2 Außenradius der Kugelschale ist, knapp 46% der Ergebnisse weg 😉

    Richtig. Aber wer sagt, dass das schlimm ist? Wenn am Anfang zur Initialisierung die Kugel in 2,17 ms statt in 1 ms mit zufälligen Punkten gefüllt wird, wen interessiert das?
    Wenn das zu langsam ist, kann man sich immer noch was besseres ausdenken.



  • Muss es denn tatsächlich eine exakte Gleichverteilung in einer Kugel sein? Ich mein, die Sterne am Nachthimmel sind jetzt auch nicht wirklich gleichverteilt, sogar ziemlich weit davon entfernt...



  • Naja, es sollten zumindest nirgens Lücken zu sehen sein. 🙂



  • Wie wär's mit nem Würfel + Sichtschutz? 🙂



  • Würde das nicht alles ein bisschen komisch aussehen? Je nach Maßstab sollten Sterne entweder praktisch unendlich weit weg sein oder du mitten durch düsen. Eine relativ begrenzte Schale von Sternen, die das das Spielgebiet umschließt, würde dagegen doch mit Sicherheit auffallen.



  • Im Moment sind die Sterne mittendrin im Bereich, in dem sich das Raumschiff bewegen soll. Sieht eigentlich gut aus, bis auf die Tatsache, dass man zu den Kugeln hinfliegen kann und die dann halt sieht.

    Bedenken habe ich da keine.



  • Wenn dein Rauschiff sich nur in einem begrenzen Bereich befindet und die nächsten Sterne nicht erreichen kann, dann ist die Näherung, dass alle Sterne unendlich weit entfernt sind, einiges realistischer. Die Lösung dafür ist einfach: Male das Bild der umgebenden Galaxis auf eine Kugelschale und projiziere die in entsprechend großem Abstand um dein Raumschiff. Und zwar so, dass es sich immer im Mittelpunkt der Kugel befindet.



  • @pumuckl:
    Ich glaube das nennt man Skybox 🙂


  • Mod

    314159265358979 schrieb:

    Ich habe dein Verfahren, SeppJ, leider nicht verstanden, denn wir haben Integralrechnung in der Schule auch noch nicht gemacht. Es wäre schön, wenn mir das jemand programmieren könnte.

    Ich habe im Moment gerade nicht die Mittel grossartig zu coden und an meinen schon fertigen Code fuer das Kugelproblem komme ich von hier gerade auch nicht dran. Wenn es dir morgen reicht, dann kann ich es dann machen, falls ich dran denke.



  • Alles klar. Alleine, dass du mir deinen 10000ten Post widmest, ist mir eine Ehre 😉



  • Das einfachste ist natürlich X/Y/Z aus einem die Kugel umschließenden Würfel gleichverteilt zu ziehen und das solange zu wiederholen, bis der Radius passt.

    Sonst könnte man das vielleicht noch so machen:
    Richtung und Radius unabhängig ziehen.

    Gleichverteilte Richtung:
    X/Y/Z/ Gauß-verteilt ziehen und normalisieren

    Radius ziehen:
    Die Wahrscheinlichkeitsdichte für den Radius muss mit dem Radius quadratisch zunehmen, also:
    P(r) \propto r^2
    da die Kugeloberfläche ja mit dem Radius auch quadratisch zunimmt. Sonst bekommt man hinterher keine Gleichverteilung.



  • Das grundsätzliche Problem bei dieser Aufgabe ist, dass der Gültigkeitsbereich (und damit auch das Maximum) jeder Dimension sich in Abhängigkeit von den Werten der anderen zwei Dimensionen ergibt.
    Ich habe zwar nichts von dem verstanden, was SeppJ erklärt hat, aber aus dem genannten Grund sehe ich keine andere Möglichkeit als den Würfel.



  • krümelkacker schrieb:

    Radius ziehen:
    Die Wahrscheinlichkeitsdichte für den Radius muss mit dem Radius quadratisch zunehmen, also:
    P(r) \propto r^2
    da die Kugeloberfläche ja mit dem Radius auch quadratisch zunimmt. Sonst bekommt man hinterher keine Gleichverteilung.

    Wie bastelt man das dann im Endeffekt? Wenn Radius zwischen r1 und r2 liegen soll: Kann man einfach gleichverteilt zwischen r1*r2 und r2*r2 ziehen und daraus die Wurzel als Radius nehmen? Müsste doch eine quadratische Verteilung ergeben.



  • [Rewind] schrieb:

    Das grundsätzliche Problem bei dieser Aufgabe ist, dass der Gültigkeitsbereich (und damit auch das Maximum) jeder Dimension sich in Abhängigkeit von den Werten der anderen zwei Dimensionen ergibt.

    Nur wenn du mit X/Y/Z Koordinaten rechnest.
    Wenn du dagegen mit Kugelkoordinaten (quasi Längengrad/Breitengrad/Radius) rechnest, dann sind alle drei Werte unabhängig.

    Einer der Winkel hat immer den Bereich [0°...180°), der andere immer [0...360°), und der Radius eben immer [0...Radius].

    Wenn du dann noch wie krümelkacker & SeppJ beschreiben haben die Verteilung anpasst, dann bekommst du auch Punkte raus, die im X/Y/Z Raum gleichverteilt sind.



  • fdfdg schrieb:

    krümelkacker schrieb:

    Radius ziehen:
    Die Wahrscheinlichkeitsdichte für den Radius muss mit dem Radius quadratisch zunehmen, also:
    P(r) \propto r^2
    da die Kugeloberfläche ja mit dem Radius auch quadratisch zunimmt. Sonst bekommt man hinterher keine Gleichverteilung.

    Wie bastelt man das dann im Endeffekt? Wenn Radius zwischen r1 und r2 liegen soll: Kann man einfach gleichverteilt zwischen r1*r2 und r2*r2 ziehen und daraus die Wurzel als Radius nehmen? Müsste doch eine quadratische Verteilung ergeben.

    Stell eine Wahrscheinlichkeitsdichte Proportional zu r^2 auf und bestimme den Faktor mit der Bedingung, dass das Integral der Dichte von r1 bis r2 gleich 1 wird. Dann wendet man die Inversionsmethode an.

    http://de.wikipedia.org/wiki/Inversionsmethode



  • µ schrieb:

    fdfdg schrieb:

    krümelkacker schrieb:

    Radius ziehen:
    Die Wahrscheinlichkeitsdichte für den Radius muss mit dem Radius quadratisch zunehmen, also:
    P(r) \propto r^2
    da die Kugeloberfläche ja mit dem Radius auch quadratisch zunimmt. Sonst bekommt man hinterher keine Gleichverteilung.

    Wie bastelt man das dann im Endeffekt? Wenn Radius zwischen r1 und r2 liegen soll: Kann man einfach gleichverteilt zwischen r1*r2 und r2*r2 ziehen und daraus die Wurzel als Radius nehmen? Müsste doch eine quadratische Verteilung ergeben.

    Stell eine Wahrscheinlichkeitsdichte Proportional zu r^2 auf und bestimme den Faktor mit der Bedingung, dass das Integral der Dichte von r1 bis r2 gleich 1 wird. Dann wendet man die Inversionsmethode an.

    http://de.wikipedia.org/wiki/Inversionsmethode

    Oder kurz: Ja, das stimmt so, fdfdg. Bis auf den Typo und die exakten Exponenten halt 🙂

    Wen es interessiert, hab hier kurz was gebastelt: http://ideone.com/IsAj2



  • otze schrieb:

    Für manche Dinge braucht es nicht C++11 sondern einfache Mathematik.

    genau .. und es kommt öfter vor, als man denkt 😉

    Folgender Code sollte in etwa das sein, was PI braucht. Er sollte Positionen in einer Kugelschale zwischen zwei gegebenen Radien R1 und R2 erzeugen, die im Volumen annähernd gleich verteilt sind.

    Im Gegensatz zu pumuckl und fdfdg bin ich aber der Meinung, dass man beim Radius die 3.Potenz nehmen muss, da der Radius im Volumen mit der 3.Potenz eingeht. Bei einer Kugelschale mit den Innenradius 1 und Außenradius 2 befinden sich 50% des Volumens jenseits eines Radius von ca. 1,651 bzw. = 3.Wurzel( 1 + (2^3 - 1^3)/2 ).

    #include <boost/random/uniform_real.hpp>
    #include <boost/random/linear_congruential.hpp> // minstd_rand
    
    #include <iostream>
    #include <cmath>
    
    class Vector // nur für Demozwecke
    {
    public:
        typedef double value_type;
        Vector( double x, double y, double z )
            : m_x(x), m_y(y), m_z(z)
        {}
        friend Vector operator*( double factor, const Vector& v )
        {
            return Vector( v.m_x * factor, v.m_y * factor, v.m_z * factor );
        }
        friend double abs( const Vector& v )
        {
            return std::sqrt( v.m_x * v.m_x + v.m_y * v.m_y + v.m_z * v.m_z );
        }
        friend std::ostream& operator<<( std::ostream& out, const Vector& v )
        {
            return out << v.m_x << " " << v.m_y << " " << v.m_z;
        }
    private:
        double m_x, m_y, m_z;
    };
    
    namespace
    {
        const double PI = std::acos(-1.0);
    } 
    
    // -- Verteilung zur Generierung eines 'gleichverteilten' Einheitsvektors
    template< typename V, typename T = typename V::value_type >
    class Sphere
    {
    public:
        typedef T input_type;
        typedef V result_type;
    
        Sphere() 
            : m_sin_phi( -1., +1. )
            , m_beta( -PI, PI )
        {}
        template< typename G >
        result_type operator()( G& gen )
        {
            using std::cos;
            using std::sin;
            using std::sqrt;
            // siehe auch http://de.wikipedia.org/wiki/Kugelkalotte
            const T sin_phi = m_sin_phi( gen ); // sin( Breitengrad ) ist gleichverteilt, da H=2*PI*sin(phi)
            const T cos_phi = sqrt( 1 - sin_phi*sin_phi );
            const T beta = m_beta( gen ); // Längenwinkel
            return result_type( cos( beta )*cos_phi, sin( beta )*cos_phi, sin_phi );
        }
    private:
        boost::uniform_real< T > m_sin_phi;
        boost::uniform_real< T > m_beta;
    };
    
    // --   Verteilung zur Generierung eines Radius im Intervall [x0, x1)
    //      mit dem Ziel im Volumen einer Kugelschale eine 'Gleichverteilung' zu erreichen
    template< typename T >
    class Cubic
    {
    public:
        typedef T input_type;
        typedef T result_type;
        Cubic( result_type x0, result_type x1  )
            : m_distribution3( x0 * x0 *x0, x1 * x1 * x1 )
        {}
        template< typename G >
        result_type operator()( G& gen )
        {
            using std::pow;
            return pow( m_distribution3( gen ), result_type( 1/3. ) );
        }
    private:
        boost::uniform_real< T > m_distribution3;
    };
    
    int main()
    {
        using namespace std;
        const double R1 = 1.5;
        const double R2 = 4;
        boost::minstd_rand gen;
        Sphere< Vector > sphere;
        Cubic< double > cubic( R1, R2 );
        cout << fixed;
        cout.precision( 2 ); // 2 NK reichen hier
        for( int i=0; i<20; ++i )
        {
            Vector pos = cubic( gen ) * sphere( gen );
            cout << pos << "  " << abs(pos) << endl;
        }
        return 0;
    }
    

    Gruß
    Werner

    @Edit: in den Zeilen 42 und 58 den Typ 'Vector' gegen das Template-Argument V bzw. result_type ersetzt


Anmelden zum Antworten