Typové informace v knihovně Open Inventor

V jazyce C++ si rozsáhlé knihovny sami vytvářejí informace o svých typech (a každá knihovna používá odlišné datové struktury pro typové informace)

Předvedeme si typové informace na příkladu třírozměrných objektů zobrazovaných pomocí knihovny Open Inventor nebo Coin3D

Instalace a první pokus

Jednoduchá scéna

Vytvoříme scénu obsahující kužel, kouli a krychli.
Výsledek je vidět na obrázku na konci kapitoly spolu se stromem objektů.

  • group1 je větev stromu zobrazující červený kužel
  • pod group1 je shift1, posun o 2 jednotky doleva
  • níže je redMaterial
  • a pod ním je cone (který by sám byl šedý)
void MainWindow::simpleScene (SoSeparator * top)
{
    // cone
    SoSeparator * group1 = new SoSeparator;
 
    SoTransform * shift1 = new SoTransform;
    shift1->translation.setValue (-2.0, 0.0, 0.0);
    group1->addChild (shift1);
 
    SoMaterial * redMaterial = new SoMaterial;
    redMaterial->diffuseColor.setValue (1.0, 0.0, 0.0);
    group1->addChild (redMaterial);
 
    SoCone * cone = new SoCone ();
    group1->addChild (cone);
 
    top->addChild (group1);
 
    // sphere
    SoSeparator * group2 = new SoSeparator;
 
    SoMaterial * greenMaterial = new SoMaterial;
    greenMaterial->diffuseColor.setValue (0.0, 1.0, 0.0);
    group2->addChild (greenMaterial);
 
    SoSphere * sphere = new SoSphere ();
    group2->addChild (sphere);
 
    top->addChild (group2);
 
    // cube
    SoSeparator * group3 = new SoSeparator;
 
    SoTransform * shift3 = new SoTransform ();
    shift3->translation.setValue (1.6, 0.0, 1.6);
    shift3->scaleFactor.setValue (0.7, 0.7, 0.7);
    group3->addChild (shift3);
 
    SoMaterial * blueMaterial = new SoMaterial;
    blueMaterial->diffuseColor.setValue (0.0, 0.0, 1.0);
    group3->addChild (blueMaterial);
 
    SoCube * cube = new SoCube ();
    group3->addChild (cube);
 
    top->addChild (group3);
}

Strom zobrazující strukturu grafických objektů

Objekty naší grafické scény scény jsou odvozeny ze z třídy SoNode
Pro každou instanci SoNode vytvoříme branch typu TreeItem, která bude zobrazena ve stromy typu QTreeWidget na levé straně okna.
Třída TreeItem je rošířením QTreeWidgetItem o položku node typu SoNode

class TreeItem : public QTreeWidgetItem
{
public:
    SoNode * node;
};

Z objektu typu SoNode získáme typové informace poskytované knihovnou OpenInventor

    SoType type = node->getTypeId ();

Z typových informací získáme jméno skutečného typu objektu

    type.getName().getString()

Zajímalo by nás, zda objekt typy SoNode není také odvozeného typu SoGroup, který umí skladovat podřízené prvky typu SoNode

Zda SoNode je také SoGroup můžeme zjistit z typových informací

    if ( type.isDerivedFrom ( SoGroup::getClassTypeId() ) )

Také můžeme použít dynamic_cast a otestovat zda výsledek není nulový ukazatel

    SoGroup * group = dynamic_cast <SoGroup *> (node);

Pokud je objekt typy SoGroup získáme jednotlivé prvky a opět je zobrazíme v Qt stromu

       int count = group->getNumChildren ();
       for (int i = 0; i < count; i++)
       {
           SoNode * sub_node = group->getChild (i);
           displayBranch (branch, sub_node);
       }

Celá funkce displayBranch rekuzivně zobrazující strom objektů pro zadané node typu SoNode

