├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── DraggableWire.cpp ├── DraggableWire.h ├── EventHandler.cpp ├── EventHandler.h ├── LICENSE ├── LineIntersector.cpp ├── LineIntersector.h ├── PointIntersector.cpp ├── PointIntersector.h ├── README.md ├── SVMData.cpp ├── SVMData.h ├── VirtualPlaneIntersector.cpp ├── VirtualPlaneIntersector.h ├── images └── intersectors.gif └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | # other 32 | CMakeLists.txt.user 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | os: linux 3 | compiler: gcc 4 | sudo: required 5 | dist: trusty 6 | 7 | addons: 8 | apt: 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | packages: 12 | - cmake 13 | - g++-4.8 14 | - gcc-4.8 15 | 16 | before_install: 17 | - wget https://github.com/vicrucann/OpenSceneGraph/releases/download/OpenSceneGraph-3.4.0/osg-340-deb.tar.gz 18 | - tar -zxvf osg-340-deb.tar.gz 19 | 20 | install: 21 | - export CXX="g++-4.8" 22 | - export CC="gcc-4.8" 23 | - export CXXFLAGS="-std=c++11" 24 | - sudo cp -rv osg-340-deb/lib64 /usr/local/ 25 | - sudo cp -rv osg-340-deb/include /usr/local/ 26 | - sudo cp -rv osg-340-deb/bin /usr/local/ 27 | 28 | before_script: 29 | - export LD_LIBRARY_PATH="/usr/local/lib64:/usr/local/lib:$LD_LIBRARY_PATH" 30 | - export OPENTHREADS_INC_DIR="/usr/local/include" 31 | - export OPENTHREADS_LIB_DIR="/usr/local/lib64:/usr/local/lib" 32 | - export PATH="$OPENTHREADS_LIB_DIR:$PATH" 33 | - cmake -DCMAKE_BUILD_TYPE=Release 34 | 35 | script: 36 | - make 37 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.11) 2 | project(osgIntersectors) 3 | 4 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 5 | set(CMAKE_AUTOMOC ON) 6 | 7 | find_package(OpenSceneGraph REQUIRED COMPONENTS osgGA osgUtil osgViewer) 8 | 9 | include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) 10 | 11 | set(SOURCES 12 | main.cpp 13 | SVMData.h 14 | SVMData.cpp 15 | DraggableWire.h 16 | DraggableWire.cpp 17 | EventHandler.h 18 | EventHandler.cpp 19 | LineIntersector.h 20 | LineIntersector.cpp 21 | PointIntersector.h 22 | PointIntersector.cpp 23 | VirtualPlaneIntersector.h 24 | VirtualPlaneIntersector.cpp 25 | ) 26 | 27 | add_executable(${PROJECT_NAME} ${SOURCES}) 28 | 29 | target_link_libraries(${PROJECT_NAME} 30 | ${OPENSCENEGRAPH_LIBRARIES} 31 | ) 32 | -------------------------------------------------------------------------------- /DraggableWire.cpp: -------------------------------------------------------------------------------- 1 | #include "DraggableWire.h" 2 | 3 | #include "assert.h" 4 | #include 5 | 6 | DraggableWire::DraggableWire() 7 | : osg::MatrixTransform() 8 | , m_geode(new osg::Geode) 9 | , m_wire(new osg::Geometry) 10 | , m_points(new osg::Geometry) 11 | , m_selectedPoint(-1) 12 | { 13 | this->addChild(m_geode); 14 | m_geode->addDrawable(m_wire); 15 | m_geode->addDrawable(m_points); 16 | 17 | m_wire->setUseDisplayList(false); 18 | m_wire->setName("Wire"); 19 | m_points->setUseDisplayList(false); 20 | m_points->setName("Point"); 21 | 22 | osg::Vec3Array* verts = new osg::Vec3Array; 23 | verts->push_back(osg::Vec3f(1.f, 1.f, 0.f)); 24 | verts->push_back(osg::Vec3f(-1.f, 1.f, 0.f)); 25 | verts->push_back(osg::Vec3f(-1.f, -1.f, 0.f)); 26 | verts->push_back(osg::Vec3f(1.f, -1.f, 0.f)); 27 | 28 | osg::Vec4Array* clrWire = new osg::Vec4Array(4); 29 | m_wire->addPrimitiveSet(new osg::DrawArrays(GL_LINE_LOOP, 0, verts->size())); 30 | m_wire->setVertexArray(verts); 31 | m_wire->setColorArray(clrWire, osg::Array::BIND_PER_VERTEX); 32 | this->setColorWire(CLR_WIRE); 33 | 34 | osg::Vec4Array* clrPts = new osg::Vec4Array(4); 35 | m_points->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, verts->size())); 36 | m_points->setVertexArray(verts); 37 | m_points->setColorArray(clrPts, osg::Array::BIND_PER_VERTEX); 38 | this->setColorPointsDefaults(); 39 | 40 | m_points->getOrCreateStateSet()->setAttribute(new osg::Point(20.f), osg::StateAttribute::ON); 41 | m_wire->getOrCreateStateSet()->setAttribute(new osg::LineWidth(3.5f), osg::StateAttribute::ON); 42 | } 43 | 44 | osg::Vec3f DraggableWire::getCenter3D() const 45 | { 46 | return osg::Vec3f(0,0,0) * this->getMatrix(); 47 | } 48 | 49 | osg::Plane DraggableWire::getPlane() const 50 | { 51 | osg::Vec3f P1 = osg::Vec3f(1,0,0) * this->getMatrix(); 52 | osg::Vec3f P2 = osg::Vec3f(1,1,0) * this->getMatrix(); 53 | osg::Vec3f P3 = osg::Vec3f(0,1,0) * this->getMatrix(); 54 | return osg::Plane(P1, P2, P3); 55 | } 56 | 57 | const osg::Geode *DraggableWire::getGeode() const 58 | { 59 | return m_geode; 60 | } 61 | 62 | void DraggableWire::editPick(double u, double v) 63 | { 64 | if (m_selectedPoint < 0 || m_selectedPoint>3) return; 65 | osg::Vec3Array* vertsWire = static_cast (m_wire->getVertexArray()); 66 | osg::Vec3Array* vertsPoints = static_cast (m_points->getVertexArray()); 67 | assert(vertsWire && vertsPoints); 68 | (*vertsWire)[m_selectedPoint] = osg::Vec3f(u,v,0); 69 | (*vertsPoints)[m_selectedPoint] = osg::Vec3f(u,v,0); 70 | this->updateGeometry(m_wire); 71 | this->updateGeometry(m_points); 72 | } 73 | 74 | void DraggableWire::unselect() 75 | { 76 | this->setColorWire(CLR_WIRE); 77 | this->setColorPointsDefaults(); 78 | m_selectedPoint = -1; 79 | } 80 | 81 | void DraggableWire::select() 82 | { 83 | this->setColorWire(CLR_WIRE_HOVER); 84 | m_selectedPoint = -1; 85 | } 86 | 87 | void DraggableWire::pick(int index) 88 | { 89 | if (index<0 || index > 3) return; 90 | this->select(); 91 | for (int i=0; i<4; ++i){ 92 | osg::Vec4f clr = i==index? CLR_POINTS_HOVER : CLR_POINTS; 93 | this->setColorPoint(i, clr); 94 | } 95 | m_selectedPoint = index; 96 | } 97 | 98 | void DraggableWire::unpick() 99 | { 100 | this->setColorPointsDefaults(); 101 | m_selectedPoint = -1; 102 | } 103 | 104 | void DraggableWire::drag() 105 | { 106 | if (m_selectedPoint < 0 || m_selectedPoint>3) return; 107 | this->setColorPointWire(m_selectedPoint, CLR_DRAG); 108 | } 109 | 110 | void DraggableWire::dragStop() 111 | { 112 | if (m_selectedPoint < 0 || m_selectedPoint>3) return; 113 | this->pick(m_selectedPoint); 114 | } 115 | 116 | void DraggableWire::setColorPointsDefaults() 117 | { 118 | this->setColorPoint(0, CLR_POINTS); 119 | this->setColorPoint(1, CLR_POINTS); 120 | this->setColorPoint(2, CLR_POINTS); 121 | this->setColorPoint(3, CLR_POINTS); 122 | 123 | m_selectedPoint = -1; 124 | } 125 | 126 | void DraggableWire::setColorWire(osg::Vec4f color) 127 | { 128 | osg::Vec4Array* clr = static_cast (m_wire->getColorArray()); 129 | assert(clr); 130 | assert(clr->size() == 4); 131 | (*clr)[0] = color; 132 | (*clr)[1] = color; 133 | (*clr)[2] = color; 134 | (*clr)[3] = color; 135 | this->updateGeometry(m_wire); 136 | } 137 | 138 | void DraggableWire::setColorPoint(int index, osg::Vec4f color) 139 | { 140 | assert(index>=0 && index<4); 141 | osg::Vec4Array* clr = static_cast(m_points->getColorArray()); 142 | assert(clr); 143 | (*clr)[index] = color; 144 | 145 | this->updateGeometry(m_points); 146 | } 147 | 148 | void DraggableWire::setColorPointWire(int index, osg::Vec4f color) 149 | { 150 | this->setColorPoint(index, color); 151 | 152 | assert(index>=0 && index<4); 153 | osg::Vec4Array* clr = static_cast(m_wire->getColorArray()); 154 | assert(clr); 155 | (*clr)[index] = color; 156 | 157 | this->updateGeometry(m_wire); 158 | } 159 | 160 | void DraggableWire::updateGeometry(osg::Geometry *geom) 161 | { 162 | geom->dirtyDisplayList(); 163 | geom->dirtyBound(); 164 | } 165 | -------------------------------------------------------------------------------- /DraggableWire.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief A polygon class whose corners are draggable by user. 3 | * \details This file is a part of osgIntersectors example program. See more details: 4 | * https://github.com/vicrucann/osg-intersectors-example 5 | * \autor Victoria Rudakova 6 | * \date 2016-2017 7 | * \copyright MIT License 8 | */ 9 | 10 | #ifndef DRAGGABLEWIRE_H 11 | #define DRAGGABLEWIRE_H 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | class DraggableWire : public osg::MatrixTransform 22 | { 23 | public: 24 | /*! A constructor - initializes the scene graph and sets default wire colors */ 25 | DraggableWire(); 26 | 27 | /*! \return global center of the wire plane. In local coordinates, the center is always (0,0). */ 28 | osg::Vec3f getCenter3D() const; 29 | 30 | /*! \return a plane that describes the position of all the points of the wire. */ 31 | osg::Plane getPlane() const; 32 | 33 | /*! \return const pointer on geode node which contains all the drawables (wire and points). */ 34 | const osg::Geode* getGeode() const; 35 | 36 | /*! A method to edit a location of a selected point within the plane of the wire. \param u is the new local u coordinate, \param v is the new local v coordinate. */ 37 | void editPick(double u, double v); 38 | 39 | /*! A method to set up defult colors for wire and point geometries. */ 40 | void unselect(); 41 | 42 | /*! A method to set up selected color for the wire geometry. */ 43 | void select(); 44 | 45 | /*! A method to set up selected color to a specified point. 46 | * \param index is the point index at which the color will be assigned. */ 47 | void pick(int index); 48 | 49 | /*! A method to set up selected point color to defaults. */ 50 | void unpick(); 51 | 52 | /*! A method to set up gragged colors to a point and adjacent edges of the wire. */ 53 | void drag(); 54 | 55 | /*! A method to indicate color changes from state drag to state hover over point. */ 56 | void dragStop(); 57 | 58 | protected: 59 | /*! A method to set up default colors to all the points. */ 60 | void setColorPointsDefaults(); 61 | 62 | /*! Set a given color to the whole wire geometry. \param color is the color input. */ 63 | void setColorWire(osg::Vec4f color); 64 | 65 | /*! A method to assign a color to a specific point. \param index is the point index, \param color is the input color. */ 66 | void setColorPoint(int index, osg::Vec4f color); 67 | 68 | /*! A method to assign a color to a specific point and wire index. \sa setColorPoint(). */ 69 | void setColorPointWire(int index, osg::Vec4f color); 70 | 71 | private: 72 | const osg::Vec4f CLR_POINTS = osg::Vec4f(0.2f,0.4f,0.1f,1.f); 73 | const osg::Vec4f CLR_WIRE = osg::Vec4f(0.6f, 0.6f, 0.6f, 1.f); 74 | const osg::Vec4f CLR_WIRE_HOVER = osg::Vec4f(0.8f,0.4f,0.9f,1.f); 75 | const osg::Vec4f CLR_POINTS_HOVER = osg::Vec4f(0.4f,0.8f,0.2f,1.f); 76 | const osg::Vec4f CLR_DRAG = osg::Vec4f(1.f,0.8f,0.4f,1.f); 77 | 78 | protected: 79 | /*! A method to update geometries after new colors are assigned. */ 80 | void updateGeometry(osg::Geometry* geom); 81 | 82 | private: 83 | osg::Geode* m_geode; 84 | osg::Geometry* m_wire; /*!< pointer on a geometry for wireframe */ 85 | osg::Geometry* m_points; /*!< pointer on a geometry for points */ 86 | int m_selectedPoint; /*!< index of a selected point, in a range [0,3]; if none, it is -1 */ 87 | }; 88 | 89 | #endif // DRAGGABLEWIRE_H 90 | -------------------------------------------------------------------------------- /EventHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "EventHandler.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "LineIntersector.h" 11 | #include "SVMData.h" 12 | 13 | EventHandler::EventHandler() 14 | : osgGA::GUIEventHandler() 15 | , m_selection(0) 16 | , m_mode(MOUSE_IDLE) 17 | { 18 | } 19 | 20 | bool EventHandler::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) 21 | { 22 | bool handled = true; 23 | switch(m_mode){ 24 | case MOUSE_HOVER_WIRE: 25 | case MOUSE_DRAG_WIRE: 26 | this->doHoverWire(ea, aa); 27 | break; 28 | case MOUSE_HOVER_POINT: 29 | this->doHoverPoint(ea, aa); 30 | break; 31 | case MOUSE_DRAG_POINT: 32 | this->doDragPoint(ea, aa); 33 | break; 34 | case MOUSE_IDLE: 35 | default: 36 | this->doIdleMouse(ea, aa); 37 | handled = false; 38 | break; 39 | } 40 | return handled; 41 | } 42 | 43 | void EventHandler::doIdleMouse(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) 44 | { 45 | if (ea.getEventType() != osgGA::GUIEventAdapter::MOVE) 46 | return; 47 | 48 | bool isModeSame = true; 49 | LineIntersector::Intersection intersection; 50 | std::tie(isModeSame, intersection) = this->setMouseState(ea, aa, MOUSE_IDLE); 51 | this->updateWireGeometry(intersection); 52 | } 53 | 54 | void EventHandler::doHoverWire(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) 55 | { 56 | if (ea.getEventType() != osgGA::GUIEventAdapter::MOVE) 57 | return; 58 | 59 | bool isModeSame = true; 60 | LineIntersector::Intersection intersectionLine; 61 | std::tie(isModeSame, intersectionLine) = this->setMouseState(ea, aa, MOUSE_IDLE); 62 | this->updateWireGeometry(intersectionLine); 63 | if (!isModeSame) return; 64 | 65 | PointIntersector::Intersection intersectionPoint; 66 | std::tie(isModeSame, intersectionPoint) = 67 | this->setMouseState(ea, aa, MOUSE_HOVER_WIRE); 68 | this->updatePointGeometry(intersectionPoint); 69 | } 70 | 71 | void EventHandler::doHoverPoint(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) 72 | { 73 | if ( !(ea.getEventType() == osgGA::GUIEventAdapter::MOVE || 74 | (ea.getEventType() == osgGA::GUIEventAdapter::DRAG && ea.getButtonMask() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)) ) 75 | return; 76 | 77 | bool isModeSame = true; 78 | PointIntersector::Intersection intersectionPoint; 79 | std::tie(isModeSame, intersectionPoint) = 80 | this->setMouseState(ea, aa, MOUSE_HOVER_WIRE); 81 | this->updatePointGeometry(intersectionPoint); 82 | } 83 | 84 | void EventHandler::doDragPoint(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) 85 | { 86 | if (!( (ea.getEventType() == osgGA::GUIEventAdapter::PUSH && ea.getButtonMask()== osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) 87 | || (ea.getEventType() == osgGA::GUIEventAdapter::DRAG && ea.getButtonMask()== osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) 88 | || (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton()==osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) 89 | )) 90 | return; 91 | 92 | /* obtain new location of the dragging point and edit the selection */ 93 | osg::ref_ptr vpi = new VirtualPlaneIntersector(m_selection.get()); 94 | VirtualPlaneIntersector::Intersection intersection = vpi->getIntersection(ea, aa); 95 | this->updateDragPointGeometry(intersection, ea); 96 | } 97 | 98 | DraggableWire *EventHandler::getDraggableWire(const osgUtil::LineSegmentIntersector::Intersection &result) 99 | { 100 | if (!result.drawable.get()) return NULL; 101 | osg::Group* group = result.drawable->getParent(0); 102 | if (!group) return NULL; 103 | osg::Group* parent = group->getParent(0); 104 | return parent? dynamic_cast(parent) : NULL; 105 | } 106 | 107 | int EventHandler::getSelectedPoint(const osgUtil::LineSegmentIntersector::Intersection &result) 108 | { 109 | if (!result.drawable.get()) return -1; 110 | 111 | return result.primitiveIndex; 112 | } 113 | 114 | EDIT_MODE EventHandler::getModeFromName(const osgUtil::LineSegmentIntersector::Intersection &result, EDIT_MODE mode_default) const 115 | { 116 | std::string name = result.drawable->getName(); 117 | if (name == "Wire") 118 | return MOUSE_HOVER_WIRE; 119 | else if (name == "Point") 120 | return MOUSE_HOVER_POINT; 121 | return mode_default; 122 | } 123 | 124 | EDIT_MODE EventHandler::getModeFromEvent(EDIT_MODE mode, const osgGA::GUIEventAdapter &ea) 125 | { 126 | return static_cast((ea.getEventType() == osgGA::GUIEventAdapter::DRAG)? 127 | (mode | EDIT_MODE::DRAG_MASK) : mode); 128 | } 129 | 130 | void EventHandler::updateWireGeometry(const osgUtil::LineSegmentIntersector::Intersection &intersection) 131 | { 132 | if (intersection.drawable.get()){ 133 | if (!m_selection.get()){ 134 | DraggableWire* wire = this->getDraggableWire(intersection); 135 | if (!wire) return; 136 | wire->select(); 137 | m_selection = wire; 138 | } 139 | } 140 | else { 141 | if (m_selection.get()){ 142 | m_selection->unselect(); 143 | m_selection = 0; 144 | } 145 | } 146 | } 147 | 148 | void EventHandler::updatePointGeometry(const osgUtil::LineSegmentIntersector::Intersection &intersection) 149 | { 150 | if (intersection.drawable.get()){ 151 | // pick a point 152 | if (!m_selection.get()){ 153 | DraggableWire* wire = this->getDraggableWire(intersection); 154 | if (!wire) return; 155 | wire->select(); 156 | } 157 | if (!m_selection->getGeode()->containsDrawable(intersection.drawable.get())) return; 158 | int index = this->getSelectedPoint(intersection); 159 | if (! (m_mode & EDIT_MODE::DRAG_MASK)) 160 | m_selection->pick(index); 161 | else 162 | m_selection->drag(); 163 | } 164 | else { 165 | // unpick the point 166 | if (m_selection.get()){ 167 | m_selection->unpick(); 168 | } 169 | } 170 | } 171 | 172 | void EventHandler::updateDragPointGeometry(const std::tuple &intersection, const osgGA::GUIEventAdapter &ea) 173 | { 174 | if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE || !std::get<2>(intersection)){ 175 | m_selection->dragStop(); 176 | m_mode = MOUSE_HOVER_POINT; 177 | } 178 | else { 179 | m_selection->editPick(std::get<0>(intersection), std::get<1>(intersection)); 180 | } 181 | } 182 | 183 | template 184 | bool EventHandler::getIntersection(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, TypeIntersection& resultIntersection) 185 | { 186 | osgViewer::View* viewer = dynamic_cast(&aa); 187 | if (!viewer) return false; 188 | osg::ref_ptr intersector = new TypeIntersector(osgUtil::Intersector::WINDOW, ea.getX(), ea.getY()); 189 | osgUtil::IntersectionVisitor iv(intersector); 190 | osg::Camera* cam = viewer->getCamera(); 191 | if (!cam) return false; 192 | cam->accept(iv); 193 | if (!intersector->containsIntersections()) return false; 194 | 195 | resultIntersection = intersector->getFirstIntersection(); 196 | return true; 197 | } 198 | 199 | template 200 | std::tuple EventHandler::setMouseState(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, EDIT_MODE modeDefault) 201 | { 202 | bool isModeSame = true; 203 | TResult intersection; 204 | bool inter_occured = this->getIntersection(ea,aa, intersection); 205 | 206 | /* if mouse is hovering over certain drawable, set the corresponding mode */ 207 | if (inter_occured){ 208 | EDIT_MODE mode = this->getModeFromName(intersection, modeDefault); 209 | mode = this->getModeFromEvent(mode, ea); 210 | isModeSame = (mode == m_mode); 211 | m_mode = mode; 212 | } 213 | /* if not, or if the mouse left the drawable area, make sure it is in entity select mode */ 214 | else{ 215 | isModeSame = m_mode == modeDefault; 216 | m_mode = modeDefault; 217 | } 218 | 219 | return std::make_tuple(isModeSame, intersection); 220 | } 221 | -------------------------------------------------------------------------------- /EventHandler.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief OSG-based event handler. 3 | * \details This file is a part of osgIntersectors example program. See more details: 4 | * https://github.com/vicrucann/osg-intersectors-example 5 | * \autor Victoria Rudakova 6 | * \date 2016-2017 7 | * \copyright MIT License 8 | */ 9 | 10 | #ifndef EVENTHANDLER_H 11 | #define EVENTHANDLER_H 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "DraggableWire.h" 23 | #include "LineIntersector.h" 24 | #include "PointIntersector.h" 25 | #include "VirtualPlaneIntersector.h" 26 | 27 | enum EDIT_MODE 28 | { 29 | MOUSE_IDLE = 0x000, 30 | MOUSE_HOVER_WIRE = 0x100, 31 | MOUSE_DRAG_WIRE = 0x110, 32 | MOUSE_HOVER_POINT = 0x200, 33 | MOUSE_DRAG_POINT = 0x210, 34 | 35 | DRAG_MASK = 0x010 36 | }; 37 | 38 | /*! \class EventHandler 39 | * \brief Class that handles events for scene. 40 | * This class is designed to be used in conjuction with DraggableWire class. The wire 41 | * plays role of "selection" - something that changes geometry color based on mouse events. 42 | * For example, the user can select the DraggableWire by hovering over its frame (wire); they can 43 | * also select a point by hovering over one of the points; at last it is possible to perform a drag 44 | * operation. For the latter the push, drag and release mouse events are used. 45 | * 46 | * The class uses three types of intersectors: 47 | * 48 | * 1. Intersector of a raycast and a line - refer to LineIntersector 49 | * 2. Intersector of a raycast and a point - refer to PointIntersector 50 | * 3. Intersector of a raycast and a virtual plane - refer to VirtualPlaneIntersector 51 | * 52 | * The intersector results help to determine which EDIT_MODE is currently on. Depending on the EDIT_MODE, 53 | * the visual appearence of geometry and the mouse behaviour change. 54 | */ 55 | class EventHandler : public osgGA::GUIEventHandler 56 | { 57 | public: 58 | /*! Default constructor */ 59 | EventHandler(); 60 | 61 | /*! Re-defined OSG method that behaves depending on the mouse events and current edit mode. */ 62 | bool handle(const osgGA::GUIEventAdapter & ea, osgGA::GUIActionAdapter & aa); 63 | 64 | protected: 65 | void doIdleMouse(const osgGA::GUIEventAdapter & ea, osgGA::GUIActionAdapter & aa); 66 | void doHoverWire(const osgGA::GUIEventAdapter & ea, osgGA::GUIActionAdapter & aa); 67 | void doHoverPoint(const osgGA::GUIEventAdapter & ea, osgGA::GUIActionAdapter & aa); 68 | void doDragPoint(const osgGA::GUIEventAdapter & ea, osgGA::GUIActionAdapter & aa); 69 | 70 | protected: 71 | DraggableWire* getDraggableWire(const LineIntersector::Intersection& result); 72 | int getSelectedPoint(const PointIntersector::Intersection& result); 73 | 74 | EDIT_MODE getModeFromName(const osgUtil::LineSegmentIntersector::Intersection& result, EDIT_MODE mode_default) const; 75 | EDIT_MODE getModeFromEvent(EDIT_MODE mode, const osgGA::GUIEventAdapter& ea); 76 | 77 | void updateWireGeometry(const LineIntersector::Intersection& intersection); 78 | void updatePointGeometry(const PointIntersector::Intersection& intersection); 79 | void updateDragPointGeometry(const std::tuple& intersection, const osgGA::GUIEventAdapter& ea); 80 | 81 | protected: 82 | template 83 | bool getIntersection(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, TypeIntersection &resultIntersection); 84 | 85 | template 86 | std::tuple setMouseState(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, EDIT_MODE modeDefault); 87 | 88 | private: 89 | osg::observer_ptr m_selection; /*!< current selection, if any */ 90 | EDIT_MODE m_mode; /*!< current state of the selection in relation to mouse events */ 91 | }; 92 | 93 | #endif // EVENTHANDLER_H 94 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Victoria Rudakova 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LineIntersector.cpp: -------------------------------------------------------------------------------- 1 | #include "LineIntersector.h" 2 | #include 3 | 4 | LineIntersector::LineIntersector() 5 | : osgUtil::LineSegmentIntersector(MODEL, 0.f, 0.f) 6 | , m_offset(0.05f) 7 | { 8 | m_hitIndices.clear(); 9 | } 10 | 11 | LineIntersector::LineIntersector(const osg::Vec3 &start, const osg::Vec3 &end) 12 | : osgUtil::LineSegmentIntersector(start, end) 13 | , m_offset(0.05f) 14 | { 15 | m_hitIndices.clear(); 16 | } 17 | 18 | LineIntersector::LineIntersector(osgUtil::Intersector::CoordinateFrame cf, double x, double y) 19 | : osgUtil::LineSegmentIntersector(cf, x, y) 20 | , m_offset(0.05f) 21 | { 22 | m_hitIndices.clear(); 23 | } 24 | 25 | LineIntersector::LineIntersector(osgUtil::Intersector::CoordinateFrame cf, const osg::Vec3d &start, const osg::Vec3d &end) 26 | : osgUtil::LineSegmentIntersector(cf, start, end) 27 | , m_offset(0.05f) 28 | { 29 | } 30 | 31 | void LineIntersector::setOffset(float offset) 32 | { 33 | m_offset = offset; 34 | } 35 | 36 | float LineIntersector::getOffset() const 37 | { 38 | return m_offset; 39 | } 40 | 41 | void LineIntersector::getHitIndices(int &first, int &last) const 42 | { 43 | if (m_hitIndices.empty()){ 44 | first = -1; 45 | last = -1; 46 | } 47 | else { 48 | first = m_hitIndices.front(); 49 | last = m_hitIndices.back(); 50 | } 51 | } 52 | 53 | osgUtil::Intersector *LineIntersector::clone(osgUtil::IntersectionVisitor &iv) 54 | { 55 | if ( _coordinateFrame==MODEL && iv.getModelMatrix()==0 ) 56 | { 57 | osg::ref_ptr cloned = new LineIntersector( _start, _end ); 58 | cloned->_parent = this; 59 | cloned->m_offset = m_offset; 60 | return cloned.release(); 61 | } 62 | 63 | osg::Matrix matrix; 64 | switch ( _coordinateFrame ) 65 | { 66 | case WINDOW: 67 | if (iv.getWindowMatrix()) matrix.preMult( *iv.getWindowMatrix() ); 68 | if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); 69 | if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); 70 | if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); 71 | break; 72 | case PROJECTION: 73 | if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); 74 | if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); 75 | if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); 76 | break; 77 | case VIEW: 78 | if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); 79 | if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); 80 | break; 81 | case MODEL: 82 | if (iv.getModelMatrix()) matrix = *iv.getModelMatrix(); 83 | break; 84 | } 85 | 86 | osg::Matrix inverse = osg::Matrix::inverse(matrix); 87 | osg::ref_ptr cloned = new LineIntersector( _start*inverse, _end*inverse ); 88 | cloned->_parent = this; 89 | cloned->m_offset = m_offset; 90 | return cloned.release(); 91 | } 92 | 93 | void LineIntersector::intersect(osgUtil::IntersectionVisitor &iv, osg::Drawable *drawable) 94 | { 95 | osg::BoundingBox bb = drawable->getBoundingBox(); 96 | bb.xMin() -= m_offset; bb.xMax() += m_offset; 97 | bb.yMin() -= m_offset; bb.yMax() += m_offset; 98 | bb.zMin() -= m_offset; bb.zMax() += m_offset; 99 | 100 | osg::Vec3d s(_start), e(_end); 101 | if (!intersectAndClip(s, e, bb)) return; 102 | if (iv.getDoDummyTraversal()) return; 103 | 104 | osg::Geometry* geometry = drawable->asGeometry(); 105 | if (geometry) 106 | { 107 | if (!this->isRightPrimitive(geometry)) return; 108 | 109 | osg::Vec3Array* vertices = dynamic_cast(geometry->getVertexArray()); 110 | if (!vertices) return; 111 | 112 | for (unsigned int i=0; isize(); ++i) 113 | { 114 | int j = (i==0)? 3 : i-1; 115 | double distance = getSkewLinesDistance(s,e,(*vertices)[i], (*vertices)[j]); 116 | if (m_offsetgetPrimitiveSetList(); 149 | for (const auto& p : primitives){ 150 | if (p->getMode() == GL_LINE_LOOP || p->getMode() == GL_LINES || 151 | p->getMode() == GL_LINE_STRIP) 152 | return true; 153 | } 154 | return false; 155 | } 156 | -------------------------------------------------------------------------------- /LineIntersector.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief OSG-based line intersector class. 3 | * \details This file is a part of osgIntersectors example program. See more details: 4 | * https://github.com/vicrucann/osg-intersectors-example 5 | * \autor Victoria Rudakova 6 | * \date 2016-2017 7 | * \copyright MIT License 8 | */ 9 | 10 | #ifndef LINEINTERSECTOR_H 11 | #define LINEINTERSECTOR_H 12 | 13 | #include 14 | #include 15 | 16 | /*! \class LineIntersector 17 | * \brief A class that allows to catch intersections with line loops and lines OpenGL types. 18 | * It uses shortest distance between the cast ray and the geometry line which is calculated 19 | * as a distance between skew lines. 20 | * In addition, it filters out the geometries whose primitive sets are different than line-types. 21 | */ 22 | 23 | class LineIntersector : public osgUtil::LineSegmentIntersector 24 | { 25 | public: 26 | LineIntersector(); 27 | 28 | LineIntersector(const osg::Vec3& start, const osg::Vec3& end); 29 | LineIntersector(CoordinateFrame cf, double x, double y); 30 | LineIntersector(CoordinateFrame cf, const osg::Vec3d& start, const osg::Vec3d& end); 31 | 32 | void setOffset(float offset); 33 | float getOffset() const; 34 | void getHitIndices(int& first, int& last) const; 35 | 36 | virtual Intersector* clone( osgUtil::IntersectionVisitor& iv ); 37 | virtual void intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable); 38 | 39 | bool isVirtualIntersector() const; 40 | 41 | protected: 42 | double getSkewLinesDistance(const osg::Vec3d &r1, const osg::Vec3d &r2, const osg::Vec3d &v1, const osg::Vec3d &v2); 43 | virtual bool isRightPrimitive(const osg::Geometry* geometry); 44 | 45 | float m_offset; 46 | std::vector m_hitIndices; 47 | }; 48 | 49 | #endif // LINEINTERSECTOR_H 50 | -------------------------------------------------------------------------------- /PointIntersector.cpp: -------------------------------------------------------------------------------- 1 | #include "PointIntersector.h" 2 | 3 | #include 4 | 5 | PointIntersector::PointIntersector() 6 | : LineIntersector() 7 | { 8 | } 9 | 10 | PointIntersector::PointIntersector(const osg::Vec3 &start, const osg::Vec3 &end) 11 | : LineIntersector(start, end) 12 | { 13 | } 14 | 15 | PointIntersector::PointIntersector(osgUtil::Intersector::CoordinateFrame cf, double x, double y) 16 | : LineIntersector(cf, x, y) 17 | { 18 | } 19 | 20 | PointIntersector::PointIntersector(osgUtil::Intersector::CoordinateFrame cf, const osg::Vec3d &start, const osg::Vec3d &end) 21 | : LineIntersector(cf, start, end) 22 | { 23 | 24 | } 25 | 26 | osgUtil::Intersector *PointIntersector::clone(osgUtil::IntersectionVisitor &iv) 27 | { 28 | if ( _coordinateFrame==MODEL && iv.getModelMatrix()==0 ) 29 | { 30 | osg::ref_ptr cloned = new PointIntersector( _start, _end ); 31 | cloned->_parent = this; 32 | cloned->m_offset = m_offset; 33 | return cloned.release(); 34 | } 35 | 36 | osg::Matrix matrix; 37 | switch ( _coordinateFrame ) 38 | { 39 | case WINDOW: 40 | if (iv.getWindowMatrix()) matrix.preMult( *iv.getWindowMatrix() ); 41 | if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); 42 | if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); 43 | if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); 44 | break; 45 | case PROJECTION: 46 | if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); 47 | if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); 48 | if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); 49 | break; 50 | case VIEW: 51 | if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); 52 | if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); 53 | break; 54 | case MODEL: 55 | if (iv.getModelMatrix()) matrix = *iv.getModelMatrix(); 56 | break; 57 | } 58 | 59 | osg::Matrix inverse = osg::Matrix::inverse(matrix); 60 | osg::ref_ptr cloned = new PointIntersector( _start*inverse, _end*inverse ); 61 | cloned->_parent = this; 62 | cloned->m_offset = m_offset; 63 | return cloned.release(); 64 | } 65 | 66 | void PointIntersector::intersect(osgUtil::IntersectionVisitor &iv, osg::Drawable *drawable) 67 | { 68 | osg::BoundingBox bb = drawable->getBoundingBox(); 69 | 70 | bb.xMin() -= m_offset; bb.xMax() += m_offset; 71 | bb.yMin() -= m_offset; bb.yMax() += m_offset; 72 | bb.zMin() -= m_offset; bb.zMax() += m_offset; 73 | 74 | osg::Vec3d s(_start), e(_end); 75 | if (!intersectAndClip(s, e, bb)) return; 76 | if (iv.getDoDummyTraversal()) return; 77 | 78 | osg::Geometry* geometry = drawable->asGeometry(); 79 | if (geometry) 80 | { 81 | if (!this->isRightPrimitive(geometry)) return; 82 | 83 | osg::Vec3Array* vertices = dynamic_cast(geometry->getVertexArray()); 84 | if (!vertices) return; 85 | 86 | osg::Vec3d dir = e - s; 87 | double invLength = 1.0 / dir.length(); 88 | for (unsigned int i=0; isize(); ++i) 89 | { 90 | double distance = std::fabs( (((*vertices)[i] - s)^dir).length() ); 91 | distance *= invLength; 92 | if ( m_offsetgetPrimitiveSetList(); 110 | for (const auto& p : primitives){ 111 | if (p->getMode() == GL_POINTS) 112 | return true; 113 | } 114 | return false; 115 | } 116 | -------------------------------------------------------------------------------- /PointIntersector.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief OSG-based point intersector. 3 | * \details This file is a part of osgIntersectors example program. See more details: 4 | * https://github.com/vicrucann/osg-intersectors-example 5 | * \autor Victoria Rudakova 6 | * \date 2016-2017 7 | * \copyright MIT License 8 | */ 9 | 10 | #ifndef POINTINTERSECTOR_H 11 | #define POINTINTERSECTOR_H 12 | 13 | #include "LineIntersector.h" 14 | #include 15 | #include 16 | 17 | /*! \class PointIntersector 18 | * \brief It allows to catch intersections with point OpenGL types. 19 | * It uses shortest distance between the cast ray and geometry's vertices. 20 | * In addition, it filters out the geometries whose primitive sets are different than GL_POINTS. 21 | * The result primitive index is saved to `hit.primitiveIndex`. 22 | */ 23 | class PointIntersector : public LineIntersector 24 | { 25 | public: 26 | PointIntersector(); 27 | PointIntersector(const osg::Vec3& start, const osg::Vec3& end); 28 | PointIntersector(CoordinateFrame cf, double x, double y); 29 | PointIntersector(CoordinateFrame cf, const osg::Vec3d& start, const osg::Vec3d& end); 30 | 31 | virtual Intersector* clone(osgUtil::IntersectionVisitor &iv); 32 | virtual void intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable); 33 | 34 | protected: 35 | virtual bool isRightPrimitive(const osg::Geometry* geometry); 36 | }; 37 | 38 | #endif // POINTINTERSECTOR_H 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Line, point and virtual plane intersectors using C++11 and OpenSceneGraph 2 | 3 | [![Build Status](https://travis-ci.org/vicrucann/osg-intersectors-example.svg?branch=master)](https://travis-ci.org/vicrucann/osg-intersectors-example) 4 | 5 | ![Intersectors example: screenshots](https://github.com/vicrucann/osg-intersectors-example/blob/master/images/intersectors.gif) 6 | 7 | This is an example project that demonstrates the work of three types of intersectors: **line**, **point** and **virtual plane**. While the line and point intersectors are based on standard OSG intersector, the virtual plane intersector utilizes ray casting algorithm - when the intersection is calculated between the ray and a virtual plane. 8 | 9 | ## Requirements 10 | 11 | * Compiler that supports C++11, e.g., GCC-4.8 12 | * OpenSceneGraph library (>=3.4.0) 13 | * CMake (>= 2.8.11) 14 | 15 | ## Intersectors 16 | 17 | The project is composed of two wire rectangles in two different 3D planes. User can select each of the wires by hovering above them and then drag the wire outline by dragging the corresponding corner point. 18 | 19 | Each intersector is responsible for one part: 20 | 21 | 1. Line intersector is used to determine over what wire the mouse is hovering. Based on the intersection result, that wire gets "selected" which is depicted by wire's color change. **Magenta** color is used to denote the line intersector is in action. 22 | 23 | 2. Point intersector is used to determine whether a mouse is hovering over any point of the wire or not. If it is hovering, that point gets "selected" (depicted as color change) and it also enables point dragging in case if mouse was pushed. **Bright green** color for a point geometry is used to denote the intersector is in action. 24 | 25 | 3. Virtual plane intersector is used to determine the intersection between the ray which is cast from the current camera view and virtual plane which contains the selected wire. This intersector is used for dragging functionality and helps to determine the new position of the drag point in its 3D plane. **Yellow** color is used for a point geometry and a for a part of a line geometry to denote the virtual plane intersector is in action. 26 | -------------------------------------------------------------------------------- /SVMData.cpp: -------------------------------------------------------------------------------- 1 | #include "SVMData.h" 2 | 3 | SVMData::SVMData() 4 | : osg::Group() 5 | , m_switch(new osg::Switch()) 6 | , m_wire1(new DraggableWire()) 7 | , m_wire2(new DraggableWire()) 8 | { 9 | this->addChild(m_switch); 10 | m_switch->addChild(m_wire1); 11 | m_switch->addChild(m_wire2); 12 | } 13 | 14 | void SVMData::setTransformWall(osg::Matrix m) 15 | { 16 | m_wire1->setMatrix(m); 17 | } 18 | 19 | void SVMData::setTransformFloor(osg::Matrix m) 20 | { 21 | m_wire2->setMatrix(m); 22 | } 23 | -------------------------------------------------------------------------------- /SVMData.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief A tester class. 3 | * \details This file is a part of osgIntersectors example program. See more details: 4 | * https://github.com/vicrucann/osg-intersectors-example 5 | * \autor Victoria Rudakova 6 | * \date 2016-2017 7 | * \copyright MIT License 8 | */ 9 | 10 | #ifndef SVMDATA_H 11 | #define SVMDATA_H 12 | 13 | #include 14 | #include 15 | 16 | #include "DraggableWire.h" 17 | 18 | /*! \class SVMData 19 | * \brief A tester class that contains two DraggableWire geometries which are called "Wall" and "Floor". 20 | */ 21 | 22 | class SVMData : public osg::Group 23 | { 24 | public: 25 | SVMData(); 26 | 27 | void setTransformWall(osg::Matrix m); 28 | 29 | void setTransformFloor(osg::Matrix m); 30 | 31 | private: 32 | osg::Switch* m_switch; 33 | DraggableWire* m_wire1; 34 | DraggableWire* m_wire2; 35 | }; 36 | 37 | #endif // SVMDATA_H 38 | -------------------------------------------------------------------------------- /VirtualPlaneIntersector.cpp: -------------------------------------------------------------------------------- 1 | #include "VirtualPlaneIntersector.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | VirtualPlaneIntersector::VirtualPlaneIntersector(DraggableWire *wire) 10 | : osg::Referenced(), 11 | m_planeGeometry(wire) 12 | { 13 | } 14 | 15 | bool VirtualPlaneIntersector::getIntersection(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa, double &u, double &v) 16 | { 17 | osg::Matrix VPW, invVPW; 18 | if (!this->getViewProjectionWorld(aa, VPW, invVPW)) return false; 19 | 20 | /* get far and near in global 3D coords */ 21 | osg::Vec3f nearPoint, farPoint; 22 | 23 | this->getFarNear(ea.getX(), ea.getY(), invVPW, nearPoint, farPoint); 24 | 25 | /* get intersection point in global 3D coords */ 26 | osg::Vec3f P; 27 | osg::Plane plane = m_planeGeometry->getPlane(); 28 | osg::Vec3f center = m_planeGeometry->getCenter3D(); 29 | if (!this->getRayPlaneIntersection(plane,center, nearPoint, farPoint, P)) 30 | return false; 31 | 32 | /* get model matrix and its inverse */ 33 | osg::Matrix M = m_planeGeometry->getMatrix(); 34 | osg::Matrix invM; 35 | if (!invM.invert(M)) return false; 36 | 37 | /* obtain intersection in local 2D point */ 38 | osg::Vec3f p = P * invM; 39 | assert(std::fabs( p.z()) < 0.000001 ); 40 | u=p.x(); 41 | v=p.y(); 42 | 43 | return true; 44 | } 45 | 46 | VirtualPlaneIntersector::Intersection VirtualPlaneIntersector::getIntersection(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa) 47 | { 48 | double u=0,v=0; 49 | bool success = this->getIntersection(ea, aa, u, v); 50 | return std::make_tuple(u,v,success); 51 | } 52 | 53 | bool VirtualPlaneIntersector::getViewProjectionWorld(osgGA::GUIActionAdapter &aa, osg::Matrix &VPW, osg::Matrix &invVPW) 54 | { 55 | if (!m_planeGeometry.get()) return false; 56 | osgViewer::View* viewer = dynamic_cast(&aa); 57 | if (!viewer) return false; 58 | osg::Camera* camera = viewer->getCamera(); 59 | if (!camera) return false; 60 | if (!camera->getViewport()) return false; 61 | 62 | /* get far and near points of the ray */ 63 | VPW = camera->getViewMatrix() 64 | * camera->getProjectionMatrix() 65 | * camera->getViewport()->computeWindowMatrix(); 66 | if (!invVPW.invert(VPW)) return false; 67 | 68 | return true; 69 | } 70 | 71 | void VirtualPlaneIntersector::getFarNear(double x, double y, const osg::Matrix &invVPW, osg::Vec3f &near, osg::Vec3f &far) 72 | { 73 | near = osg::Vec3f(x, y, 0.f) * invVPW; 74 | far = osg::Vec3f(x, y, 1.f) * invVPW; 75 | } 76 | 77 | bool VirtualPlaneIntersector::getRayPlaneIntersection(const osg::Plane &plane, const osg::Vec3f ¢er, const osg::Vec3f &nearPoint, const osg::Vec3f &farPoint, osg::Vec3f &P) 78 | { 79 | 80 | std::vector ray(2); 81 | ray[0] = nearPoint; 82 | ray[1] = farPoint; 83 | if (plane.intersect(ray)) { // 1 or -1 means no intersection 84 | std::cerr << "rayPlaneIntersection: not intersection with ray" << std::endl; 85 | return false; 86 | } 87 | 88 | osg::Vec3f dir = farPoint-nearPoint; 89 | if (!plane.dotProductNormal(dir)){ 90 | std::cerr << "rayPlaneIntersection: projected ray is almost parallel to plane. " 91 | "Change view point." << std::endl; 92 | return false; 93 | } 94 | 95 | if (! plane.dotProductNormal(center-nearPoint)){ 96 | std::cerr << "rayPlaneIntersection: plane contains the line. " 97 | "Change view point" << std::endl; 98 | return false; 99 | } 100 | 101 | double len = plane.dotProductNormal(center-nearPoint) / plane.dotProductNormal(dir); 102 | P = dir * len + nearPoint; 103 | 104 | return true; 105 | } 106 | -------------------------------------------------------------------------------- /VirtualPlaneIntersector.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief Virtual plane intersection class. 3 | * \details This file is a part of osgIntersectors example program. See more details: 4 | * https://github.com/vicrucann/osg-intersectors-example 5 | * \autor Victoria Rudakova 6 | * \date 2016-2017 7 | * \copyright MIT License 8 | */ 9 | 10 | #ifndef VIRTUALPLANEINTERSECTOR_H 11 | #define VIRTUALPLANEINTERSECTOR_H 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "DraggableWire.h" 20 | 21 | 22 | /*! \class VirtualPlaneIntersector 23 | * \brief Performs a raycast intersection with a virtual plane where there geometry is located. 24 | * This class is not a standard OSG-based intersector. It assumes that all the points of the given 25 | * geometry lie within the same plane in 3D - virtual plane. Then it performs the raycast of the 26 | * current camera position and finds an intersection point with the virtual plane. The intersection 27 | * point is returned in local coordiante system: it has a format `(u,v)`, assuming the z-coordinate is 28 | * zero. 29 | * For the math details, refer to http://vicrucann.github.io/tutorials/osg-raycast/ 30 | */ 31 | class VirtualPlaneIntersector : public osg::Referenced 32 | { 33 | public: 34 | typedef std::tuple Intersection; 35 | 36 | VirtualPlaneIntersector(DraggableWire* wire); 37 | 38 | protected: 39 | bool getIntersection(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa, double& u, double& v); 40 | 41 | public: 42 | Intersection getIntersection(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa); 43 | 44 | protected: 45 | bool getViewProjectionWorld(osgGA::GUIActionAdapter &aa, osg::Matrix &VPW, osg::Matrix &invVPW); 46 | 47 | void getFarNear(double x, double y, const osg::Matrix &invVPW, osg::Vec3f &near, osg::Vec3f &far); 48 | 49 | bool getRayPlaneIntersection(const osg::Plane &plane, const osg::Vec3f ¢er, const osg::Vec3f &nearPoint, const osg::Vec3f &farPoint, osg::Vec3f &P); 50 | 51 | private: 52 | osg::observer_ptr m_planeGeometry; 53 | }; 54 | 55 | #endif // VIRTUALPLANEINTERSECTOR_H 56 | -------------------------------------------------------------------------------- /images/intersectors.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vicrucann/osg-intersectors-example/a809d9de7b06b550995093e0b5e657ea9533f5ce/images/intersectors.gif -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include 3 | #endif 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | /*! 12 | * \brief Main file that adds tester and reference geometries to the scene graph. 13 | * \author Victoria Rudakova 14 | * \date 2016-2017 15 | * \copyright MIT License 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "SVMData.h" 24 | #include "DraggableWire.h" 25 | #include "EventHandler.h" 26 | 27 | const int OSG_WIDTH = 1280; 28 | const int OSG_HEIGHT = 960; 29 | 30 | osg::Node* createReferenceNode() 31 | { 32 | osg::Cylinder* cylinder = new osg::Cylinder(osg::Vec3( 0.f, 0.f, 0.f ), 0.25f, 0.5f); 33 | osg::ShapeDrawable* sd = new osg::ShapeDrawable( cylinder ); 34 | sd->setColor( osg::Vec4( 0.8f, 0.5f, 0.2f, 1.f ) ); 35 | osg::Geode* geode = new osg::Geode; 36 | geode->addDrawable(sd); 37 | 38 | return geode; 39 | } 40 | 41 | int main(int, char**) 42 | { 43 | #ifdef _WIN32 44 | ::SetProcessDPIAware(); 45 | #endif 46 | 47 | std::cout << "Line, point and virtual plane intersectors demo." << std::endl; 48 | 49 | osgViewer::Viewer viewer; 50 | 51 | osg::ref_ptr root = new osg::Group(); 52 | 53 | // create a tester node 54 | SVMData* svm = new SVMData(); 55 | svm->setTransformFloor(osg::Matrix::identity() * osg::Matrix::translate(0,1.5,0)); 56 | svm->setTransformWall(osg::Matrix::rotate(3.14157*0.5, 1, 0, 0)); 57 | 58 | root->addChild(svm); 59 | osg::Node* node = createReferenceNode(); 60 | root->addChild(node); 61 | 62 | root->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); 63 | node->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::ON); 64 | root->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); 65 | root->getOrCreateStateSet()->setMode(GL_LINE_SMOOTH, osg::StateAttribute::ON); 66 | 67 | viewer.setSceneData(root.get()); 68 | viewer.setUpViewInWindow(100,100,OSG_WIDTH, OSG_HEIGHT); 69 | viewer.addEventHandler(new EventHandler()); 70 | viewer.setCameraManipulator(new osgGA::TrackballManipulator()); 71 | return viewer.run(); 72 | } 73 | 74 | --------------------------------------------------------------------------------