osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthUtil/ClampCallback.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003 * Copyright 2008-2010 Pelican Mapping
00004 * http://osgearth.org
00005 *
00006 * osgEarth is free software; you can redistribute it and/or modify
00007 * it under the terms of the GNU Lesser General Public License as published by
00008 * the Free Software Foundation; either version 2 of the License, or
00009 * (at your option) any later version.
00010 *
00011 * This program is distributed in the hope that it will be useful,
00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 * GNU Lesser General Public License for more details.
00015 *
00016 * You should have received a copy of the GNU Lesser General Public License
00017 * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018 */
00019 
00020 #include <osgEarthUtil/ClampCallback>
00021 #include <osgEarth/Notify>
00022 #include <osgUtil/IntersectionVisitor>
00023 #include <osgUtil/LineSegmentIntersector>
00024 #include <osgEarth/FindNode>
00025 #include <OpenThreads/ScopedLock>
00026 #include <osg/MatrixTransform>
00027 
00028 #include <osg/io_utils>
00029 
00030 using namespace osg;
00031 using namespace osgEarth;
00032 using namespace osgEarth::Util;
00033 using namespace OpenThreads;
00034 
00035 ClampCallback::ClampCallback(osg::Node* terrainNode)
00036 {
00037     _offset = 0;
00038     _lastCulledFrame = 0;
00039     setTerrainNode( terrainNode );
00040     _intersectionMask = 0xffffffff;
00041 }
00042 
00043 bool ClampCallback::clamp(const osg::Vec3d& pos, osg::Vec3d& out) const
00044 {
00045     //Return if there is no terrain node assigned
00046     if (!_terrainNode.valid()) return false;    
00047 
00048     //Compute the up vector
00049     osg::Vec3d up = _csn.valid() ? _csn->computeLocalUpVector( pos ) : osg::Vec3d(0,0,1);
00050     up.normalize();
00051 
00052     double segOffset = 50000;
00053 
00054     osg::Vec3d start = pos + (up * segOffset);
00055     osg::Vec3d end = pos - (up * segOffset);
00056     
00057     osgUtil::LineSegmentIntersector* i = new osgUtil::LineSegmentIntersector( start, end );
00058     
00059     osgUtil::IntersectionVisitor iv;
00060     iv.setTraversalMask(_intersectionMask);
00061     iv.setIntersector( i );
00062     _terrainNode->accept( iv );
00063 
00064     osgUtil::LineSegmentIntersector::Intersections& results = i->getIntersections();
00065     if ( !results.empty() )
00066     {
00067         const osgUtil::LineSegmentIntersector::Intersection& result = *results.begin();
00068         out = result.getWorldIntersectPoint();
00069         out += (up * _offset);
00070         return true;
00071     }
00072     return false;    
00073 }
00074 
00075 bool ClampCallback::clampGeometry(osg::Geometry* geom, const osg::Matrixd& localToWorld, const osg::Matrixd& worldToLocal) const
00076 {
00077     osg::Vec3Array* verts = static_cast<osg::Vec3Array*>(geom->getVertexArray());
00078     for (unsigned int i = 0; i < verts->size(); ++i)
00079     {
00080         osg::Vec3d pos = (*verts)[i];
00081         pos = pos * localToWorld;
00082         
00083         osg::Vec3d out;
00084         if (clamp(pos, out))
00085         {
00086             out = out * worldToLocal;
00087             (*verts)[i].set(out.x(), out.y(), out.z() );
00088         }
00089     }
00090     geom->dirtyBound();
00091     geom->dirtyDisplayList();
00092 
00093     return true;
00094 }
00095 
00096 void ClampCallback::setTerrainNode(osg::Node* terrainNode)
00097 {
00098     _terrainNode = terrainNode;
00099     if (_terrainNode.valid())
00100     {
00101         _csn = findTopMostNodeOfType<osg::CoordinateSystemNode>(_terrainNode.get());
00102     }
00103 }
00104 
00105 void ClampCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
00106 {
00107     if (nv->getVisitorType() == NodeVisitor::UPDATE_VISITOR)
00108     {
00109         //Only clamp if this node has been culled in the last few frames
00110         if (nv->getFrameStamp()->getFrameNumber() - _lastCulledFrame < 2)
00111         {
00112             osg::MatrixTransform* mt = dynamic_cast<osg::MatrixTransform*>(node);
00113             if (mt)
00114             {
00115                 osg::Matrixd matrix = mt->getMatrix();
00116                 osg::Vec3d pos = matrix.getTrans();
00117                 osg::Vec3d clamped;
00118                 if (clamp(pos, clamped))
00119                 {
00120                     //We need to translate the current matrix by an amount that would move the current position to the clamped position
00121                     osg::Vec3d trans = (clamped - pos );
00122                     matrix *= osg::Matrixd::translate( trans );
00123                     mt->setMatrix( matrix );
00124                 }
00125             }
00126             else
00127             {
00128                 osg::Geode* geode = dynamic_cast<osg::Geode*>(node);
00129                 if (geode)
00130                 {
00131                     osg::Matrixd localToWorld = osg::computeLocalToWorld( nv->getNodePath() );
00132                     osg::Matrixd worldToLocal = osg::computeWorldToLocal( nv->getNodePath() );
00133 
00134                     for (unsigned int i = 0; i < geode->getNumDrawables(); ++i)
00135                     {
00136                         osg::Geometry* geom = geode->getDrawable(i)->asGeometry();
00137                         if (geom)
00138                         {
00139                             clampGeometry( geom, localToWorld, worldToLocal);
00140                         }
00141                     }
00142                 }
00143             }
00144         }
00145     }
00146     else if (nv->getVisitorType() == NodeVisitor::CULL_VISITOR)
00147     {                   
00148         _lastCulledFrame = nv->getFrameStamp()->getFrameNumber();
00149     }
00150     //Continue traversal
00151     traverse(node, nv);
00152 }
00153 
00154 void
00155 ClampCallback::setOffset(double offset)
00156 {
00157     _offset = offset;
00158 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines