osgEarth 2.1.1
|
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/MeasureTool> 00021 #include <osgEarth/GeoMath> 00022 00023 #include <osgEarthFeatures/Feature> 00024 00025 using namespace osgEarth; 00026 using namespace osgEarth::Util; 00027 using namespace osgEarth::Symbology; 00028 using namespace osgEarth::Features; 00029 00030 00031 00032 00033 MeasureToolHandler::MeasureToolHandler( osg::Group* group, osgEarth::MapNode* mapNode ): 00034 _mouseDown(false), 00035 _group(group), 00036 _gotFirstLocation(false), 00037 _lastPointTemporary(false), 00038 _finished(false), 00039 _geoInterpolation( GEOINTERP_GREAT_CIRCLE ), 00040 _mouseButton( osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON), 00041 _isPath( false ), 00042 _mapNode( mapNode ), 00043 _intersectionMask(0xffffffff) 00044 { 00045 LineString* line = new LineString(); 00046 _feature = new Feature(); 00047 _feature->setGeometry( line ); 00048 _feature->geoInterp() = _geoInterpolation; 00049 00050 //Define a style for the line 00051 Style style; 00052 LineSymbol* ls = style.getOrCreateSymbol<LineSymbol>(); 00053 ls->stroke()->color() = osg::Vec4f( 1,0,0,1 ); 00054 ls->stroke()->width() = 2.0f; 00055 00056 _feature->style() = style; 00057 00058 _featureNode = new FeatureNode( _mapNode.get(), _feature.get(), false); 00059 00060 00061 //Disable lighting and depth testing for the feature graph 00062 _featureNode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); 00063 _featureNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); 00064 00065 _group->addChild (_featureNode.get() ); 00066 } 00067 00068 MeasureToolHandler::~MeasureToolHandler() 00069 { 00070 if (_group.valid()) _group->removeChild( _featureNode.get() ); 00071 } 00072 00073 bool 00074 MeasureToolHandler::getIsPath() const 00075 { 00076 return _isPath; 00077 } 00078 00079 void 00080 MeasureToolHandler::setIsPath( bool path ) 00081 { 00082 if (_isPath != path) 00083 { 00084 _isPath = path; 00085 _finished = true; 00086 clear(); 00087 _gotFirstLocation = false; 00088 } 00089 } 00090 00091 00092 GeoInterpolation 00093 MeasureToolHandler::getGeoInterpolation() const 00094 { 00095 return _geoInterpolation; 00096 } 00097 00098 void 00099 MeasureToolHandler::setGeoInterpolation( GeoInterpolation geoInterpolation ) 00100 { 00101 if (_geoInterpolation != geoInterpolation) 00102 { 00103 _geoInterpolation = geoInterpolation; 00104 _feature->geoInterp() = _geoInterpolation; 00105 _featureNode->init(); 00106 fireDistanceChanged(); 00107 } 00108 } 00109 00110 void 00111 MeasureToolHandler::setLineStyle( const Style& style ) 00112 { 00113 _feature->style() = style; 00114 _featureNode->init(); 00115 } 00116 00117 00118 bool MeasureToolHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) 00119 { 00120 if ( ea.getHandled() ) 00121 { 00122 return false; 00123 } 00124 00125 00126 osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView()); 00127 if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH && ea.getButton() == _mouseButton) 00128 { 00129 _mouseDown = true; 00130 _mouseDownX = ea.getX(); 00131 _mouseDownY = ea.getY(); 00132 } 00133 else if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE && ea.getButton() == _mouseButton) 00134 { 00135 float eps = 1.0f; 00136 _mouseDown = false; 00137 if (osg::equivalent(ea.getX(), _mouseDownX) && osg::equivalent(ea.getY(), _mouseDownY)) 00138 { 00139 double lon, lat; 00140 if (getLocationAt(view, ea.getX(), ea.getY(), lon, lat)) 00141 { 00142 if (!_gotFirstLocation) 00143 { 00144 _finished = false; 00145 clear(); 00146 _gotFirstLocation = true; 00147 _feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) ); 00148 } 00149 else 00150 { 00151 if (_lastPointTemporary) 00152 { 00153 _feature->getGeometry()->back() = osg::Vec3d( lon, lat, 0 ); 00154 _lastPointTemporary = false; 00155 } 00156 else 00157 { 00158 _feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) ); 00159 } 00160 _featureNode->init(); 00161 //_gotFirstLocation = false; 00162 //_finished = true; 00163 if (_finished || !_isPath) { 00164 _gotFirstLocation = false; 00165 } 00166 fireDistanceChanged(); 00167 } 00168 } 00169 } 00170 } 00171 else if (ea.getEventType() == osgGA::GUIEventAdapter::DOUBLECLICK) { 00172 if (_gotFirstLocation) 00173 { 00174 //_gotFirstLocation = false; 00175 _finished = true; 00176 return true; 00177 } 00178 } 00179 else if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE) 00180 { 00181 if (_gotFirstLocation) 00182 { 00183 double lon, lat; 00184 if (getLocationAt(view, ea.getX(), ea.getY(), lon, lat)) 00185 { 00186 if (!_lastPointTemporary) 00187 { 00188 _feature->getGeometry()->push_back( osg::Vec3d( lon, lat, 0 ) ); 00189 _lastPointTemporary = true; 00190 } 00191 else 00192 { 00193 _feature->getGeometry()->back() = osg::Vec3d( lon, lat, 0 ); 00194 } 00195 _featureNode->init(); 00196 fireDistanceChanged(); 00197 } 00198 } 00199 } 00200 return false; 00201 } 00202 00203 bool MeasureToolHandler::getLocationAt(osgViewer::View* view, double x, double y, double &lon, double &lat) 00204 { 00205 osgUtil::LineSegmentIntersector::Intersections results; 00206 if ( view->computeIntersections( x, y, results, _intersectionMask ) ) 00207 { 00208 // find the first hit under the mouse: 00209 osgUtil::LineSegmentIntersector::Intersection first = *(results.begin()); 00210 osg::Vec3d point = first.getWorldIntersectPoint(); 00211 00212 double lat_rad, lon_rad, height; 00213 _mapNode->getMap()->getProfile()->getSRS()->getEllipsoid()->convertXYZToLatLongHeight( point.x(), point.y(), point.z(), lat_rad, lon_rad, height ); 00214 lat = osg::RadiansToDegrees( lat_rad ); 00215 lon = osg::RadiansToDegrees( lon_rad ); 00216 return true; 00217 } 00218 return false; 00219 } 00220 00221 void MeasureToolHandler::clear() 00222 { 00223 //Clear the locations 00224 _feature->getGeometry()->clear(); 00225 //_features->dirty(); 00226 _featureNode->init(); 00227 fireDistanceChanged(); 00228 00229 _gotFirstLocation = false; 00230 _lastPointTemporary = false; 00231 } 00232 00233 void 00234 MeasureToolHandler::setMouseButton(int mouseButton) 00235 { 00236 _mouseButton = mouseButton; 00237 } 00238 00239 int 00240 MeasureToolHandler::getMouseButton() const 00241 { 00242 return _mouseButton; 00243 } 00244 00245 00246 void MeasureToolHandler::addEventHandler(MeasureToolEventHandler* handler ) 00247 { 00248 _eventHandlers.push_back( handler ); 00249 } 00250 00251 00252 void MeasureToolHandler::fireDistanceChanged() 00253 { 00254 double distance = 0; 00255 if (_geoInterpolation == GEOINTERP_GREAT_CIRCLE) 00256 { 00257 distance = GeoMath::distance(_feature->getGeometry()->asVector()); 00258 } 00259 else if (_geoInterpolation == GEOINTERP_RHUMB_LINE) 00260 { 00261 distance = GeoMath::rhumbDistance(_feature->getGeometry()->asVector()); 00262 } 00263 for (MeasureToolEventHandlerList::const_iterator i = _eventHandlers.begin(); i != _eventHandlers.end(); ++i) 00264 { 00265 i->get()->onDistanceChanged( this, distance ); 00266 } 00267 }