OpenSceneGraph/examples/osgkeyboardmouse/osgkeyboardmouse.cpp

500 lines
17 KiB
C++
Raw Normal View History

/* OpenSceneGraph example, osgkeyboardmouse.
*
* 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 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.
*/
// Simple example of use of osgViewer::GraphicsWindow + Viewer
// example that provides the user with control over view position with basic picking.
#include <osg/Timer>
#include <osg/KdTree>
2005-04-08 17:45:06 +08:00
#include <osg/io_utils>
2006-06-12 22:04:40 +08:00
#include <osg/observer_ptr>
#include <osgUtil/IntersectionVisitor>
#include <osgUtil/PolytopeIntersector>
#include <osgUtil/LineSegmentIntersector>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgGA/TrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <osgViewer/Viewer>
#include <osgFX/Scribe>
#include <iostream>
2006-06-12 22:04:40 +08:00
class CreateModelToSaveVisitor : public osg::NodeVisitor
{
public:
CreateModelToSaveVisitor():
2014-05-14 18:19:43 +08:00
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
2006-06-12 22:04:40 +08:00
{
_group = new osg::Group;
_addToModel = false;
}
2014-05-14 18:19:43 +08:00
2006-06-12 22:04:40 +08:00
virtual void apply(osg::Node& node)
{
osgFX::Scribe* scribe = dynamic_cast<osgFX::Scribe*>(&node);
if (scribe)
{
for(unsigned int i=0; i<scribe->getNumChildren(); ++i)
{
_group->addChild(scribe->getChild(i));
}
}
else
{
traverse(node);
}
}
2014-05-14 18:19:43 +08:00
2006-06-12 22:04:40 +08:00
osg::ref_ptr<osg::Group> _group;
bool _addToModel;
};
class DeleteSelectedNodesVisitor : public osg::NodeVisitor
{
public:
DeleteSelectedNodesVisitor():
2014-05-14 18:19:43 +08:00
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
}
2014-05-14 18:19:43 +08:00
virtual void apply(osg::Node& node)
{
osgFX::Scribe* scribe = dynamic_cast<osgFX::Scribe*>(&node);
if (scribe)
{
_selectedNodes.push_back(scribe);
}
else
{
traverse(node);
}
}
2014-05-14 18:19:43 +08:00
void pruneSelectedNodes()
{
for(SelectedNodes::iterator itr = _selectedNodes.begin();
itr != _selectedNodes.end();
++itr)
{
osg::Node* node = itr->get();
osg::Node::ParentList parents = node->getParents();
for(osg::Node::ParentList::iterator pitr = parents.begin();
pitr != parents.end();
++pitr)
{
(*pitr)->removeChild(node);
}
}
}
2014-05-14 18:19:43 +08:00
typedef std::vector< osg::ref_ptr<osgFX::Scribe> > SelectedNodes;
SelectedNodes _selectedNodes;
2014-05-14 18:19:43 +08:00
};
2006-06-12 22:04:40 +08:00
// class to handle events with a pick
2014-05-14 18:19:43 +08:00
class PickHandler : public osgGA::GUIEventHandler
{
2014-05-14 18:19:43 +08:00
public:
2006-06-12 22:04:40 +08:00
PickHandler():
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
_mx(0.0),_my(0.0),
_usePolytopeIntersector(false),
_useWindowCoordinates(false),
_precisionHint(osgUtil::Intersector::USE_DOUBLE_CALCULATIONS) {}
2006-06-12 22:04:40 +08:00
~PickHandler() {}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
2006-06-12 22:04:40 +08:00
{
osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
if (!viewer) return false;
2006-06-12 22:04:40 +08:00
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::KEYUP):
{
if (ea.getKey()=='s')
2006-06-12 22:04:40 +08:00
{
saveSelectedModel(viewer->getSceneData());
2014-05-14 18:19:43 +08:00
}
else if (ea.getKey()=='o')
{
2011-06-15 00:54:20 +08:00
osg::notify(osg::NOTICE)<<"Saved model to file 'saved_model.osgt'"<<std::endl;
osgDB::writeNodeFile(*(viewer->getSceneData()), "saved_model.osgt");
}
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
else if (ea.getKey()=='p')
{
_usePolytopeIntersector = !_usePolytopeIntersector;
if (_usePolytopeIntersector)
{
osg::notify(osg::NOTICE)<<"Using PolytopeIntersector"<<std::endl;
} else {
osg::notify(osg::NOTICE)<<"Using LineSegmentIntersector"<<std::endl;
}
}
else if (ea.getKey()=='c')
{
_useWindowCoordinates = !_useWindowCoordinates;
if (_useWindowCoordinates)
{
osg::notify(osg::NOTICE)<<"Using window coordinates for picking"<<std::endl;
} else {
osg::notify(osg::NOTICE)<<"Using projection coordiates for picking"<<std::endl;
}
}
else if (ea.getKey()=='a')
{
fullWindowIntersectionTest(viewer);
}
else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Delete || ea.getKey()==osgGA::GUIEventAdapter::KEY_BackSpace)
{
osg::notify(osg::NOTICE)<<"Delete"<<std::endl;
DeleteSelectedNodesVisitor dsnv;
viewer->getSceneData()->accept(dsnv);
dsnv.pruneSelectedNodes();
2006-06-12 22:04:40 +08:00
}
return false;
}
case(osgGA::GUIEventAdapter::PUSH):
case(osgGA::GUIEventAdapter::MOVE):
{
_mx = ea.getX();
_my = ea.getY();
return false;
}
case(osgGA::GUIEventAdapter::RELEASE):
{
if (_mx == ea.getX() && _my == ea.getY())
{
// only do a pick if the mouse hasn't moved
pick(ea,viewer);
2006-06-12 22:04:40 +08:00
}
return true;
2014-05-14 18:19:43 +08:00
}
2006-06-12 22:04:40 +08:00
default:
return false;
}
}
void fullWindowIntersectionTest(osgViewer::Viewer* viewer)
{
osg::ref_ptr<osgUtil::IntersectorGroup> intersectors = new osgUtil::IntersectorGroup;
osg::Viewport* viewport = viewer->getCamera()->getViewport();
unsigned int numX = 100;
unsigned int numY = 100;
double dx = viewport->width()/double(numX-1);
double dy = viewport->width()/double(numX-1);
double y = viewport->x();
for(unsigned int r=0; r<numY; ++r)
{
double x = viewport->x();
for(unsigned int c=0; c<numX; ++c)
{
osg::ref_ptr<osgUtil::Intersector> intersector;
if (_usePolytopeIntersector)
{
intersector = new osgUtil::PolytopeIntersector( osgUtil::Intersector::WINDOW, x-dx*0.5, y-dy*0.5, x+dx*0.5, y+dy*0.5);
}
else
{
intersector = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, x, y);
}
intersector->setPrecisionHint(_precisionHint);
intersectors->getIntersectors().push_back(intersector);
x += dx;
}
y += dy;
}
osgUtil::IntersectionVisitor iv(intersectors.get());
osg::ElapsedTime elapsedTime;
viewer->getCamera()->accept(iv);
OSG_NOTICE<<"Intersection traversal took "<<elapsedTime.elapsedTime_m()<<"ms for "<<intersectors->getIntersectors().size()<<" intersectors"<<std::endl;
}
void pick(const osgGA::GUIEventAdapter& ea, osgViewer::Viewer* viewer)
2006-06-12 22:04:40 +08:00
{
osg::Node* scene = viewer->getSceneData();
2006-06-12 22:04:40 +08:00
if (!scene) return;
osg::notify(osg::NOTICE)<<std::endl;
osg::Node* node = 0;
osg::Group* parent = 0;
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
if (_usePolytopeIntersector)
{
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
osgUtil::PolytopeIntersector* picker;
if (_useWindowCoordinates)
{
// use window coordinates
// remap the mouse x,y into viewport coordinates.
osg::Viewport* viewport = viewer->getCamera()->getViewport();
double mx = viewport->x() + (int)((double )viewport->width()*(ea.getXnormalized()*0.5+0.5));
double my = viewport->y() + (int)((double )viewport->height()*(ea.getYnormalized()*0.5+0.5));
// half width, height.
double w = 5.0f;
double h = 5.0f;
picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::WINDOW, mx-w, my-h, mx+w, my+h );
} else {
double mx = ea.getXnormalized();
double my = ea.getYnormalized();
double w = 0.05;
double h = 0.05;
picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx-w, my-h, mx+w, my+h );
}
picker->setPrecisionHint(_precisionHint);
osgUtil::IntersectionVisitor iv(picker);
osg::ElapsedTime elapsedTime;
viewer->getCamera()->accept(iv);
OSG_NOTICE<<"PoltyopeIntersector traversal took "<<elapsedTime.elapsedTime_m()<<"ms"<<std::endl;
if (picker->containsIntersections())
{
osgUtil::PolytopeIntersector::Intersection intersection = picker->getFirstIntersection();
osg::notify(osg::NOTICE)<<"Picked "<<intersection.localIntersectionPoint<<std::endl
<<" Distance to ref. plane "<<intersection.distance
<<", max. dist "<<intersection.maxDistance
<<", primitive index "<<intersection.primitiveIndex
<<", numIntersectionPoints "
<<intersection.numIntersectionPoints
<<std::endl;
osg::NodePath& nodePath = intersection.nodePath;
node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0;
parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0;
2014-05-14 18:19:43 +08:00
if (node) std::cout<<" Hits "<<node->className()<<" nodePath size "<<nodePath.size()<<std::endl;
toggleScribe(parent, node);
}
}
else
{
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
osgUtil::LineSegmentIntersector* picker;
if (!_useWindowCoordinates)
{
// use non dimensional coordinates - in projection/clip space
picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() );
} else {
// use window coordinates
// remap the mouse x,y into viewport coordinates.
osg::Viewport* viewport = viewer->getCamera()->getViewport();
float mx = viewport->x() + (int)((float)viewport->width()*(ea.getXnormalized()*0.5f+0.5f));
float my = viewport->y() + (int)((float)viewport->height()*(ea.getYnormalized()*0.5f+0.5f));
picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, mx, my );
}
picker->setPrecisionHint(_precisionHint);
osgUtil::IntersectionVisitor iv(picker);
osg::ElapsedTime elapsedTime;
viewer->getCamera()->accept(iv);
OSG_NOTICE<<"LineSegmentIntersector traversal took "<<elapsedTime.elapsedTime_m()<<"ms"<<std::endl;
if (picker->containsIntersections())
{
osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection();
osg::notify(osg::NOTICE)<<"Picked "<<intersection.localIntersectionPoint<<std::endl;
osg::NodePath& nodePath = intersection.nodePath;
node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0;
parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0;
if (node) std::cout<<" Hits "<<node->className()<<" nodePath size"<<nodePath.size()<<std::endl;
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
toggleScribe(parent, node);
}
2014-05-14 18:19:43 +08:00
}
// now we try to decorate the hit node by the osgFX::Scribe to show that its been "picked"
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
}
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
void toggleScribe(osg::Group* parent, osg::Node* node) {
if (!parent || !node) return;
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
std::cout<<" parent "<<parent->className()<<std::endl;
osgFX::Scribe* parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent);
if (!parentAsScribe)
{
// node not already picked, so highlight it with an osgFX::Scribe
osgFX::Scribe* scribe = new osgFX::Scribe();
scribe->addChild(node);
parent->replaceChild(node,scribe);
}
else
{
// node already picked so we want to remove scribe to unpick it.
osg::Node::ParentList parentList = parentAsScribe->getParents();
for(osg::Node::ParentList::iterator itr=parentList.begin();
itr!=parentList.end();
++itr)
{
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
(*itr)->replaceChild(parentAsScribe,node);
}
}
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
2006-06-12 22:04:40 +08:00
}
void saveSelectedModel(osg::Node* scene)
2006-06-12 22:04:40 +08:00
{
if (!scene) return;
2014-05-14 18:19:43 +08:00
2006-06-12 22:04:40 +08:00
CreateModelToSaveVisitor cmtsv;
scene->accept(cmtsv);
2014-05-14 18:19:43 +08:00
2006-06-12 22:04:40 +08:00
if (cmtsv._group->getNumChildren()>0)
{
2011-06-15 00:54:20 +08:00
std::cout<<"Writing selected compoents to 'selected_model.osgt'"<<std::endl;
osgDB::writeNodeFile(*cmtsv._group, "selected_model.osgt");
2006-06-12 22:04:40 +08:00
}
}
void setPrecisionHint(osgUtil::Intersector::PrecisionHint hint) { _precisionHint = hint; }
2006-06-12 22:04:40 +08:00
protected:
float _mx,_my;
From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor mention below to TemplatePrimitiveFunctor). "Since we desperately needed a means for picking Lines and Points I implemented (hopefully!) proper geometrical tests for the PolytopeIntersector. First of all I implemented a new "GenericPrimiteFunctor" which is basically an extended copy TriangleFunctor which also handles Points, Lines and Quads through suitable overloads of operator(). I would have liked to call it "PrimitiveFunctor" but that name was already used... I used a template method to remove redundancy in the drawElements method overloads. If you know of platforms where this will not work I can change it to the style used in TriangleFunctor. In PolytopeIntersector.cpp I implemented a "PolytopePrimitiveIntersector" which provides the needed overloads for Points, Lines, Triangles and Quads to the GenericPrimitiveFunctor. This is then used in the intersect method of PolytopeIntersector. Implementation summary: - Points: Check distance to all planes - Lines: Check distance of both ends against each plane. If both are outside -> line is out If both are in -> continue checking One is in, one is out -> compute intersection point (candidate) Then check all candidates against all other polytope planes. The remaining candidates are the proper intersection points of the line with the polytope. - Triangles: Perform Line-Checks for all edges of the triangle as above. If there is an proper intersection -> done. In the case where there are more than 2 polytope plane to check against we have to check for the case where the triangle encloses the polytope. In that case the intersection lines of the polytope planes are computed and checked against the triangle. - Quads: handled as two triangles. This is implementation is certainly not the fastest. There are certainly ways and strategies to improve it. I also enabled the code for PolytopeIntersector in osgkeyboardmouse and added keybindings to switch the type of intersector ('p') and the picking coordinate system ('c') on the fly. Since the PolytopeIntersector does not have a canonical ordering for its intersections (as opposed to the LineSegementIntersector) I chaged the implementation to toggle all hit geometries. I tested the functionality with osgkeyboardmouse and several models and it seems to work for polygonal models. Special nodes such as billboards do not work. The next thing on my todo-list is to implement a an improved Intersection-Structure for the PolytopeIntersector. We need to know which primitives where hit (and where). "
2007-05-23 19:05:59 +08:00
bool _usePolytopeIntersector;
bool _useWindowCoordinates;
osgUtil::Intersector::PrecisionHint _precisionHint;
2006-06-12 22:04:40 +08:00
};
class ConvertPrimitives : public osg::NodeVisitor
{
public:
osg::PrimitiveSet::Mode _mode;
ConvertPrimitives(osg::PrimitiveSet::Mode mode):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_mode(mode) {}
void apply(osg::Geometry& geometry)
{
if (!geometry.getVertexArray()) return;
unsigned int numVertices = geometry.getVertexArray()->getNumElements();
if (_mode==osg::PrimitiveSet::POINTS)
{
// remove previous primitive sets.
geometry.removePrimitiveSet(0, geometry.getNumPrimitiveSets());
geometry.addPrimitiveSet(new osg::DrawArrays(_mode, 0,numVertices));
}
else if (_mode==osg::PrimitiveSet::LINES)
{
geometry.removePrimitiveSet(0, geometry.getNumPrimitiveSets());
geometry.addPrimitiveSet(new osg::DrawArrays(_mode, 0,numVertices));
}
}
};
int main( int argc, char **argv )
{
osg::ArgumentParser arguments(&argc, argv);
osgViewer::Viewer viewer(arguments);
bool useKdTree = false;
while (arguments.read("--kdtree")) { useKdTree = true; }
2014-05-14 18:19:43 +08:00
osg::ref_ptr<PickHandler> pickhandler = new PickHandler;
while (arguments.read("--double")) { pickhandler->setPrecisionHint(osgUtil::Intersector::USE_DOUBLE_CALCULATIONS); }
while (arguments.read("--float")) { pickhandler->setPrecisionHint(osgUtil::Intersector::USE_FLOAT_CALCULATIONS); }
// load model
osg::ref_ptr<osg::Node> loadedModel = osgDB::readRefNodeFiles(arguments);
2014-05-14 18:19:43 +08:00
// if not loaded assume no arguments passed in, try use default mode instead.
Introduced CMake option OSG_PROVIDE_READFILE option that defaults to ON, but when switched to OFF disables the building of the osgDB::read*File() methods, forcing users to use osgDB::readRef*File() methods. The later is preferable as it closes a potential threading bug when using paging databases in conjunction with the osgDB::Registry Object Cache. This threading bug occurs when one thread gets an object from the Cache via an osgDB::read*File() call where only a pointer to the object is passed back, so taking a reference to the object is delayed till it gets reassigned to a ref_ptr<>, but at the same time another thread calls a flush of the Object Cache deleting this object as it's referenceCount is now zero. Using osgDB::readREf*File() makes sure the a ref_ptr<> is passed back and the referenceCount never goes to zero. To ensure the OSG builds when OSG_PROVIDE_READFILE is to OFF the many cases of osgDB::read*File() usage had to be replaced with a ref_ptr<> osgDB::readRef*File() usage. The avoid this change causing lots of other client code to be rewritten to handle the use of ref_ptr<> in place of C pointer I introduced a serious of templte methods in various class to adapt ref_ptr<> to the underly C pointer to be passed to old OSG API's, example of this is found in include/osg/Group: bool addChild(Node* child); // old method which can only be used with a Node* tempalte<class T> bool addChild(const osg::ref_ptr<T>& child) { return addChild(child.get()); } // adapter template method These changes together cover 149 modified files, so it's a large submission. This extent of changes are warrent to make use of the Object Cache and multi-threaded loaded more robust. git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@15164 16af8721-9629-0410-8352-f15c8da7e697
2015-10-22 21:42:19 +08:00
if (!loadedModel) loadedModel = osgDB::readRefNodeFile("dumptruck.osgt");
2014-05-14 18:19:43 +08:00
if (!loadedModel)
{
std::cout << argv[0] <<": No data loaded." << std::endl;
return 1;
}
2014-05-14 18:19:43 +08:00
while(arguments.read("--points")) { ConvertPrimitives cp(osg::PrimitiveSet::POINTS); loadedModel->accept(cp); }
while(arguments.read("--lines")) { ConvertPrimitives cp(osg::PrimitiveSet::LINES); loadedModel->accept(cp); }
if (useKdTree)
{
OSG_NOTICE<<"Buildering KdTrees"<<std::endl;
osg::ref_ptr<osg::KdTreeBuilder> builder = new osg::KdTreeBuilder;
loadedModel->accept(*builder);
}
// assign the scene graph to viewer
Introduced CMake option OSG_PROVIDE_READFILE option that defaults to ON, but when switched to OFF disables the building of the osgDB::read*File() methods, forcing users to use osgDB::readRef*File() methods. The later is preferable as it closes a potential threading bug when using paging databases in conjunction with the osgDB::Registry Object Cache. This threading bug occurs when one thread gets an object from the Cache via an osgDB::read*File() call where only a pointer to the object is passed back, so taking a reference to the object is delayed till it gets reassigned to a ref_ptr<>, but at the same time another thread calls a flush of the Object Cache deleting this object as it's referenceCount is now zero. Using osgDB::readREf*File() makes sure the a ref_ptr<> is passed back and the referenceCount never goes to zero. To ensure the OSG builds when OSG_PROVIDE_READFILE is to OFF the many cases of osgDB::read*File() usage had to be replaced with a ref_ptr<> osgDB::readRef*File() usage. The avoid this change causing lots of other client code to be rewritten to handle the use of ref_ptr<> in place of C pointer I introduced a serious of templte methods in various class to adapt ref_ptr<> to the underly C pointer to be passed to old OSG API's, example of this is found in include/osg/Group: bool addChild(Node* child); // old method which can only be used with a Node* tempalte<class T> bool addChild(const osg::ref_ptr<T>& child) { return addChild(child.get()); } // adapter template method These changes together cover 149 modified files, so it's a large submission. This extent of changes are warrent to make use of the Object Cache and multi-threaded loaded more robust. git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@15164 16af8721-9629-0410-8352-f15c8da7e697
2015-10-22 21:42:19 +08:00
viewer.setSceneData(loadedModel);
2014-05-14 18:19:43 +08:00
// create a tracball manipulator to move the camera around in response to keyboard/mouse events
viewer.setCameraManipulator( new osgGA::TrackballManipulator );
osg::ref_ptr<osgGA::StateSetManipulator> statesetManipulator = new osgGA::StateSetManipulator(viewer.getCamera()->getStateSet());
viewer.addEventHandler(statesetManipulator.get());
// add the pick handler
viewer.addEventHandler(pickhandler.get());
viewer.realize();
// main loop (note, window toolkits which take control over the main loop will require a window redraw callback containing the code below.)
while(!viewer.done())
{
viewer.frame();
}
return 0;
}