void MainWindow::displayBranch (QTreeWidgetItem * target, SoNode * node)
{
    TreeItem * branch = new TreeItem;
    branch->node = node;
 
    SoType type = node->getTypeId ();
    branch->setText (0, type.getName().getString());
 
    if ( type.isDerivedFrom ( SoGroup::getClassTypeId() ) )
    {
       SoGroup * group = dynamic_cast <SoGroup *> (node);
       int count = group->getNumChildren ();
       for (int i = 0; i < count; i++)
       {
           SoNode * sub_node = group->getChild (i);
           displayBranch (branch, sub_node);
       }
    }
 
    target->addChild (branch);
}

Zobrazení atributů grafického objektu na základě typových informací

Pokud “klikneme” na uzel ve stromu na levé straně okna, zobrazíme parametry grafického objektu v tabulce na pravé straně.

Pomocí dynamic_cast ověříme, že uzel stromu je našeho typy TreeItem a v něm nalezneme node typu SoNode

void MainWindow::on_tree_itemActivated (QTreeWidgetItem * param, int column)
{
   TreeItem * item = dynamic_cast <TreeItem *> (param);
   if (item != nullptr)
      displayNode (item->node);
}

Objekt typu SoNode lze přetypovat na nadřazenou třídu SoFieldContainer, která obsahuje SoFieldList se seznamem atributů.

Z jednotlivých atributů SoField získáme jméno a hodnotu, kterou zobrazíme v tabulce

       SoField * field = list [i];
 
       SbName name;
       obj->getFieldName (field, name);
 
       SbString value;
       field->get (value);
 
       displayLine (name.getString (), value.getString ());

Celá funkce displayNode zobrazující tabulku atributů

void MainWindow::displayNode (SoNode * node)
{
   ui->prop->clear ();
 
   SoFieldContainer * obj = node;
 
   SoFieldList list;
   obj->getFields (list);
   int len = list.getLength ();
 
   // display fields
   for (int i = 0; i < len; i++)
   {
       SoField * field = list [i];
 
       // retrieve field name
       SbName name;
       obj->getFieldName (field, name);
 
       // retrieve field value
       SbString value;
       field->get (value);
 
       displayLine (name.getString (), value.getString ());
   }
}
void MainWindow::displayLine (QString name, QString value)
{
    QTreeWidgetItem * item = new QTreeWidgetItem (ui->prop);
    item->setText (0, name);
    item->setText (1, value);
}

Hlavičkový soubor

#ifndef QT_INVENTOR_H
#define QT_INVENTOR_H
 
#include <QMainWindow>
#include <QTreeWidgetItem>
 
#include <Inventor/nodes/SoSeparator.h>
 
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow ( );
 
private:
    void displayBranch (QTreeWidgetItem * target, SoNode *node);
    void displayNode (SoNode *node);
    void displayLine (QString name, QString value);
 
    void simpleScene (SoSeparator * top);
 
private slots:
    void on_tree_itemActivated(QTreeWidgetItem *item, int column);
 
private:
    Ui::MainWindow *ui;
};
 
#endif // QT_INVENTOR_H

Program

#include "qt-inventor.h"
#include "ui_qt-inventor.h"
 
#include <Inventor/Qt/SoQt.h>
#include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoCube.h>
#include <Inventor/nodes/SoCone.h>
#include <Inventor/nodes/SoSphere.h>
#include <Inventor/nodes/SoCylinder.h>
#include <Inventor/nodes/SoTransform.h>
#include <Inventor/nodes/SoMaterial.h>
 
class TreeItem : public QTreeWidgetItem
{
public:
    SoNode * node;
};
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    ui->splitter->setStretchFactor (0, 1);
    ui->splitter->setStretchFactor (1, 5);
    ui->splitter->setStretchFactor (2, 1);
 
    ui->prop->setColumnCount (2);
    ui->prop->setHeaderLabels (QStringList () << "name" << "value");
 
    SoQtExaminerViewer * examiner = new SoQtExaminerViewer (ui->widget);
 
    SoSeparator * root = new SoSeparator;
    simpleScene (root);
 
    // SoCone * cone = new SoCone;
    // root->addChild(cone);
 
    examiner->setSceneGraph(root);
 
    displayBranch (ui->tree->invisibleRootItem (), root);
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
 
