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