Skip to content

Commit

Permalink
Merge branch 'master' of github.com:gwaldron/osgearth
Browse files Browse the repository at this point in the history
  • Loading branch information
gwaldron committed Feb 5, 2015
2 parents 6e54311 + 376e954 commit c43738e
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 26 deletions.
42 changes: 41 additions & 1 deletion src/applications/osgearth_manip/osgearth_manip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ namespace
"c :", "toggle perspective/ortho",
"t :", "toggle tethering",
"a :", "toggle viewpoint arcing",
"z :", "toggle throwing"
"z :", "toggle throwing",
"k :", "toggle collision"
};

Grid* g = new Grid();
Expand Down Expand Up @@ -253,6 +254,38 @@ namespace
osg::ref_ptr<EarthManipulator> _manip;
};

/**
* Toggles the collision feature.
*/
struct ToggleCollisionHandler : public osgGA::GUIEventHandler
{
ToggleCollisionHandler(char key, EarthManipulator* manip)
: _key(key), _manip(manip)
{
}

bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
bool collision = _manip->getSettings()->getDisableCollisionAvoidance();
_manip->getSettings()->setDisableCollisionAvoidance( !collision );
aa.requestRedraw();
return true;
}
return false;
}

void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Toggle collision avoidance"));
}

char _key;
osg::ref_ptr<EarthManipulator> _manip;
};