void MainWindow::displayBranch (QTreeWidgetItem * target, SoNode * node)
{
    TreeItem * branch = new TreeItem;
    branch->node = node;
 
    SoType type = node->getTypeId ();
    branch->setText (0, type.getName().getString());
 
    if (type.isDerivedFrom (SoGroup::getClassTypeId ()) )
    {
       SoGroup * group = dynamic_cast <SoGroup *> (node);
       int count = group->getNumChildren ();
       for (int i = 0; i < count; i++)
       {
           SoNode * sub_node = group->getChild (i);
           displayBranch (branch, sub_node);
       }
    }
 
    target->addChild (branch);
}
 
void MainWindow::displayLine (QString name, QString value)
{
    QTreeWidgetItem * item = new QTreeWidgetItem (ui->prop);
    item->setText (0, name);
    item->setText (1, value);
}
 
void MainWindow::displayNode (SoNode * node)
{
   ui->prop->clear ();
 
   SoFieldContainer * obj = node;
 
   SoFieldList list;
   obj->getFields (list);
   int len = list.getLength ();
 
   // display fields
   for (int i = 0; i < len; i++)
   {
       SoField * field = list [i];
 
       // retrieve field name
       SbName name;
       obj->getFieldName (field, name);
 
       // retrieve field value
       SbString value;
       field->get (value);
 
       displayLine (name.getString (), value.getString ());
   }
}
 
void MainWindow::on_tree_itemActivated (QTreeWidgetItem * param, int column)
{
   TreeItem * item = dynamic_cast <TreeItem *> (param);
   if (item != nullptr)
      displayNode (item->node);
}
 
void MainWindow::simpleScene (SoSeparator * top)
{
    // cone
    SoSeparator * group1 = new SoSeparator;
 
    SoTransform * shift1 = new SoTransform;
    shift1->translation.setValue (-2.0, 0.0, 0.0);
    group1->addChild (shift1);
 
    SoMaterial * redMaterial = new SoMaterial;
    redMaterial->diffuseColor.setValue (1.0, 0.0, 0.0);
    group1->addChild (redMaterial);
 
    SoCone * cone = new SoCone ();
    group1->addChild (cone);
 
    top->addChild (group1);
 
    // sphere
    SoSeparator * group2 = new SoSeparator;
 
    SoMaterial * greenMaterial = new SoMaterial;
    greenMaterial->diffuseColor.setValue (0.0, 1.0, 0.0);
    group2->addChild (greenMaterial);
 
    SoSphere * sphere = new SoSphere ();
    group2->addChild (sphere);
 
    top->addChild (group2);
 
    // cube
    SoSeparator * group3 = new SoSeparator;
 
    SoTransform * shift3 = new SoTransform ();
    shift3->translation.setValue (1.6, 0.0, 1.6);
    shift3->scaleFactor.setValue (0.7, 0.7, 0.7);
    group3->addChild (shift3);
 
    SoMaterial * blueMaterial = new SoMaterial;
    blueMaterial->diffuseColor.setValue (0.0, 0.0, 1.0);
    group3->addChild (blueMaterial);
 
    SoCube * cube = new SoCube ();
    group3->addChild (cube);
 
    top->addChild (group3);
}
 
int main (int argc, char ** argv)
{
  QApplication app (argc, argv);
 
  SoQt::init ((QWidget*)NULL);
 
  MainWindow * win = new MainWindow();
  win->show();
 
  QObject::connect (&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
 
  SoQt::mainLoop();
 
  return 0;
}

Do .pro doplnit

CONFIG += link_pkgconfig 
PKGCONFIG += SoQt 
LIBS += -lSoQt 

gitlab zip

 
uop/qtinventor.txt · Last modified: 2022/10/01 19:55 by 88.103.111.44
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki