CoordinateSystemNode 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
  2. *
  3. * This library is open source and may be redistributed and/or modified under
  4. * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
  5. * (at your option) any later version. The full license is in LICENSE file
  6. * included with this distribution, and on the openscenegraph.org website.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * OpenSceneGraph Public License for more details.
  12. */
  13. #ifndef OSG_COORDINATESYSTEMNODE
  14. #define OSG_COORDINATESYSTEMNODE 1
  15. #include <osg/Group>
  16. #include <osg/Matrixd>
  17. namespace osg
  18. {
  19. const double WGS_84_RADIUS_EQUATOR = 6378137.0;
  20. const double WGS_84_RADIUS_POLAR = 6356752.3142;
  21. /** EllipsoidModel encapsulates the ellipsoid used to model astronomical bodies,
  22. * such as sun, planets, moon etc.
  23. * All distance quantities (i.e. heights + radius) are in meters,
  24. * and latitude and longitude are in radians.*/
  25. class EllipsoidModel : public Object
  26. {
  27. public:
  28. /** WGS_84 is a common representation of the earth's spheroid */
  29. EllipsoidModel(double radiusEquator = WGS_84_RADIUS_EQUATOR,
  30. double radiusPolar = WGS_84_RADIUS_POLAR):
  31. _radiusEquator(radiusEquator),
  32. _radiusPolar(radiusPolar) { computeCoefficients(); }
  33. EllipsoidModel(const EllipsoidModel& et,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
  34. Object(et,copyop),
  35. _radiusEquator(et._radiusEquator),
  36. _radiusPolar(et._radiusPolar) { computeCoefficients(); }
  37. META_Object(osg,EllipsoidModel);
  38. void setRadiusEquator(double radius) { _radiusEquator = radius; computeCoefficients(); }
  39. double getRadiusEquator() const { return _radiusEquator; }
  40. void setRadiusPolar(double radius) { _radiusPolar = radius; computeCoefficients(); }
  41. double getRadiusPolar() const { return _radiusPolar; }
  42. inline void convertLatLongHeightToXYZ(double latitude, double longitude, double height,
  43. double& X, double& Y, double& Z) const;
  44. inline void convertXYZToLatLongHeight(double X, double Y, double Z,
  45. double& latitude, double& longitude, double& height) const;
  46. inline void computeLocalToWorldTransformFromLatLongHeight(double latitude, double longitude, double height, osg::Matrixd& localToWorld) const;
  47. inline void computeLocalToWorldTransformFromXYZ(double X, double Y, double Z, osg::Matrixd& localToWorld) const;
  48. inline void computeCoordinateFrame(double latitude, double longitude, osg::Matrixd& localToWorld) const;
  49. inline osg::Vec3d computeLocalUpVector(double X, double Y, double Z) const;
  50. // Convenience method for determining if EllipsoidModel is a stock WGS84 ellipsoid
  51. inline bool isWGS84() const {return(_radiusEquator == WGS_84_RADIUS_EQUATOR && _radiusPolar == WGS_84_RADIUS_POLAR);}
  52. // Compares two EllipsoidModel by comparing critical internal values.
  53. // Ignores _eccentricitySquared since it's just a cached value derived from
  54. // the _radiusEquator and _radiusPolar members.
  55. friend bool operator == ( const EllipsoidModel & e1, const EllipsoidModel& e2) {return(e1._radiusEquator == e2._radiusEquator && e1._radiusPolar == e2._radiusPolar);}
  56. protected:
  57. void computeCoefficients()
  58. {
  59. double flattening = (_radiusEquator-_radiusPolar)/_radiusEquator;
  60. _eccentricitySquared = 2*flattening - flattening*flattening;
  61. }
  62. double _radiusEquator;
  63. double _radiusPolar;
  64. double _eccentricitySquared;
  65. };
  66. /** CoordinateFrame encapsulates the orientation of east, north and up.*/
  67. typedef Matrixd CoordinateFrame;
  68. /** CoordinateSystem encapsulate the coordinate system that is associated with objects in a scene.
  69. For an overview of common earth bases coordinate systems see http://www.colorado.edu/geography/gcraft/notes/coordsys/coordsys_f.html */
  70. class OSG_EXPORT CoordinateSystemNode : public Group
  71. {
  72. public:
  73. CoordinateSystemNode();
  74. CoordinateSystemNode(const std::string& format, const std::string& cs);
  75. /** Copy constructor using CopyOp to manage deep vs shallow copy.*/
  76. CoordinateSystemNode(const CoordinateSystemNode&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
  77. META_Node(osg,CoordinateSystemNode);
  78. /** Set the coordinate system node up by copying the format, coordinate system string, and ellipsoid model of another coordinate system node.*/
  79. void set(const CoordinateSystemNode& csn);
  80. /** Set the coordinate system format string. Typical values would be WKT, PROJ4, USGS etc.*/
  81. void setFormat(const std::string& format) { _format = format; }
  82. /** Get the coordinate system format string.*/
  83. const std::string& getFormat() const { return _format; }
  84. /** Set the CoordinateSystem reference string, should be stored in a form consistent with the Format.*/
  85. void setCoordinateSystem(const std::string& cs) { _cs = cs; }
  86. /** Get the CoordinateSystem reference string.*/
  87. const std::string& getCoordinateSystem() const { return _cs; }
  88. /** Set EllipsoidModel to describe the model used to map lat, long and height into geocentric XYZ and back. */
  89. void setEllipsoidModel(EllipsoidModel* ellipsode) { _ellipsoidModel = ellipsode; }
  90. /** Get the EllipsoidModel.*/
  91. EllipsoidModel* getEllipsoidModel() { return _ellipsoidModel.get(); }
  92. /** Get the const EllipsoidModel.*/
  93. const EllipsoidModel* getEllipsoidModel() const { return _ellipsoidModel.get(); }
  94. /** Compute the local coordinate frame for specified point.*/
  95. CoordinateFrame computeLocalCoordinateFrame(const Vec3d& position) const;
  96. /** Compute the local up-vector for specified point.*/
  97. osg::Vec3d computeLocalUpVector(const Vec3d& position) const;
  98. protected:
  99. virtual ~CoordinateSystemNode() {}
  100. std::string _format;
  101. std::string _cs;
  102. ref_ptr<EllipsoidModel> _ellipsoidModel;
  103. };
  104. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. // implement inline methods.
  106. //
  107. inline void EllipsoidModel::convertLatLongHeightToXYZ(double latitude, double longitude, double height,
  108. double& X, double& Y, double& Z) const
  109. {
  110. // for details on maths see http://www.colorado.edu/geography/gcraft/notes/datum/gif/llhxyz.gif
  111. double sin_latitude = sin(latitude);
  112. double cos_latitude = cos(latitude);
  113. double N = _radiusEquator / sqrt( 1.0 - _eccentricitySquared*sin_latitude*sin_latitude);
  114. X = (N+height)*cos_latitude*cos(longitude);
  115. Y = (N+height)*cos_latitude*sin(longitude);
  116. Z = (N*(1-_eccentricitySquared)+height)*sin_latitude;
  117. }
  118. inline void EllipsoidModel::convertXYZToLatLongHeight(double X, double Y, double Z,
  119. double& latitude, double& longitude, double& height) const
  120. {
  121. // handle polar and center-of-earth cases directly.
  122. if (X != 0.0)
  123. longitude = atan2(Y,X);
  124. else
  125. {
  126. if (Y > 0.0)
  127. longitude = PI_2;
  128. else if (Y < 0.0)
  129. longitude = -PI_2;
  130. else
  131. {
  132. // at pole or at center of the earth
  133. longitude = 0.0;
  134. if (Z > 0.0)
  135. { // north pole.
  136. latitude = PI_2;
  137. height = Z - _radiusPolar;
  138. }
  139. else if (Z < 0.0)
  140. { // south pole.
  141. latitude = -PI_2;
  142. height = -Z - _radiusPolar;
  143. }
  144. else
  145. { // center of earth.
  146. latitude = PI_2;
  147. height = -_radiusPolar;
  148. }
  149. return;
  150. }
  151. }
  152. // http://www.colorado.edu/geography/gcraft/notes/datum/gif/xyzllh.gif
  153. double p = sqrt(X*X + Y*Y);
  154. double theta = atan2(Z*_radiusEquator , (p*_radiusPolar));
  155. double eDashSquared = (_radiusEquator*_radiusEquator - _radiusPolar*_radiusPolar)/
  156. (_radiusPolar*_radiusPolar);
  157. double sin_theta = sin(theta);
  158. double cos_theta = cos(theta);
  159. latitude = atan( (Z + eDashSquared*_radiusPolar*sin_theta*sin_theta*sin_theta) /
  160. (p - _eccentricitySquared*_radiusEquator*cos_theta*cos_theta*cos_theta) );
  161. double sin_latitude = sin(latitude);
  162. double N = _radiusEquator / sqrt( 1.0 - _eccentricitySquared*sin_latitude*sin_latitude);
  163. height = p/cos(latitude) - N;
  164. }
  165. inline void EllipsoidModel::computeLocalToWorldTransformFromLatLongHeight(double latitude, double longitude, double height, osg::Matrixd& localToWorld) const
  166. {
  167. double X, Y, Z;
  168. convertLatLongHeightToXYZ(latitude,longitude,height,X,Y,Z);
  169. localToWorld.makeTranslate(X,Y,Z);
  170. computeCoordinateFrame(latitude, longitude, localToWorld);
  171. }
  172. inline void EllipsoidModel::computeLocalToWorldTransformFromXYZ(double X, double Y, double Z, osg::Matrixd& localToWorld) const
  173. {
  174. double latitude, longitude, height;
  175. convertXYZToLatLongHeight(X,Y,Z,latitude,longitude,height);
  176. localToWorld.makeTranslate(X,Y,Z);
  177. computeCoordinateFrame(latitude, longitude, localToWorld);
  178. }
  179. inline void EllipsoidModel::computeCoordinateFrame(double latitude, double longitude, osg::Matrixd& localToWorld) const
  180. {
  181. // Compute up vector
  182. osg::Vec3d up ( cos(longitude)*cos(latitude), sin(longitude)*cos(latitude), sin(latitude));
  183. // Compute east vector
  184. osg::Vec3d east (-sin(longitude), cos(longitude), 0);
  185. // Compute north vector = outer product up x east
  186. osg::Vec3d north = up ^ east;
  187. // set matrix
  188. localToWorld(0,0) = east[0];
  189. localToWorld(0,1) = east[1];
  190. localToWorld(0,2) = east[2];
  191. localToWorld(1,0) = north[0];
  192. localToWorld(1,1) = north[1];
  193. localToWorld(1,2) = north[2];
  194. localToWorld(2,0) = up[0];
  195. localToWorld(2,1) = up[1];
  196. localToWorld(2,2) = up[2];
  197. }
  198. inline osg::Vec3d EllipsoidModel::computeLocalUpVector(double X, double Y, double Z) const
  199. {
  200. // Note latitude is angle between normal to ellipsoid surface and XY-plane
  201. double latitude;
  202. double longitude;
  203. double altitude;
  204. convertXYZToLatLongHeight(X,Y,Z,latitude,longitude,altitude);
  205. // Compute up vector
  206. return osg::Vec3d( cos(longitude) * cos(latitude),
  207. sin(longitude) * cos(latitude),
  208. sin(latitude));
  209. }
  210. }
  211. #endif