/**
* A simple simulator that moves an object around the Earth. We use this to
Expand Down Expand Up @@ -381,6 +414,9 @@ int main(int argc, char** argv)
manip->getSettings()->getBreakTetherActions().push_back( EarthManipulator::ACTION_PAN );
manip->getSettings()->getBreakTetherActions().push_back( EarthManipulator::ACTION_GOTO );

// Set the minimum distance to something larger than the default
manip->getSettings()->setMinMaxDistance(5.0, manip->getSettings()->getMaxDistance());


viewer.setSceneData( root );

Expand All @@ -396,6 +432,10 @@ int main(int argc, char** argv)
viewer.addEventHandler(new ToggleProjectionHandler('c', manip));
viewer.addEventHandler(new ToggleArcViewpointTransitionsHandler('a', manip));
viewer.addEventHandler(new ToggleThrowingHandler('z', manip));
viewer.addEventHandler(new ToggleCollisionHandler('k', manip));

viewer.getCamera()->setNearFarRatio(0.00002);
viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);

while(!viewer.done())
{
Expand Down
6 changes: 5 additions & 1 deletion src/osgEarthUtil/EarthManipulator
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <osgEarth/GeoData>
#include <osgEarth/Revisioning>
#include <osgEarth/Terrain>
#include <osgEarth/MapNode>
#include <osg/Timer>
#include <osgGA/CameraManipulator>
#include <map>
Expand Down Expand Up @@ -738,7 +739,7 @@ namespace osgEarth { namespace Util

virtual ~EarthManipulator();

bool intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const;
bool intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection, osg::Vec3d& normal) const;

bool intersectLookVector(osg::Vec3d& eye, osg::Vec3d& out_target, osg::Vec3d& up) const;

Expand Down Expand Up @@ -889,6 +890,7 @@ namespace osgEarth { namespace Util

osg::observer_ptr<osg::Node> _node;
osg::observer_ptr<osg::CoordinateSystemNode> _csn;
osg::observer_ptr<MapNode> _mapNode;
#ifdef USE_OBSERVER_NODE_PATH
osg::ObserverNodePath _csnObserverPath;
#endif
Expand Down Expand Up @@ -997,6 +999,8 @@ namespace osgEarth { namespace Util

// Traversal mask used in established and dtor methods to find MapNode and CoordinateSystemNode
osg::Node::NodeMask _findNodeTraversalMask;

void collisionDetect();
};

} } // namespace osgEarth::Util
Expand Down
116 changes: 92 additions & 24 deletions src/osgEarthUtil/EarthManipulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ namespace


//------------------------------------------------------------------------
namespace
{
// Callback that notifies the manipulator whenever the terrain changes
// around its center point.
struct ManipTerrainCallback : public TerrainCallback
{
ManipTerrainCallback(EarthManipulator* manip) : _manip(manip) { }
void onTileAdded(const TileKey& key, osg::Node* tile, TerrainCallbackContext& context)
{
osg::ref_ptr<EarthManipulator> safe;
if ( _manip.lock(safe) )
{
safe->handleTileAdded(key, tile, context);
}
}
osg::observer_ptr<EarthManipulator> _manip;
};
}



Expand Down Expand Up @@ -450,15 +468,10 @@ _findNodeTraversalMask ( rhs._findNodeTraversalMask )

EarthManipulator::~EarthManipulator()
{
osg::ref_ptr<osg::Node> safeNode = _node.get();
if (safeNode && _terrainCallback)
osg::ref_ptr<MapNode> mapNode = _mapNode;
if (mapNode.valid() && _terrainCallback)
{
// find a map node.
MapNode* mapNode = MapNode::findMapNode( safeNode.get(), _findNodeTraversalMask );
if ( mapNode )
{
mapNode->getTerrain()->removeTerrainCallback( _terrainCallback );
}
mapNode->getTerrain()->removeTerrainCallback( _terrainCallback );
}
}

Expand Down Expand Up @@ -595,6 +608,19 @@ EarthManipulator::established()
// find a CSN node - if there is one, we want to attach the manip to that
_csn = findRelativeNodeOfType<osg::CoordinateSystemNode>( safeNode.get(), _findNodeTraversalMask );

_mapNode = osgEarth::MapNode::findMapNode( safeNode.get() );

if (_mapNode.valid())
{
if ( _terrainCallback.valid() )
{
_mapNode->getTerrain()->removeTerrainCallback( _terrainCallback.get() );
}

_terrainCallback = new ManipTerrainCallback( this );
_mapNode->getTerrain()->addTerrainCallback( _terrainCallback );
}

if ( _csn.valid() )
{
_node = _csn.get();
Expand Down Expand Up @@ -651,19 +677,18 @@ EarthManipulator::established()
void
EarthManipulator::handleTileAdded(const TileKey& key, osg::Node* tile, TerrainCallbackContext& context)
{
#if 0
// Only do collision avoidance if it's enabled, we're not tethering and we're not in the middle of setting a viewpoint.
if (!getSettings()->getDisableCollisionAvoidance() &&
!getTetherNode() &&
!isSettingViewpoint() )
{
{
const GeoPoint& pt = centerMap();
if ( key.getExtent().contains(pt.x(), pt.y()) )
{
recalculateCenterFromLookVector();
collisionDetect();
}
}
#endif
}

bool
Expand Down Expand Up @@ -705,6 +730,7 @@ EarthManipulator::setNode(osg::Node* node)
{
_node = node;
_csn = 0L;
_mapNode = 0L;

if ( _viewCamera.valid() && _cameraUpdateCB.valid() )
{
Expand Down Expand Up @@ -742,12 +768,11 @@ EarthManipulator::getSRS() const

nonconst_this->_is_geocentric = false;

// first try to find a map node:
osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode( safeNode.get() );
if ( mapNode )
// first try to find a map node:
if ( _mapNode.valid() )
{
nonconst_this->_cached_srs = mapNode->getMap()->getProfile()->getSRS();
nonconst_this->_is_geocentric = mapNode->isGeocentric();
nonconst_this->_cached_srs = _mapNode->getMap()->getProfile()->getSRS();
nonconst_this->_is_geocentric = _mapNode->isGeocentric();
}

// if that doesn't work, try gleaning info from a CSN:
Expand Down Expand Up @@ -977,7 +1002,42 @@ EarthManipulator::setViewpoint( const Viewpoint& vp, double duration_s )
osg::Matrix new_rot = osg::Matrixd( azim_q * pitch_q );

_rotation = osg::Matrixd::inverse(new_rot).getRotate();
}

collisionDetect();
}

void EarthManipulator::collisionDetect()
{
if (getSettings()->getDisableCollisionAvoidance())
{
return;
}

// The camera has changed, so make sure we aren't under the ground.

osg::Vec3d eye = getMatrix().getTrans();
osg::CoordinateFrame eyeCoordFrame;
createLocalCoordFrame( eye, eyeCoordFrame );
osg::Vec3d eyeUp = getUpVector(eyeCoordFrame);

// Try to intersect the terrain with a vector going
double r = std::min( _cached_srs->getEllipsoid()->getRadiusEquator(), _cached_srs->getEllipsoid()->getRadiusPolar() );
osg::Vec3d ip, normal;
if (intersect(eye + eyeUp * r, eye - eyeUp * r, ip, normal))
{
double eps = _settings->getMinDistance();
// Now determine if the point is above the ground or not
osg::Vec3d v0 = eyeUp;
v0.normalize();
osg::Vec3d v1 = eye - (ip + eyeUp * eps);
v1.normalize();
if (v0 * v1 <= 0 )
{
setByLookAtRaw(ip + normal * eps, _center, eyeUp);
}
}

}

void
Expand Down Expand Up @@ -1118,7 +1178,7 @@ EarthManipulator::getTetherNode() const


bool
EarthManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection) const
EarthManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg::Vec3d& intersection, osg::Vec3d& normal) const
{
osg::ref_ptr<osg::Node> safeNode = _node.get();
if ( safeNode.valid() )
Expand All @@ -1136,6 +1196,7 @@ EarthManipulator::intersect(const osg::Vec3d& start, const osg::Vec3d& end, osg:
if (lsi->containsIntersections())
{
intersection = lsi->getIntersections().begin()->getWorldIntersectPoint();
normal = lsi->getIntersections().begin()->getWorldIntersectNormal();
return true;
}
}
Expand Down Expand Up @@ -2066,9 +2127,9 @@ EarthManipulator::setByMatrix(const osg::Matrixd& matrix)
osg::Vec3d start_segment = eye;
osg::Vec3d end_segment = eye + lookVector*distance;

osg::Vec3d ip;
osg::Vec3d ip, normal;
bool hitFound = false;
if (intersect(start_segment, end_segment, ip))
if (intersect(start_segment, end_segment, ip, normal))
{
setCenter( ip );
_centerRotation = makeCenterRotation(_center);
Expand All @@ -2088,7 +2149,7 @@ EarthManipulator::setByMatrix(const osg::Matrixd& matrix)

osg::Vec3d eyeUp = getUpVector(eyeCoordFrame);

if (intersect(eye + eyeUp*distance, eye - eyeUp*distance, ip))
if (intersect(eye + eyeUp*distance, eye - eyeUp*distance, ip, normal))
{
setCenter( ip );
_centerRotation = makeCenterRotation(_center);
Expand All @@ -2104,6 +2165,8 @@ EarthManipulator::setByMatrix(const osg::Matrixd& matrix)

recalculateRoll();
//recalculateLocalPitchAndAzimuth();

collisionDetect();
}

osg::Matrixd
Expand Down Expand Up @@ -2147,8 +2210,8 @@ EarthManipulator::setByLookAt(const osg::Vec3d& eye,const osg::Vec3d& center,con
{
// compute the intersection with the scene.

osg::Vec3d ip;
if (intersect(eye, endPoint, ip))
osg::Vec3d ip, normal;
if (intersect(eye, endPoint, ip, normal))
{
setCenter( ip );
setDistance( (ip-eye).length() );
Expand Down Expand Up @@ -2219,9 +2282,10 @@ EarthManipulator::recalculateCenter( const osg::CoordinateFrame& frame )

osg::Vec3d ip1;
osg::Vec3d ip2;
osg::Vec3d normal;
// extend coordonate to fall on the edge of the boundingbox see http://www.osgearth.org/ticket/113
bool hit_ip1 = intersect(_center - up * ilen * 0.1, _center + up * ilen, ip1);
bool hit_ip2 = intersect(_center + up * ilen * 0.1, _center - up * ilen, ip2);
bool hit_ip1 = intersect(_center - up * ilen * 0.1, _center + up * ilen, ip1, normal);
bool hit_ip2 = intersect(_center + up * ilen * 0.1, _center - up * ilen, ip2, normal);
if (hit_ip1)
{
if (hit_ip2)
Expand Down Expand Up @@ -2330,6 +2394,8 @@ EarthManipulator::pan( double dx, double dy )
if (_offset_x > _settings->getMaxXOffset()) _offset_x = _settings->getMaxXOffset();
if (_offset_y > _settings->getMaxYOffset()) _offset_y = _settings->getMaxYOffset();
}

collisionDetect();
}

void
Expand Down Expand Up @@ -2380,6 +2446,7 @@ EarthManipulator::rotate( double dx, double dy )
rotate_azim.makeRotate(-dx,localUp);

_rotation = _rotation * rotate_elevation * rotate_azim;
collisionDetect();
}

void
Expand All @@ -2391,6 +2458,7 @@ EarthManipulator::zoom( double dx, double dy )

double scale = 1.0f + dy;
setDistance( _distance * scale );
collisionDetect();
}


Expand Down

0 comments on commit c43738e

Please sign in to comment.