Gewissensfrage



  • Die Frage wäre jetzt: Wann konkret kommst Du in den Fall rein ?

    Wenn Du die Elemente in der Liste hast sind i.d.r. doch nur allegemeine Routinen angesagt. Wenn das nicht klappt wäre vor einem test durch IDs oder dynamic_cast zu prüfen ob man diese Operationen nicht in eine gruppe schieben kann um diese durch eine Allgemeine Routine aufzurufen.

    Mach mal bitte ein konkretes Beispiel aus Deinem Projekt. Komme gedanklich irgendwie nicht mit. 😕



  • Gut, auf ein Neues! 😉

    Im Wesentlichen handelt es sich schon um die Klassenhierarchie, die ich bereits erwähnt habe:

    +-----------------+
                           | TBoundingVolume |
                           +-----------------+
                                    ^
                                    |
                 +------------------+---------------------+
                 |                                        |
         +-----------------+                      +----------------+
         | TBoundingSphere |                      |  TBoundingBox  |
         +-----------------+                      +----------------+
    

    Aus solchen BoundingVolumes könnte ich nun auf Basis eines vorgegebenen 3DModells einen Baum aus Volumes erzeugen. In etwa so:

    TBoundingVolume *root=new TBoundingSphere();
    TBoundingVolume *node=root->add(TBoundingSphere());
    node->add(TBoundingSphere());
    node=root->add(TBoundingSphere()); 
    node->add(TBoundingSphere()); usw ...
    

    Im obigen Beispiel erzeuge ich z.B. eine Baumstruktur, die sich nur aus BoundingSpheres zusammensetzt (also ein noch verhältnismäßig simples Beispiel)
    Problematisch wird es allerdings, wenn ich einen solchen Baum gegen einen anderen Baum auf Kollisionen hin überprüfen möchte:

    if(root1->testAgainst(root2);) cout<<"root1 und root2 kollidieren!"<<endl;
    else                           cout<<"keine Kollision!"<<endl;
    

    Denn die komplette Logik für den Aufbau und die Verwaltung einer solchen Baumstruktur wurde ja in der Klasse 'TBoundingVolume' implementiert.
    D.h.: Bei Aufruf der Methode
    'virtual bool TBoundingVolume::testAgainst(TBoundingVolume *node)=0', welche sowohl in 'TBoundingSphere' als auch in 'TBoundingBox' implementiert wird, ist dem Objekt auf das die Methode angewandt wird zwar sein eigener Klassentyp bekannt, jedoch der Pointer 'node' gibt lediglich Auskunft darüber, dass eine Kollisionskontrolle mit irgendeinem anderen BoundingVolume durchgeführt werden soll. z.B.:

    bool TBoundingSphere::testAgainst(TBoundingVolume *node)
    {
       //hier: Kollisionskontrolle zwischen Sphere und <unbekannt>
    }
    

    Und genau das ist das Problem! Bei einer Kollisionskontrolle muss genau bekannt sein, welche Volumes überprüft werden (Sphere<->Box,Sphere<->Sphere,Box<->Box,Box<->Sphere). Nur auf alle erforderlichen Parameter der Sphere bzw. der Box, die für die Kollisionskontrolle erforderlich sind, kann nicht zugegriffen werden, solange ich über die Schnittstelle 'TBoundingVolume' gehe. Es müsste also über 'typeid' der Klassentyp ermittelt und ein DownCast durchgeführt werden!

    Nur was es mit den DownCasts auf sich hat, hab ich ja bereits erwähnt! 🙄

    Auf ein derartiges Problem kann man doch jederzeit, unabhängig von meiner konkreten Problemstellung, in Verbindung mit Baumstrukturen stossen.

    Eigentlich sind doch DownCasts nur bei virtuellen Klassen explizit verboten.(Obwohl man's da auch hinkriegt 😉 )
    Wenn in so einem Fall das vorliegende Problem eben nicht über Polymorphismus gelöst werden kann, ist es dann legitim einen DownCast auf eine solche nichtvirtuelle Klasse durchzuführen?

    Wird man für eine solche Vorgehensweise gesteinigt? 😉

    Grüße,
    TS++

    [ Dieser Beitrag wurde am 07.07.2003 um 09:50 Uhr von TS++ editiert. ]



  • Und genau das ist das Problem! Bei einer Kollisionskontrolle muss genau bekannt sein, welche Volumes überprüft werden (Sphere<->Box,Sphere<->Sphere,Box<->Box,Box<->Sphere).

    Falsch. Beim Implementieren einer gemeinsamen Klasse müssen Eigenschaften dieser Objekte bekannt sein, die überall die Gleichen sind.
    Das bedeutet, dass TBoundingVolume nicht wissen muss, ob es sich um eine Sphere oder eine Box handelt. Einzig und allein die Position im 3dimensionalen Raum bleibt übrig, nicht die Form.
    Als Beispiel könnte man ein Objekt 3DRegion bilden, welches sämtliche Volumenelemente (Würfel) enthält. Als Grundlage würde dann hier ein Tree dienen, um das Ganze effizient zu gestalten. Jetzt wird also bei testAgainst nur noch Tree1 mit Volumenelementen gegen Tree2 mit Volumenelementen getestet.



  • Hallo!

    Nur bei Spheres wird die quadrierte Distanz zwischen den beiden Zentralvektoren der betroffenen Spheres und die Summe der Radien herangezogen um eine Kollisionskontrolle durchzuführen.
    ==> erforderlich: Zentralvektor, Radius

    Bei Boxen bedient man sich ja der Ebenengleichung: Ax + By + Cz = d
    Und dies für alle 6 Seiten der Box
    ==> erforderlich: Normalenvektor der Ebene zur innenseite der Box, Abstand der Ebene zum Koordinatenursprung

    Und diese Volumes können nun in 4 unterschiedlichen Varianten aufeinandertreffen. Wie soll ich denn das in eine neutrale VolumesKlasse packen?

    Grüße,
    TS++



  • Kugeln und Quader sind nur spezielle geometrische Objekte, mit denen es aufgrund weniger Parameter und einer simplen Gleichung möglich ist, die Lage im Raum zu bestimmen.
    Wie sieht es denn bei Deiner Kugelformel aus, wenn sie bei 2/3. abgeschnitten wurde?



  • Wie sieht es denn bei Deiner Kugelformel aus, wenn sie bei 2/3. abgeschnitten wurde?

    Ist mir ehrlich gesagt nicht so ganz klar, was du damit meinst!

    Grüße,
    TS++



  • Du suchst scheinbar sowas wie eine virtuelle Methode, die aber anhand von zwei oder mehr Objekten ausgewählt wird. Sowas läuft glaub ich unter dem Stichwort double-dispatching. => Google hilft.



  • du kommst um einen downcast nicht herum. den kannst du aber schick hinter einem visitor mechanismus verstecken.
    dabei abstrahierst du gleichzeitig vom container, und einen baum von aussen zu durchwandern ist ja auch nicht so ganz ohne, und wenn man das in verschiedenen zusammenhaengen macht, hat man einen haufen unuebersichtlicher schleifen, die man nicht braucht.



  • Erstmal: Danke Jester, bin noch am RumGooglen! 😉

    @PeterTheMaster:
    Was meinst du denn bitte genau mit visitor mechanismus?

    Grüße,
    TS++



  • Original erstellt von TS++:
    Was meinst du denn bitte genau mit visitor mechanismus?

    Ich vermute er meint das Visitor Pattern.



  • @all:
    Danke euch für eure Antworten!

    Grüße,
    TS++



  • Nur ein Entwurf, nicht kompiliert und nur 2x durchgelesen 😉
    Erklärung folgt bei Bedarf morgen

    //Funktionen zur Überprüfung der Kollision
    
     bool
    ChckCollision( CGlobe& , CGlobe&);
    
     bool
    ChckCollision( CGlobe& , CCube&);
    
    /* abstrakte Basisklasse für Kollisionsüberprüfungsklassen*/
     class
    CCollisionChecker
    {
    public:
      /** - */
       virtual
       bool
      ChckCollision( CGlobe&) = 0;
    
      /** - */
       virtual
       bool
      ChckCollision( CCube&) = 0;
    };
    
    /* CollisionChecker-Klasse für Vergleiche mit Globes*/
     class
    CGlobeCollisionChecker
    :public CCollisionChecker
    {
       CGlobe&
      m_Globe;
    
    public:
    
      CGlobeCollisionChecker(CGlobe& Globe)
      :m_Globe(Globe)
      {
      }
    
       bool
      ChckCollision( CGlobe& Other)
      {
        ChckCollision( m_Globe, Other);
      }
    
       bool
      ChckCollision( CCube& Other)
      {
        ChckCollision( m_Globe, Other);
      }
    
    };
    
    /* CollisionChecker-Klasse für Vergleiche mit Cubes*/
     class
    CCubeCollisionChecker
    :public CCollisionChecker
    {
       CCube&
      m_Cube;
    
    public:
    
      CGlobeCollisionChecker(CCube& Globe)
      :m_Globe(Globe)
      {
      }
    
       bool
      ChckCollision( CGlobe& Other)
      {
        ChckCollision( m_Cube, Other);
      }
    
       bool
      ChckCollision( CCube& Other)
      {
        ChckCollision( m_Cube, Other);
      }
    
    };
    
    /** Basisklasse für Körper*/
     class
    CGeometricBody
    {
    public:
    
       bool
      ChckCollision( CGeometricBody& OtherBody)
      {
         std::auto_ptr<CCollisionChecker>
        CollisionChecker( GenCollisionChecker());
    
        return OtherBody.PerfCollisionCheck( *CollisionChecker);
      }
    
    protected:
    
       virtual
       std::auto_ptr<CCollisionChecker>
      GenCollisionChecker() = 0;
    
       virtual
       std::auto_ptr<CCollisionChecker>
      PerfCollisionCheck( CCollisionChecker& ) = 0;
    
    };
    
    //Implementationen konkreter Körper
     class
    CGlobe
    :public CGeometricBody
    {
    
    protected:
    
       virtual
       std::auto_ptr<CCollisionChecker>
      GenCollisionChecker()
      {
        return new (CGlobeCollisionChecker(*this));
      }
    
       virtual
       std::auto_ptr<CCollisionChecker>
      PerfCollisionCheck( CCollisionChecker& )
      {
        return CCollisionChecker.ChckCollision(*this));
      }
    
    };
    
    //Implementationen konkreter Körper
     class
    CCube  
    :public CGeometricBody
    {
    
    protected:
    
       virtual
       std::auto_ptr<CCollisionChecker>
      GenCollisionChecker()
      {
        return new (CCubeCollisionChecker(*this));  )
      }
    
       virtual
       std::auto_ptr<CCollisionChecker>
      PerfCollisionCheck( CCollisionChecker& )
      {
        return CCollisionChecker.ChckCollision(*this));
        //bin mir nicht sicher: könnte
        //das nicht auch in die 
        //Basisklasse? (d.h. hat this in
        //der Basisklasse den Typ der
        //der konkreten Ableitung?)
      }
    
    };
    

    [ Dieser Beitrag wurde am 08.07.2003 um 22:31 Uhr von kartoffelsack editiert. ]

    [ Dieser Beitrag wurde am 09.07.2003 um 12:06 Uhr von kartoffelsack editiert. ]



  • Morgen kartoffelsack!

    bool CGeometricBody::ChckCollision( CGeometricBody& secondBody )
    {
        std::auto_ptr<CCollisionChecker> 
        CollisionChecker( GenCollisionChecker());
        return PerfCollisionCheck( *CollisionChecker);
    }
    

    Wo verwertest du denn die Referenz auf den GeometricBody, gegen den getestet werden soll?
    Ich müsste, wenn schon, dann von secondBody einen CollisionChecker anfordern und auf diesen dann 'PerfCollisionCheck' anwenden.

    Ach übrigens:
    (Gehört zwar eigentlich in ein anderes Forum)
    Ich bin jetzt auf ein Konzept zur Kollisionskontrolle gestossen, das es nicht mehr erforderlich macht, den exakten Typen des jeweiligen Volumes zu kennen.
    Nennt sich: Separating Axis Theorem (unter Gamasutra)
    Jedoch was die Effizienz anbelangt, bin ich mir noch nicht so ganz sicher.

    Das DownCast-Problem kann natürlich bei anderen Fallbeispielen, als dem aktuellen, mit diesem Theorem nicht gelöst werden, klar!

    Grüße,
    TS++



  • @TS++
    Zu meinem letzten Beitrag, schau Dir mal das an: http://www-sst.informatik.tu-cottbus.de/~wk/cg_v08b.pdf



  • @TS++
    Jo, hast recht. Habs ausgebessert


Anmelden zum Antworten