diff --git a/examples/SimpleViewerExampleQt/Resources/styles.css b/examples/SimpleViewerExampleQt/Resources/styles.css index 7e2e05304..6b393b1f4 100644 --- a/examples/SimpleViewerExampleQt/Resources/styles.css +++ b/examples/SimpleViewerExampleQt/Resources/styles.css @@ -6,6 +6,8 @@ QFrame { QWidget#OpenFileWidget { background-color: rgba(240,240,240,0.5); border: 1px solid #cecece; margin: 10px;} QWidget#SettingsWidget { background-color: rgba(240,240,240,0.5); border: 1px solid #cecece; margin: 10px;} +QStatusBar { height:20px;max-height: 24px;} + QTextEdit { border: 1px solid #cecece; diff --git a/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj b/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj index 10f909164..fa03b4cf2 100644 --- a/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj +++ b/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj @@ -255,7 +255,7 @@ 4305;4005 - Console + Windows $(OutDir)\$(ProjectName).exe ..\..\IfcPlusPlus\bin;$(OSG_DIR)\lib;$(OSG_DIR)\build\lib;$(FREETYPE_DIR)\objs\vc2010\x64;%(AdditionalLibraryDirectories) true @@ -299,7 +299,10 @@ - + + + + @@ -356,6 +359,8 @@ + + @@ -374,7 +379,8 @@ - + + diff --git a/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj.filters b/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj.filters index 4ad6337fa..4dd4a9e87 100644 --- a/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj.filters +++ b/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj.filters @@ -47,9 +47,6 @@ Source Dateien - - Source Dateien - Source Dateien @@ -77,6 +74,18 @@ Source Dateien + + Source Dateien + + + Source Dateien + + + Source Dateien + + + Source Dateien + @@ -141,19 +150,28 @@ Header Dateien - - Header Dateien - Header Dateien Header Dateien + + Header Dateien + + + Header Dateien + + + Header Dateien + Header Dateien + + Header Dateien + \ No newline at end of file diff --git a/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj.user b/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj.user index be5130eb3..38ba48f46 100644 --- a/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj.user +++ b/examples/SimpleViewerExampleQt/SimpleViewerExampleQt.vcxproj.user @@ -18,15 +18,15 @@ PATH=$(QTDIR)\bin%3b"$(QTDIR)\bin%3b$(PATH) - 2024-01-17T08:47:27.8852167Z + 2024-01-18T07:50:24.9045647Z - 2024-01-17T08:47:27.9653823Z + 2024-01-18T07:50:24.9860178Z - 2024-01-17T08:47:28.2838514Z + 2024-01-18T07:50:25.2048710Z - 2024-01-17T08:47:28.7635906Z + 2024-01-18T07:50:25.3122549Z \ No newline at end of file diff --git a/examples/SimpleViewerExampleQt/src/IfcPlusPlusSystem.cpp b/examples/SimpleViewerExampleQt/src/IfcPlusPlusSystem.cpp index a2e6e70ff..7063568f1 100644 --- a/examples/SimpleViewerExampleQt/src/IfcPlusPlusSystem.cpp +++ b/examples/SimpleViewerExampleQt/src/IfcPlusPlusSystem.cpp @@ -2,7 +2,7 @@ * MIT License -Copyright (c) 2017 Fabian Gerold +Copyright (c) 2024 Fabian Gerold Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell @@ -36,48 +36,21 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include "cmd/CommandManager.h" #include "IncludeGeometryHeaders.h" #include "IfcPlusPlusSystem.h" +#include "viewer/IntersectionHandler.h" #include "viewer/ViewerWidget.h" -#include "viewer/OrbitCameraManipulator.h" - -std::string getGUID(const shared_ptr& ent) -{ - std::string guid; - shared_ptr ifc_root = dynamic_pointer_cast(ent); - if (ifc_root) - { - if (ifc_root->m_GlobalId) - { - guid = ifc_root->m_GlobalId->m_value; - } - } - return guid; -} +#include "viewer/ViewController.h" +#include "viewer/Orbit3DManipulator.h" +#include "viewer/ViewerUtil.h" IfcPlusPlusSystem::IfcPlusPlusSystem() { m_command_manager = shared_ptr( new CommandManager() ); m_ifc_model = shared_ptr( new BuildingModel() ); m_geometry_converter = shared_ptr( new GeometryConverter( m_ifc_model ) ); - - m_rootnode = new osg::Group(); - m_rootnode->setName( "m_rootnode" ); - - m_sw_model = new osg::Switch(); - m_sw_model->setName( "m_sw_model" ); - m_rootnode->addChild( m_sw_model.get() ); - - m_sw_coord_axes = new osg::Switch(); - m_sw_coord_axes->setName( "m_sw_coord_axes" ); - m_rootnode->addChild( m_sw_coord_axes.get() ); - - m_show_curve_representation = true; - m_light_on = false; - - m_material_selected = new osg::Material(); - m_material_selected->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4f( 0.2f, 0.98f, 0.2f, 0.5f ) ); - m_material_selected->setSpecular( osg::Material::FRONT_AND_BACK, osg::Vec4f( 0.2f, 0.85f, 0.2f, 1.0f ) ); - m_material_selected->setShininess( osg::Material::FRONT_AND_BACK, 35.0 ); - m_material_selected->setColorMode( osg::Material::SPECULAR ); + IntersectionHandler* ih = new IntersectionHandler(this); + Orbit3DManipulator* camera_manip = new Orbit3DManipulator(this, ih); + m_view_controller = shared_ptr(new ViewController(camera_manip)); + m_view_controller->getRootNode()->addChild(ih->m_group_selected); } IfcPlusPlusSystem::~IfcPlusPlusSystem(){} @@ -87,11 +60,6 @@ void IfcPlusPlusSystem::setIfcModel( shared_ptr& model ) m_ifc_model = model; } -void IfcPlusPlusSystem::setRootNode( osg::Group* root ) -{ - m_rootnode = root; -} - bool IfcPlusPlusSystem::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /*aa*/) { bool handled=false; @@ -143,6 +111,11 @@ bool IfcPlusPlusSystem::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActio return handled; } +void IfcPlusPlusSystem::setCtrlKeyDown(bool ctrl_key_down) +{ + m_control_key_down = ctrl_key_down; +} + #ifdef _DEBUG #define _DEBUG_GEOMETRY #endif @@ -191,7 +164,7 @@ void IfcPlusPlusSystem::setObjectSelected( shared_ptr ifc_object const std::string guid = getGUID(ifc_object); if( !grp ) { - grp = findNodeByIfcId( m_sw_model, guid ); + grp = findNodeByIfcId( m_view_controller->getModelNode(), guid); } if( selected ) @@ -221,19 +194,7 @@ void IfcPlusPlusSystem::setObjectSelected( shared_ptr ifc_object if( select_child ) { - osg::ref_ptr stateset = grp->getOrCreateStateSet(); - osg::Material* material_previous = (osg::Material*)stateset->getAttribute( osg::StateAttribute::MATERIAL ); - if( material_previous ) - { - selected_entity->m_material_previous = material_previous; - } - - //stateset->setAttribute( m_material_selected, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); - - osg::ref_ptr statesetSelected = new osg::StateSet(); - statesetSelected->setAttribute(m_material_selected, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - grp->setStateSet(statesetSelected); - selected_entity->m_material_selected = m_material_selected; + selected_entity->setSelected(m_view_controller->getMaterialSelected()); } std::unordered_map > map_objects; @@ -250,20 +211,7 @@ void IfcPlusPlusSystem::setObjectSelected( shared_ptr ifc_object if( it_selected != m_map_selected.end() ) { shared_ptr selected_entity = it_selected->second; - - if( selected_entity->m_osg_group ) - { - osg::ref_ptr stateset_selected_node = selected_entity->m_osg_group->getOrCreateStateSet(); - if( selected_entity->m_material_previous ) - { - stateset_selected_node->setAttribute( selected_entity->m_material_previous, osg::StateAttribute::ON ); - } - else if( selected_entity->m_material_selected ) - { - stateset_selected_node->removeAttribute( selected_entity->m_material_selected ); - } - } - + selected_entity->setUnselected(); m_map_selected.erase( it_selected ); } } @@ -279,19 +227,7 @@ void IfcPlusPlusSystem::clearSelection() { shared_ptr& selected_entity = (*it).second; shared_ptr entity = selected_entity->m_entity; - - if( selected_entity->m_osg_group ) - { - osg::ref_ptr stateset_selected_node = selected_entity->m_osg_group->getOrCreateStateSet(); - if( selected_entity->m_material_previous ) - { - stateset_selected_node->setAttribute( selected_entity->m_material_previous, osg::StateAttribute::ON ); - } - else if( selected_entity->m_material_selected ) - { - stateset_selected_node->removeAttribute( selected_entity->m_material_selected ); - } - } + selected_entity->setUnselected(); } m_map_selected.clear(); } @@ -311,76 +247,7 @@ void IfcPlusPlusSystem::notifyModelLoadingDone() emit( signalModelLoadingDone() ); } -void IfcPlusPlusSystem::toggleSceneLight() -{ - osg::StateSet* stateset_root = m_rootnode->getOrCreateStateSet(); - - if( !m_transform_light.valid() ) - { - osg::ref_ptr light_group = new osg::Group(); - light_group->setName( "light_group" ); - double model_size = 100; // TODO: adjust when model is loaded - - osg::ref_ptr light6 = new osg::Light(); - light6->setLightNum( 6 ); - light6->setPosition( osg::Vec4( 0.0, 0.0, 0.0, 1.0f ) ); - light6->setAmbient( osg::Vec4( 0.5f, 0.53f, 0.57f, 0.4f ) ); - light6->setDiffuse( osg::Vec4( 0.5f, 0.53f, 0.57f, 0.4f ) ); - light6->setConstantAttenuation( 1.0f ); - light6->setLinearAttenuation( 2.0f/model_size ); - light6->setQuadraticAttenuation( 2.0f/(model_size*model_size) ); - - osg::ref_ptr light_source6 = new osg::LightSource(); - light_source6->setLight( light6 ); - light_source6->setLocalStateSetModes( osg::StateAttribute::ON ); - light_source6->setStateSetModes( *stateset_root, osg::StateAttribute::ON ); - m_transform_light = new osg::MatrixTransform( osg::Matrix::translate( 5, 5, 50 ) ); - m_transform_light->addChild( light_source6 ); - - light_group->addChild( m_transform_light ); - m_rootnode->addChild( light_group ); - - m_light_on = false; - } - - m_light_on = !m_light_on; - if( m_light_on ) - { - stateset_root->setMode( GL_LIGHT6, osg::StateAttribute::ON ); - } - else - { - stateset_root->setMode( GL_LIGHT6, osg::StateAttribute::OFF ); - } -} - -void IfcPlusPlusSystem::switchCurveRepresentation( osg::Group* grp, bool on_off ) +void IfcPlusPlusSystem::notifyCursorCoordinates(double x, double y, double z) { - m_show_curve_representation = on_off; - osg::Switch* grp_switch = dynamic_cast( grp ); - if( grp_switch ) - { - if( grp_switch->getName().compare( "CurveRepresentation" ) == 0 ) - { - if( on_off ) - { - grp_switch->setAllChildrenOn(); - } - else - { - grp_switch->setAllChildrenOff(); - } - } - } - - unsigned int num_children = grp->getNumChildren(); - for( unsigned int i=0; igetChild(i); - osg::Group* child_grp = dynamic_cast( child_node ); - if( child_grp ) - { - switchCurveRepresentation( child_grp, on_off ); - } - } + emit(signalCursorCoordinates(x, y, z)); } diff --git a/examples/SimpleViewerExampleQt/src/IfcPlusPlusSystem.h b/examples/SimpleViewerExampleQt/src/IfcPlusPlusSystem.h index 163234c40..102d69992 100644 --- a/examples/SimpleViewerExampleQt/src/IfcPlusPlusSystem.h +++ b/examples/SimpleViewerExampleQt/src/IfcPlusPlusSystem.h @@ -26,15 +26,8 @@ class BuildingModel; class BuildingEntity; class GeometryConverter; class CommandManager; - -struct SelectedEntity -{ - shared_ptr m_entity; - osg::ref_ptr m_osg_group; - osg::ref_ptr m_material_previous; - osg::ref_ptr m_material_selected; -}; -std::string getGUID(const shared_ptr& ent); +class ViewController; +struct SelectedEntity; class IfcPlusPlusSystem : public QObject, public osgGA::GUIEventHandler { @@ -49,12 +42,9 @@ class IfcPlusPlusSystem : public QObject, public osgGA::GUIEventHandler shared_ptr& getIfcModel() { return m_ifc_model; } void setIfcModel( shared_ptr& model ); shared_ptr getCommandManager() { return m_command_manager; } - osg::Group* getRootNode() { return m_rootnode; } - osg::Switch* getModelNode() { return m_sw_model; } - osg::Switch* getCoordinateAxesNode() { return m_sw_coord_axes; } - void setRootNode( osg::Group* root ); - void toggleSceneLight(); - void switchCurveRepresentation( osg::Group* grp, bool on_off ); + shared_ptr& getViewController() { return m_view_controller; } + void setCtrlKeyDown(bool ctrl_key_down); + bool isCtrlKeyDown() { return m_control_key_down; } void setObjectSelected( shared_ptr object, bool selected, osg::Group* node = 0 ); const std::unordered_map >& getSelectedObjects() { return m_map_selected; } @@ -62,18 +52,14 @@ class IfcPlusPlusSystem : public QObject, public osgGA::GUIEventHandler void notifyModelCleared(); void notifyModelLoadingStart(); void notifyModelLoadingDone(); + void notifyCursorCoordinates(double, double, double); shared_ptr m_geometry_converter; shared_ptr m_command_manager; + shared_ptr m_view_controller; std::unordered_map > m_map_selected; shared_ptr m_ifc_model; - osg::ref_ptr m_rootnode; - osg::ref_ptr m_sw_coord_axes; - osg::ref_ptr m_sw_model; - osg::ref_ptr m_transform_light; - osg::ref_ptr m_material_selected; - bool m_light_on; - bool m_show_curve_representation; + bool m_control_key_down = false; signals: void signalObjectsSelected( std::unordered_map >& map_objects ); @@ -81,4 +67,5 @@ class IfcPlusPlusSystem : public QObject, public osgGA::GUIEventHandler void signalModelCleared(); void signalModelLoadingStart(); void signalModelLoadingDone(); + void signalCursorCoordinates(double, double, double); }; diff --git a/examples/SimpleViewerExampleQt/src/cmd/CmdRemoveSelectedObjects.cpp b/examples/SimpleViewerExampleQt/src/cmd/CmdRemoveSelectedObjects.cpp index 20b165040..669f012f0 100644 --- a/examples/SimpleViewerExampleQt/src/cmd/CmdRemoveSelectedObjects.cpp +++ b/examples/SimpleViewerExampleQt/src/cmd/CmdRemoveSelectedObjects.cpp @@ -24,6 +24,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include "IncludeGeometryHeaders.h" #include "Command.h" #include "IfcPlusPlusSystem.h" +#include "viewer/ViewerUtil.h" #include "CmdRemoveSelectedObjects.h" CmdRemoveSelectedObjects::CmdRemoveSelectedObjects( IfcPlusPlusSystem* system ): Command(system) diff --git a/examples/SimpleViewerExampleQt/src/gui/EntityAttributeWidget.cpp b/examples/SimpleViewerExampleQt/src/gui/EntityAttributeWidget.cpp index a2d59bd6d..5a51521b9 100644 --- a/examples/SimpleViewerExampleQt/src/gui/EntityAttributeWidget.cpp +++ b/examples/SimpleViewerExampleQt/src/gui/EntityAttributeWidget.cpp @@ -574,6 +574,7 @@ PropertyValueContainer::PropertyValueContainer(const shared_ptr& } } } + PropertyValueContainer::PropertyValueContainer(const shared_ptr& pSet, std::string& prop_name, std::string& prop_description, std::string& prop_value, std::string& prop_unit, std::string& prop_type) { if( pSet ) @@ -639,7 +640,6 @@ void readIfcProperty(const shared_ptr& pset, const shared_ptr complex_property = dynamic_pointer_cast(ifc_prop); if( complex_property ) { - //UsageName : IfcIdentifier; //HasProperties : SET [1:?] OF IfcProperty; } @@ -648,7 +648,6 @@ void readIfcProperty(const shared_ptr& pset, const shared_ptr simple_property = dynamic_pointer_cast(ifc_prop); if( simple_property ) { - //ENTITY IfcSimpleProperty ABSTRACT SUPERTYPE OF(ONEOF(IfcPropertyBoundedValue, IfcPropertyEnumeratedValue, IfcPropertyListValue, IfcPropertyReferenceValue, IfcPropertySingleValue, IfcPropertyTableValue)) shared_ptr ifc_prop_single_value = dynamic_pointer_cast(simple_property); @@ -677,7 +676,6 @@ void readIfcProperty(const shared_ptr& pset, const shared_ptr ifc_prop_list_value = dynamic_pointer_cast(simple_property); if( ifc_prop_list_value ) { diff --git a/examples/SimpleViewerExampleQt/src/gui/IfcTreeWidget.cpp b/examples/SimpleViewerExampleQt/src/gui/IfcTreeWidget.cpp index dd6baafd0..f68ff743f 100644 --- a/examples/SimpleViewerExampleQt/src/gui/IfcTreeWidget.cpp +++ b/examples/SimpleViewerExampleQt/src/gui/IfcTreeWidget.cpp @@ -33,32 +33,12 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include "IncludeGeometryHeaders.h" #include "IfcPlusPlusSystem.h" #include "IfcTreeWidget.h" +#include "viewer/ViewerUtil.h" #include -QTreeWidgetItem* findItemByIfcId( QTreeWidgetItem* item, int ifc_id ) -{ - int num_children = item->childCount(); - for( int i = 0; ichild( i ); - int id = child->text( 1 ).toUInt(); - if( id == ifc_id ) - { - return child; - } - QTreeWidgetItem* child_of_child = findItemByIfcId( child, ifc_id ); - if( child_of_child != 0 ) - { - return child_of_child; - } - } - return 0; -} - IfcTreeWidget::IfcTreeWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QTreeWidget(parent), m_system(sys) { - m_block_selection_signals = false; setColumnCount( 2 ); QStringList tree_headers; tree_headers << "Label" << "Object id" << "Class name"; @@ -66,20 +46,16 @@ IfcTreeWidget::IfcTreeWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QTreeW setColumnWidth( 0, 100 ); setColumnWidth( 1, 60 ); setColumnWidth( 2, 60 ); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) header()->setSectionResizeMode(0, QHeaderView::Stretch); -#else - header()->setResizeMode(0, QHeaderView::Stretch); -#endif setSelectionBehavior( QAbstractItemView::SelectRows ); setIndentation( 12 ); - connect( this, SIGNAL( currentItemChanged( QTreeWidgetItem*, QTreeWidgetItem* ) ), this, SLOT( slotTreewidgetSelectionChanged(QTreeWidgetItem*, QTreeWidgetItem*) ) ); - connect( this, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int )), this, SLOT(slotTreeWidgetItemDoubleClick(QTreeWidgetItem*, int))); - connect( m_system, &IfcPlusPlusSystem::signalObjectsSelected, this, &IfcTreeWidget::slotObjectsSelected ); - connect( m_system, SIGNAL( signalModelCleared() ), this, SLOT( slotModelCleared() ) ); - connect( m_system, SIGNAL( signalModelLoadingStart() ), this, SLOT( slotModelLoadingStart() ) ); - connect( m_system, SIGNAL( signalModelLoadingDone() ), this, SLOT( slotModelLoadingDone() ) ); + connect( this, &QTreeWidget::currentItemChanged, this, &IfcTreeWidget::slotTreewidgetSelectionChanged ); + connect( this, &QTreeWidget::itemDoubleClicked, this, &IfcTreeWidget::slotTreeWidgetItemDoubleClick); + connect( m_system, &IfcPlusPlusSystem::signalObjectsSelected, this, &IfcTreeWidget::slotObjectsSelected ); + connect( m_system, &IfcPlusPlusSystem::signalModelCleared, this, &IfcTreeWidget::slotModelCleared ); + connect( m_system, &IfcPlusPlusSystem::signalModelLoadingStart,this, &IfcTreeWidget::slotModelLoadingStart ); + connect( m_system, &IfcPlusPlusSystem::signalModelLoadingDone, this, &IfcTreeWidget::slotModelLoadingDone ); } IfcTreeWidget::~IfcTreeWidget(){} @@ -123,25 +99,31 @@ void IfcTreeWidget::slotTreewidgetSelectionChanged( QTreeWidgetItem* current, QT return; } const std::map >& map_ifc_objects = m_system->getIfcModel()->getMapIfcEntities(); - std::map >::const_iterator it_find; - if( previous ) + + if (!m_system->isCtrlKeyDown()) { - int id = previous->text(1).toUInt(); - it_find = map_ifc_objects.find(id); - if( it_find != map_ifc_objects.end() ) + m_system->clearSelection(); + } + else + { + if (previous) { - shared_ptr ifc_object = it_find->second; - //const shared_ptr ifc_object = map_ifc_objects[id]; - m_block_selection_signals = true; - m_system->setObjectSelected( ifc_object, false ); - m_block_selection_signals = false; + int id = previous->text(1).toUInt(); + auto it_find = map_ifc_objects.find(id); + if (it_find != map_ifc_objects.end()) + { + shared_ptr ifc_object = it_find->second; + m_block_selection_signals = true; + m_system->setObjectSelected(ifc_object, false); + m_block_selection_signals = false; + } } } if( current ) { int id = current->text(1).toUInt(); - it_find = map_ifc_objects.find(id); + auto it_find = map_ifc_objects.find(id); if( it_find != map_ifc_objects.end() ) { shared_ptr ifc_object = it_find->second; @@ -152,11 +134,6 @@ void IfcTreeWidget::slotTreewidgetSelectionChanged( QTreeWidgetItem* current, QT } } -void IfcTreeWidget::slotTreewidgetSelectionChanged() -{ - -} - void IfcTreeWidget::slotTreeWidgetItemDoubleClick( QTreeWidgetItem* item, int column ) { if( m_block_selection_signals ) @@ -393,5 +370,5 @@ void IfcTreeWidget::slotModelLoadingDone() m_block_selection_signals = false; } } - expandToDepth(2); + expandToDepth(3); } diff --git a/examples/SimpleViewerExampleQt/src/gui/IfcTreeWidget.h b/examples/SimpleViewerExampleQt/src/gui/IfcTreeWidget.h index bff590f2d..3c79ce623 100644 --- a/examples/SimpleViewerExampleQt/src/gui/IfcTreeWidget.h +++ b/examples/SimpleViewerExampleQt/src/gui/IfcTreeWidget.h @@ -38,7 +38,6 @@ class IfcTreeWidget : public QTreeWidget public slots: void slotObjectsSelected( std::unordered_map >& map ); void slotTreewidgetSelectionChanged( QTreeWidgetItem* current, QTreeWidgetItem* previous ); - void slotTreewidgetSelectionChanged(); void slotTreeWidgetItemDoubleClick( QTreeWidgetItem* item, int column ); void slotModelCleared(); @@ -50,5 +49,5 @@ public slots: protected: IfcPlusPlusSystem* m_system; - bool m_block_selection_signals; + bool m_block_selection_signals = false; }; diff --git a/examples/SimpleViewerExampleQt/src/gui/MainWindow.cpp b/examples/SimpleViewerExampleQt/src/gui/MainWindow.cpp index feeb2a6eb..9b5dbec72 100644 --- a/examples/SimpleViewerExampleQt/src/gui/MainWindow.cpp +++ b/examples/SimpleViewerExampleQt/src/gui/MainWindow.cpp @@ -17,8 +17,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include -#include #include +#include #include #include #include @@ -26,8 +26,10 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include "IncludeGeometryHeaders.h" #include "EntityAttributeWidget.h" #include "IfcPlusPlusSystem.h" +#include "viewer/ViewController.h" +#include "viewer/ViewerUtil.h" #include "viewer/ViewerWidget.h" -#include "viewer/OrbitCameraManipulator.h" +#include "viewer/Orbit3DManipulator.h" #include "cmd/CmdRemoveSelectedObjects.h" #include "cmd/CommandManager.h" #include "OpenFileWidget.h" @@ -52,12 +54,9 @@ MainWindow::MainWindow( IfcPlusPlusSystem* sys, QWidget *parent) : m_system(sys) { m_autoHideFileWidget= settings.value("AutoHideFileWidget").toBool(); } - - + m_viewerWidget = new ViewerWidget(sys); - OrbitCameraManipulator* camera_manip = new OrbitCameraManipulator(sys); - m_viewerWidget->getMainView()->setCameraManipulator(camera_manip); - m_viewerWidget->setRootNode(sys->getRootNode()); + sys->getViewController()->setGLWidget(m_viewerWidget->getOpenGLWidget()); // create OpenFileWidget m_openFileWidget = new OpenFileWidget(m_system, this); @@ -66,8 +65,6 @@ MainWindow::MainWindow( IfcPlusPlusSystem* sys, QWidget *parent) : m_system(sys) m_openFileWidget->setParent(m_viewerWidget); connect(m_openFileWidget, &OpenFileWidget::signalProgressValue, this, &MainWindow::slotProgressValue); connect(m_openFileWidget, &OpenFileWidget::signalClearSignalQueue, this, &MainWindow::slotClearSignalQueue); - connect(m_openFileWidget, &OpenFileWidget::signalFileLoadingDone, this, &MainWindow::slotFileLoadingDone); - m_buttonToggleOpenFileWidget = new QPushButton("<<"); m_buttonToggleOpenFileWidget->setMinimumHeight(80); @@ -89,8 +86,7 @@ MainWindow::MainWindow( IfcPlusPlusSystem* sys, QWidget *parent) : m_system(sys) zoom_bounds_btn->setGeometry(3, 6, 24, 24); connect(zoom_bounds_btn, &QToolButton::clicked, this, &MainWindow::slotBtnZoomBoundingsClicked); - - + m_settingsWidget = new SettingsWidget(m_system, m_viewerWidget, m_autoHideFileWidget); connect(m_settingsWidget, &SettingsWidget::signalAutoHideFileWidget, this, [this](bool autoHide) { QSettings settings(QSettings::UserScope, QLatin1String("IfcPlusPlus")); @@ -160,7 +156,6 @@ IFC++ can also be used in server applications without dependencies like Qt and O sizesMainSplitter.append(100); mainSplitter->setSizes(sizesMainSplitter); - // progress bar m_progressBar = new QProgressBar(); m_progressBar->setRange(0, 1000); @@ -197,6 +192,9 @@ IFC++ can also be used in server applications without dependencies like Qt and O m_viewerWidget->startTimer(); m_viewerWidget->getMainView()->addEventHandler(sys); updateOpenFileWidget(); + + connect(m_system, &IfcPlusPlusSystem::signalModelLoadingDone, this, &MainWindow::slotFileLoadingDone); + connect(m_system, &IfcPlusPlusSystem::signalCursorCoordinates, this, &MainWindow::slotCursorCoordinates); } MainWindow::~MainWindow(){} @@ -240,10 +238,10 @@ void MainWindow::slotFileLoadingDone() if (main_view) { osgGA::CameraManipulator* camera_manip = main_view->getCameraManipulator(); - OrbitCameraManipulator* orbit_manip = dynamic_cast(camera_manip); + Orbit3DManipulator* orbit_manip = dynamic_cast(camera_manip); if (orbit_manip) { - osg::BoundingSphere bs = m_system->getModelNode()->computeBound(); + osg::BoundingSphere bs = m_system->getViewController()->getModelNode()->computeBound(); orbit_manip->zoomToBoundingSphere(bs); } } @@ -254,6 +252,22 @@ void MainWindow::slotFileLoadingDone() } } +void MainWindow::keyPressEvent(QKeyEvent* e) +{ + if (e->key() == Qt::Key_Control) + { + m_system->setCtrlKeyDown(true); + } +} + +void MainWindow::keyReleaseEvent(QKeyEvent* e) +{ + if (e->key() == Qt::Key_Control) + { + m_system->setCtrlKeyDown(false); + } +} + void MainWindow::updateOpenFileWidget() { int w = m_viewerWidget->width(); @@ -288,13 +302,13 @@ void MainWindow::slotToggleOpenFileWidget() void MainWindow::slotBtnZoomBoundingsClicked() { - osg::BoundingSphere bs = m_system->getModelNode()->computeBound(); + osg::BoundingSphere bs = m_system->getViewController()->getModelNode()->computeBound(); osgViewer::View* main_view = m_viewerWidget->getMainView(); if( main_view ) { osgGA::CameraManipulator* camera_manip = main_view->getCameraManipulator(); - OrbitCameraManipulator* orbit_manip = dynamic_cast( camera_manip ); + Orbit3DManipulator* orbit_manip = dynamic_cast( camera_manip ); if( orbit_manip ) { orbit_manip->zoomToBoundingSphere( bs ); @@ -377,7 +391,7 @@ void MainWindow::slotZoomToObject(shared_ptr ifc_object, osg::Gr const std::string guid = getGUID(ifc_object); if (!grp) { - grp = findNodeByIfcId( m_system->getModelNode(), guid); + grp = findNodeByIfcId( m_system->getViewController()->getModelNode(), guid); if (!grp) { return; @@ -390,7 +404,7 @@ void MainWindow::slotZoomToObject(shared_ptr ifc_object, osg::Gr return; } - OrbitCameraManipulator* orbit_manip = dynamic_cast(main_view->getCameraManipulator()); + Orbit3DManipulator* orbit_manip = dynamic_cast(main_view->getCameraManipulator()); if (!orbit_manip) { return; @@ -398,3 +412,8 @@ void MainWindow::slotZoomToObject(shared_ptr ifc_object, osg::Gr orbit_manip->zoomToBoundingSphere(grp->getBound()); } + +void MainWindow::slotCursorCoordinates(double x, double y, double z) +{ + m_labelStatusCursor->setText(QString::number(x, 'f', 4) + ", " + QString::number(y, 'f', 4) + "," + QString::number(z, 'f', 4)); +} diff --git a/examples/SimpleViewerExampleQt/src/gui/MainWindow.h b/examples/SimpleViewerExampleQt/src/gui/MainWindow.h index 89631db90..60c891d0b 100644 --- a/examples/SimpleViewerExampleQt/src/gui/MainWindow.h +++ b/examples/SimpleViewerExampleQt/src/gui/MainWindow.h @@ -46,6 +46,8 @@ class MainWindow : public QMainWindow void closeEvent( QCloseEvent *event ); void resizeEvent(QResizeEvent* event); void showEvent(QShowEvent* e); + void keyPressEvent(QKeyEvent* e); + void keyReleaseEvent(QKeyEvent* e); private: IfcPlusPlusSystem* m_system; @@ -72,4 +74,5 @@ private slots: void slotZoomToObject(shared_ptr object, osg::Group* node = 0); void slotToggleOpenFileWidget(); void slotFileLoadingDone(); + void slotCursorCoordinates(double x, double y, double z); }; diff --git a/examples/SimpleViewerExampleQt/src/gui/OpenFileWidget.cpp b/examples/SimpleViewerExampleQt/src/gui/OpenFileWidget.cpp index 0e38dded0..13e25cd05 100644 --- a/examples/SimpleViewerExampleQt/src/gui/OpenFileWidget.cpp +++ b/examples/SimpleViewerExampleQt/src/gui/OpenFileWidget.cpp @@ -37,7 +37,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include "IncludeGeometryHeaders.h" #include "IfcPlusPlusSystem.h" #include "viewer/ViewerWidget.h" -#include "viewer/OrbitCameraManipulator.h" +#include "viewer/ViewController.h" +#include "viewer/Orbit3DManipulator.h" #include "cmd/CommandManager.h" #include "StoreyShiftWidget.h" #include "OpenFileWidget.h" @@ -282,7 +283,7 @@ void OpenFileWidget::loadIfcFile( QString& path_in ) } // first remove previously loaded geometry from scenegraph - osg::ref_ptr model_switch = m_system->getModelNode(); + osg::ref_ptr model_switch = m_system->getViewController()->getModelNode(); SceneGraphUtils::clearAllChildNodes(model_switch); m_system->clearSelection(); @@ -321,13 +322,10 @@ void OpenFileWidget::loadIfcFile( QString& path_in ) const osg::BoundingSphere& bsphere = model_switch->getBound(); if (bsphere.center().length() > 10000) { - if (bsphere.center().length()/bsphere.radius() > 100) + if (bsphere.center().length() / bsphere.radius() > 100) { - //std::unordered_set set_applied; - //SceneGraphUtils::translateGroup(model_switch, , set_applied, length_in_meter*0.001); - osg::MatrixTransform* mt = new osg::MatrixTransform(); - mt->setMatrix(osg::Matrix::translate(-bsphere.center()*0.98)); + mt->setMatrix(osg::Matrix::translate(-bsphere.center() * 0.98)); int num_children = model_switch->getNumChildren(); for (int i = 0; i < num_children; ++i) @@ -354,8 +352,6 @@ void OpenFileWidget::loadIfcFile( QString& path_in ) txtOutError( e.what() ); } - emit(signalFileLoadingDone()); - int time_diff = (clock() - millisecs)/(double)CLOCKS_PER_SEC; int num_entities = m_system->getIfcModel()->getMapIfcEntities().size(); txtOut( tr("File loaded: ") + QString::number(num_entities) + " entities in " + QString::number( round(time_diff*10)*0.1 ) + " sec." ); @@ -440,7 +436,8 @@ void OpenFileWidget::slotAddOtherIfcFileClicked() { default_dir = settings.value( "defaultDir" ).toString(); } - QString selected_file = QFileDialog::getOpenFileName(this, "Choose IFC file", default_dir, QString(), Q_NULLPTR, QFileDialog::DontUseNativeDialog); + QString selectedFilter = "IFC files (*.ifc *.ifczip)"; + QString selected_file = QFileDialog::getOpenFileName(this, "Choose IFC file", default_dir, selectedFilter); if( !selected_file.isEmpty() ) { @@ -453,7 +450,7 @@ void OpenFileWidget::slotAddOtherIfcFileClicked() void OpenFileWidget::slotSetWritePathClicked() { QString selectedFilter; - QString fileName = QFileDialog::getSaveFileName(this, "IfcPlusPlus - choose path to write ifc file", m_le_path_write->text(), "All Files (*);;Text Files (*.ifc)", &selectedFilter, QFileDialog::DontUseNativeDialog); + QString fileName = QFileDialog::getSaveFileName(this, "IfcPlusPlus - choose path to write ifc file", m_le_path_write->text(), "All Files (*);;IFC file (*.ifc)", &selectedFilter, QFileDialog::DontUseNativeDialog); if( !fileName.isEmpty() ) { m_le_path_write->setText(fileName); diff --git a/examples/SimpleViewerExampleQt/src/gui/OpenFileWidget.h b/examples/SimpleViewerExampleQt/src/gui/OpenFileWidget.h index 044399389..eb6c7c9d8 100644 --- a/examples/SimpleViewerExampleQt/src/gui/OpenFileWidget.h +++ b/examples/SimpleViewerExampleQt/src/gui/OpenFileWidget.h @@ -74,7 +74,6 @@ class OpenFileWidget : public QWidget signals: void signalProgressValue(double progress_value, const std::string& progress_type); void signalClearSignalQueue(); - void signalFileLoadingDone(); private slots: void slotAddOtherIfcFileClicked(); diff --git a/examples/SimpleViewerExampleQt/src/gui/SettingsWidget.cpp b/examples/SimpleViewerExampleQt/src/gui/SettingsWidget.cpp index c63b4dace..978571638 100644 --- a/examples/SimpleViewerExampleQt/src/gui/SettingsWidget.cpp +++ b/examples/SimpleViewerExampleQt/src/gui/SettingsWidget.cpp @@ -20,8 +20,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include #include #include -#include -#include #include #include @@ -32,7 +30,8 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include "IncludeGeometryHeaders.h" #include "IfcPlusPlusSystem.h" #include "viewer/ViewerWidget.h" -#include "viewer/OrbitCameraManipulator.h" +#include "viewer/ViewController.h" +#include "viewer/Orbit3DManipulator.h" #include "MainWindow.h" #include "SettingsWidget.h" @@ -55,7 +54,7 @@ SettingsWidget::SettingsWidget( IfcPlusPlusSystem* sys, ViewerWidget* vw, bool a { m_cullBack = settings.value("cullBackFaces").toBool(); } - SceneGraphUtils::cullFrontBack(m_cullFront, m_cullBack, m_system->getRootNode()->getOrCreateStateSet() ); + SceneGraphUtils::cullFrontBack(m_cullFront, m_cullBack, m_system->getViewController()->getRootNode()->getOrCreateStateSet() ); // cull face buttons QCheckBox* cull_front_faces = new QCheckBox( "Cull front faces" ); @@ -77,7 +76,7 @@ SettingsWidget::SettingsWidget( IfcPlusPlusSystem* sys, ViewerWidget* vw, bool a QCheckBox* btn_toggle_light = new QCheckBox("Light on/off"); btn_toggle_light->setToolTip("Light on/off"); btn_toggle_light->setChecked(true); - connect(btn_toggle_light, &QCheckBox::clicked, this, [this]() { m_system->toggleSceneLight(); }); + connect(btn_toggle_light, &QCheckBox::clicked, this, [this]() { m_system->getViewController()->toggleSunLight(); }); // number of vertices per cycle @@ -192,7 +191,7 @@ void SettingsWidget::slotCullFrontFaces( int state ) QSettings settings(QSettings::UserScope, QLatin1String("IfcPlusPlus")); settings.setValue("cullFrontFaces", m_cullFront ); - SceneGraphUtils::cullFrontBack(m_cullFront, m_cullBack, m_system->getRootNode()->getOrCreateStateSet() ); + SceneGraphUtils::cullFrontBack(m_cullFront, m_cullBack, m_system->getViewController()->getRootNode()->getOrCreateStateSet() ); } void SettingsWidget::slotCullBackFaces( int state ) @@ -208,7 +207,7 @@ void SettingsWidget::slotCullBackFaces( int state ) QSettings settings(QSettings::UserScope, QLatin1String("IfcPlusPlus")); settings.setValue("cullBackFaces", m_cullBack ); - SceneGraphUtils::cullFrontBack( m_cullFront, m_cullBack, m_system->getRootNode()->getOrCreateStateSet() ); + SceneGraphUtils::cullFrontBack( m_cullFront, m_cullBack, m_system->getViewController()->getRootNode()->getOrCreateStateSet() ); } void SettingsWidget::slotSetNumVertices( int num_vertices ) @@ -221,7 +220,7 @@ void SettingsWidget::slotSetNumVertices( int num_vertices ) void SettingsWidget::slotShowCurves( int state ) { bool curves_on = state == Qt::Checked; - m_system->switchCurveRepresentation( m_system->getModelNode(), curves_on ); + m_system->getViewController()->switchCurveRepresentation( m_system->getViewController()->getModelNode(), curves_on ); QSettings settings(QSettings::UserScope, QLatin1String("IfcPlusPlus")); settings.setValue( "ShowCurveRepresentations", curves_on ); } diff --git a/examples/SimpleViewerExampleQt/src/gui/StoreyShiftWidget.cpp b/examples/SimpleViewerExampleQt/src/gui/StoreyShiftWidget.cpp index b3f4edea5..7bd29508c 100644 --- a/examples/SimpleViewerExampleQt/src/gui/StoreyShiftWidget.cpp +++ b/examples/SimpleViewerExampleQt/src/gui/StoreyShiftWidget.cpp @@ -34,6 +34,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include #include "ScopedLockAndBlock.h" +#include "viewer/ViewController.h" #include "StoreyShiftWidget.h" #include "IfcPlusPlusSystem.h" @@ -163,7 +164,7 @@ void StoreyShiftWidget::shiftStoreys() std::vector > vec_transform; std::vector > vec_transform_no_elevation; - osg::Switch* grp = m_system->getModelNode(); + osg::Switch* grp = m_system->getViewController()->getModelNode(); collectBuildingStoreys( grp, vec_transform ); std::map > map_transform; diff --git a/examples/SimpleViewerExampleQt/src/main.cpp b/examples/SimpleViewerExampleQt/src/main.cpp index b307e76d3..32edbdc44 100644 --- a/examples/SimpleViewerExampleQt/src/main.cpp +++ b/examples/SimpleViewerExampleQt/src/main.cpp @@ -15,23 +15,16 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTH LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include #include #include #include -#include -#include +#include #include #include - -#include "gui/OpenFileWidget.h" #include "gui/MainWindow.h" -#include "viewer/ViewerWidget.h" -#include "viewer/OrbitCameraManipulator.h" +#include "gui/OpenFileWidget.h" #include "IfcPlusPlusSystem.h" #include "IncludeGeometryHeaders.h" @@ -74,7 +67,7 @@ int main(int argc, char *argv[]) MainWindow* window = new MainWindow( sys ); app.connect( window, SIGNAL(signalMainWindowClosed()), &app, SLOT(quit()) ); window->show(); - + #ifdef _DEBUG GeomDebugDump::clearMeshsetDump(); #endif diff --git a/examples/SimpleViewerExampleQt/src/viewer/IntersectionHandler.cpp b/examples/SimpleViewerExampleQt/src/viewer/IntersectionHandler.cpp new file mode 100644 index 000000000..025a6b71f --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer/IntersectionHandler.cpp @@ -0,0 +1,324 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2024 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "IfcPlusPlusSystem.h" +#include "Orbit3DManipulator.h" +#include "ViewerUtil.h" +#include "ViewController.h" +#include "IntersectionHandler.h" + +IntersectionHandler::IntersectionHandler(IfcPlusPlusSystem* s ) : m_system( s ) +{ + +} + +IntersectionHandler::~IntersectionHandler() +{ +} + +void IntersectionHandler::intersectGroup( osg::Group* group, const carve::geom::vector<3> ray_point, const carve::geom::vector<3> ray_direction, double& smallest_d, osg::Vec3f& closest_point ) +{ + for( size_t ii = 0; ii < group->getNumChildren(); ++ii ) + { + osg::Node* node = group->getChild( ii ); + + const osg::BoundingSphere& bs = node->computeBound(); + const carve::geom::vector<3> bs_center( carve::geom::VECTOR( bs.center().x(), bs.center().y(), bs.center().z() ) ); + double d = GeomUtils::distancePoint2LineUnitDirection( bs_center, ray_point, ray_direction ); + + if( d < bs.radius() ) + { + // node is close to pointer ray + osg::Group* child_group = dynamic_cast( node ); + if( child_group ) + { + intersectGroup( child_group, ray_point, ray_direction, smallest_d, closest_point ); + continue; + } + + osg::Geode* child_geode = dynamic_cast( node ); + if( child_geode ) + { + for( size_t i_drawable = 0; i_drawable < child_geode->getNumDrawables(); ++i_drawable ) + { + osg::Drawable* drawable = child_geode->getDrawable( i_drawable ); + + osg::Geometry* geometry = dynamic_cast( drawable ); + if( geometry ) + { + const osg::BoundingSphere& bs_geometry = geometry->computeBound(); + const carve::geom::vector<3> bs_center( carve::geom::VECTOR( bs_geometry.center().x(), bs_geometry.center().y(), bs_geometry.center().z() ) ); + + //double d = GeomUtils::distancePoint2Line( const carve::geom::vector<3>& point, const carve::geom::vector<3>& line_p0, const carve::geom::vector<3>& line_p1 ); + double d = GeomUtils::distancePoint2LineUnitDirection( bs_center, ray_point, ray_direction ); + + if( d < bs_geometry.radius() ) + { + osg::Vec3Array* vertex_array = dynamic_cast( geometry->getVertexArray() ); + if( vertex_array ) + { + osg::Vec3Array& vertex_array_ref = *vertex_array; + for( size_t i_vertex = 0; i_vertex < vertex_array->size(); ++i_vertex ) + { + osg::Vec3& vec3_osg = vertex_array_ref[i_vertex]; + const carve::geom::vector<3> vec3( carve::geom::VECTOR( vec3_osg.x(), vec3_osg.y(), vec3_osg.z() ) ); + double d = GeomUtils::distancePoint2LineUnitDirection( vec3, ray_point, ray_direction ); + if( d < smallest_d && d < 0.5 ) + { + smallest_d = d; + closest_point = vertex_array_ref[i_vertex]; + } + } + } + } + } + } + } + } + } +} + +bool IntersectionHandler::intersectSceneSimple( const osgGA::GUIEventAdapter& ea, osgViewer::View* view, osg::Vec3d& intersect_point ) +{ +#ifdef POLYTOPE_INTERSECTOR + double mx = ea.getXnormalized(); + double my = ea.getYnormalized(); + double w = 0.005; + double h = 0.005; + osg::ref_ptr picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx - w, my - h, mx + w, my + h ); +#else + osg::ref_ptr picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(), ea.getYnormalized() ); +#endif + //picker->setIntersectionLimit( osgUtil::Intersector::LIMIT_ONE_PER_DRAWABLE ); + //picker->setIntersectionLimit( osgUtil::Intersector::LIMIT_NEAREST ); + + osgUtil::IntersectionVisitor iv( picker.get() ); + osg::Camera* cam = view->getCamera(); + cam->accept( iv ); + + if( picker->containsIntersections() ) + { +#ifdef POLYTOPE_INTERSECTOR + osgUtil::PolytopeIntersector::Intersection intersection = picker->getFirstIntersection(); +#else + osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection(); +#endif + + osg::NodePath& nodePath = intersection.nodePath; + for( unsigned int i = 0; igetName(); + + // check if picked object is a representation of an IfcProduct + if( node_name.length() == 0 ) continue; + if( node_name.substr( 0, 9 ).compare( "intersect" ) == 0 ) continue; + + intersect_point = intersection.getWorldIntersectPoint(); + return true; + } + } + + return false; +} + +enum selectEraseMode { SELECT_ERASE_NONE, SELECT_ERASE_TRIANGLE, SELECT_ERASE_PRIMITIVE_SET }; + +bool IntersectionHandler::intersectSceneSelect( const osgGA::GUIEventAdapter& ea, osgViewer::View* view ) +{ + //m_group_selected->removeChildren( 0, m_group_selected->getNumChildren() ); + bool only_first_intesection = false; + double closest_intersection_distance = DBL_MAX; + selectEraseMode select_erase_mode = SELECT_ERASE_NONE; + // selectEraseMode select_erase_mode = SELECT_ERASE_PRIMITIVE_SET; + // TODO: select object/primitive set/mesh/triangle/face (=all connected planar triangles) button in GUI + // TODO: rubberband area selection + +#ifdef POLYTOPE_INTERSECTOR + double mx = ea.getXnormalized(); + double my = ea.getYnormalized(); + double w = 0.005; + double h = 0.005; + osg::ref_ptr picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx - w, my - h, mx + w, my + h ); +#else + osg::ref_ptr picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(), ea.getYnormalized() ); +#endif + osgUtil::IntersectionVisitor iv( picker.get() ); + osg::Camera* cam = view->getCamera(); + iv.apply( *cam ); + + osg::Vec3d eye_point = m_system->getViewController()->getOrbitManipulator3D()->getEye(); + bool intersection_geometry_found = false; + osgUtil::LineSegmentIntersector::Intersection closest_intersection; + int closest_intersection_nodepath_idx = 0; + + if (picker->containsIntersections()) + { +#ifdef POLYTOPE_INTERSECTOR + osgUtil::PolytopeIntersector::Intersections& intersections = picker->getIntersections(); +#else + osgUtil::LineSegmentIntersector::Intersections& intersections = picker->getIntersections(); +#endif + + for (auto it_intersections = intersections.begin(); it_intersections != intersections.end(); ++it_intersections) + { + osgUtil::LineSegmentIntersector::Intersection intersection = *it_intersections; + osg::NodePath& nodePath = intersection.nodePath; + for (unsigned int i_nodepath = 0; i_nodepath < nodePath.size(); ++i_nodepath) + { + int node_path_idx = nodePath.size() - i_nodepath - 1; + osg::Node* node = nodePath[node_path_idx]; + std::string node_name = node->getName(); + + // check if picked object is IfcProduct + if (node_name.length() < 22) continue; + + node_name = node_name.substr(0, 22); + + std::string guid; + std::regex re("[a-zA-Z0-9_$]{22}"); + std::smatch match; + if (std::regex_search(node_name, match, re)) + { + guid = match.str(0); + } + else + { + continue; + } + + if (node_name.compare(0, 9, "intersect") == 0) continue; + + osg::Group* group = dynamic_cast(node); + if (!group) + { + continue; + } + + osg::Vec3d world_intersect_point = intersection.getWorldIntersectPoint(); + m_pointer_intersection.set(world_intersect_point); + double distance_to_eye = (eye_point - world_intersect_point).length(); + if (distance_to_eye < closest_intersection_distance) + { + intersection_geometry_found = true; + closest_intersection_distance = distance_to_eye; + closest_intersection = intersection; + closest_intersection_nodepath_idx = node_path_idx; + } + + continue; + } + } + + if( intersection_geometry_found ) + { + osg::NodePath& nodePath = closest_intersection.nodePath; + if (closest_intersection_nodepath_idx < nodePath.size()) + { + osg::Node* node = nodePath[closest_intersection_nodepath_idx]; + std::string node_name = node->getName(); + + // extract guid + if (node_name.size() >= 22) + { + node_name = node_name.substr(0, 22); + + std::string guid_selected; + std::regex re("[a-zA-Z0-9_$]{22}"); + std::smatch match; + if (std::regex_search(node_name, match, re)) + { + guid_selected = match.str(0); + } + + osg::Vec3d world_intersect_point = closest_intersection.getWorldIntersectPoint(); + m_pointer_intersection.set(world_intersect_point); + + osg::Group* group = dynamic_cast(node); + if (group) + { + const std::unordered_map >& map_selected = m_system->getSelectedObjects(); + auto it_selected = map_selected.find(guid_selected); + + if (it_selected != map_selected.end()) + { + shared_ptr selected_entity = it_selected->second; + // is already selected, so deselect + m_system->setObjectSelected(selected_entity->m_entity, false, selected_entity->m_osg_group); + return true; + } + else + { + // select + shared_ptr ifc_model = m_system->getGeometryConverter()->getBuildingModel(); + const std::map >& map_ifc_objects = ifc_model->getMapIfcEntities(); + for (auto it_find : map_ifc_objects) + { + shared_ptr entity = it_find.second; + std::string guid = getGUID(entity); + if (guid.compare(guid_selected) == 0) + { + shared_ptr entitiy_selected = entity; + if (!m_system->isCtrlKeyDown()) + { + m_system->clearSelection(); + } + m_system->setObjectSelected(entitiy_selected, true, group); + break; + } + } + return true; + } + } + } + } + } + } + else + { + // no geometry has been hit, so intersect with XY-plane + //intersectRayWithPlane( m_ray_pointer_start, m_ray_pointer_direction, IntersectionPlane::XY_PLANE, m_pointer_intersection ); + } + + return intersection_geometry_found; +} diff --git a/examples/SimpleViewerExampleQt/src/viewer/IntersectionHandler.h b/examples/SimpleViewerExampleQt/src/viewer/IntersectionHandler.h new file mode 100644 index 000000000..e9f8803c9 --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer/IntersectionHandler.h @@ -0,0 +1,42 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include + +class IfcPlusPlusSystem; + +class IntersectionHandler +{ +public: + IntersectionHandler(IfcPlusPlusSystem* s ); + ~IntersectionHandler(); + + void intersectGroup( osg::Group* group, const carve::geom::vector<3> ray_point, const carve::geom::vector<3> ray_direction, double& smallest_d, osg::Vec3f& closest_point ); + bool intersectSceneSelect( const osgGA::GUIEventAdapter& ea, osgViewer::View* view ); + bool intersectSceneSimple( const osgGA::GUIEventAdapter& ea, osgViewer::View* view, osg::Vec3d& intersect_point ); + + osg::ref_ptr m_group_selected; + osg::Vec3d m_pointer_intersection; + osg::Vec3f m_snapped_point; + bool m_has_snapped_point; + IfcPlusPlusSystem* m_system; +}; diff --git a/examples/SimpleViewerExampleQt/src/viewer/Orbit3DManipulator.cpp b/examples/SimpleViewerExampleQt/src/viewer/Orbit3DManipulator.cpp new file mode 100644 index 000000000..5df18b130 --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer/Orbit3DManipulator.cpp @@ -0,0 +1,936 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "IfcPlusPlusSystem.h" +#include "ViewerUtil.h" +#include "ViewController.h" +#include "viewer/IntersectionHandler.h" +#include "Orbit3DManipulator.h" + +int Orbit3DManipulator::m_minimum_distance_flag_index = allocateRelativeFlag(); + +Orbit3DManipulator::Orbit3DManipulator( IfcPlusPlusSystem* s, IntersectionHandler* ih, int flags ) + : StandardManipulator(flags), m_system(s), m_intersection_handler( ih ) +{ + m_eye.set( 10, 10, 10 ); + m_up.set( 0, 0, 1 ); + m_rotate_center.set( 0, 0, 0 ); + setMinimumDistance( 0.05, true ); + m_wheel_zoom_factor = 0.05; + + initManipulator(); + + connect( m_system, &IfcPlusPlusSystem::signalModelLoadingDone, this, &Orbit3DManipulator::slotModelLoadingDone ); +} + +Orbit3DManipulator::Orbit3DManipulator( const Orbit3DManipulator& om, const osg::CopyOp& copyOp ) : osg::Object(om, copyOp), StandardManipulator( om, copyOp ), + m_system( om.m_system), m_eye( om.m_eye ), m_lookat( om.m_lookat ), m_rotate_center( om.m_rotate_center ), + m_wheel_zoom_factor( om.m_wheel_zoom_factor ), m_minimum_distance( om.m_minimum_distance ) +{ + initManipulator(); +} + +Orbit3DManipulator::~Orbit3DManipulator(){} + +void Orbit3DManipulator::initManipulator() +{ + setAnimationTime( 0.2 ); + + _homeEye.set( m_eye ); + _homeCenter.set( m_lookat ); + _homeUp.set( m_up ); + setAutoComputeHomePosition( false ); + _allowThrow = false; + + m_animation_data = new OrbitAnimationData(); + m_selection_disabled = false; + m_fovy = 30; + + osg::Vec4f color( 249.f/255, 129.f/255, 12.f/255, 1.f ); + osg::Geode* intersect_geode = new osg::Geode(); + + osg::Vec3Array* vertices = new osg::Vec3Array(); + vertices->push_back( osg::Vec3d( 0, 0, -1 ) ); + vertices->push_back( osg::Vec3d( 0, 0, 1 ) ); + + osg::Geometry* geometry = new osg::Geometry(); + geometry->setVertexArray( vertices ); + geometry->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, vertices->size()) ); + osg::ref_ptr colors = new osg::Vec4Array(); + colors->resize( vertices->size(), color ); + colors->setBinding( osg::Array::BIND_PER_VERTEX ); + geometry->setColorArray( colors ); + osg::StateSet* stateset_geom = geometry->getOrCreateStateSet(); + stateset_geom->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + int lineStipplePattern = 0XAAAA; + osg::ref_ptr stipple= new osg::LineStipple(); + stipple->setPattern( (short)lineStipplePattern ); + stipple->setFactor( 4 ); + stateset_geom->setAttributeAndModes( stipple, osg::StateAttribute::ON ); + intersect_geode->addDrawable(geometry); + + // circle + osg::Vec3Array* vertices_circle = new osg::Vec3Array(); + for( int i=0; i<41; ++i ) + { + vertices_circle->push_back( osg::Vec3d( sin(M_PI*double(i)*0.05)*0.2, cos(M_PI*double(i)*0.05)*0.2, 0 ) ); + } + + osg::Geometry* geometry_circle = new osg::Geometry(); + geometry_circle->setVertexArray( vertices_circle ); + geometry_circle->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, vertices_circle->size()) ); + osg::ref_ptr colors_circle = new osg::Vec4Array(); + colors_circle->resize( vertices_circle->size(), color ); + colors_circle->setBinding( osg::Array::BIND_PER_VERTEX ); + geometry_circle->setColorArray( colors_circle ); + osg::StateSet* stateset_circle = geometry_circle->getOrCreateStateSet(); + stateset_circle->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + osg::ref_ptr antialias_hint = new osg::Hint(GL_LINE_SMOOTH_HINT, GL_NICEST); + stateset_circle->setAttributeAndModes(antialias_hint.get(), osg::StateAttribute::ON); + intersect_geode->addDrawable(geometry_circle); + + osg::Geometry* geometry_thick_line = new osg::Geometry(); + geometry_thick_line->setVertexArray( vertices_circle ); + geometry_thick_line->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, vertices_circle->size()) ); + osg::ref_ptr colors_thick_line = new osg::Vec4Array(); + colors_thick_line->setBinding( osg::Array::BIND_PER_VERTEX ); + colors_thick_line->resize( vertices_circle->size(), color ); + geometry_thick_line->setColorArray( colors_thick_line ); + osg::StateSet* stateset_geom_thick_line = geometry_thick_line->getOrCreateStateSet(); + osg::LineWidth* linewidth = new osg::LineWidth(); + linewidth->setWidth(4.0f); + stateset_geom_thick_line->setAttributeAndModes(linewidth,osg::StateAttribute::ON); + stateset_geom_thick_line->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + intersect_geode->addDrawable(geometry_thick_line); + + osg::MatrixTransform* cone_transform_self = new osg::MatrixTransform(); + m_intersect_geom_transform = new osg::MatrixTransform(); + + cone_transform_self->addChild(intersect_geode); + m_intersect_geom_transform->addChild(cone_transform_self); + m_intersect_geom_switch = new osg::Switch(); + m_intersect_geom_switch->setAllChildrenOff(); + m_intersect_geom_switch->addChild( m_intersect_geom_transform ); + + + m_snap_radius = 0.025; + + { + osg::Vec3Array* vertices = new osg::Vec3Array(); + for( size_t ii = 0; ii < 21; ++ii ) + { + float sin_alpha = m_snap_radius*0.5*sin( float( ii ) / 20 * 2 * M_PI ); + float cos_alpha = m_snap_radius*0.5*cos( float( ii ) / 20 * 2 * M_PI ); + vertices->push_back( osg::Vec3( m_snapped_point.x() + sin_alpha, m_snapped_point.y() + cos_alpha, m_snapped_point.z() ) ); + } + for( size_t ii = 0; ii < 21; ++ii ) + { + float sin_alpha = m_snap_radius*0.5*sin( float( ii ) / 20 * 2 * M_PI ); + float cos_alpha = m_snap_radius*0.5*cos( float( ii ) / 20 * 2 * M_PI ); + vertices->push_back( osg::Vec3( m_snapped_point.x() + sin_alpha, m_snapped_point.y(), m_snapped_point.z() + cos_alpha ) ); + } + for( size_t ii = 0; ii < 21; ++ii ) + { + float sin_alpha = m_snap_radius*0.5*sin( float( ii ) / 20 * 2 * M_PI ); + float cos_alpha = m_snap_radius*0.5*cos( float( ii ) / 20 * 2 * M_PI ); + vertices->push_back( osg::Vec3( m_snapped_point.x(), m_snapped_point.y() + sin_alpha, m_snapped_point.z() + cos_alpha ) ); + } + + vertices->push_back( osg::Vec3( m_snapped_point.x() - m_snap_radius*0.5, m_snapped_point.y(), m_snapped_point.z() ) ); + vertices->push_back( osg::Vec3( m_snapped_point.x() + m_snap_radius*0.5, m_snapped_point.y(), m_snapped_point.z() ) ); + + vertices->push_back( osg::Vec3( m_snapped_point.x(), m_snapped_point.y() - m_snap_radius*0.5, m_snapped_point.z() ) ); + vertices->push_back( osg::Vec3( m_snapped_point.x(), m_snapped_point.y() + m_snap_radius*0.5, m_snapped_point.z() ) ); + + vertices->push_back( osg::Vec3( m_snapped_point.x(), m_snapped_point.y(), m_snapped_point.z() - m_snap_radius*0.5 ) ); + vertices->push_back( osg::Vec3( m_snapped_point.x(), m_snapped_point.y(), m_snapped_point.z() + m_snap_radius*0.5 ) ); + + osg::Geometry* geom = new osg::Geometry(); + geom->setVertexArray( vertices ); + geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 0, 21 ) ); // 0, ..., 20 + geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 21, 21 ) ); // 21, ..., 41 + geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 42, 21 ) ); // 42, ..., 62 + geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, 63, 6 ) ); + geom->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); + + osg::Vec4Array* colors = new osg::Vec4Array(); + colors->push_back( osg::Vec4( 0.99, 0.99, 0.1, 0.1 ) ); + colors->setBinding( osg::Array::BIND_OVERALL ); + geom->setColorArray( colors ); + + osg::Geode* geode = new osg::Geode(); + geode->addDrawable( geom ); + + m_snap_wire_cone = new osg::AutoTransform(); + m_snap_wire_cone->addChild( geode ); + } +} + +void Orbit3DManipulator::slotModelLoadingDone() +{ + +} + +void Orbit3DManipulator::setSelectionDisabled( bool disabled ) +{ + m_selection_disabled = disabled; +} + +void Orbit3DManipulator::setByMatrix( const osg::Matrixd& matrix ) +{ + matrix.getLookAt( m_eye, m_lookat, m_up ); +} + +void Orbit3DManipulator::setByInverseMatrix( const osg::Matrixd& matrix ) +{ + setByMatrix( osg::Matrixd::inverse( matrix ) ); +} + +osg::Matrixd Orbit3DManipulator::getMatrix() const +{ + osg::Matrix m; + m.makeLookAt( m_eye, m_lookat, m_up ); + return m; +} + +osg::Matrixd Orbit3DManipulator::getInverseMatrix() const +{ + osg::Matrix m; + m.makeLookAt( m_eye, m_lookat, m_up ); + return m; +} + +// doc in parent +void Orbit3DManipulator::setTransformation( const osg::Vec3d& eye, const osg::Quat& rotation ) +{ + m_eye.set( eye ); + // TODO: implement + //m_lookat = eye + rotation * osg::Vec3d( 0., 0., -m_distance ); + //m_rotation = rotation; + + // fix current rotation + if( getVerticalAxisFixed() ) + { + //fixVerticalAxis( m_lookat, m_rotation, true ); + } +} + +void Orbit3DManipulator::getTransformation( osg::Vec3d& eye, osg::Quat& rotation ) const +{ + eye.set( m_eye ); + // TODO: implement + +} + +void Orbit3DManipulator::setTransformation( const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up ) +{ + m_eye.set( eye ); + m_lookat.set( center ); + m_up.set( up ); + emit( signalEyeLookatChanged() ); +} + +void Orbit3DManipulator::getTransformation( osg::Vec3d& eye, osg::Vec3d& center, osg::Vec3d& up ) const +{ + center.set( m_lookat ); + eye.set( m_eye ); + up.set( m_up ); +} + +void Orbit3DManipulator::setEyeLookat( const osg::Vec3d& eye, const osg::Vec3d& lookat ) +{ + m_eye.set( eye ); + m_lookat.set( lookat ); + emit( signalEyeLookatChanged() ); +} + +void Orbit3DManipulator::setRotateCenter( const osg::Vec3d& center ) +{ + m_rotate_center.set( center ); +} + +void Orbit3DManipulator::computeRayPointer( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgViewer::View* view = dynamic_cast(&aa); + if (!view) return; + + osg::Matrix model_screen( osg::Matrix::identity() ); + // do not apply viewport here ( m_cam->getViewport()->computeWindowMatrix() ). Use normalized screen coords instead (ea.getXnormalized()) + osg::Matrixd pm( view->getCamera()->getProjectionMatrix() ); + osg::Matrixd vm( getInverseMatrix() ); + + if( pm.valid() ) model_screen.preMult( pm ); + if( vm.valid() ) model_screen.preMult( vm ); + + osg::Matrix screen_model; + screen_model.invert( model_screen ); + + m_system->getViewController()->setModelScreen( model_screen ); + m_system->getViewController()->setScreenModel( screen_model ); + + osg::Vec3d ray_pointer_start( screen_model.preMult( osg::Vec3d( ea.getXnormalized(), ea.getYnormalized(), 0.0) ) ); + osg::Vec3d pointer_end = screen_model.preMult( osg::Vec3d( ea.getXnormalized(), ea.getYnormalized(), 0.1) ); + + osg::Vec3d ray_direction = pointer_end - ray_pointer_start; + ray_direction.normalize(); + + glm::dvec3 ray_pointer_start_glm(ray_pointer_start.x(), ray_pointer_start.y(), ray_pointer_start.z()); + glm::dvec3 ray_direction_glm(ray_direction.x(), ray_direction.y(), ray_direction.z()); + m_system->getViewController()->setPointerRay( ray_pointer_start_glm, ray_direction_glm ); + + double fovy, apect_ratio, zNear, zFar; + bool perspective = pm.getPerspective( fovy, apect_ratio, zNear, zFar ); + if( perspective ) + { + m_fovy = fovy; + } +} + +bool Orbit3DManipulator::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + bool handled_by_kernel = m_system->handle( ea, aa ); + + switch( ea.getEventType() ) + { + + case osgGA::GUIEventAdapter::FRAME: + return handleFrame( ea, aa ); + + case osgGA::GUIEventAdapter::RESIZE: + return handleResize( ea, aa ); + + default: + break; + } + + if( ea.getHandled() ) + { + return false; + } + + computeRayPointer( ea, aa ); + + bool handled = false; + switch( ea.getEventType() ) + { + case osgGA::GUIEventAdapter::MOVE: + handled = handleMouseMove( ea, aa ); + break; + + case osgGA::GUIEventAdapter::DRAG: + handled = handleMouseDrag( ea, aa ); + break; + + case osgGA::GUIEventAdapter::PUSH: + handled = handleMousePush( ea, aa ); + break; + + case osgGA::GUIEventAdapter::RELEASE: + handled = handleMouseRelease( ea, aa ); + + if( m_has_snapped_point ) + { + if( !m_system->getViewController()->m_pointer_push_drag ) + { + m_system->notifyCursorCoordinates( m_snapped_point.x(), m_snapped_point.y(), m_snapped_point.z() ); + } + } + + break; + + case osgGA::GUIEventAdapter::KEYDOWN: + handled = handleKeyDown( ea, aa ); + break; + + case osgGA::GUIEventAdapter::KEYUP: + handled = handleKeyUp( ea, aa ); + break; + + case osgGA::GUIEventAdapter::SCROLL: + if( _flags & PROCESS_MOUSE_WHEEL ) + handled = handleMouseWheel( ea, aa ); + else + handled = false; + break; + + default: + handled = false; + } + + return handled; +} + +bool Orbit3DManipulator::handleFrame( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + double current_frame_time = ea.getTime(); + + _delta_frame_time = current_frame_time - _last_frame_time; + _last_frame_time = current_frame_time; + + unsigned int button_mask = ea.getButtonMask(); + int button = ea.getButton(); + if( button_mask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON + || button_mask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON + || button_mask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON ) + { + // some button is currently pressed + } + else + { + m_intersect_geom_switch->setAllChildrenOff(); + } + + if( _thrown && performMovement( ea, aa ) ) + { + aa.requestRedraw(); + } + + if( m_animation_data && m_animation_data->_isAnimating ) + { + if( m_animation_data->_startTime < 0 ) + { + // animation has been started from some location without acces to a GUIEventAdapter object, so no start time could be set. Do it now. + m_animation_data->start( current_frame_time ); + } + performAnimationMovement( ea, aa ); + } + + return false; +} + +bool Orbit3DManipulator::handleMouseMove( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + SceneGraphUtils::removeChildren( m_system->getViewController()->getSnapNode() ); + + const GeomUtils::Ray& pointer_ray = m_system->getViewController()->m_current_pointer_ray; + carve::geom::vector<3> ray_point( carve::geom::VECTOR( pointer_ray.origin.x, pointer_ray.origin.y, pointer_ray.origin.z ) ); + carve::geom::vector<3> ray_direction( carve::geom::VECTOR( pointer_ray.direction.x, pointer_ray.direction.y, pointer_ray.direction.z ) ); + + osg::Group* model_group = m_system->getViewController()->getModelNode(); + double smallest_distance = DBL_MAX; + m_snapped_point.set( 0, 0, 0 ); + m_has_snapped_point = false; + + m_intersection_handler->intersectGroup( model_group, ray_point, ray_direction, smallest_distance, m_snapped_point ); + + + if( smallest_distance < m_snap_radius ) + { + m_has_snapped_point = true; + + osg::MatrixTransform* mt = new osg::MatrixTransform(); + mt->addChild( m_snap_wire_cone ); + mt->setMatrix( osg::Matrix::translate( m_snapped_point ) ); + m_system->getViewController()->getSnapNode()->addChild( mt ); + m_system->notifyCursorCoordinates( m_snapped_point.x(), m_snapped_point.y(), m_snapped_point.z() ); + } + else + { + m_system->notifyCursorCoordinates( 0, 0, 0 ); + } + + return false; +} + +bool Orbit3DManipulator::handleMousePush( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgViewer::View* view = dynamic_cast(&aa); + if( !view ) + { + return false; + } + + unsigned int button_mask = ea.getButtonMask(); + + m_system->getViewController()->m_pointer_push_drag = false; + flushMouseEventStack(); + addMouseEvent( ea ); + + + // TODO: intersect pan plane instead + osg::Vec3d pointer_intersection; + + if( m_intersection_handler->intersectSceneSimple( ea, view, pointer_intersection ) ) + { + m_rotate_center.set( pointer_intersection ); + } + + if( button_mask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON || button_mask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON ) + { + m_pan_start.set( ea.getXnormalized(), ea.getYnormalized() ); + m_pan_end.set( ea.getXnormalized(), ea.getYnormalized() ); + m_pan_ray.setRay( &(m_system->getViewController()->m_current_pointer_ray) ); + + glm::dvec3 panPlaneNormal(m_rotate_center.x() - m_eye.x(), m_rotate_center.y() - m_eye.y(), m_rotate_center.z() - -m_eye.z()); + panPlaneNormal = glm::normalize( panPlaneNormal ); + m_pan_plane.setPlane( glm::dvec3( m_rotate_center.x(), m_rotate_center.y(), m_rotate_center.z() ), panPlaneNormal); + + m_system->getViewController()->setCursor( Qt::OpenHandCursor ); + } + + if( button_mask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) + { + osg::Vec3d distance_intersect_eye( m_rotate_center - m_eye ); + double distance_eye_intersection = distance_intersect_eye.length(); + + if( !m_selection_disabled ) + { + osg::Matrix mat_scale( osg::Matrix::scale( distance_eye_intersection*0.1, distance_eye_intersection*0.1, distance_eye_intersection*0.1 ) ); + distance_intersect_eye.normalize(); + osg::Matrix mat_rotate( osg::Matrix::rotate( osg::Vec3d( 0, 0, 1 ), distance_intersect_eye ) ); + osg::Matrix mat_translate( osg::Matrix::translate(m_rotate_center) ); + m_intersect_geom_transform->setMatrix(mat_scale*mat_translate ); + m_intersect_geom_switch->setAllChildrenOn(); + m_system->getViewController()->getSnapNode()->addChild( m_intersect_geom_switch ); + } + } + + aa.requestRedraw(); + aa.requestContinuousUpdate( false ); + _thrown = false; + + return false; +} + +bool Orbit3DManipulator::handleMouseRelease( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgViewer::View* view = dynamic_cast(&aa); + if( !view ) return false; + + osg::Group* root_node = dynamic_cast(view->getScene()->getSceneData()); + + m_intersect_geom_switch->setAllChildrenOff(); + m_system->getViewController()->restoreCursor(); + + if( ea.getButtonMask() == 0 ) + { + double timeSinceLastRecordEvent = _ga_t0.valid() ? (ea.getTime() - _ga_t0->getTime()) : DBL_MAX; + if( timeSinceLastRecordEvent > 0.02 ) + { + flushMouseEventStack(); + } + + if( isMouseMoving() ) + { + if( performMovement( ea, aa ) && _allowThrow ) + { + aa.requestRedraw(); + aa.requestContinuousUpdate( true ); + _thrown = true; + // TODO: fade out throw animation + } + + return true; + } + } + + if( !m_system->getViewController()->m_pointer_push_drag && !m_selection_disabled ) + { + // select object + bool intersection_geometry_found = m_intersection_handler->intersectSceneSelect( ea, view ); + + if( !intersection_geometry_found ) + { + // click to background -> unselect all + m_system->clearSelection(); + + } + } + + m_system->getViewController()->m_pointer_push_drag = false; + + flushMouseEventStack(); + addMouseEvent( ea ); + if( performMovement( ea, aa ) ) + { + aa.requestRedraw(); + } + aa.requestContinuousUpdate( false ); + _thrown = false; + + return true; +} + + +bool Orbit3DManipulator::handleMouseWheel( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion(); + + // TODO: increase scroll factor when eye is far away from model bounding sphere + double scroll_distance_factor = ( m_eye - m_rotate_center ).length()*0.1; + + switch( sm ) + { + // mouse scroll up event + case osgGA::GUIEventAdapter::SCROLL_UP: + { + // perform zoom + zoomCamera( m_wheel_zoom_factor*scroll_distance_factor ); + aa.requestRedraw(); + aa.requestContinuousUpdate( isAnimating() || _thrown ); + return true; + } + + // mouse scroll down event + case osgGA::GUIEventAdapter::SCROLL_DOWN: + { + // perform zoom + zoomCamera( -m_wheel_zoom_factor*scroll_distance_factor ); + aa.requestRedraw(); + aa.requestContinuousUpdate( isAnimating() || _thrown ); + return true; + } + + // unhandled mouse scrolling motion + default: + return false; + } +} + +bool Orbit3DManipulator::handleMouseDrag( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + addMouseEvent( ea ); + + m_system->getViewController()->m_pointer_push_drag = true; + if( performMovement( ea, aa ) ) + { + aa.requestRedraw(); + } + + aa.requestContinuousUpdate( false ); + _thrown = false; + + return true; +} + +bool Orbit3DManipulator::performMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + if( _ga_t0.get() == nullptr || _ga_t1.get() == nullptr ) + { + // not yet enough pointer events to determine a delta + return false; + } + + // get delta time + double eventTimeDelta = _ga_t0->getTime() - _ga_t1->getTime(); + if( eventTimeDelta < 0. ) + { + OSG_WARN << "Manipulator warning: eventTimeDelta = " << eventTimeDelta << std::endl; + eventTimeDelta = 0.; + } + + // get deltaX and deltaY + float dx = _ga_t0->getXnormalized() - _ga_t1->getXnormalized(); + float dy = _ga_t0->getYnormalized() - _ga_t1->getYnormalized(); + float scale = getThrowScale( eventTimeDelta ); + dx = dx*scale; + dy = dy*scale; + + // return if there is no movement. + if( dx == 0. && dy == 0. ) + { + return false; + } + + // call appropriate methods + unsigned int button_mask = _ga_t1->getButtonMask(); + if( button_mask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) + { + rotateCamera( dx, dy ); + return true; + } + else if( button_mask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON || button_mask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON ) + { + // pan model + m_system->getViewController()->setCursor( Qt::ClosedHandCursor ); + m_pan_end.set( ea.getXnormalized(), ea.getYnormalized() ); + panCamera( dx, dy, ea, aa ); + + return true; + } + + return false; +} + +bool Orbit3DManipulator::performMouseDeltaMovement( const float dx, const float dy ) +{ + rotateCamera( dx, dy ); + return true; +} + +void Orbit3DManipulator::rotateCamera( float dx, float dy ) +{ + if( dx != 0.0 || dy != 0.0 ) + { + // yaw + osg::CoordinateFrame coordinate_frame = getCoordinateFrame( m_lookat ); + osg::Vec3d yaw_axis = getUpVector( coordinate_frame ); + + yaw_axis.normalize(); + + // lookat is the center of the screen. rotation center can be different (intersection point) + osg::Vec3d center_eye = m_eye - m_rotate_center; + osg::Vec3d center_lookat = m_lookat - m_rotate_center; + osg::Vec3d eye_lookat = m_lookat - m_eye; + + // pitch + osg::Vec3d pitch_axis(0,0,1); + pitch_axis = pitch_axis ^ center_eye; + pitch_axis.normalize(); + + // apply yaw and pitch around the rotation center + osg::Quat quatpitch( dy*2.2, pitch_axis ); + osg::Vec3d center_eye_pitch = quatpitch * center_eye; + osg::Vec3d center_lookat_pitch = quatpitch * center_lookat; + + osg::Quat quatyaw( -dx*5.2, yaw_axis ); + osg::Vec3d center_eye_new = quatyaw*center_eye_pitch; + osg::Vec3d center_lookat_new = quatyaw*center_lookat_pitch; + + m_eye.set( m_rotate_center + center_eye_new ); + m_lookat.set( m_rotate_center + center_lookat_new ); + + emit( signalEyeLookatChanged() ); + } +}; + +void Orbit3DManipulator::panCamera( const float dx, const float dy, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + const GeomUtils::Ray& current_pan_ray = m_system->getViewController()->m_current_pointer_ray; + osg::Vec2d mouse_change = m_pan_end - m_pan_start; + double length_mouse_move = mouse_change.length2(); + if( length_mouse_move > 0.00001 ) + { + double intersectionDistance = 0; + bool planeIntersects = GeomUtils::intersectRayPlane(m_pan_ray.origin, m_pan_ray.direction, m_pan_plane.getPosition(), m_pan_plane.getNormal(), intersectionDistance); + + if( planeIntersects ) + { + glm::dvec3 intersect_point = m_pan_ray.origin + intersectionDistance*m_pan_ray.direction; + + double intersectionDistance = 0; + bool planeIntersects2 = GeomUtils::intersectRayPlane(current_pan_ray.origin, current_pan_ray.direction, m_pan_plane.getPosition(), m_pan_plane.getNormal(), intersectionDistance); + + if( planeIntersects2 ) + { + glm::dvec3 intersect_point2 = current_pan_ray.origin + intersectionDistance*current_pan_ray.direction; + glm::dvec3 diff = intersect_point - intersect_point2; + m_eye += osg::Vec3d( diff.x, diff.y, diff.z ); + m_lookat += osg::Vec3d( diff.x, diff.y, diff.z ); + } + + m_pan_start = m_pan_end; + } + emit( signalEyeLookatChanged() ); + } +} + +void Orbit3DManipulator::zoomCamera( const float dy ) +{ + // push camera forwared along mouse ray + glm::dvec3 zoom_direction = m_system->getViewController()->m_current_pointer_ray.direction; + zoom_direction = glm::normalize(zoom_direction); + zoom_direction *= dy*100; + m_eye += osg::Vec3d( zoom_direction.x, zoom_direction.y, zoom_direction.z ); + m_lookat += osg::Vec3d( zoom_direction.x, zoom_direction.y, zoom_direction.z ); + + emit( signalEyeLookatChanged() ); +} + +////////////////////////////////////////////////////// animation ////////////////////////////////////////////////////////////////// +void Orbit3DManipulator::setAnimationData( OrbitAnimationData* anim_data ) +{ + m_animation_data = anim_data; + //m_animation_data->m_start_eye = anim_data->m_start_eye; + //m_animation_data->m_start_lookat = anim_data->m_start_lookat; + //m_animation_data->m_start_up = anim_data->m_start_up; + //m_animation_data->m_target_eye = anim_data->m_target_eye; + //m_animation_data->m_target_lookat = anim_data->m_target_lookat; + //m_animation_data->m_target_up = anim_data->m_target_up; +} + +void Orbit3DManipulator::applyAnimationStep( const double currentProgress, const double prevProgress ) +{ + osg::Vec3d new_eye( m_animation_data->m_start_eye + (m_animation_data->m_target_eye - m_animation_data->m_start_eye) * (currentProgress) ); + osg::Vec3d new_lookat( m_animation_data->m_start_lookat + (m_animation_data->m_target_lookat - m_animation_data->m_start_lookat) * (currentProgress) ); + osg::Vec3d new_up( m_animation_data->m_start_up + (m_animation_data->m_target_up - m_animation_data->m_start_up) * (currentProgress) ); + + m_eye.set( new_eye ); + m_lookat.set( new_lookat ); + m_up.set( new_up ); + emit( signalEyeLookatChanged() ); +} + + +Orbit3DManipulator::OrbitAnimationData::OrbitAnimationData() : AnimationData() +{ +} + +void Orbit3DManipulator::OrbitAnimationData::start( const double startTime ) +{ + AnimationData::start( startTime ); + _isAnimating = true; +} + +void Orbit3DManipulator::setAnimationTime( const double t ) +{ + if( t <= 0. ) + { + finishAnimation(); + m_animation_data = nullptr; + return; + } + + if( !m_animation_data ) + { + allocAnimationData(); + } + + m_animation_data->_animationTime = t; +} + +bool Orbit3DManipulator::performAnimationMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + double f = (ea.getTime() - m_animation_data->_startTime) / m_animation_data->_animationTime; + if( f >= 1. ) + { + f = 1.; + m_animation_data->_isAnimating = false; + if( !_thrown ) + { + aa.requestContinuousUpdate( false ); + } + } + + applyAnimationStep( f, m_animation_data->_phase ); + + m_animation_data->_phase = f; + aa.requestRedraw(); + + return m_animation_data->_isAnimating; +} + +bool Orbit3DManipulator::isAnimating() const +{ + if( m_animation_data ) + { + return m_animation_data->_isAnimating; + } + else + { + return false; + } +} + +osgUtil::SceneView::FusionDistanceMode Orbit3DManipulator::getFusionDistanceMode() const +{ + return osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE; +} + +float Orbit3DManipulator::getFusionDistanceValue() const +{ + return 0;//m_distance; +} + +void Orbit3DManipulator::setWheelZoomFactor( double wheelZoomFactor ) +{ + m_wheel_zoom_factor = wheelZoomFactor; +} + +void Orbit3DManipulator::setMinimumDistance( const double& minimumDistance, bool relativeToModelSize ) +{ + m_minimum_distance = minimumDistance; + setRelativeFlag( m_minimum_distance_flag_index, relativeToModelSize ); +} + +double Orbit3DManipulator::getMinimumDistance( bool *relativeToModelSize ) const +{ + if( relativeToModelSize ) + { + *relativeToModelSize = getRelativeFlag( m_minimum_distance_flag_index ); + } + + return m_minimum_distance; +} + +void Orbit3DManipulator::zoomToHome( double animation_time ) +{ + zoomToBoundingSphere( osg::BoundingSphere( osg::Vec3f( 0, 0, 0 ), 2.f ), animation_time ); +} + +void Orbit3DManipulator::zoomToBoundingSphere( const osg::BoundingSphere& bs, double _animation_time ) +{ + double animation_time = 0.4; + if( _animation_time > 0 ) + { + animation_time = _animation_time; + } + + osg::Vec3f bs_center( bs.center() ); + double bs_radius = bs.radius(); + if( bs_radius <= 0.5 ) + { + bs_radius = 0.5; + } + + m_rotate_center.set( bs.center() ); + + osg::Vec3d lookat_eye( m_eye - m_lookat ); + lookat_eye.normalize(); + + // define animation path + if( m_animation_data ) + { + osg::Vec3d target_lookat( bs.center() ); + double d_eye = bs_radius/sin( osg::DegreesToRadians(m_fovy*0.5) ); + osg::Vec3d target_eye( target_lookat + lookat_eye*d_eye ); + + m_animation_data->m_start_eye.set( m_eye ); + m_animation_data->m_start_lookat.set( m_lookat ); + m_animation_data->m_start_up.set( m_up ); + + m_animation_data->m_target_eye.set( target_eye ); + m_animation_data->m_target_lookat.set( target_lookat ); + m_animation_data->m_target_up.set( m_up ); + + m_animation_data->_animationTime = animation_time; + m_animation_data->start( -1 ); + } +} diff --git a/examples/SimpleViewerExampleQt/src/viewer/Orbit3DManipulator.h b/examples/SimpleViewerExampleQt/src/viewer/Orbit3DManipulator.h new file mode 100644 index 000000000..0186bd3c5 --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer/Orbit3DManipulator.h @@ -0,0 +1,146 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class IfcPlusPlusSystem; +class IntersectionHandler; + +class Orbit3DManipulator : public QObject, public osgGA::StandardManipulator +{ + Q_OBJECT +public: + Orbit3DManipulator(IfcPlusPlusSystem* s, IntersectionHandler* ih, int flags = UPDATE_MODEL_SIZE | COMPUTE_HOME_USING_BBOX | PROCESS_MOUSE_WHEEL ); + Orbit3DManipulator( const Orbit3DManipulator& om, const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY ); + ~Orbit3DManipulator(); + + // inherited from osg::Object + virtual osg::Object* cloneType() const { return new Orbit3DManipulator( m_system, m_intersection_handler ); } + virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new Orbit3DManipulator( *this, copyop ); } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=nullptr; } + virtual const char* libraryName() const { return ""; } + virtual const char* className() const { return "Orbit3DManipulator"; } + + // inherited from osgGA::CameraManipulator + virtual void setByMatrix( const osg::Matrixd& matrix ); + virtual void setByInverseMatrix( const osg::Matrixd& matrix ); + virtual osg::Matrixd getMatrix() const; + virtual osg::Matrixd getInverseMatrix() const; + virtual osgUtil::SceneView::FusionDistanceMode getFusionDistanceMode() const; + virtual float getFusionDistanceValue() const; + + // inherited from osgGA::StandardManipulator + virtual void setTransformation( const osg::Vec3d& eye, const osg::Quat& rotation ); + virtual void setTransformation( const osg::Vec3d& eye, const osg::Vec3d& lookat, const osg::Vec3d& up ); + virtual void getTransformation( osg::Vec3d& eye, osg::Quat& rotation ) const; + virtual void getTransformation( osg::Vec3d& eye, osg::Vec3d& lookat, osg::Vec3d& up ) const; + + virtual bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleFrame( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMouseMove( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMousePush( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMouseRelease( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMouseWheel( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMouseDrag( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool performMouseDeltaMovement( const float dx, const float dy ); + virtual void applyAnimationStep( const double currentProgress, const double prevProgress ); + virtual void allocAnimationData() { m_animation_data = new OrbitAnimationData(); } + virtual void setAnimationTime( const double t ); + virtual bool performAnimationMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool isAnimating() const; + + class OrbitAnimationData : public AnimationData + { + public: + OrbitAnimationData(); + osg::Vec3d m_start_eye; + osg::Vec3d m_start_lookat; + osg::Vec3d m_start_up; + osg::Vec3d m_target_eye; + osg::Vec3d m_target_lookat; + osg::Vec3d m_target_up; + void start( const double startTime ); + }; + + // own methods + void initManipulator(); + void setWheelZoomFactor( double wheelZoomFactor ); + double getWheelZoomFactor() const { return m_wheel_zoom_factor; }; + bool performMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + double getMinimumDistance( bool *relativeToModelSize = nullptr ) const; + void setMinimumDistance( const double& minimumDistance, bool relativeToModelSize = false ); + void panCamera( const float dx, const float dy, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa );//const float dx, const float dy, const float dz = 0.f ); + void zoomCamera( const float dy ); + void rotateCamera( const float dx, const float dy ); + void computeRayPointer( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + void zoomToHome( double animation_time = -1 ); + void zoomToBoundingSphere( const osg::BoundingSphere& bs, double animation_time = -1 ); + OrbitAnimationData* getOrbitAnimationData() { return m_animation_data.get(); } + void setSelectionDisabled( bool disabled ); + + const osg::Vec3d& getLookat() { return m_lookat; } + const osg::Vec3d& getEye() { return m_eye; } + const osg::Vec3d& getUp() { return m_up; } + double getFovy() { return m_fovy; }; + const OrbitAnimationData* getAnimationData() { return m_animation_data; } + void setAnimationData( OrbitAnimationData* ); + void setEyeLookat( const osg::Vec3d& eye, const osg::Vec3d& lookat ); + void setRotateCenter( const osg::Vec3d& center ); + +protected: + // point snap, dimensioning + osg::ref_ptr m_intersect_geom_switch; + osg::ref_ptr m_intersect_geom_transform; + osg::Vec3d m_pointer_intersection; + osg::Vec3d m_eye; + osg::Vec3d m_lookat; + osg::Vec3d m_up; + osg::Vec3d m_rotate_center; + osg::Vec2d m_pan_start; + osg::Vec2d m_pan_end; + GeomUtils::Ray m_pan_ray; + GeomUtils::Plane m_pan_plane; + osg::Vec3f m_snapped_point; + bool m_has_snapped_point; + bool m_selection_disabled; + double m_fovy; + double m_wheel_zoom_factor; + double m_minimum_distance; + static int m_minimum_distance_flag_index; + osg::ref_ptr m_animation_data; + IfcPlusPlusSystem* m_system; + IntersectionHandler* m_intersection_handler; + osg::ref_ptr m_hud_cam; + double m_snap_radius; + osg::ref_ptr m_snap_wire_cone; + +signals: + void signalEyeLookatChanged(); + +public slots: + void slotModelLoadingDone(); +}; diff --git a/examples/SimpleViewerExampleQt/src/viewer/ViewController.cpp b/examples/SimpleViewerExampleQt/src/viewer/ViewController.cpp new file mode 100644 index 000000000..24727884c --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer/ViewController.cpp @@ -0,0 +1,294 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "viewer/Orbit3DManipulator.h" +#include "IfcPlusPlusSystem.h" +#include "GraphicsWindowQt.h" +#include "ViewController.h" + +ViewController::ViewController( Orbit3DManipulator* camera_manip ) +{ + m_camera_manip = camera_manip; + m_rootnode = new osg::Group(); + m_rootnode->setName("m_rootnode"); + m_model_switch = new osg::Switch(); + m_rootnode->addChild( m_model_switch.get() ); + + m_temp_node = new osg::Group(); + m_temp_node->setName( "m_temp_node" ); + m_rootnode->addChild( m_temp_node ); + + m_snap_node = new osg::Group(); + m_snap_node->setName( "m_snap_node" ); + m_rootnode->addChild( m_snap_node ); + + { + m_transform_light = new osg::MatrixTransform();// osg::Matrix::translate( 5, 5, 50 ) ); + osg::Group* light_group = new osg::Group(); + light_group->setName("light_group"); + light_group->addChild(m_transform_light); + m_rootnode->addChild( light_group ); + + m_sun_light = new osg::Light(); + m_sun_light->setLightNum(6); + m_sun_light->setPosition(osg::Vec4(0.0,0.0,0.0,1.0f)); + m_sun_light->setAmbient(osg::Vec4(0.5f,0.53f,0.57f,0.1f)); + m_sun_light->setDiffuse(osg::Vec4(0.5f,0.53f,0.57f,0.1f)); + m_sun_light->setSpecular( osg::Vec4( 0.5f, 0.53f, 0.57f, 0.4f ) ); + double model_size = 100; + m_sun_light->setConstantAttenuation(1.0f); + m_sun_light->setLinearAttenuation(2.0f/model_size); + m_sun_light->setQuadraticAttenuation(1.0f/(model_size*model_size)); + + osg::LightSource* light_source6 = new osg::LightSource(); + //light_source6->setLightingMode( HEAD_LIGHT ); + light_source6->setReferenceFrame( osg::LightSource::ABSOLUTE_RF ); + light_source6->setLight(m_sun_light); + light_source6->setLocalStateSetModes(osg::StateAttribute::ON); + light_source6->setStateSetModes(*(m_rootnode->getOrCreateStateSet()),osg::StateAttribute::ON); + m_transform_light->addChild(light_source6); + } + + m_material_default = new osg::Material(); + m_material_default->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4f( 0.2f, 0.25f, 0.3f, 1.f ) ); + m_material_default->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4( 0.8, 0.82, 0.84, 1.f ) ); + m_material_default->setSpecular( osg::Material::FRONT_AND_BACK, osg::Vec4f( 0.02f, 0.025f, 0.03f, 1.f ) ); + m_material_default->setShininess( osg::Material::FRONT_AND_BACK, m_shinyness ); + m_material_default->setColorMode( osg::Material::SPECULAR ); + m_material_default->setTransparency( osg::Material::FRONT_AND_BACK, 1.f ); + + osg::LightModel* light_model = new osg::LightModel(); + light_model->setAmbientIntensity( osg::Vec4f( 0.2f, 0.25f, 0.3f, 0.1f ) ); + light_model->setTwoSided(true); + m_rootnode->getOrCreateStateSet()->setAttribute( light_model ); + + m_stateset_default = m_model_switch->getOrCreateStateSet(); + m_stateset_default->setAttribute( m_material_default, osg::StateAttribute::ON ); + + m_stateset_transparent = new osg::StateSet(); + m_stateset_transparent->setAttribute( m_material_default, osg::StateAttribute::ON ); + m_stateset_transparent->setMode(GL_BLEND, osg::StateAttribute::ON); + m_stateset_transparent->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + m_stateset_transparent->setRenderBinDetails(11, "DepthSortedBin"); + + m_material_selected = new osg::Material(); + m_material_selected->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4f( 0.98f, 0.98f, 0.22f, 0.9f ) ); + m_material_selected->setSpecular( osg::Material::FRONT_AND_BACK, osg::Vec4f( 0.3f, 0.35f, 0.3f, 1.0f ) ); + m_material_selected->setShininess( osg::Material::FRONT_AND_BACK, m_shinyness ); + m_material_selected->setColorMode( osg::Material::SPECULAR ); + m_material_selected->setAlpha(osg::Material::FRONT_AND_BACK, 0.8f); + + // create coordinate axes + m_coordinate_axes_switch = new osg::Switch(); + m_coordinate_axes_switch->setName("m_coordinate_axes_switch"); + m_coordinate_axes_switch->addChild( SceneGraphUtils::createCoordinateAxes(500) ); + m_coordinate_axes_switch->addChild( SceneGraphUtils::createCoordinateAxesArrows() ); + + m_rootnode->addChild( m_coordinate_axes_switch.get() ); + m_rootnode->getOrCreateStateSet()->setAttributeAndModes( new osg::Hint( GL_LINE_SMOOTH_HINT, GL_NICEST ), osg::StateAttribute::ON ); + m_rootnode->getOrCreateStateSet()->setAttributeAndModes( new osg::Hint( GL_POLYGON_SMOOTH_HINT, GL_NICEST ), osg::StateAttribute::ON ); + m_rootnode->getOrCreateStateSet()->setMode( GL_BLEND, osg::StateAttribute::ON ); + + m_main_view = new osgViewer::View(); + m_main_view->setSceneData( m_rootnode ); + m_main_view->setCameraManipulator( m_camera_manip ); + + if( m_hud_camera ) + { + m_rootnode->addChild( m_hud_camera ); + } + + //m_current_pointer_ray = new GeomUtils::Ray(); + m_pointer_push_drag = false; + m_show_curve_representation = false; +} + +ViewController::~ViewController(){} + +void ViewController::setGLWidget(QtOSGWidget* glw) +{ + m_gl_widget = glw; +} + +QtOSGWidget* ViewController::getGLWidget() +{ +#ifdef _DEBUG + if (m_gl_widget == nullptr) + { + std::cout << "m_gl_widget not initialized" << std::endl; + } +#endif + return m_gl_widget; +} + +void ViewController::setPointerRay( glm::dvec3& origin, glm::dvec3& direction ) +{ + m_current_pointer_ray.origin = origin; + m_current_pointer_ray.direction = direction; +} + +void ViewController::setModelTransparent( bool transparent ) +{ + m_transparent_model = transparent; + if( transparent ) + { + m_model_switch->setStateSet( m_stateset_transparent ); + } + else + { + m_model_switch->setStateSet( m_stateset_default ); + } +} + +void ViewController::toggleModelTransparency() +{ + setModelTransparent( !m_transparent_model ); +} + +void ViewController::setViewerMode( ViewerMode mode ) +{ + if( mode != m_viewer_mode ) + { + // first disable previous mode + if( m_viewer_mode == VIEWER_MODE_WIREFRAME ) + { + SceneGraphUtils::WireFrameModeOff( m_model_switch.get() ); + } + else if( m_viewer_mode == VIEWER_MODE_HIDDEN_LINE ) + { + //SceneGraphUtils::HiddenLineModeOff( m_model_switch.get() ); + } + + m_viewer_mode = mode; + if( m_viewer_mode == VIEWER_MODE_WIREFRAME ) + { + SceneGraphUtils::WireFrameModeOn( m_model_switch.get() ); + } + else if( m_viewer_mode == VIEWER_MODE_HIDDEN_LINE ) + { + //GeomUtils::HiddenLineModeOn( m_model_switch.get() ); + } + } +} + +void ViewController::setProjection( ViewerProjection p, int width, int height ) +{ + m_projection = p; + double ratio = double( height )/double( width ); + + osg::Camera* cam = getMainView()->getCamera(); + cam->setViewport( new osg::Viewport( 0, 0, width, height ) ); + + if( m_projection == PROJECTION_PARALLEL ) + { + // for some reason, osg auto computed near/far planes cause unintended clipping... + //cam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR); + cam->setProjectionMatrixAsOrtho( -100, 100, -100.0*ratio, 100.0*ratio, m_near_plane-1000, m_near_plane/0.0005+100 ); + } + else if( m_projection == PROJECTION_PERSPECTIVE ) + { + //cam->setComputeNearFarMode(osg::CullSettings::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES); + cam->setProjectionMatrixAsPerspective( 90.0, 1.0/ratio, m_near_plane, m_far_plane ); + cam->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR ); + } + + if( m_hud_camera ) + { + m_hud_camera->setProjectionMatrixAsOrtho2D( 0, width, 0, height ); + } +} + +void ViewController::setSunLightOn( bool light_on ) +{ + m_light_on = light_on; + osg::StateSet* stateset_root = m_rootnode->getOrCreateStateSet(); + if( light_on ) + { + stateset_root->setMode( GL_LIGHT6, osg::StateAttribute::ON ); + } + else + { + stateset_root->setMode( GL_LIGHT6, osg::StateAttribute::OFF ); + } +} + +void ViewController::toggleSunLight() +{ + m_light_on = !m_light_on; + setSunLightOn( m_light_on ); +} + +void ViewController::setCursor( const QCursor& cursor ) +{ + if( m_gl_widget ) + { + m_gl_widget->setCursor( cursor ); + } +} + +void ViewController::restoreCursor() +{ + if( m_gl_widget ) + { + m_gl_widget->setCursor( Qt::ArrowCursor ); + } +} + +void ViewController::switchCurveRepresentation( osg::Group* grp, bool on ) +{ + m_show_curve_representation = on; + osg::Switch* grp_switch = dynamic_cast( grp ); + if( grp_switch ) + { + if( grp_switch->getName().compare( "CurveRepresentation" ) == 0 ) + { + if( on ) + { + grp_switch->setAllChildrenOn(); + } + else + { + grp_switch->setAllChildrenOff(); + } + } + } + + unsigned int num_children = grp->getNumChildren(); + for( unsigned int i=0; igetChild(i); + osg::Group* child_grp = dynamic_cast( child_node ); + if( child_grp ) + { + switchCurveRepresentation( child_grp, on ); + } + } +} diff --git a/examples/SimpleViewerExampleQt/src/viewer/ViewController.h b/examples/SimpleViewerExampleQt/src/viewer/ViewController.h new file mode 100644 index 000000000..8ac9a8428 --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer/ViewController.h @@ -0,0 +1,113 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +class Orbit3DManipulator; +class QtOSGWidget; + +class ViewController +{ +public: + enum ViewerMode + { + VIEWER_MODE_SHADED, + VIEWER_MODE_WIREFRAME, + VIEWER_MODE_HIDDEN_LINE + }; + enum ViewerProjection + { + PROJECTION_PARALLEL, + PROJECTION_PERSPECTIVE + }; + + ViewController( Orbit3DManipulator* camera_manip ); + ~ViewController(); + + osg::Group* getRootNode() { return m_rootnode.get(); } + osg::Switch* getModelNode() { return m_model_switch.get(); } + osg::Group* getTempNode() { return m_temp_node.get(); } + osg::Group* getSnapNode() { return m_snap_node.get(); } + osg::Switch* getCoordinateAxesNode() { return m_coordinate_axes_switch.get(); } + osg::MatrixTransform* getLightTransform() { return m_transform_light.get(); } + osg::StateSet* getStateSetDefault() { return m_stateset_default.get(); } + osg::Material* getMaterialSelected() { return m_material_selected.get(); } + osg::Material* getDefaultMaterial() { return m_material_default; } + osg::StateSet* getStateSetTransparent() { return m_stateset_transparent; } + osg::Light* getSunLight() { return m_sun_light; } + osg::Camera* getHUDCamera() { return m_hud_camera; } + ViewerMode getViewerMode() { return m_viewer_mode; } + osgViewer::View* getMainView() { return m_main_view.get(); } + Orbit3DManipulator* getOrbitManipulator3D() { return m_camera_manip; } + double getShininess() { return m_shinyness; } + void toggleSunLight(); + void setSunLightOn( bool on ); + void toggleModelTransparency(); + void setModelTransparent( bool transparent ); + void setViewerMode( ViewerMode mode ); + void setProjection( ViewerProjection p, int width, int height ); + + void setGLWidget(QtOSGWidget* glw); + QtOSGWidget* getGLWidget(); + + void setCursor( const QCursor& cursor ); + void restoreCursor(); + osg::Matrix& getModelScreen() { return m_model_screen; } + osg::Matrix& getScreenModel() { return m_screen_model; } + void setModelScreen( osg::Matrix& m ) { m_model_screen.set(m); } + void setScreenModel( osg::Matrix& m ) { m_screen_model.set(m); } + void switchCurveRepresentation( osg::Group* grp, bool on ); + + void setPointerRay( glm::dvec3& origin, glm::dvec3& direction ); + GeomUtils::Ray m_current_pointer_ray; + bool m_pointer_push_drag = false; + bool m_show_curve_representation = true; + +private: + osg::ref_ptr m_rootnode; + osg::ref_ptr m_temp_node; + osg::ref_ptr m_snap_node; + osg::ref_ptr m_coordinate_axes_switch; + osg::ref_ptr m_model_switch; + osg::ref_ptr m_transform_light; + osg::ref_ptr m_main_view; + QtOSGWidget* m_gl_widget = nullptr; + osg::ref_ptr m_camera_manip; + osg::ref_ptr m_hud_camera; + osg::ref_ptr m_material_default; + osg::ref_ptr m_material_selected; + osg::ref_ptr m_stateset_default; + osg::ref_ptr m_stateset_transparent; + osg::ref_ptr m_sun_light; + osg::Matrix m_model_screen; + osg::Matrix m_screen_model; + ViewerProjection m_projection = PROJECTION_PERSPECTIVE; + ViewerMode m_viewer_mode = VIEWER_MODE_SHADED; + bool m_light_on = false; + bool m_transparent_model = false; + double m_shinyness = 35.0; + double m_factor_graphics_scale = 1.0; + double m_near_plane = 0.1; + double m_far_plane = 10000.0; +}; diff --git a/examples/SimpleViewerExampleQt/src/viewer/ViewerUtil.cpp b/examples/SimpleViewerExampleQt/src/viewer/ViewerUtil.cpp new file mode 100644 index 000000000..39995a467 --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer/ViewerUtil.cpp @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include + +#define _USE_MATH_DEFINES +#include +#include "ViewerWidget.h" +#include "ViewerUtil.h" + +void SelectedEntity::setSelected(osg::Material* materialSelectedObjects) +{ + if (m_osg_group) + { + osg::ref_ptr stateset = m_osg_group->getOrCreateStateSet(); + osg::Material* material_previous = (osg::Material*)stateset->getAttribute(osg::StateAttribute::MATERIAL); + if (material_previous) + { + m_material_previous = material_previous; + } + + stateset->setAttribute(materialSelectedObjects, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + m_material_selected = materialSelectedObjects; + } +} + +void SelectedEntity::setUnselected() +{ + if (m_osg_group) + { + osg::ref_ptr stateset_selected_node = m_osg_group->getOrCreateStateSet(); + if (m_material_previous) + { + stateset_selected_node->setAttribute(m_material_previous, osg::StateAttribute::ON); + } + else if (m_material_selected) + { + stateset_selected_node->removeAttribute(m_material_selected); + } + } +} + +void intersectRayWithPlane( const osg::Vec3d& ray_origin, const osg::Vec3d& ray_direction, const IntersectionPlane& plane, osg::Vec3d& intersection_point ) +{ + double n = 0; + if( plane == IntersectionPlane::INTERSECTION_PLANE_XY ) + { + // intersect mouse ray with x-y-plane + // g = vec1 + n*(vec2-vec1), z = 0 + // 0 = vec1.z + n*(vec2.z - vec1.z) + n = -ray_origin.z() / (ray_direction.z()); + } + else if( plane == IntersectionPlane::INTERSECTION_PLANE_XZ ) + { + n = -ray_origin.y() / (ray_direction.y()); + } + + intersection_point.set( ray_origin.x() + n * (ray_direction.x()), ray_origin.y() + n * (ray_direction.y()), ray_origin.z() + n * (ray_direction.z() ) ); +} + +std::string getGUID(const shared_ptr& ent) +{ + std::string guid; + shared_ptr ifc_root = dynamic_pointer_cast(ent); + if (ifc_root) + { + if (ifc_root->m_GlobalId) + { + guid = ifc_root->m_GlobalId->m_value; + } + } + return guid; +} + +QTreeWidgetItem* findItemByIfcId( QTreeWidgetItem* item, int ifc_id ) +{ + int num_children = item->childCount(); + for( int i=0; ichild( i ); + if( child_item->columnCount() > 0 ) + { + QString text = child_item->text( 1 ); + int id = text.toUInt(); + if( id == ifc_id ) + { + return child_item; + } + QTreeWidgetItem* child_of_child = findItemByIfcId( child_item, ifc_id ); + if( child_of_child != 0 ) + { + return child_of_child; + } + } + } + return 0; +} + +void applyMatrix( osg::Group* grp, osg::Matrix& mat ) +{ + for( size_t i = 0; i < grp->getNumChildren(); ++i ) + { + osg::Node* node = grp->getChild( i ); + + osg::Group* child_grp = dynamic_cast( node ); + if( child_grp ) + { + applyMatrix( child_grp, mat ); + continue; + } + + osg::Geode* child_geode = dynamic_cast( node ); + if( child_geode ) + { + for( size_t i_drawable = 0; i_drawable < child_geode->getNumDrawables(); ++i_drawable ) + { + osg::Drawable* drawable = child_geode->getDrawable( i_drawable ); + osg::Geometry* geometry = dynamic_cast( drawable ); + if( geometry ) + { + osg::Vec3Array* vertex_array = dynamic_cast( geometry->getVertexArray() ); + if( vertex_array ) + { + + //osg::ref_ptr dt = new osgUtil::DelaunayTriangulator( vertex_array ); + //dt->triangulate(); // Generate the triangles + //geometry->setVertexArray( vertex_array ); + //geometry->addPrimitiveSet( dt->getTriangles() ); + + + osg::Vec3Array& vertex_array_ref = *vertex_array; + for( size_t i_vertex = 0; i_vertex < vertex_array->size(); ++i_vertex ) + { + osg::Vec3& vec3 = vertex_array_ref[i_vertex]; + vec3 = mat*vec3; + } + vertex_array->dirty(); + child_geode->dirtyBound(); + geometry->dirtyDisplayList(); + geometry->dirtyBound(); + } + } + } + } + } +} + diff --git a/examples/SimpleViewerExampleQt/src/viewer/ViewerUtil.h b/examples/SimpleViewerExampleQt/src/viewer/ViewerUtil.h new file mode 100644 index 000000000..2cf623858 --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer/ViewerUtil.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +enum IntersectionPlane { INTERSECTION_PLANE_XY, INTERSECTION_PLANE_YZ, INTERSECTION_PLANE_XZ }; +void intersectRayWithPlane( const osg::Vec3d& ray_origin, const osg::Vec3d& ray_direction, const IntersectionPlane& plane, osg::Vec3d& intersection_point ); +QTreeWidgetItem* findItemByIfcId( QTreeWidgetItem* item, int ifc_id ); + +void applyMatrix( osg::Group* grp, osg::Matrix& mat ); +std::string getGUID(const shared_ptr& ent); + +struct SelectedEntity +{ + shared_ptr m_entity; + osg::ref_ptr m_osg_group; + osg::ref_ptr m_material_previous; + osg::ref_ptr m_material_selected; + + void setSelected(osg::Material* materialSelectedObjects); + void setUnselected(); +}; diff --git a/examples/SimpleViewerExampleQt/src/viewer/ViewerWidget.cpp b/examples/SimpleViewerExampleQt/src/viewer/ViewerWidget.cpp index 7d7155ee2..f64433235 100644 --- a/examples/SimpleViewerExampleQt/src/viewer/ViewerWidget.cpp +++ b/examples/SimpleViewerExampleQt/src/viewer/ViewerWidget.cpp @@ -33,11 +33,13 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OU #include #include "IfcPlusPlusSystem.h" -#include "OrbitCameraManipulator.h" +#include "IntersectionHandler.h" +#include "Orbit3DManipulator.h" #include "GraphicsWindowQt.h" +#include "ViewController.h" #include "ViewerWidget.h" -ViewerWidget::ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QWidget( parent ) +ViewerWidget::ViewerWidget(IfcPlusPlusSystem* sys, QWidget* parent ) : QWidget( parent ) { m_system = sys; m_parent = parent; @@ -55,9 +57,9 @@ ViewerWidget::ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QWidget( osg::ref_ptr light_model = new osg::LightModel(); light_model->setTwoSided( true ); light_model->setAmbientIntensity( osg::Vec4f( r, g, b, 0.6f ) ); - sys->getRootNode()->getOrCreateStateSet()->setAttribute( light_model ); + sys->getViewController()->getRootNode()->getOrCreateStateSet()->setAttribute( light_model ); - m_stateset_default = sys->getModelNode()->getOrCreateStateSet(); + m_stateset_default = sys->getViewController()->getModelNode()->getOrCreateStateSet(); m_stateset_default->setAttribute( m_material_default, osg::StateAttribute::ON ); m_stateset_transparent = new osg::StateSet(); @@ -74,7 +76,7 @@ ViewerWidget::ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QWidget( m_stateset_selected = new osg::StateSet(); m_stateset_selected->setAttribute( material_selected, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON ); - sys->toggleSceneLight(); + sys->getViewController()->toggleSunLight(); { osg::ref_ptr geode = new osg::Geode(); @@ -82,7 +84,7 @@ ViewerWidget::ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QWidget( osg::ref_ptr stateset = geode->getOrCreateStateSet(); stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); float alpha = 0.5f; - m_system->getCoordinateAxesNode()->addChild( geode ); + m_system->getViewController()->getCoordinateAxesNode()->addChild( geode ); // positive axes { @@ -164,7 +166,7 @@ ViewerWidget::ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QWidget( } } - m_camera_manipulator = new OrbitCameraManipulator( sys ); + m_camera_manipulator = sys->getViewController()->getOrbitManipulator3D(); QtOSGWidget* opengl_widget = getOpenGLWidget(); QVBoxLayout* vbox = new QVBoxLayout(); @@ -173,20 +175,21 @@ ViewerWidget::ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QWidget( setLayout( vbox ); connect( &m_timer, SIGNAL( timeout() ), this, SLOT( slotAnimationFrame() ) ); + sys->getViewController()->setGLWidget(opengl_widget); } ViewerWidget::~ViewerWidget() {} void ViewerWidget::initGLWidgetAndViewer() { osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; - m_system->getRootNode()->setCullingActive( false ); + m_system->getViewController()->getRootNode()->setCullingActive( false ); Qt::WindowFlags f; m_graphics_window = new GraphicsWindowQt( this, f ); QtOSGWidget* opengl_widget = m_graphics_window->getOpenGLWidget(); opengl_widget->setMinimumSize( QSize( 150, 150 ) ); m_main_view = opengl_widget->getView(); - m_main_view->setSceneData( m_system->getRootNode() ); + m_main_view->setSceneData( m_system->getViewController()->getRootNode() ); m_composite_viewer = opengl_widget->getViewer(); m_composite_viewer->setThreadingModel( threadingModel ); m_composite_viewer->setKeyEventSetsDone( 0 ); // disable the default setting of viewer.done() by pressing Escape. @@ -200,7 +203,7 @@ void ViewerWidget::initGLWidgetAndViewer() if( m_main_view ) { m_main_view->setCameraManipulator( m_camera_manipulator ); - m_main_view->setSceneData( m_system->getRootNode() ); + m_main_view->setSceneData( m_system->getViewController()->getRootNode() ); } } @@ -277,15 +280,15 @@ void ViewerWidget::updateCamera() } } -void ViewerWidget::setRootNode( osg::Group* root ) -{ - m_main_view->setSceneData( root ); - if( m_hud_camera ) - { - root->addChild( m_hud_camera ); - } - m_system->setRootNode( root ); -} +//void ViewerWidget::setRootNode( osg::Group* root ) +//{ +// m_main_view->setSceneData( root ); +// if( m_hud_camera ) +// { +// root->addChild( m_hud_camera ); +// } +// m_system->getViewController()->setRootNode( root ); +//} void ViewerWidget::stopTimer() { diff --git a/examples/SimpleViewerExampleQt/src/viewer/ViewerWidget.h b/examples/SimpleViewerExampleQt/src/viewer/ViewerWidget.h index 9ff5cba55..4e01a8968 100644 --- a/examples/SimpleViewerExampleQt/src/viewer/ViewerWidget.h +++ b/examples/SimpleViewerExampleQt/src/viewer/ViewerWidget.h @@ -34,7 +34,7 @@ class ViewerWidget : public QWidget Q_OBJECT public: - ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent = nullptr ); + ViewerWidget(IfcPlusPlusSystem* sys, QWidget* parent = nullptr ); ~ViewerWidget(); QtOSGWidget* getOpenGLWidget(); @@ -44,7 +44,6 @@ class ViewerWidget : public QWidget osg::Camera* getHeadUpCamera() { return m_hud_camera.get(); } osgGA::StandardManipulator* getCameraManipulator() { return m_camera_manipulator.get(); } void updateCamera(); - void setRootNode( osg::Group* node ); void stopTimer(); void startTimer(); diff --git a/examples/SimpleViewerExampleQt/src/viewer2/GraphicsWindowQt.cpp b/examples/SimpleViewerExampleQt/src/viewer2/GraphicsWindowQt.cpp new file mode 100644 index 000000000..c46d89f0f --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer2/GraphicsWindowQt.cpp @@ -0,0 +1,674 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + #define USE_GESTURES + #include + #include +#endif + +#include "GraphicsWindowQt.h" + +QtOSGWidget::QtOSGWidget( QWidget* parent, Qt::WindowFlags f ) : QOpenGLWidget( parent, f ) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)) + m_device_pixel_ratio = devicePixelRatio(); +#endif + m_main_view = new osgViewer::View(); + m_viewer = new osgViewer::CompositeViewer(); + + m_key_map[Qt::Key_Escape] = osgGA::GUIEventAdapter::KEY_Escape; + m_key_map[Qt::Key_Delete] = osgGA::GUIEventAdapter::KEY_Delete; + m_key_map[Qt::Key_Home] = osgGA::GUIEventAdapter::KEY_Home; + m_key_map[Qt::Key_Enter] = osgGA::GUIEventAdapter::KEY_KP_Enter; + m_key_map[Qt::Key_End] = osgGA::GUIEventAdapter::KEY_End; + m_key_map[Qt::Key_Return] = osgGA::GUIEventAdapter::KEY_Return; + m_key_map[Qt::Key_PageUp] = osgGA::GUIEventAdapter::KEY_Page_Up; + m_key_map[Qt::Key_PageDown] = osgGA::GUIEventAdapter::KEY_Page_Down; + m_key_map[Qt::Key_Left] = osgGA::GUIEventAdapter::KEY_Left; + m_key_map[Qt::Key_Right] = osgGA::GUIEventAdapter::KEY_Right; + m_key_map[Qt::Key_Up] = osgGA::GUIEventAdapter::KEY_Up; + m_key_map[Qt::Key_Down] = osgGA::GUIEventAdapter::KEY_Down; + m_key_map[Qt::Key_Backspace] = osgGA::GUIEventAdapter::KEY_BackSpace; + m_key_map[Qt::Key_Tab] = osgGA::GUIEventAdapter::KEY_Tab; + m_key_map[Qt::Key_Space] = osgGA::GUIEventAdapter::KEY_Space; + m_key_map[Qt::Key_Delete] = osgGA::GUIEventAdapter::KEY_Delete; + m_key_map[Qt::Key_Alt] = osgGA::GUIEventAdapter::KEY_Alt_L; + m_key_map[Qt::Key_Shift] = osgGA::GUIEventAdapter::KEY_Shift_L; + m_key_map[Qt::Key_Control] = osgGA::GUIEventAdapter::KEY_Control_L; + m_key_map[Qt::Key_Meta] = osgGA::GUIEventAdapter::KEY_Meta_L; + m_key_map[Qt::Key_F1] = osgGA::GUIEventAdapter::KEY_F1; + m_key_map[Qt::Key_F2] = osgGA::GUIEventAdapter::KEY_F2; + m_key_map[Qt::Key_F3] = osgGA::GUIEventAdapter::KEY_F3; + m_key_map[Qt::Key_F4] = osgGA::GUIEventAdapter::KEY_F4; + m_key_map[Qt::Key_F5] = osgGA::GUIEventAdapter::KEY_F5; + m_key_map[Qt::Key_F6] = osgGA::GUIEventAdapter::KEY_F6; + m_key_map[Qt::Key_F7] = osgGA::GUIEventAdapter::KEY_F7; + m_key_map[Qt::Key_F8] = osgGA::GUIEventAdapter::KEY_F8; + m_key_map[Qt::Key_F9] = osgGA::GUIEventAdapter::KEY_F9; + m_key_map[Qt::Key_F10] = osgGA::GUIEventAdapter::KEY_F10; + m_key_map[Qt::Key_F11] = osgGA::GUIEventAdapter::KEY_F11; + m_key_map[Qt::Key_F12] = osgGA::GUIEventAdapter::KEY_F12; + m_key_map[Qt::Key_F13] = osgGA::GUIEventAdapter::KEY_F13; + m_key_map[Qt::Key_F14] = osgGA::GUIEventAdapter::KEY_F14; + m_key_map[Qt::Key_F15] = osgGA::GUIEventAdapter::KEY_F15; + m_key_map[Qt::Key_F16] = osgGA::GUIEventAdapter::KEY_F16; + m_key_map[Qt::Key_F17] = osgGA::GUIEventAdapter::KEY_F17; + m_key_map[Qt::Key_F18] = osgGA::GUIEventAdapter::KEY_F18; + m_key_map[Qt::Key_F19] = osgGA::GUIEventAdapter::KEY_F19; + m_key_map[Qt::Key_F20] = osgGA::GUIEventAdapter::KEY_F20; + m_key_map[Qt::Key_hyphen] = '-'; + m_key_map[Qt::Key_Equal] = '='; + m_key_map[Qt::Key_division] = osgGA::GUIEventAdapter::KEY_KP_Divide; + m_key_map[Qt::Key_multiply] = osgGA::GUIEventAdapter::KEY_KP_Multiply; + m_key_map[Qt::Key_Minus] = '-'; + m_key_map[Qt::Key_Plus] = '+'; + m_key_map[Qt::Key_Insert] = osgGA::GUIEventAdapter::KEY_KP_Insert; +} + +QtOSGWidget::~QtOSGWidget() +{ + if( m_graphics_window ) + { + m_graphics_window->close(); + m_graphics_window = NULL; + } +} + +int QtOSGWidget::convertQKeyEnventToOSG( QKeyEvent* event ) +{ + auto itr = m_key_map.find( event->key() ); + if( itr == m_key_map.end() ) + { + return int( *(event->text().toLatin1().data()) ); + } + else + { + return itr->second; + } +} + +void QtOSGWidget::setTouchEventsEnabled( bool e ) +{ +#ifdef USE_GESTURES + if( e==m_touchEventsEnabled ) + { + return; + } + + m_touchEventsEnabled = e; + + if( m_touchEventsEnabled ) + { + grabGesture( Qt::PinchGesture ); + } + else + { + ungrabGesture( Qt::PinchGesture ); + } +#endif +} + +void QtOSGWidget::processDeferredEvents() +{ + QQueue deferredEventQueueCopy; + { + QMutexLocker lock( &m_deferredEventQueueMutex ); + deferredEventQueueCopy = m_deferredEventQueue; + m_eventCompressor.clear(); + m_deferredEventQueue.clear(); + } + + while( !deferredEventQueueCopy.isEmpty() ) + { + QEvent event( deferredEventQueueCopy.dequeue() ); + QOpenGLWidget::event( &event ); + } +} + +void QtOSGWidget::initializeGL() +{ + // Set up the rendering context, load shaders and other resources, etc.: + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); + +} + +void QtOSGWidget::resizeGL( int w, int h ) +{ + double x = this->geometry().x(); + double y = this->geometry().y(); + m_graphics_window->getEventQueue()->windowResize( x, y, w, h ); + + // graphics window resize + double xx = this->x(); + double yy = this->y(); + m_graphics_window->resized( xx, yy, w, h ); + + // camera viewport + std::list& cameras = m_graphics_window->getCameras(); + for( auto cam : cameras ) + { + cam->setViewport( 0, 0, w, h ); + } + + QOpenGLWidget::resizeGL( w, h ); +} + +bool QtOSGWidget::event( QEvent* event ) +{ +#ifdef USE_GESTURES + if( event->type()==QEvent::Gesture ) + { + return gestureEvent( static_cast(event) ); + } +#endif + + // QEvent::Hide + // + // workaround "Qt-workaround" that does glFinish before hiding the widget + // (the Qt workaround was seen at least in Qt 4.6.3 and 4.7.0) + // + // Qt makes the context current, performs glFinish, and releases the context. + // This makes the problem in OSG multithreaded environment as the context + // is active in another thread, thus it can not be made current for the purpose + // of glFinish in this thread. + + // QEvent::ParentChange + // + // Reparenting QtOSGWidget may create a new underlying window and a new GL context. + // Qt will then call doneCurrent on the GL context about to be deleted. The thread + // where old GL context was current has no longer current context to render to and + // we cannot make new GL context current in this thread. + + // We workaround above problems by deferring execution of problematic event requests. + // These events has to be enqueue and executed later in a main GUI thread (GUI operations + // outside the main thread are not allowed) just before makeCurrent is called from the + // right thread. The good place for doing that is right after swap in a swapBuffersImplementation. + + if( event->type() == QEvent::Hide ) + { + // enqueue only the last of QEvent::Hide and QEvent::Show + enqueueDeferredEvent( QEvent::Hide, QEvent::Show ); + return true; + } + else if( event->type() == QEvent::Show ) + { + // enqueue only the last of QEvent::Show or QEvent::Hide + enqueueDeferredEvent( QEvent::Show, QEvent::Hide ); + return true; + } + else if( event->type() == QEvent::ParentChange ) + { + // enqueue only the last QEvent::ParentChange + enqueueDeferredEvent( QEvent::ParentChange ); + return true; + } + + // perform regular event handling + return QOpenGLWidget::event( event ); +} + +void QtOSGWidget::setKeyboardModifiers( QInputEvent* event ) +{ + int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier); + unsigned int mask = 0; + if( modkey & Qt::ShiftModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT; + if( modkey & Qt::ControlModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_CTRL; + if( modkey & Qt::AltModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_ALT; + m_graphics_window->getEventQueue()->getCurrentEventState()->setModKeyMask( mask ); +} + +void QtOSGWidget::paintEvent( QPaintEvent* ) +{ + m_graphics_window->requestRedraw(); +} + +void QtOSGWidget::moveEvent( QMoveEvent* event ) +{ + const QPoint& pos = event->pos(); + int scaled_width = static_cast(width()*m_device_pixel_ratio); + int scaled_height = static_cast(height()*m_device_pixel_ratio); + m_graphics_window->resized( pos.x(), pos.y(), scaled_width, scaled_height ); + m_graphics_window->getEventQueue()->windowResize( pos.x(), pos.y(), scaled_width, scaled_height ); +} + +void QtOSGWidget::keyPressEvent( QKeyEvent* event ) +{ + setKeyboardModifiers( event ); + int value = convertQKeyEnventToOSG( event ); + m_graphics_window->getEventQueue()->keyPress( value ); +} + +void QtOSGWidget::keyReleaseEvent( QKeyEvent* event ) +{ + if( event->isAutoRepeat() ) + { + event->ignore(); + } + else + { + setKeyboardModifiers( event ); + int value = convertQKeyEnventToOSG( event ); + m_graphics_window->getEventQueue()->keyRelease( value ); + } +} + +void QtOSGWidget::mousePressEvent( QMouseEvent* event ) +{ + int button = 0; + switch( event->button() ) + { + case Qt::LeftButton: button = 1; break; + case Qt::MiddleButton: button = 2; break; + case Qt::RightButton: button = 3; break; + case Qt::NoButton: button = 0; break; + default: button = 0; break; + } + setKeyboardModifiers( event ); + m_graphics_window->getEventQueue()->mouseButtonPress( event->x()*m_device_pixel_ratio, event->y()*m_device_pixel_ratio, button ); +} + +void QtOSGWidget::mouseReleaseEvent( QMouseEvent* event ) +{ + int button = 0; + switch( event->button() ) + { + case Qt::LeftButton: button = 1; break; + case Qt::MiddleButton: button = 2; break; + case Qt::RightButton: button = 3; break; + case Qt::NoButton: button = 0; break; + default: button = 0; break; + } + setKeyboardModifiers( event ); + m_graphics_window->getEventQueue()->mouseButtonRelease( event->x()*m_device_pixel_ratio, event->y()*m_device_pixel_ratio, button ); +} + + + +void QtOSGWidget::mouseDoubleClickEvent( QMouseEvent* event ) +{ + int button = 0; + switch( event->button() ) + { + case Qt::LeftButton: button = 1; break; + case Qt::MiddleButton: button = 2; break; + case Qt::RightButton: button = 3; break; + case Qt::NoButton: button = 0; break; + default: button = 0; break; + } + setKeyboardModifiers( event ); + m_graphics_window->getEventQueue()->mouseDoubleButtonPress( event->x()*m_device_pixel_ratio, event->y()*m_device_pixel_ratio, button ); +} + +void QtOSGWidget::mouseMoveEvent( QMouseEvent* event ) +{ + setKeyboardModifiers( event ); + double x = event->x() * m_device_pixel_ratio; + double y = event->y() * m_device_pixel_ratio; + osgGA::EventQueue* eventQueue = m_graphics_window->getEventQueue(); + eventQueue->mouseMotion( x, y ); +} + +void QtOSGWidget::wheelEvent( QWheelEvent* event ) +{ + setKeyboardModifiers( event ); + m_graphics_window->getEventQueue()->mouseScroll( + (event->angleDelta().y() > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN)); +} + +#ifdef USE_GESTURES +static osgGA::GUIEventAdapter::TouchPhase translateQtGestureState( Qt::GestureState state ) +{ + osgGA::GUIEventAdapter::TouchPhase touchPhase; + switch( state ) + { + case Qt::GestureStarted: + touchPhase = osgGA::GUIEventAdapter::TOUCH_BEGAN; + break; + case Qt::GestureUpdated: + touchPhase = osgGA::GUIEventAdapter::TOUCH_MOVED; + break; + case Qt::GestureFinished: + case Qt::GestureCanceled: + touchPhase = osgGA::GUIEventAdapter::TOUCH_ENDED; + break; + default: + touchPhase = osgGA::GUIEventAdapter::TOUCH_UNKNOWN; + }; + + return touchPhase; +} +#endif + + +bool QtOSGWidget::gestureEvent( QGestureEvent* qevent ) +{ +#ifndef USE_GESTURES + return false; +#else + + bool accept = false; + + if( QPinchGesture* pinch = static_cast(qevent->gesture( Qt::PinchGesture )) ) + { + const QPointF qcenterf = pinch->centerPoint(); + const float angle = pinch->totalRotationAngle(); + const float scale = pinch->totalScaleFactor(); + + const QPoint pinchCenterQt = mapFromGlobal( qcenterf.toPoint() ); + const osg::Vec2 pinchCenter( pinchCenterQt.x(), pinchCenterQt.y() ); + + //We don't have absolute positions of the two touches, only a scale and rotation + //Hence we create pseudo-coordinates which are reasonable, and centered around the + //real position + const float radius = float( width()+height() )/4.0f; + const osg::Vec2 vector( scale*cos( angle )*radius, scale*sin( angle )*radius ); + const osg::Vec2 p0 = pinchCenter+vector; + const osg::Vec2 p1 = pinchCenter-vector; + + osg::ref_ptr event = 0; + const osgGA::GUIEventAdapter::TouchPhase touchPhase = translateQtGestureState( pinch->state() ); + if( touchPhase==osgGA::GUIEventAdapter::TOUCH_BEGAN ) + { + event = m_graphics_window->getEventQueue()->touchBegan( 0, touchPhase, p0[0], p0[1] ); + } + else if( touchPhase==osgGA::GUIEventAdapter::TOUCH_MOVED ) + { + event = m_graphics_window->getEventQueue()->touchMoved( 0, touchPhase, p0[0], p0[1] ); + } + else + { + event = m_graphics_window->getEventQueue()->touchEnded( 0, touchPhase, p0[0], p0[1], 1 ); + } + + if( event ) + { + event->addTouchPoint( 1, touchPhase, p1[0], p1[1] ); + accept = true; + } + } + + if( accept ) + qevent->accept(); + + return accept; +#endif +} + + + +GraphicsWindowQt::GraphicsWindowQt( QWidget* parent, Qt::WindowFlags f ) +{ + osg::DisplaySettings* ds = osg::DisplaySettings::instance().get(); + osg::setNotifyLevel( osg::NotifySeverity::FATAL ); + + _traits = new osg::GraphicsContext::Traits(); + _traits->windowDecoration = false; + _traits->x = 0; + _traits->y = 0; + _traits->width = 100; + _traits->height = 100; + _traits->doubleBuffer = true; + if( ds ) + { + _traits->alpha = ds->getMinimumNumAlphaBits(); + _traits->stencil = ds->getMinimumNumStencilBits(); + _traits->sampleBuffers = ds->getMultiSamples(); + _traits->samples = ds->getNumMultiSamples(); + } + if( parent ) + { + _traits->width = parent->width(); + _traits->height = parent->height(); + } + + // create widget if it does not exist + if( !m_opengl_widget ) + { + // WindowFlags + Qt::WindowFlags flags = f | Qt::Widget; + // create widget + m_opengl_widget = new QtOSGWidget( parent, flags ); + } + + m_opengl_widget->setMouseTracking( true ); + m_opengl_widget->setFocusPolicy( Qt::WheelFocus ); + m_opengl_widget->setGraphicsWindow( this ); + useCursor( _traits->useCursor ); + + // initialize State + setState( new osg::State ); + getState()->setGraphicsContext( this ); + + // initialize contextID + if( _traits.valid() && _traits->sharedContext.valid() ) + { + getState()->setContextID( _traits->sharedContext->getState()->getContextID() ); + incrementContextIDUsageCount( getState()->getContextID() ); + } + else + { + getState()->setContextID( osg::GraphicsContext::createNewContextID() ); + } + + // make sure the event queue has the correct window rectangle size and input range +#if (OPENSCENEGRAPH_MAJOR_VERSION == 3) && (OPENSCENEGRAPH_MINOR_VERSION == 2) + getEventQueue()->syncWindowRectangleWithGraphcisContext(); +#else + getEventQueue()->syncWindowRectangleWithGraphicsContext(); +#endif +} + +GraphicsWindowQt::~GraphicsWindowQt() +{ + close(); + + // remove reference from QtOSGWidget + if( m_opengl_widget ) + { + m_opengl_widget->m_graphics_window = NULL; + } +} + +void GraphicsWindowQt::grabFocus() +{ + if( m_opengl_widget ) + { + m_opengl_widget->setFocus( Qt::ActiveWindowFocusReason ); + } +} + +void GraphicsWindowQt::grabFocusIfPointerInWindow() +{ + if( m_opengl_widget->underMouse() ) + { + m_opengl_widget->setFocus( Qt::ActiveWindowFocusReason ); + } +} + +void GraphicsWindowQt::useCursor( bool cursorOn ) +{ + if( m_opengl_widget ) + { + _traits->useCursor = cursorOn; + if( !cursorOn ) m_opengl_widget->setCursor( Qt::BlankCursor ); + else m_opengl_widget->setCursor( m_current_cursor ); + } +} + +void GraphicsWindowQt::setCursor( MouseCursor cursor ) +{ + if( cursor==InheritCursor && m_opengl_widget ) + { + m_opengl_widget->unsetCursor(); + } + + switch( cursor ) + { + case NoCursor: m_current_cursor = Qt::BlankCursor; break; + case RightArrowCursor: case LeftArrowCursor: m_current_cursor = Qt::ArrowCursor; break; + case InfoCursor: m_current_cursor = Qt::SizeAllCursor; break; + case DestroyCursor: m_current_cursor = Qt::ForbiddenCursor; break; + case HelpCursor: m_current_cursor = Qt::WhatsThisCursor; break; + case CycleCursor: m_current_cursor = Qt::ForbiddenCursor; break; + case SprayCursor: m_current_cursor = Qt::SizeAllCursor; break; + case WaitCursor: m_current_cursor = Qt::WaitCursor; break; + case TextCursor: m_current_cursor = Qt::IBeamCursor; break; + case CrosshairCursor: m_current_cursor = Qt::CrossCursor; break; + case HandCursor: m_current_cursor = Qt::OpenHandCursor; break; + case UpDownCursor: m_current_cursor = Qt::SizeVerCursor; break; + case LeftRightCursor: m_current_cursor = Qt::SizeHorCursor; break; + case TopSideCursor: case BottomSideCursor: m_current_cursor = Qt::UpArrowCursor; break; + case LeftSideCursor: case RightSideCursor: m_current_cursor = Qt::SizeHorCursor; break; + case TopLeftCorner: m_current_cursor = Qt::SizeBDiagCursor; break; + case TopRightCorner: m_current_cursor = Qt::SizeFDiagCursor; break; + case BottomRightCorner: m_current_cursor = Qt::SizeBDiagCursor; break; + case BottomLeftCorner: m_current_cursor = Qt::SizeFDiagCursor; break; + default: break; + }; + if( m_opengl_widget ) + { + m_opengl_widget->setCursor( m_current_cursor ); + } +} + +bool GraphicsWindowQt::valid() const +{ + if( m_opengl_widget == nullptr ) + { + return false; + } + return m_opengl_widget->isValid(); +} + +bool GraphicsWindowQt::realizeImplementation() +{ + const QOpenGLContext *saved_context = QOpenGLContext::currentContext(); + + // initialize GL context for the widget + if( !valid() ) + { + m_opengl_widget->initializeGL(); + } + + // make current + m_realized = true; + bool result = makeCurrent(); + m_realized = false; + + // fail if we do not have current context + if( !result ) + { + if( saved_context ) + { + QSurface* surf = saved_context->surface(); + const_cast(saved_context)->makeCurrent( surf ); + } + + OSG_WARN << "Window realize: Can make context current." << std::endl; + return false; + } + + m_realized = true; + + // make sure the event queue has the correct window rectangle size and input range +#if (OPENSCENEGRAPH_MAJOR_VERSION == 3) && (OPENSCENEGRAPH_MINOR_VERSION == 2) + getEventQueue()->syncWindowRectangleWithGraphcisContext(); +#else + getEventQueue()->syncWindowRectangleWithGraphicsContext(); +#endif + + // make this window's context not current + // note: this must be done as we will probably make the context current from another thread + // and it is not allowed to have one context current in two threads + if( !releaseContext() ) + { + OSG_WARN << "Window realize: Can not release context." << std::endl; + } + + // restore previous context + if( saved_context ) + { + const_cast(saved_context)->makeCurrent( saved_context->surface() ); + } + + return true; +} + +bool GraphicsWindowQt::isRealizedImplementation() const +{ + return m_realized; +} + +void GraphicsWindowQt::closeImplementation() +{ + if( m_opengl_widget ) + { + m_opengl_widget->close(); + } + m_realized = false; +} + +void GraphicsWindowQt::runOperations() +{ + // While in graphics thread this is last chance to do something useful before + // graphics thread will execute its operations. + if( m_opengl_widget->getNumDeferredEvents() > 0 ) + { + m_opengl_widget->processDeferredEvents(); + } + + if( QOpenGLContext::currentContext() != m_opengl_widget->context() ) + { + m_opengl_widget->makeCurrent(); + } + + GraphicsWindow::runOperations(); +} + +bool GraphicsWindowQt::makeCurrentImplementation() +{ + if( m_opengl_widget->getNumDeferredEvents() > 0 ) + { + m_opengl_widget->processDeferredEvents(); + } + + m_opengl_widget->makeCurrent(); + + return true; +} + +bool GraphicsWindowQt::releaseContextImplementation() +{ + m_opengl_widget->doneCurrent(); + return true; +} + +void GraphicsWindowQt::requestWarpPointer( float x, float y ) +{ + if( m_opengl_widget ) + { + QCursor::setPos( m_opengl_widget->mapToGlobal( QPoint( (int)x, (int)y ) ) ); + } +} diff --git a/examples/SimpleViewerExampleQt/src/viewer2/GraphicsWindowQt.h b/examples/SimpleViewerExampleQt/src/viewer2/GraphicsWindowQt.h new file mode 100644 index 000000000..eacfde9e3 --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer2/GraphicsWindowQt.h @@ -0,0 +1,124 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +class QInputEvent; +class QGestureEvent; + +class QtOSGWidget : public QOpenGLWidget, protected QOpenGLFunctions +{ +public: + QtOSGWidget( QWidget* parent, Qt::WindowFlags f ); + virtual ~QtOSGWidget(); + + void setGraphicsWindow( osgViewer::GraphicsWindow* gw ) { m_graphics_window = gw; } + osgViewer::View* getView() { return m_main_view; } + osgViewer::CompositeViewer* getViewer() { return m_viewer; } + bool getTouchEventsEnabled() const { return m_touchEventsEnabled; } + void setTouchEventsEnabled( bool e ); + void setKeyboardModifiers( QInputEvent* event ); + virtual void keyPressEvent( QKeyEvent* event ); + virtual void keyReleaseEvent( QKeyEvent* event ); + virtual void mousePressEvent( QMouseEvent* event ); + virtual void mouseReleaseEvent( QMouseEvent* event ); + virtual void mouseDoubleClickEvent( QMouseEvent* event ); + virtual void mouseMoveEvent( QMouseEvent* event ); + virtual void wheelEvent( QWheelEvent* event ); + virtual bool gestureEvent( QGestureEvent* event ); + +protected: + virtual void initializeGL(); + virtual void resizeGL( int w, int h ); + + int getNumDeferredEvents() + { + QMutexLocker lock( &m_deferredEventQueueMutex ); + return m_deferredEventQueue.count(); + } + void enqueueDeferredEvent( QEvent::Type eventType, QEvent::Type removeEventType = QEvent::None ) + { + QMutexLocker lock( &m_deferredEventQueueMutex ); + + if( removeEventType != QEvent::None ) + { + if( m_deferredEventQueue.removeOne( removeEventType ) ) + m_eventCompressor.remove( eventType ); + } + + if( m_eventCompressor.find( eventType ) == m_eventCompressor.end() ) + { + m_deferredEventQueue.enqueue( eventType ); + m_eventCompressor.insert( eventType ); + } + } + void processDeferredEvents(); + int convertQKeyEnventToOSG( QKeyEvent* event ); + virtual void paintEvent( QPaintEvent *e ); + virtual void moveEvent( QMoveEvent* event ); + virtual bool event( QEvent* event ); + + friend class GraphicsWindowQt; + osgViewer::GraphicsWindow* m_graphics_window = nullptr; + + osg::ref_ptr m_main_view; + osg::ref_ptr m_viewer; + + std::map m_key_map; + QMutex m_deferredEventQueueMutex; + QQueue m_deferredEventQueue; + QSet m_eventCompressor; + bool m_touchEventsEnabled = false; + qreal m_device_pixel_ratio = 1.0; +}; + +class GraphicsWindowQt : public osgViewer::GraphicsWindowEmbedded +{ +public: + GraphicsWindowQt( QWidget* parent, Qt::WindowFlags f ); + virtual ~GraphicsWindowQt(); + + QtOSGWidget* getOpenGLWidget() { return m_opengl_widget; } + virtual void grabFocus(); + virtual void grabFocusIfPointerInWindow(); + virtual void useCursor( bool cursorOn ); + virtual void setCursor( MouseCursor cursor ); + virtual bool valid() const; + virtual bool realizeImplementation(); + virtual bool isRealizedImplementation() const; + virtual void closeImplementation(); + virtual bool makeCurrentImplementation(); + virtual bool releaseContextImplementation(); + virtual void runOperations(); + virtual void requestWarpPointer( float x, float y ); + +protected: + friend class QtOSGWidget; + QtOSGWidget* m_opengl_widget = nullptr; + QCursor m_current_cursor; + bool m_realized = false; +}; diff --git a/examples/SimpleViewerExampleQt/src/viewer/OrbitCameraManipulator.cpp b/examples/SimpleViewerExampleQt/src/viewer2/OrbitCameraManipulator.cpp similarity index 96% rename from examples/SimpleViewerExampleQt/src/viewer/OrbitCameraManipulator.cpp rename to examples/SimpleViewerExampleQt/src/viewer2/OrbitCameraManipulator.cpp index 381b55309..157557db2 100644 --- a/examples/SimpleViewerExampleQt/src/viewer/OrbitCameraManipulator.cpp +++ b/examples/SimpleViewerExampleQt/src/viewer2/OrbitCameraManipulator.cpp @@ -1,886 +1,886 @@ -/* -*-c++-*- IfcQuery www.ifcquery.com -* -MIT License - -Copyright (c) 2017 Fabian Gerold - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include "IfcPlusPlusSystem.h" -#include "OrbitCameraManipulator.h" - -int OrbitCameraManipulator::m_minimum_distance_flag_index = allocateRelativeFlag(); - -OrbitCameraManipulator::OrbitCameraManipulator( IfcPlusPlusSystem* sys, int flags ) : StandardManipulator( flags ), m_system( sys ) -{ - m_eye.set( 10, 10, 10 ); - m_up.set( 0, 0, 1 ); - m_rotate_center.set( 0, 0, 0 ); - setMinimumDistance( 0.01, true ); - m_wheel_zoom_factor = 0.05; - - initManipulator(); -} - -OrbitCameraManipulator::OrbitCameraManipulator( const OrbitCameraManipulator& om, const osg::CopyOp& copyOp ) : osg::Object(om, copyOp), StandardManipulator( om, copyOp ), - m_system( om.m_system), m_eye( om.m_eye ), m_lookat( om.m_lookat ), m_rotate_center( om.m_rotate_center ), - m_wheel_zoom_factor( om.m_wheel_zoom_factor ), m_minimum_distance( om.m_minimum_distance ) -{ - initManipulator(); -} - -void OrbitCameraManipulator::initManipulator() -{ - setAnimationTime( 0.2 ); - - _homeEye.set( m_eye ); - _homeCenter.set( m_lookat ); - _homeUp.set( m_up ); - setAutoComputeHomePosition( false ); - _allowThrow = false; - - m_animation_data = new OrbitAnimationData(); - m_intersect_hit_geometry = false; - m_control_key_down = false; - m_fovy = 30; - -} - -/** Set the position of the manipulator using a 4x4 matrix.*/ -void OrbitCameraManipulator::setByMatrix( const osg::Matrixd& matrix ) -{ - matrix.getLookAt( m_eye, m_lookat, m_up ); -} - - -/** Set the position of the manipulator using a 4x4 matrix.*/ -void OrbitCameraManipulator::setByInverseMatrix( const osg::Matrixd& matrix ) -{ - setByMatrix( osg::Matrixd::inverse( matrix ) ); -} - - -/** Get the position of the manipulator as 4x4 matrix.*/ -osg::Matrixd OrbitCameraManipulator::getMatrix() const -{ - osg::Matrix m; - m.makeLookAt( m_eye, m_lookat, m_up ); - return m; -} - -/** Get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/ -osg::Matrixd OrbitCameraManipulator::getInverseMatrix() const -{ - osg::Matrix m; - m.makeLookAt( m_eye, m_lookat, m_up ); - return m; -} - -void OrbitCameraManipulator::setTransformation( const osg::Vec3d& eye, const osg::Quat& /*rotation*/ ) -{ - m_eye.set( eye ); - // TODO: implement - //m_lookat = eye + rotation * osg::Vec3d( 0., 0., -m_distance ); - //m_rotation = rotation; -} - -void OrbitCameraManipulator::getTransformation( osg::Vec3d& eye, osg::Quat& /*rotation*/ ) const -{ - eye.set( m_eye ); - // TODO: implement -} - -void OrbitCameraManipulator::setTransformation( const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up ) -{ - m_eye.set( eye ); - m_lookat.set( center ); - m_up.set( up ); -} - -// doc in parent -void OrbitCameraManipulator::getTransformation( osg::Vec3d& eye, osg::Vec3d& center, osg::Vec3d& up ) const -{ - center.set( m_lookat ); - eye.set( m_eye ); - up.set( m_up ); -} - -void OrbitCameraManipulator::computeRayPointer( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - osgViewer::View* view = dynamic_cast(&aa); - if (!view) return; - - m_model_screen.makeIdentity(); - // do not apply viewport here ( m_cam->getViewport()->computeWindowMatrix() ). Use normalized screen coords instead (ea.getXnormalized()) - osg::Matrixd pm( view->getCamera()->getProjectionMatrix() ); - osg::Matrixd vm( getInverseMatrix() ); - - if( pm.valid() ) m_model_screen.preMult( pm ); - if( vm.valid() ) m_model_screen.preMult( vm ); - - m_screen_model.invert( m_model_screen ); - - m_ray_pointer_start.set( m_screen_model.preMult( osg::Vec3d( ea.getXnormalized(), ea.getYnormalized(), 0.0) ) ); - osg::Vec3d pointer_end = m_screen_model.preMult( osg::Vec3d( ea.getXnormalized(), ea.getYnormalized(), 0.1) ); - - osg::Vec3d ray_direction = pointer_end - m_ray_pointer_start; - ray_direction.normalize(); - m_ray_pointer_direction.set( ray_direction ); - - double fovy, apect_ratio, zNear, zFar; - bool perspective = pm.getPerspective( fovy, apect_ratio, zNear, zFar ); - if( perspective ) - { - m_fovy = fovy; - } -} - -/** Handles events. Returns true if handled, false otherwise.*/ -bool OrbitCameraManipulator::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - switch( ea.getEventType() ) - { - - case osgGA::GUIEventAdapter::FRAME: - return handleFrame( ea, aa ); - - case osgGA::GUIEventAdapter::RESIZE: - return handleResize( ea, aa ); - - default: - break; - } - - if( ea.getHandled() ) - { - return false; - } - - computeRayPointer( ea, aa ); - - bool handled = false; - switch( ea.getEventType() ) - { - case osgGA::GUIEventAdapter::MOVE: - handled = handleMouseMove( ea, aa ); - break; - - case osgGA::GUIEventAdapter::DRAG: - handled = handleMouseDrag( ea, aa ); - break; - - case osgGA::GUIEventAdapter::PUSH: - handled = handleMousePush( ea, aa ); - break; - - case osgGA::GUIEventAdapter::RELEASE: - handled = handleMouseRelease( ea, aa ); - break; - - case osgGA::GUIEventAdapter::KEYDOWN: - handled = handleKeyDown( ea, aa ); - break; - - case osgGA::GUIEventAdapter::KEYUP: - m_control_key_down = false; - handled = handleKeyUp( ea, aa ); - break; - - case osgGA::GUIEventAdapter::SCROLL: - if( _flags & PROCESS_MOUSE_WHEEL ) - handled = handleMouseWheel( ea, aa ); - else - handled = false; - break; - - default: - handled = false; - } - - return handled; -} - - -/// Handles GUIEventAdapter::FRAME event. -bool OrbitCameraManipulator::handleFrame( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - double current_frame_time = ea.getTime(); - - _delta_frame_time = current_frame_time - _last_frame_time; - _last_frame_time = current_frame_time; - - if( _thrown && performMovement( ea, aa ) ) - { - aa.requestRedraw(); - } - - if( m_animation_data && m_animation_data->_isAnimating ) - { - if( m_animation_data->_startTime < 0 ) - { - // animation has been started from some location without access to a GUIEventAdapter object, so no start time could be set. Do it now. - m_animation_data->start( current_frame_time ); - } - performAnimationMovement( ea, aa ); - } - - return false; -} - -bool OrbitCameraManipulator::handleMouseMove( const osgGA::GUIEventAdapter& /*ea*/, osgGA::GUIActionAdapter& /*aa*/ ) -{ - return false; -} - - -// mouse button has been pushed down -bool OrbitCameraManipulator::handleMousePush( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - osgViewer::View* view = dynamic_cast(&aa); - if( !view ) - { - return false; - } - - m_pointer_push_drag = false; - flushMouseEventStack(); - addMouseEvent( ea ); - m_ga_pointer_push = &ea; - - intersectSceneRotateCenter( ea, view ); - - int buttonMask = ea.getButtonMask(); - //if( buttonMask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask == (osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON | osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) ) - if (buttonMask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) - { - m_pan_point.set( m_pointer_intersection ); - } - - if( buttonMask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) - { - osg::Vec3d distance_intersect_eye( m_pointer_intersection - m_eye ); - //double distance_eye_intersection = distance_intersect_eye.length(); - - // rotate the intersection cone into mouse ray direction - if( m_intersect_hit_geometry ) - { - - } - } - aa.requestRedraw(); - aa.requestContinuousUpdate( false ); - _thrown = false; - - return false; -} - -bool OrbitCameraManipulator::handleMouseRelease( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - osgViewer::View* view = dynamic_cast(&aa); - if( !view ) return false; - - if( ea.getButtonMask() == 0 ) - { - double timeSinceLastRecordEvent = _ga_t0.valid() ? (ea.getTime() - _ga_t0->getTime()) : DBL_MAX; - if( timeSinceLastRecordEvent > 0.02 ) - { - flushMouseEventStack(); - } - - if( isMouseMoving() ) - { - if( performMovement( ea, aa ) && _allowThrow ) - { - aa.requestRedraw(); - aa.requestContinuousUpdate( true ); - _thrown = true; - // TODO: fade out throw animation - } - - return true; - } - } - - if( !m_pointer_push_drag ) - { - // select object - bool intersection_geometry_found = intersectSceneSelect( ea, view ); - - if( !intersection_geometry_found ) - { - // click to background -> unselect all - if( m_system != nullptr ) - { - m_system->clearSelection(); - } - } - } - m_pointer_push_drag = false; - - flushMouseEventStack(); - addMouseEvent( ea ); - if( performMovement( ea, aa ) ) - { - aa.requestRedraw(); - } - aa.requestContinuousUpdate( false ); - _thrown = false; - - return true; -} - -bool OrbitCameraManipulator::handleKeyDown( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - osgViewer::View* view = dynamic_cast(&aa); - if( !view ) return false; - - osg::Group* root_node = dynamic_cast(view->getScene()->getSceneData()); - if( !root_node ) return false; - - const int key = ea.getKey(); - if( key == osgGA::GUIEventAdapter::KEY_Control_L || key == osgGA::GUIEventAdapter::KEY_Control_R ) - { - m_control_key_down = true; - } - - return false; -} - -bool OrbitCameraManipulator::intersectSceneRotateCenter( const osgGA::GUIEventAdapter& ea, osgViewer::View* view ) -{ - m_intersect_hit_geometry = false; - osg::ref_ptr picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); - picker->setIntersectionLimit( osgUtil::Intersector::LIMIT_NEAREST ); - osgUtil::IntersectionVisitor iv( picker.get() ); - osg::Camera* cam = view->getCamera(); - - if( !cam ) - { - return false; - } - iv.apply( *cam ); - - if( picker->containsIntersections() ) - { -#ifdef POLYTOPE_INTERSECTOR - osgUtil::PolytopeIntersector::Intersection intersection = picker->getFirstIntersection(); -#else - osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection(); -#endif - - osg::NodePath& nodePath = intersection.nodePath; - for( size_t i=0; i picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); - osgUtil::IntersectionVisitor iv( picker.get() ); - osg::Camera* cam = view->getCamera(); - if( !cam ) - { - return false; - } - iv.apply( *cam ); - - bool intersection_geometry_found = false; - osgUtil::LineSegmentIntersector::Intersection closest_intersection; - int closest_intersection_nodepath_idx = 0; - double closest_intersection_distance = DBL_MAX; - - if( picker->containsIntersections() ) - { - osgUtil::LineSegmentIntersector::Intersections& intersections = picker->getIntersections(); - for( auto intersection : intersections ) - { - osg::NodePath& nodePath = intersection.nodePath; - for( size_t i = 0; igetName(); - - osg::Vec3d world_intersect_point = intersection.getWorldIntersectPoint(); - m_pointer_intersection.set( world_intersect_point ); - - // check if picked object is a representation of an IfcProduct - if( node_name.length() < 22 ) - { - continue; - } - - std::string guid; - std::regex re("[a-zA-Z0-9_$]{22}"); - std::smatch match; - if (std::regex_search(node_name, match, re)) - { - guid = match.str(0); - } - else - { - continue; - } - - if( node_name.compare( 0, 9, "intersect" ) == 0 ) - { - continue; - } - - osg::Group* group = dynamic_cast( node ); - if( !group ) - { - continue; - } - - double distance_to_eye = ( m_eye-world_intersect_point ).length(); - if( distance_to_eye < closest_intersection_distance ) - { - intersection_geometry_found = true; - closest_intersection_distance = distance_to_eye; - closest_intersection = intersection; - closest_intersection_nodepath_idx = nodePath.size()-i-1; - } - } - } - - if( intersection_geometry_found ) - { - osg::NodePath& nodePath = closest_intersection.nodePath; - if( closest_intersection_nodepath_idx < nodePath.size() ) - { - osg::Node* node = nodePath[closest_intersection_nodepath_idx]; - const std::string node_name = node->getName(); - - osg::Vec3d world_intersect_point = closest_intersection.getWorldIntersectPoint(); - m_pointer_intersection.set( world_intersect_point ); - - osg::Group* group = dynamic_cast( node ); - if( group ) - { - // extract entity id - std::string guid_selected; - std::regex re("[a-zA-Z0-9_$]{22}"); - std::smatch match; - if (std::regex_search(node_name, match, re)) - { - guid_selected = match.str(0); - } - - auto map_selected = m_system->getSelectedObjects(); - auto it_selected = map_selected.find(guid_selected); - if( it_selected != map_selected.end() ) - { - shared_ptr selected_entity = it_selected->second; - // is already selected, so deselect - m_system->setObjectSelected( selected_entity->m_entity, false, selected_entity->m_osg_group ); - return true; - } - else - { - // select - shared_ptr ifc_model = m_system->getIfcModel(); - auto map_ifc_objects = ifc_model->getMapIfcEntities(); - - for (auto it_find : map_ifc_objects) - { - shared_ptr entity = it_find.second; - std::string guid = getGUID(entity); - if (guid.compare(guid_selected) == 0) - { - shared_ptr entitiy_selected = entity; - if (!m_control_key_down) - { - m_system->clearSelection(); - } - m_system->setObjectSelected(entitiy_selected, true, group); - break; - } - } - return true; - } - } - } - } - } - - return intersection_geometry_found; -} - -bool OrbitCameraManipulator::handleMouseWheel( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion(); - - // TODO: increase scroll factor when eye is far away from model bounding sphere - double scroll_distance_factor = ( m_eye - m_rotate_center ).length()*0.1; - - switch( sm ) - { - // mouse scroll up event - case osgGA::GUIEventAdapter::SCROLL_UP: - { - // perform zoom - zoomCamera( m_wheel_zoom_factor*scroll_distance_factor ); - aa.requestRedraw(); - aa.requestContinuousUpdate( isAnimating() || _thrown ); - return true; - } - - // mouse scroll down event - case osgGA::GUIEventAdapter::SCROLL_DOWN: - { - // perform zoom - zoomCamera( -m_wheel_zoom_factor*scroll_distance_factor ); - aa.requestRedraw(); - aa.requestContinuousUpdate( isAnimating() || _thrown ); - return true; - } - - // unhandled mouse scrolling motion - default: - return false; - } -} - -bool OrbitCameraManipulator::handleMouseDrag( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - addMouseEvent( ea ); - - m_pointer_push_drag = true; - if( performMovement( ea, aa ) ) - { - aa.requestRedraw(); - } - - aa.requestContinuousUpdate( false ); - _thrown = false; - - return true; -} - -/// Make movement step of manipulator. Returns true if any movement was made. -bool OrbitCameraManipulator::performMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - // return if less then two events have been added - if( _ga_t0.get() == nullptr || _ga_t1.get() == nullptr ) - { - return false; - } - - // get delta time - double eventTimeDelta = _ga_t0->getTime() - _ga_t1->getTime(); - if( eventTimeDelta < 0. ) - { - OSG_WARN << "Manipulator warning: eventTimeDelta = " << eventTimeDelta << std::endl; - eventTimeDelta = 0.; - } - - // get deltaX and deltaY - float dx = _ga_t0->getXnormalized() - _ga_t1->getXnormalized(); - float dy = _ga_t0->getYnormalized() - _ga_t1->getYnormalized(); - float scale = getThrowScale( eventTimeDelta ); - dx = dx*scale; - dy = dy*scale; - - // return if there is no movement. - if( dx == 0. && dy == 0. ) - { - return false; - } - - // call appropriate methods - int buttonMask = _ga_t1->getButtonMask(); - if( buttonMask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) - { - rotateCamera( dx, dy ); - return true; - } - else if( buttonMask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON ) - { - // pan model - //float scale = getThrowScale( eventTimeDelta ); - panCamera( dx, dy, ea, aa ); - return true; - } - else if( buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON ) - { - zoomCamera( dy ); - return true; - } - - return false; -} - -bool OrbitCameraManipulator::performMouseDeltaMovement( const float dx, const float dy ) -{ - rotateCamera( dx, dy ); - return true; -} - -void OrbitCameraManipulator::rotateCamera( float dx, float dy ) -{ - if( dx != 0.0 || dy != 0.0 ) - { - // yaw - osg::CoordinateFrame coordinate_frame = getCoordinateFrame( m_lookat ); - osg::Vec3d yaw_axis = getUpVector( coordinate_frame ); - - yaw_axis.normalize(); - - // lookat is the center of the screen. rotation center can be different (intersection point) - osg::Vec3d center_eye = m_eye - m_rotate_center; - osg::Vec3d center_lookat = m_lookat - m_rotate_center; - osg::Vec3d eye_lookat = m_lookat - m_eye; - - // pitch - osg::Vec3d pitch_axis(0,0,1); - pitch_axis = pitch_axis ^ center_eye; - pitch_axis.normalize(); - - // apply yaw and pitch around the rotation center - osg::Quat quatpitch( dy*2.2, pitch_axis ); - osg::Vec3d center_eye_pitch = quatpitch * center_eye; - osg::Vec3d center_lookat_pitch = quatpitch * center_lookat; - - - osg::Quat quatyaw( -dx*5.2, yaw_axis ); - osg::Vec3d center_eye_new = quatyaw*center_eye_pitch; - osg::Vec3d center_lookat_new = quatyaw*center_lookat_pitch; - - m_eye.set( m_rotate_center + center_eye_new ); - m_lookat.set( m_rotate_center + center_lookat_new ); - } -}; - -/** Moves the camera such that the model remains under the cursor.*/ -void OrbitCameraManipulator::panCamera( const float /*dx*/, const float /*dy*/, const osgGA::GUIEventAdapter& /*ea*/, osgGA::GUIActionAdapter& aa ) -{ - osgViewer::View* view = dynamic_cast( &aa ); - if( !view ) - { - return; - } - -#if 0 - osg::Matrix matrix; - matrix.getLookAt( m_eye, m_lookat, m_up ); - matrix = matrix*osg::Matrix::translate( dx, dy, 0 ); - // set eye, lookat, up from matrix - matrix.getLookAt( m_eye, m_lookat, m_up ); - - return; -#endif - - - //osg::Vec3d intersect_point_screen = screen_model.preMult( m_pointer_intersection ); - osg::Vec3d p1 = m_screen_model.preMult( osg::Vec3d( _ga_t0->getXnormalized(), _ga_t0->getYnormalized(), 0 ) ); - osg::Vec3d p2 = m_screen_model.preMult( osg::Vec3d( _ga_t1->getXnormalized(), _ga_t1->getYnormalized(), 0 ) ); - osg::Vec3d n = p2 - p1; - - double length = ( m_pointer_intersection - m_eye ).length(); - n *= length*1.25; - - m_eye.set( m_eye + n ); - m_lookat.set( m_lookat + n ); - return; -} - - -/** Changes the distance of camera to the focal center. -If pushForwardIfNeeded is true and minimumDistance is reached, the focal center is moved forward. Otherwise, distance is limited to its minimum value. -\sa OrbitCameraManipulator::setMinimumDistance -*/ -void OrbitCameraManipulator::zoomCamera( const float dy ) -{ - // push camera forward along mouse ray - osg::Vec3d zoom_direction = m_ray_pointer_direction; - zoom_direction.normalize(); - zoom_direction *= dy*100; - m_eye += zoom_direction; - m_lookat += zoom_direction; -} - -////////////////////////////////////////////////////// animation ////////////////////////////////////////////////////////////////// -void OrbitCameraManipulator::applyAnimationStep( const double currentProgress, const double /*prevProgress*/ ) -{ - osg::Vec3d new_eye( m_animation_data->m_start_eye + (m_animation_data->m_target_eye - m_animation_data->m_start_eye) * (currentProgress) ); - osg::Vec3d new_lookat( m_animation_data->m_start_lookat + (m_animation_data->m_target_lookat - m_animation_data->m_start_lookat) * (currentProgress) ); - osg::Vec3d new_up( m_animation_data->m_start_up + (m_animation_data->m_target_up - m_animation_data->m_start_up) * (currentProgress) ); - - m_eye.set( new_eye ); - m_lookat.set( new_lookat ); - m_up.set( new_up ); -} - -OrbitCameraManipulator::OrbitAnimationData::OrbitAnimationData() : AnimationData() -{ -} - -void OrbitCameraManipulator::OrbitAnimationData::start( const double startTime ) -{ - AnimationData::start( startTime ); -} - -void OrbitCameraManipulator::setAnimationTime( const double t ) -{ - if( t <= 0. ) - { - finishAnimation(); - m_animation_data = nullptr; - return; - } - - if( !m_animation_data ) - { - m_animation_data = new OrbitAnimationData(); - } - - m_animation_data->_animationTime = t; -} - -bool OrbitCameraManipulator::performAnimationMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) -{ - double f = (ea.getTime() - m_animation_data->_startTime) / m_animation_data->_animationTime; - if( f >= 1. ) - { - f = 1.; - m_animation_data->_isAnimating = false; - if( !_thrown ) - { - aa.requestContinuousUpdate( false ); - } - } - - applyAnimationStep( f, m_animation_data->_phase ); - - m_animation_data->_phase = f; - aa.requestRedraw(); - - return m_animation_data->_isAnimating; -} - -bool OrbitCameraManipulator::isAnimating() const -{ - if( m_animation_data ) - { - return m_animation_data->_isAnimating; - } - else - { - return false; - } -} - - -/** Get the FusionDistanceMode. Used by SceneView for setting up stereo convergence.*/ -osgUtil::SceneView::FusionDistanceMode OrbitCameraManipulator::getFusionDistanceMode() const -{ - return osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE; -} - -/** Get the FusionDistanceValue. Used by SceneView for setting up stereo convergence.*/ -float OrbitCameraManipulator::getFusionDistanceValue() const -{ - return 0;//m_distance; -} - - -/** Set the mouse wheel zoom factor. -The amount of camera movement on each mouse wheel event is computed as the current distance to the center multiplied by this factor. -For example, value of 0.1 will short distance to center by 10% on each wheel up event. -Use negative value for reverse mouse wheel direction.*/ -void OrbitCameraManipulator::setWheelZoomFactor( double wheelZoomFactor ) -{ - m_wheel_zoom_factor = wheelZoomFactor; -} - - -/** Set the minimum distance of the eye point from the center before the center is pushed forward.*/ -void OrbitCameraManipulator::setMinimumDistance( const double& minimumDistance, bool relativeToModelSize ) -{ - m_minimum_distance = minimumDistance; - setRelativeFlag( m_minimum_distance_flag_index, relativeToModelSize ); -} - - -/** Get the minimum distance of the eye point from the center before the center is pushed forward.*/ -double OrbitCameraManipulator::getMinimumDistance( bool *relativeToModelSize ) const -{ - if( relativeToModelSize ) - { - *relativeToModelSize = getRelativeFlag( m_minimum_distance_flag_index ); - } - - return m_minimum_distance; -} - - -void OrbitCameraManipulator::zoomToBoundingSphere( const osg::BoundingSphere& bs, double /*ratio_w*/ ) -{ - osg::Vec3f bs_center( bs.center() ); - double bs_radius = bs.radius(); - if( bs_radius <= 0.5 ) - { - bs_radius = 2.0; - bs_center._v[2] = 0.5; - } - - m_rotate_center.set( bs.center() ); - - osg::Vec3d eye_lookat(m_eye - m_lookat); - eye_lookat.normalize(); - - // define animation path - if( m_animation_data ) - { - osg::Vec3d target_lookat( bs.center() ); - - double d_eye = bs_radius/sin( osg::DegreesToRadians(m_fovy*0.5) ); - osg::Vec3d target_eye( target_lookat + eye_lookat*d_eye ); - - m_animation_data->m_start_eye.set( m_eye ); - m_animation_data->m_start_lookat.set( m_lookat ); - m_animation_data->m_start_up.set( m_up ); - - m_animation_data->m_target_eye.set( target_eye ); - m_animation_data->m_target_lookat.set( target_lookat ); - m_animation_data->m_target_up.set( m_up ); - - m_animation_data->_animationTime = 0.6; - m_animation_data->start( -1 ); - } -} +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "IfcPlusPlusSystem.h" +#include "OrbitCameraManipulator.h" + +int OrbitCameraManipulator::m_minimum_distance_flag_index = allocateRelativeFlag(); + +OrbitCameraManipulator::OrbitCameraManipulator( IfcPlusPlusSystem* sys, int flags ) : StandardManipulator( flags ), m_system( sys ) +{ + m_eye.set( 10, 10, 10 ); + m_up.set( 0, 0, 1 ); + m_rotate_center.set( 0, 0, 0 ); + setMinimumDistance( 0.01, true ); + m_wheel_zoom_factor = 0.05; + + initManipulator(); +} + +OrbitCameraManipulator::OrbitCameraManipulator( const OrbitCameraManipulator& om, const osg::CopyOp& copyOp ) : osg::Object(om, copyOp), StandardManipulator( om, copyOp ), + m_system( om.m_system), m_eye( om.m_eye ), m_lookat( om.m_lookat ), m_rotate_center( om.m_rotate_center ), + m_wheel_zoom_factor( om.m_wheel_zoom_factor ), m_minimum_distance( om.m_minimum_distance ) +{ + initManipulator(); +} + +void OrbitCameraManipulator::initManipulator() +{ + setAnimationTime( 0.2 ); + + _homeEye.set( m_eye ); + _homeCenter.set( m_lookat ); + _homeUp.set( m_up ); + setAutoComputeHomePosition( false ); + _allowThrow = false; + + m_animation_data = new OrbitAnimationData(); + m_intersect_hit_geometry = false; + m_control_key_down = false; + m_fovy = 30; + +} + +/** Set the position of the manipulator using a 4x4 matrix.*/ +void OrbitCameraManipulator::setByMatrix( const osg::Matrixd& matrix ) +{ + matrix.getLookAt( m_eye, m_lookat, m_up ); +} + + +/** Set the position of the manipulator using a 4x4 matrix.*/ +void OrbitCameraManipulator::setByInverseMatrix( const osg::Matrixd& matrix ) +{ + setByMatrix( osg::Matrixd::inverse( matrix ) ); +} + + +/** Get the position of the manipulator as 4x4 matrix.*/ +osg::Matrixd OrbitCameraManipulator::getMatrix() const +{ + osg::Matrix m; + m.makeLookAt( m_eye, m_lookat, m_up ); + return m; +} + +/** Get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/ +osg::Matrixd OrbitCameraManipulator::getInverseMatrix() const +{ + osg::Matrix m; + m.makeLookAt( m_eye, m_lookat, m_up ); + return m; +} + +void OrbitCameraManipulator::setTransformation( const osg::Vec3d& eye, const osg::Quat& /*rotation*/ ) +{ + m_eye.set( eye ); + // TODO: implement + //m_lookat = eye + rotation * osg::Vec3d( 0., 0., -m_distance ); + //m_rotation = rotation; +} + +void OrbitCameraManipulator::getTransformation( osg::Vec3d& eye, osg::Quat& /*rotation*/ ) const +{ + eye.set( m_eye ); + // TODO: implement +} + +void OrbitCameraManipulator::setTransformation( const osg::Vec3d& eye, const osg::Vec3d& center, const osg::Vec3d& up ) +{ + m_eye.set( eye ); + m_lookat.set( center ); + m_up.set( up ); +} + +// doc in parent +void OrbitCameraManipulator::getTransformation( osg::Vec3d& eye, osg::Vec3d& center, osg::Vec3d& up ) const +{ + center.set( m_lookat ); + eye.set( m_eye ); + up.set( m_up ); +} + +void OrbitCameraManipulator::computeRayPointer( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgViewer::View* view = dynamic_cast(&aa); + if (!view) return; + + m_model_screen.makeIdentity(); + // do not apply viewport here ( m_cam->getViewport()->computeWindowMatrix() ). Use normalized screen coords instead (ea.getXnormalized()) + osg::Matrixd pm( view->getCamera()->getProjectionMatrix() ); + osg::Matrixd vm( getInverseMatrix() ); + + if( pm.valid() ) m_model_screen.preMult( pm ); + if( vm.valid() ) m_model_screen.preMult( vm ); + + m_screen_model.invert( m_model_screen ); + + m_ray_pointer_start.set( m_screen_model.preMult( osg::Vec3d( ea.getXnormalized(), ea.getYnormalized(), 0.0) ) ); + osg::Vec3d pointer_end = m_screen_model.preMult( osg::Vec3d( ea.getXnormalized(), ea.getYnormalized(), 0.1) ); + + osg::Vec3d ray_direction = pointer_end - m_ray_pointer_start; + ray_direction.normalize(); + m_ray_pointer_direction.set( ray_direction ); + + double fovy, apect_ratio, zNear, zFar; + bool perspective = pm.getPerspective( fovy, apect_ratio, zNear, zFar ); + if( perspective ) + { + m_fovy = fovy; + } +} + +/** Handles events. Returns true if handled, false otherwise.*/ +bool OrbitCameraManipulator::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + switch( ea.getEventType() ) + { + + case osgGA::GUIEventAdapter::FRAME: + return handleFrame( ea, aa ); + + case osgGA::GUIEventAdapter::RESIZE: + return handleResize( ea, aa ); + + default: + break; + } + + if( ea.getHandled() ) + { + return false; + } + + computeRayPointer( ea, aa ); + + bool handled = false; + switch( ea.getEventType() ) + { + case osgGA::GUIEventAdapter::MOVE: + handled = handleMouseMove( ea, aa ); + break; + + case osgGA::GUIEventAdapter::DRAG: + handled = handleMouseDrag( ea, aa ); + break; + + case osgGA::GUIEventAdapter::PUSH: + handled = handleMousePush( ea, aa ); + break; + + case osgGA::GUIEventAdapter::RELEASE: + handled = handleMouseRelease( ea, aa ); + break; + + case osgGA::GUIEventAdapter::KEYDOWN: + handled = handleKeyDown( ea, aa ); + break; + + case osgGA::GUIEventAdapter::KEYUP: + m_control_key_down = false; + handled = handleKeyUp( ea, aa ); + break; + + case osgGA::GUIEventAdapter::SCROLL: + if( _flags & PROCESS_MOUSE_WHEEL ) + handled = handleMouseWheel( ea, aa ); + else + handled = false; + break; + + default: + handled = false; + } + + return handled; +} + + +/// Handles GUIEventAdapter::FRAME event. +bool OrbitCameraManipulator::handleFrame( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + double current_frame_time = ea.getTime(); + + _delta_frame_time = current_frame_time - _last_frame_time; + _last_frame_time = current_frame_time; + + if( _thrown && performMovement( ea, aa ) ) + { + aa.requestRedraw(); + } + + if( m_animation_data && m_animation_data->_isAnimating ) + { + if( m_animation_data->_startTime < 0 ) + { + // animation has been started from some location without access to a GUIEventAdapter object, so no start time could be set. Do it now. + m_animation_data->start( current_frame_time ); + } + performAnimationMovement( ea, aa ); + } + + return false; +} + +bool OrbitCameraManipulator::handleMouseMove( const osgGA::GUIEventAdapter& /*ea*/, osgGA::GUIActionAdapter& /*aa*/ ) +{ + return false; +} + + +// mouse button has been pushed down +bool OrbitCameraManipulator::handleMousePush( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgViewer::View* view = dynamic_cast(&aa); + if( !view ) + { + return false; + } + + m_pointer_push_drag = false; + flushMouseEventStack(); + addMouseEvent( ea ); + m_ga_pointer_push = &ea; + + intersectSceneRotateCenter( ea, view ); + + int buttonMask = ea.getButtonMask(); + //if( buttonMask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask == (osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON | osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) ) + if (buttonMask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) + { + m_pan_point.set( m_pointer_intersection ); + } + + if( buttonMask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) + { + osg::Vec3d distance_intersect_eye( m_pointer_intersection - m_eye ); + //double distance_eye_intersection = distance_intersect_eye.length(); + + // rotate the intersection cone into mouse ray direction + if( m_intersect_hit_geometry ) + { + + } + } + aa.requestRedraw(); + aa.requestContinuousUpdate( false ); + _thrown = false; + + return false; +} + +bool OrbitCameraManipulator::handleMouseRelease( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgViewer::View* view = dynamic_cast(&aa); + if( !view ) return false; + + if( ea.getButtonMask() == 0 ) + { + double timeSinceLastRecordEvent = _ga_t0.valid() ? (ea.getTime() - _ga_t0->getTime()) : DBL_MAX; + if( timeSinceLastRecordEvent > 0.02 ) + { + flushMouseEventStack(); + } + + if( isMouseMoving() ) + { + if( performMovement( ea, aa ) && _allowThrow ) + { + aa.requestRedraw(); + aa.requestContinuousUpdate( true ); + _thrown = true; + // TODO: fade out throw animation + } + + return true; + } + } + + if( !m_pointer_push_drag ) + { + // select object + bool intersection_geometry_found = intersectSceneSelect( ea, view ); + + if( !intersection_geometry_found ) + { + // click to background -> unselect all + if( m_system != nullptr ) + { + m_system->clearSelection(); + } + } + } + m_pointer_push_drag = false; + + flushMouseEventStack(); + addMouseEvent( ea ); + if( performMovement( ea, aa ) ) + { + aa.requestRedraw(); + } + aa.requestContinuousUpdate( false ); + _thrown = false; + + return true; +} + +bool OrbitCameraManipulator::handleKeyDown( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgViewer::View* view = dynamic_cast(&aa); + if( !view ) return false; + + osg::Group* root_node = dynamic_cast(view->getScene()->getSceneData()); + if( !root_node ) return false; + + const int key = ea.getKey(); + if( key == osgGA::GUIEventAdapter::KEY_Control_L || key == osgGA::GUIEventAdapter::KEY_Control_R ) + { + m_control_key_down = true; + } + + return false; +} + +bool OrbitCameraManipulator::intersectSceneRotateCenter( const osgGA::GUIEventAdapter& ea, osgViewer::View* view ) +{ + m_intersect_hit_geometry = false; + osg::ref_ptr picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); + picker->setIntersectionLimit( osgUtil::Intersector::LIMIT_NEAREST ); + osgUtil::IntersectionVisitor iv( picker.get() ); + osg::Camera* cam = view->getCamera(); + + if( !cam ) + { + return false; + } + iv.apply( *cam ); + + if( picker->containsIntersections() ) + { +#ifdef POLYTOPE_INTERSECTOR + osgUtil::PolytopeIntersector::Intersection intersection = picker->getFirstIntersection(); +#else + osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection(); +#endif + + osg::NodePath& nodePath = intersection.nodePath; + for( size_t i=0; i picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); + osgUtil::IntersectionVisitor iv( picker.get() ); + osg::Camera* cam = view->getCamera(); + if( !cam ) + { + return false; + } + iv.apply( *cam ); + + bool intersection_geometry_found = false; + osgUtil::LineSegmentIntersector::Intersection closest_intersection; + int closest_intersection_nodepath_idx = 0; + double closest_intersection_distance = DBL_MAX; + + if( picker->containsIntersections() ) + { + osgUtil::LineSegmentIntersector::Intersections& intersections = picker->getIntersections(); + for( auto intersection : intersections ) + { + osg::NodePath& nodePath = intersection.nodePath; + for( size_t i = 0; igetName(); + + osg::Vec3d world_intersect_point = intersection.getWorldIntersectPoint(); + m_pointer_intersection.set( world_intersect_point ); + + // check if picked object is a representation of an IfcProduct + if( node_name.length() < 22 ) + { + continue; + } + + std::string guid; + std::regex re("[a-zA-Z0-9_$]{22}"); + std::smatch match; + if (std::regex_search(node_name, match, re)) + { + guid = match.str(0); + } + else + { + continue; + } + + if( node_name.compare( 0, 9, "intersect" ) == 0 ) + { + continue; + } + + osg::Group* group = dynamic_cast( node ); + if( !group ) + { + continue; + } + + double distance_to_eye = ( m_eye-world_intersect_point ).length(); + if( distance_to_eye < closest_intersection_distance ) + { + intersection_geometry_found = true; + closest_intersection_distance = distance_to_eye; + closest_intersection = intersection; + closest_intersection_nodepath_idx = nodePath.size()-i-1; + } + } + } + + if( intersection_geometry_found ) + { + osg::NodePath& nodePath = closest_intersection.nodePath; + if( closest_intersection_nodepath_idx < nodePath.size() ) + { + osg::Node* node = nodePath[closest_intersection_nodepath_idx]; + const std::string node_name = node->getName(); + + osg::Vec3d world_intersect_point = closest_intersection.getWorldIntersectPoint(); + m_pointer_intersection.set( world_intersect_point ); + + osg::Group* group = dynamic_cast( node ); + if( group ) + { + // extract entity id + std::string guid_selected; + std::regex re("[a-zA-Z0-9_$]{22}"); + std::smatch match; + if (std::regex_search(node_name, match, re)) + { + guid_selected = match.str(0); + } + + auto map_selected = m_system->getSelectedObjects(); + auto it_selected = map_selected.find(guid_selected); + if( it_selected != map_selected.end() ) + { + shared_ptr selected_entity = it_selected->second; + // is already selected, so deselect + m_system->setObjectSelected( selected_entity->m_entity, false, selected_entity->m_osg_group ); + return true; + } + else + { + // select + shared_ptr ifc_model = m_system->getIfcModel(); + auto map_ifc_objects = ifc_model->getMapIfcEntities(); + + for (auto it_find : map_ifc_objects) + { + shared_ptr entity = it_find.second; + std::string guid = getGUID(entity); + if (guid.compare(guid_selected) == 0) + { + shared_ptr entitiy_selected = entity; + if (!m_control_key_down) + { + m_system->clearSelection(); + } + m_system->setObjectSelected(entitiy_selected, true, group); + break; + } + } + return true; + } + } + } + } + } + + return intersection_geometry_found; +} + +bool OrbitCameraManipulator::handleMouseWheel( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion(); + + // TODO: increase scroll factor when eye is far away from model bounding sphere + double scroll_distance_factor = ( m_eye - m_rotate_center ).length()*0.1; + + switch( sm ) + { + // mouse scroll up event + case osgGA::GUIEventAdapter::SCROLL_UP: + { + // perform zoom + zoomCamera( m_wheel_zoom_factor*scroll_distance_factor ); + aa.requestRedraw(); + aa.requestContinuousUpdate( isAnimating() || _thrown ); + return true; + } + + // mouse scroll down event + case osgGA::GUIEventAdapter::SCROLL_DOWN: + { + // perform zoom + zoomCamera( -m_wheel_zoom_factor*scroll_distance_factor ); + aa.requestRedraw(); + aa.requestContinuousUpdate( isAnimating() || _thrown ); + return true; + } + + // unhandled mouse scrolling motion + default: + return false; + } +} + +bool OrbitCameraManipulator::handleMouseDrag( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + addMouseEvent( ea ); + + m_pointer_push_drag = true; + if( performMovement( ea, aa ) ) + { + aa.requestRedraw(); + } + + aa.requestContinuousUpdate( false ); + _thrown = false; + + return true; +} + +/// Make movement step of manipulator. Returns true if any movement was made. +bool OrbitCameraManipulator::performMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + // return if less then two events have been added + if( _ga_t0.get() == nullptr || _ga_t1.get() == nullptr ) + { + return false; + } + + // get delta time + double eventTimeDelta = _ga_t0->getTime() - _ga_t1->getTime(); + if( eventTimeDelta < 0. ) + { + OSG_WARN << "Manipulator warning: eventTimeDelta = " << eventTimeDelta << std::endl; + eventTimeDelta = 0.; + } + + // get deltaX and deltaY + float dx = _ga_t0->getXnormalized() - _ga_t1->getXnormalized(); + float dy = _ga_t0->getYnormalized() - _ga_t1->getYnormalized(); + float scale = getThrowScale( eventTimeDelta ); + dx = dx*scale; + dy = dy*scale; + + // return if there is no movement. + if( dx == 0. && dy == 0. ) + { + return false; + } + + // call appropriate methods + int buttonMask = _ga_t1->getButtonMask(); + if( buttonMask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) + { + rotateCamera( dx, dy ); + return true; + } + else if( buttonMask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON ) + { + // pan model + //float scale = getThrowScale( eventTimeDelta ); + panCamera( dx, dy, ea, aa ); + return true; + } + else if( buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON ) + { + zoomCamera( dy ); + return true; + } + + return false; +} + +bool OrbitCameraManipulator::performMouseDeltaMovement( const float dx, const float dy ) +{ + rotateCamera( dx, dy ); + return true; +} + +void OrbitCameraManipulator::rotateCamera( float dx, float dy ) +{ + if( dx != 0.0 || dy != 0.0 ) + { + // yaw + osg::CoordinateFrame coordinate_frame = getCoordinateFrame( m_lookat ); + osg::Vec3d yaw_axis = getUpVector( coordinate_frame ); + + yaw_axis.normalize(); + + // lookat is the center of the screen. rotation center can be different (intersection point) + osg::Vec3d center_eye = m_eye - m_rotate_center; + osg::Vec3d center_lookat = m_lookat - m_rotate_center; + osg::Vec3d eye_lookat = m_lookat - m_eye; + + // pitch + osg::Vec3d pitch_axis(0,0,1); + pitch_axis = pitch_axis ^ center_eye; + pitch_axis.normalize(); + + // apply yaw and pitch around the rotation center + osg::Quat quatpitch( dy*2.2, pitch_axis ); + osg::Vec3d center_eye_pitch = quatpitch * center_eye; + osg::Vec3d center_lookat_pitch = quatpitch * center_lookat; + + + osg::Quat quatyaw( -dx*5.2, yaw_axis ); + osg::Vec3d center_eye_new = quatyaw*center_eye_pitch; + osg::Vec3d center_lookat_new = quatyaw*center_lookat_pitch; + + m_eye.set( m_rotate_center + center_eye_new ); + m_lookat.set( m_rotate_center + center_lookat_new ); + } +}; + +/** Moves the camera such that the model remains under the cursor.*/ +void OrbitCameraManipulator::panCamera( const float /*dx*/, const float /*dy*/, const osgGA::GUIEventAdapter& /*ea*/, osgGA::GUIActionAdapter& aa ) +{ + osgViewer::View* view = dynamic_cast( &aa ); + if( !view ) + { + return; + } + +#if 0 + osg::Matrix matrix; + matrix.getLookAt( m_eye, m_lookat, m_up ); + matrix = matrix*osg::Matrix::translate( dx, dy, 0 ); + // set eye, lookat, up from matrix + matrix.getLookAt( m_eye, m_lookat, m_up ); + + return; +#endif + + + //osg::Vec3d intersect_point_screen = screen_model.preMult( m_pointer_intersection ); + osg::Vec3d p1 = m_screen_model.preMult( osg::Vec3d( _ga_t0->getXnormalized(), _ga_t0->getYnormalized(), 0 ) ); + osg::Vec3d p2 = m_screen_model.preMult( osg::Vec3d( _ga_t1->getXnormalized(), _ga_t1->getYnormalized(), 0 ) ); + osg::Vec3d n = p2 - p1; + + double length = ( m_pointer_intersection - m_eye ).length(); + n *= length*1.25; + + m_eye.set( m_eye + n ); + m_lookat.set( m_lookat + n ); + return; +} + + +/** Changes the distance of camera to the focal center. +If pushForwardIfNeeded is true and minimumDistance is reached, the focal center is moved forward. Otherwise, distance is limited to its minimum value. +\sa OrbitCameraManipulator::setMinimumDistance +*/ +void OrbitCameraManipulator::zoomCamera( const float dy ) +{ + // push camera forward along mouse ray + osg::Vec3d zoom_direction = m_ray_pointer_direction; + zoom_direction.normalize(); + zoom_direction *= dy*100; + m_eye += zoom_direction; + m_lookat += zoom_direction; +} + +////////////////////////////////////////////////////// animation ////////////////////////////////////////////////////////////////// +void OrbitCameraManipulator::applyAnimationStep( const double currentProgress, const double /*prevProgress*/ ) +{ + osg::Vec3d new_eye( m_animation_data->m_start_eye + (m_animation_data->m_target_eye - m_animation_data->m_start_eye) * (currentProgress) ); + osg::Vec3d new_lookat( m_animation_data->m_start_lookat + (m_animation_data->m_target_lookat - m_animation_data->m_start_lookat) * (currentProgress) ); + osg::Vec3d new_up( m_animation_data->m_start_up + (m_animation_data->m_target_up - m_animation_data->m_start_up) * (currentProgress) ); + + m_eye.set( new_eye ); + m_lookat.set( new_lookat ); + m_up.set( new_up ); +} + +OrbitCameraManipulator::OrbitAnimationData::OrbitAnimationData() : AnimationData() +{ +} + +void OrbitCameraManipulator::OrbitAnimationData::start( const double startTime ) +{ + AnimationData::start( startTime ); +} + +void OrbitCameraManipulator::setAnimationTime( const double t ) +{ + if( t <= 0. ) + { + finishAnimation(); + m_animation_data = nullptr; + return; + } + + if( !m_animation_data ) + { + m_animation_data = new OrbitAnimationData(); + } + + m_animation_data->_animationTime = t; +} + +bool OrbitCameraManipulator::performAnimationMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) +{ + double f = (ea.getTime() - m_animation_data->_startTime) / m_animation_data->_animationTime; + if( f >= 1. ) + { + f = 1.; + m_animation_data->_isAnimating = false; + if( !_thrown ) + { + aa.requestContinuousUpdate( false ); + } + } + + applyAnimationStep( f, m_animation_data->_phase ); + + m_animation_data->_phase = f; + aa.requestRedraw(); + + return m_animation_data->_isAnimating; +} + +bool OrbitCameraManipulator::isAnimating() const +{ + if( m_animation_data ) + { + return m_animation_data->_isAnimating; + } + else + { + return false; + } +} + + +/** Get the FusionDistanceMode. Used by SceneView for setting up stereo convergence.*/ +osgUtil::SceneView::FusionDistanceMode OrbitCameraManipulator::getFusionDistanceMode() const +{ + return osgUtil::SceneView::USE_FUSION_DISTANCE_VALUE; +} + +/** Get the FusionDistanceValue. Used by SceneView for setting up stereo convergence.*/ +float OrbitCameraManipulator::getFusionDistanceValue() const +{ + return 0;//m_distance; +} + + +/** Set the mouse wheel zoom factor. +The amount of camera movement on each mouse wheel event is computed as the current distance to the center multiplied by this factor. +For example, value of 0.1 will short distance to center by 10% on each wheel up event. +Use negative value for reverse mouse wheel direction.*/ +void OrbitCameraManipulator::setWheelZoomFactor( double wheelZoomFactor ) +{ + m_wheel_zoom_factor = wheelZoomFactor; +} + + +/** Set the minimum distance of the eye point from the center before the center is pushed forward.*/ +void OrbitCameraManipulator::setMinimumDistance( const double& minimumDistance, bool relativeToModelSize ) +{ + m_minimum_distance = minimumDistance; + setRelativeFlag( m_minimum_distance_flag_index, relativeToModelSize ); +} + + +/** Get the minimum distance of the eye point from the center before the center is pushed forward.*/ +double OrbitCameraManipulator::getMinimumDistance( bool *relativeToModelSize ) const +{ + if( relativeToModelSize ) + { + *relativeToModelSize = getRelativeFlag( m_minimum_distance_flag_index ); + } + + return m_minimum_distance; +} + + +void OrbitCameraManipulator::zoomToBoundingSphere( const osg::BoundingSphere& bs, double /*ratio_w*/ ) +{ + osg::Vec3f bs_center( bs.center() ); + double bs_radius = bs.radius(); + if( bs_radius <= 0.5 ) + { + bs_radius = 2.0; + bs_center._v[2] = 0.5; + } + + m_rotate_center.set( bs.center() ); + + osg::Vec3d eye_lookat(m_eye - m_lookat); + eye_lookat.normalize(); + + // define animation path + if( m_animation_data ) + { + osg::Vec3d target_lookat( bs.center() ); + + double d_eye = bs_radius/sin( osg::DegreesToRadians(m_fovy*0.5) ); + osg::Vec3d target_eye( target_lookat + eye_lookat*d_eye ); + + m_animation_data->m_start_eye.set( m_eye ); + m_animation_data->m_start_lookat.set( m_lookat ); + m_animation_data->m_start_up.set( m_up ); + + m_animation_data->m_target_eye.set( target_eye ); + m_animation_data->m_target_lookat.set( target_lookat ); + m_animation_data->m_target_up.set( m_up ); + + m_animation_data->_animationTime = 0.6; + m_animation_data->start( -1 ); + } +} diff --git a/examples/SimpleViewerExampleQt/src/viewer/OrbitCameraManipulator.h b/examples/SimpleViewerExampleQt/src/viewer2/OrbitCameraManipulator.h similarity index 98% rename from examples/SimpleViewerExampleQt/src/viewer/OrbitCameraManipulator.h rename to examples/SimpleViewerExampleQt/src/viewer2/OrbitCameraManipulator.h index e8152e1ed..95c3cf11e 100644 --- a/examples/SimpleViewerExampleQt/src/viewer/OrbitCameraManipulator.h +++ b/examples/SimpleViewerExampleQt/src/viewer2/OrbitCameraManipulator.h @@ -1,118 +1,118 @@ -/* -*-c++-*- IfcQuery www.ifcquery.com -* -MIT License - -Copyright (c) 2017 Fabian Gerold - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#pragma once - -#include -#include -#include - -class IfcPlusPlusSystem; - -/** OrbitCameraManipulator is a camera controller based on eye, lookat, up and rotation center. */ -class OrbitCameraManipulator : public osgGA::StandardManipulator -{ -public: - OrbitCameraManipulator( IfcPlusPlusSystem* sys, int flags = UPDATE_MODEL_SIZE | COMPUTE_HOME_USING_BBOX | PROCESS_MOUSE_WHEEL ); - OrbitCameraManipulator( const OrbitCameraManipulator& om, const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY ); - - // inherited from osg::Object - virtual osg::Object* cloneType() const { return new OrbitCameraManipulator( m_system ); } - virtual osg::Object* clone( const osg::CopyOp& copyop ) const { return new OrbitCameraManipulator( *this, copyop ); } - virtual bool isSameKindAs( const osg::Object* obj ) const { return dynamic_cast( obj )!=nullptr; } - virtual const char* libraryName() const { return ""; } - virtual const char* className() const { return "OrbitCameraManipulator"; } - - // inherited from osgGA::CameraManipulator - virtual void setByMatrix( const osg::Matrixd& matrix ); - virtual void setByInverseMatrix( const osg::Matrixd& matrix ); - virtual osg::Matrixd getMatrix() const; - virtual osg::Matrixd getInverseMatrix() const; - virtual osgUtil::SceneView::FusionDistanceMode getFusionDistanceMode() const; - virtual float getFusionDistanceValue() const; - - // inherited from osgGA::StandardManipulator - virtual void setTransformation( const osg::Vec3d& eye, const osg::Quat& rotation ); - virtual void setTransformation( const osg::Vec3d& eye, const osg::Vec3d& lookat, const osg::Vec3d& up ); - virtual void getTransformation( osg::Vec3d& eye, osg::Quat& rotation ) const; - virtual void getTransformation( osg::Vec3d& eye, osg::Vec3d& lookat, osg::Vec3d& up ) const; - - virtual bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool handleFrame( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool handleMouseMove( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool handleMousePush( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool handleMouseRelease( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool handleMouseWheel( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool handleMouseDrag( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool handleKeyDown( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool performMouseDeltaMovement( const float dx, const float dy ); - virtual void applyAnimationStep( const double currentProgress, const double prevProgress ); - virtual void setAnimationTime( const double t ); - virtual bool performAnimationMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - virtual bool isAnimating() const; - - class OrbitAnimationData : public AnimationData - { - public: - OrbitAnimationData(); - osg::Vec3d m_start_eye; - osg::Vec3d m_start_lookat; - osg::Vec3d m_start_up; - osg::Vec3d m_target_eye; - osg::Vec3d m_target_lookat; - osg::Vec3d m_target_up; - void start( const double startTime ); - }; - - // own methods - void initManipulator(); - void setWheelZoomFactor( double wheelZoomFactor ); - double getWheelZoomFactor() const { return m_wheel_zoom_factor; }; - bool intersectSceneRotateCenter( const osgGA::GUIEventAdapter& ea, osgViewer::View* view ); - bool intersectSceneSelect( const osgGA::GUIEventAdapter& ea, osgViewer::View* view ); - bool performMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - double getMinimumDistance( bool *relativeToModelSize = nullptr ) const; - void setMinimumDistance( const double& minimumDistance, bool relativeToModelSize = false ); - void panCamera( const float dx, const float dy, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa );//const float dx, const float dy, const float dz = 0.f ); - void zoomCamera( const float dy ); - void rotateCamera( const float dx, const float dy ); - void computeRayPointer( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); - void zoomToBoundingSphere( const osg::BoundingSphere& bs, double ratio_w = 1.0 ); - OrbitAnimationData* getOrbitAnimationData() { return m_animation_data.get(); } - - osg::Vec3d m_eye; - osg::Vec3d m_lookat; - osg::Vec3d m_up; - osg::Vec3d m_rotate_center; - osg::Vec3d m_ray_pointer_direction; - osg::Vec3d m_ray_pointer_start; - osg::Vec3d m_pointer_intersection; - osg::Matrix m_model_screen; - osg::Matrix m_screen_model; - osg::Vec3d m_pan_point; - - osg::ref_ptr m_ga_pointer_push; - bool m_pointer_push_drag; - bool m_control_key_down; - bool m_intersect_hit_geometry; - double m_fovy; - double m_wheel_zoom_factor; - double m_minimum_distance; - static int m_minimum_distance_flag_index; - osg::ref_ptr m_animation_data; - IfcPlusPlusSystem* m_system; -}; +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include +#include + +class IfcPlusPlusSystem; + +/** OrbitCameraManipulator is a camera controller based on eye, lookat, up and rotation center. */ +class OrbitCameraManipulator : public osgGA::StandardManipulator +{ +public: + OrbitCameraManipulator( IfcPlusPlusSystem* sys, int flags = UPDATE_MODEL_SIZE | COMPUTE_HOME_USING_BBOX | PROCESS_MOUSE_WHEEL ); + OrbitCameraManipulator( const OrbitCameraManipulator& om, const osg::CopyOp& copyOp = osg::CopyOp::SHALLOW_COPY ); + + // inherited from osg::Object + virtual osg::Object* cloneType() const { return new OrbitCameraManipulator( m_system ); } + virtual osg::Object* clone( const osg::CopyOp& copyop ) const { return new OrbitCameraManipulator( *this, copyop ); } + virtual bool isSameKindAs( const osg::Object* obj ) const { return dynamic_cast( obj )!=nullptr; } + virtual const char* libraryName() const { return ""; } + virtual const char* className() const { return "OrbitCameraManipulator"; } + + // inherited from osgGA::CameraManipulator + virtual void setByMatrix( const osg::Matrixd& matrix ); + virtual void setByInverseMatrix( const osg::Matrixd& matrix ); + virtual osg::Matrixd getMatrix() const; + virtual osg::Matrixd getInverseMatrix() const; + virtual osgUtil::SceneView::FusionDistanceMode getFusionDistanceMode() const; + virtual float getFusionDistanceValue() const; + + // inherited from osgGA::StandardManipulator + virtual void setTransformation( const osg::Vec3d& eye, const osg::Quat& rotation ); + virtual void setTransformation( const osg::Vec3d& eye, const osg::Vec3d& lookat, const osg::Vec3d& up ); + virtual void getTransformation( osg::Vec3d& eye, osg::Quat& rotation ) const; + virtual void getTransformation( osg::Vec3d& eye, osg::Vec3d& lookat, osg::Vec3d& up ) const; + + virtual bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleFrame( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMouseMove( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMousePush( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMouseRelease( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMouseWheel( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleMouseDrag( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool handleKeyDown( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool performMouseDeltaMovement( const float dx, const float dy ); + virtual void applyAnimationStep( const double currentProgress, const double prevProgress ); + virtual void setAnimationTime( const double t ); + virtual bool performAnimationMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + virtual bool isAnimating() const; + + class OrbitAnimationData : public AnimationData + { + public: + OrbitAnimationData(); + osg::Vec3d m_start_eye; + osg::Vec3d m_start_lookat; + osg::Vec3d m_start_up; + osg::Vec3d m_target_eye; + osg::Vec3d m_target_lookat; + osg::Vec3d m_target_up; + void start( const double startTime ); + }; + + // own methods + void initManipulator(); + void setWheelZoomFactor( double wheelZoomFactor ); + double getWheelZoomFactor() const { return m_wheel_zoom_factor; }; + bool intersectSceneRotateCenter( const osgGA::GUIEventAdapter& ea, osgViewer::View* view ); + bool intersectSceneSelect( const osgGA::GUIEventAdapter& ea, osgViewer::View* view ); + bool performMovement( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + double getMinimumDistance( bool *relativeToModelSize = nullptr ) const; + void setMinimumDistance( const double& minimumDistance, bool relativeToModelSize = false ); + void panCamera( const float dx, const float dy, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa );//const float dx, const float dy, const float dz = 0.f ); + void zoomCamera( const float dy ); + void rotateCamera( const float dx, const float dy ); + void computeRayPointer( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ); + void zoomToBoundingSphere( const osg::BoundingSphere& bs, double ratio_w = 1.0 ); + OrbitAnimationData* getOrbitAnimationData() { return m_animation_data.get(); } + + osg::Vec3d m_eye; + osg::Vec3d m_lookat; + osg::Vec3d m_up; + osg::Vec3d m_rotate_center; + osg::Vec3d m_ray_pointer_direction; + osg::Vec3d m_ray_pointer_start; + osg::Vec3d m_pointer_intersection; + osg::Matrix m_model_screen; + osg::Matrix m_screen_model; + osg::Vec3d m_pan_point; + + osg::ref_ptr m_ga_pointer_push; + bool m_pointer_push_drag; + bool m_control_key_down; + bool m_intersect_hit_geometry; + double m_fovy; + double m_wheel_zoom_factor; + double m_minimum_distance; + static int m_minimum_distance_flag_index; + osg::ref_ptr m_animation_data; + IfcPlusPlusSystem* m_system; +}; diff --git a/examples/SimpleViewerExampleQt/src/viewer2/ViewerWidget.cpp b/examples/SimpleViewerExampleQt/src/viewer2/ViewerWidget.cpp new file mode 100644 index 000000000..98479d09a --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer2/ViewerWidget.cpp @@ -0,0 +1,306 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "IfcPlusPlusSystem.h" +#include "OrbitCameraManipulator.h" +#include "GraphicsWindowQt.h" +#include "ViewerWidget.h" + +ViewerWidget::ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent ) : QWidget( parent ) +{ + m_system = sys; + m_parent = parent; + m_shinyness = 35.0; + m_material_default = new osg::Material(); + float r = 90.6f / 175.f; + float g = 91.1f / 175.f; + float b = 84.1f / 175.f; + m_material_default->setAmbient( osg::Material::FRONT_AND_BACK, osg::Vec4f(r, g, b, 1.0f ) ); + m_material_default->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4(r, g, b, 1.0f ) ); + m_material_default->setSpecular( osg::Material::FRONT_AND_BACK, osg::Vec4f(r, g, b, 1.0f ) ); + m_material_default->setShininess( osg::Material::FRONT_AND_BACK, m_shinyness ); + m_material_default->setColorMode( osg::Material::SPECULAR ); + + osg::ref_ptr light_model = new osg::LightModel(); + light_model->setTwoSided( true ); + light_model->setAmbientIntensity( osg::Vec4f( r, g, b, 0.6f ) ); + sys->getRootNode()->getOrCreateStateSet()->setAttribute( light_model ); + + m_stateset_default = sys->getModelNode()->getOrCreateStateSet(); + m_stateset_default->setAttribute( m_material_default, osg::StateAttribute::ON ); + + m_stateset_transparent = new osg::StateSet(); + m_stateset_transparent->setAttribute( m_material_default, osg::StateAttribute::ON ); + m_stateset_transparent->setMode( GL_BLEND, osg::StateAttribute::ON ); + m_stateset_transparent->setRenderingHint( osg::StateSet::TRANSPARENT_BIN ); + m_stateset_transparent->setRenderBinDetails( 11, "DepthSortedBin" ); + + osg::ref_ptr material_selected = new osg::Material(); + material_selected->setDiffuse( osg::Material::FRONT_AND_BACK, osg::Vec4f( 0.4f, 0.92f, 0.92f, 0.5f ) ); + material_selected->setSpecular( osg::Material::FRONT_AND_BACK, osg::Vec4f( 0.3f, 0.35f, 0.3f, 1.0f ) ); + material_selected->setShininess( osg::Material::FRONT_AND_BACK, m_shinyness ); + material_selected->setColorMode( osg::Material::SPECULAR ); + m_stateset_selected = new osg::StateSet(); + m_stateset_selected->setAttribute( material_selected, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON ); + + sys->toggleSceneLight(); + + { + osg::ref_ptr geode = new osg::Geode(); + geode->setName( "createCoordinateAxes::geode" ); + osg::ref_ptr stateset = geode->getOrCreateStateSet(); + stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF ); + float alpha = 0.5f; + m_system->getCoordinateAxesNode()->addChild( geode ); + + // positive axes + { + osg::ref_ptr geom = new osg::Geometry(); + geode->addDrawable( geom ); + + osg::ref_ptr vertices = new osg::Vec3Array(); + vertices->push_back( osg::Vec3f( 0.0, 0.0, 0.0 ) ); + vertices->push_back( osg::Vec3f( 100, 0.0, 0.0 ) ); + + vertices->push_back( osg::Vec3f( 0.0, 0.0, 0.0 ) ); + vertices->push_back( osg::Vec3f( 0.0, 100, 0.0 ) ); + + vertices->push_back( osg::Vec3f( 0.0, 0.0, 0.0 ) ); + vertices->push_back( osg::Vec3f( 0.0, 0.0, 100 ) ); + + osg::ref_ptr colors = new osg::Vec4Array(); + colors->push_back( osg::Vec4f( 1.f, 0.f, 0.f, alpha ) ); + colors->push_back( osg::Vec4f( 1.f, 0.f, 0.f, alpha ) ); + colors->push_back( osg::Vec4f( 0.f, 0.8f, 0.f, alpha ) ); + colors->push_back( osg::Vec4f( 0.f, 0.8f, 0.f, alpha ) ); + colors->push_back( osg::Vec4f( 0.f, 0.f, 1.f, alpha ) ); + colors->push_back( osg::Vec4f( 0.f, 0.f, 1.f, alpha ) ); + colors->setBinding( osg::Array::BIND_PER_VERTEX ); + geom->setColorArray( colors ); + + geom->setVertexArray( vertices ); + geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, 0, 6 ) ); + } + + // positive axes + { + osg::ref_ptr geom = new osg::Geometry(); + geode->addDrawable( geom ); + + osg::ref_ptr vertices = new osg::Vec3Array(); + vertices->push_back( osg::Vec3f( 0.0, 0.0, 0.0 ) ); + vertices->push_back( osg::Vec3f( -100, 0.0, 0.0 ) ); + + vertices->push_back( osg::Vec3f( 0.0, 0.0, 0.0 ) ); + vertices->push_back( osg::Vec3f( 0.0, -100, 0.0 ) ); + + vertices->push_back( osg::Vec3f( 0.0, 0.0, 0.0 ) ); + vertices->push_back( osg::Vec3f( 0.0, 0.0, -100 ) ); + + osg::ref_ptr colors = new osg::Vec4Array(); + colors->push_back( osg::Vec4f( 1.f, 0.f, 0.f, alpha ) ); + colors->push_back( osg::Vec4f( 1.f, 0.f, 0.f, alpha ) ); + colors->push_back( osg::Vec4f( 0.f, 1.f, 0.f, alpha ) ); + colors->push_back( osg::Vec4f( 0.f, 1.f, 0.f, alpha ) ); + colors->push_back( osg::Vec4f( 0.f, 0.f, 1.f, alpha ) ); + colors->push_back( osg::Vec4f( 0.f, 0.f, 1.f, alpha ) ); + colors->setBinding( osg::Array::BIND_PER_VERTEX ); + geom->setColorArray( colors ); + + geom->setVertexArray( vertices ); + geom->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 0, 6 ) ); + + // make negative axed dotted + osg::ref_ptr stateset_negative = geom->getOrCreateStateSet(); + stateset_negative->setAttributeAndModes( new osg::LineStipple( 2, 0xAAAA ), osg::StateAttribute::ON ); + } + + // x axis label + bool add_x_label = false; + if( add_x_label ) + { + osg::ref_ptr label_x = new osgText::Text(); + //label_x->setFont( "ARIAL.TTF" ); + label_x->setFont( "fonts/calibri.ttf" ); + label_x->setAlignment( osgText::Text::RIGHT_TOP ); + label_x->setAxisAlignment( osgText::Text::SCREEN ); + label_x->setColor( osg::Vec4( 0.8, 0.0, 0.0, 1.0 ) ); + label_x->setCharacterSize( 0.5f ); + label_x->setText( "x" ); + label_x->setPosition( osg::Vec3( 1, 0, 0 ) ); + label_x->setEnableDepthWrites( false ); + geode->addDrawable( label_x ); + } + } + + m_camera_manipulator = new OrbitCameraManipulator( sys ); + + QtOSGWidget* opengl_widget = getOpenGLWidget(); + QVBoxLayout* vbox = new QVBoxLayout(); + vbox->setContentsMargins( 0, 0, 0, 1 ); + vbox->addWidget( opengl_widget ); + setLayout( vbox ); + + connect( &m_timer, SIGNAL( timeout() ), this, SLOT( slotAnimationFrame() ) ); +} +ViewerWidget::~ViewerWidget() {} + +void ViewerWidget::initGLWidgetAndViewer() +{ + osgViewer::ViewerBase::ThreadingModel threadingModel = osgViewer::ViewerBase::SingleThreaded; + m_system->getRootNode()->setCullingActive( false ); + + Qt::WindowFlags f; + m_graphics_window = new GraphicsWindowQt( this, f ); + QtOSGWidget* opengl_widget = m_graphics_window->getOpenGLWidget(); + opengl_widget->setMinimumSize( QSize( 150, 150 ) ); + m_main_view = opengl_widget->getView(); + m_main_view->setSceneData( m_system->getRootNode() ); + m_composite_viewer = opengl_widget->getViewer(); + m_composite_viewer->setThreadingModel( threadingModel ); + m_composite_viewer->setKeyEventSetsDone( 0 ); // disable the default setting of viewer.done() by pressing Escape. + m_composite_viewer->addView( m_main_view ); + + // set up the camera + osg::ref_ptr camera = m_main_view->getCamera(); + camera->setGraphicsContext( m_graphics_window ); + camera->setClearColor( osg::Vec4f( 0.92, 0.93, 0.94, 1.0 ) ); + + if( m_main_view ) + { + m_main_view->setCameraManipulator( m_camera_manipulator ); + m_main_view->setSceneData( m_system->getRootNode() ); + } +} + +QtOSGWidget* ViewerWidget::getOpenGLWidget() +{ + if( !m_graphics_window ) + { + initGLWidgetAndViewer(); + } + if( m_graphics_window ) + { + QtOSGWidget* opengl_widget = m_graphics_window->getOpenGLWidget(); + return opengl_widget; + } + + return nullptr; +} +GraphicsWindowQt* ViewerWidget::getGraphicsWindowQt() +{ + if( !m_graphics_window ) + { + initGLWidgetAndViewer(); + } + return m_graphics_window; +} +osgViewer::View* ViewerWidget::getMainView() +{ + if( !m_main_view ) + { + initGLWidgetAndViewer(); + } + return m_main_view; +} +osgViewer::CompositeViewer* ViewerWidget::getCompositeViewer() +{ + if( !m_composite_viewer ) + { + initGLWidgetAndViewer(); + } + return m_composite_viewer; +} + +void ViewerWidget::slotAnimationFrame() +{ + update(); +} + +void ViewerWidget::paintEvent( QPaintEvent* ) +{ + QtOSGWidget* gl_widget = getOpenGLWidget(); + if( gl_widget ) + { + osgViewer::CompositeViewer* composite_viewer = getCompositeViewer(); + if( composite_viewer ) + { + composite_viewer->frame(); + } + } +} + +void ViewerWidget::updateCamera() +{ + int w = width(); + int h = height(); + double ratio = double(h)/double(w); + + osg::Camera* cam = m_main_view->getCamera(); + cam->setViewport( new osg::Viewport(0, 0, w, h) ); + cam->setProjectionMatrixAsOrtho(-100, 100, -100.0*ratio, 100.0*ratio, m_near_plane-1000, m_near_plane/0.0005+100 ); + + if( m_hud_camera ) + { + m_hud_camera->setProjectionMatrixAsOrtho2D(0, w, 0, h); + } +} + +void ViewerWidget::setRootNode( osg::Group* root ) +{ + m_main_view->setSceneData( root ); + if( m_hud_camera ) + { + root->addChild( m_hud_camera ); + } + m_system->setRootNode( root ); +} + +void ViewerWidget::stopTimer() +{ + m_timer.stop(); +} + +void ViewerWidget::startTimer() +{ + m_timer.start(10); +} + +void ViewerWidget::resizeEvent( QResizeEvent * ev ) +{ + QSize s = ev->size(); + int width = s.width(); + int height = s.height(); + m_main_view->getEventQueue()->windowResize(0, 0, width, height ); +} diff --git a/examples/SimpleViewerExampleQt/src/viewer2/ViewerWidget.h b/examples/SimpleViewerExampleQt/src/viewer2/ViewerWidget.h new file mode 100644 index 000000000..41eb6a803 --- /dev/null +++ b/examples/SimpleViewerExampleQt/src/viewer2/ViewerWidget.h @@ -0,0 +1,78 @@ +/* -*-c++-*- IfcQuery www.ifcquery.com +* +MIT License + +Copyright (c) 2017 Fabian Gerold + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "GraphicsWindowQt.h" +class IfcPlusPlusSystem; + +//\brief class to combine OSG Viewer and Qt widget +class ViewerWidget : public QWidget +{ + Q_OBJECT + +public: + ViewerWidget( IfcPlusPlusSystem* sys, QWidget* parent = nullptr ); + ~ViewerWidget(); + + QtOSGWidget* getOpenGLWidget(); + GraphicsWindowQt* getGraphicsWindowQt(); + osgViewer::View* getMainView(); + osgViewer::CompositeViewer* getCompositeViewer(); + osg::Camera* getHeadUpCamera() { return m_hud_camera.get(); } + osgGA::StandardManipulator* getCameraManipulator() { return m_camera_manipulator.get(); } + void updateCamera(); + void setRootNode( osg::Group* node ); + void stopTimer(); + void startTimer(); + + virtual QSize minimumSizeHint() const { return QSize( 100, 100 ); } + virtual QSize sizeHint() const { return QSize( 800, 600 ); } + virtual void paintEvent( QPaintEvent* event ); + virtual void resizeEvent( QResizeEvent * ); + +public slots: + void slotAnimationFrame(); + +protected: + IfcPlusPlusSystem* m_system; + QWidget* m_parent = nullptr; + std::string m_window_name; + QTimer m_timer; + double m_shinyness = 35; + double m_near_plane = 0.001; + double m_far_plane = 1000.0; + osg::ref_ptr m_main_view; + osg::ref_ptr m_composite_viewer; + osg::ref_ptr m_hud_camera; + osg::ref_ptr m_graphics_window; + osg::ref_ptr m_camera_manipulator; + osg::ref_ptr m_material_default; + osg::ref_ptr m_stateset_selected; + osg::ref_ptr m_stateset_default; + osg::ref_ptr m_stateset_transparent; + + void initGLWidgetAndViewer(); +};