1 /* -*-c++-*- */
2 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
3  * Copyright 2008-2009 Pelican Ventures, Inc.
4  * http://osgearth.org
5  *
6  * osgEarth is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>
18  */
19 #include "GeodeticManifold"
20 #include <osgEarth/Registry>
21 
22 #define LC "[osgEarth::GeodeticManifold] "
23 
GeodeticManifold()24 GeodeticManifold::GeodeticManifold()
25 {
26     _profile = osgEarth::Registry::instance()->getGlobalGeodeticProfile();
27     _ellipsoid = _profile->getSRS()->getGeographicSRS()->getEllipsoid();
28 }
29 
30 void
initialize(MeshManager * mesh)31 GeodeticManifold::initialize( MeshManager* mesh )
32 {
33     mesh->_minGeomLevel = 1;
34     mesh->_minActiveLevel = 3;
35 
36     // Construct the "vertex diamonds".
37     _vd[0] = new Diamond(mesh, TileKey(), 0, "vd0"); // north pole 1
38     _vd[0]->setCoord( -90, 90, 0 );
39 
40     _vd[1] = new Diamond(mesh, TileKey(), 0, "vd1"); // north pole 2
41     _vd[1]->setCoord( 90, 90, 0 );
42 
43     _vd[2] = new Diamond(mesh, TileKey(), 0, "vd2"); // south pole 1
44     _vd[2]->setCoord( -90, -90, 0 );
45 
46     _vd[3] = new Diamond(mesh, TileKey(), 0, "vd3"); // south pole 2
47     _vd[3]->setCoord( 90, -90, 0 );
48 
49     _vd[4] = new Diamond(mesh, TileKey(), 0, "vd4");
50     _vd[4]->setCoord( -180, 0, 0 );
51 
52     _vd[5] = new Diamond(mesh, TileKey(), 0, "vd5");
53     _vd[5]->setCoord( 0, 0, 0 );
54 
55     // The 4 "face diamonds":
56     _fd[0] = new Diamond(mesh, TileKey(), 0, "fd0");
57     _fd[0]->setCoord( -90, 0, 0 );
58     _fd[0]->_a[GDPARENT] = _vd[0].get();
59     _fd[0]->_a[QUADTREE] = _vd[2].get();
60     _fd[0]->_a[PARENT_L] = _vd[4].get();
61     _fd[0]->_a[PARENT_R] = _vd[5].get();
62 
63     _fd[1] = new Diamond(mesh, TileKey(), 0, "fd1");
64     _fd[1]->setCoord( 90, 0, 0 );
65     _fd[1]->_a[GDPARENT] = _vd[3].get();
66     _fd[1]->_a[QUADTREE] = _vd[1].get();
67     _fd[1]->_a[PARENT_L] = _vd[4].get();
68     _fd[1]->_a[PARENT_R] = _vd[5].get();
69 
70     _fd[2] = new Diamond(mesh, TileKey(), 0, "fd2"); // virtual north pole diamond
71     _fd[2]->setCoord( 0, 90, 0 );
72     _fd[2]->_a[GDPARENT] = _vd[0].get();
73     _fd[2]->_a[QUADTREE] = _vd[1].get();
74     _fd[2]->_a[PARENT_L] = _vd[5].get();
75     _fd[2]->_a[PARENT_R] = _vd[4].get();
76 
77     _fd[3] = new Diamond(mesh, TileKey(), 0, "fd3"); // virtual south pole diamond
78     _fd[3]->setCoord( 0, -90, 0 );
79     _fd[3]->_a[GDPARENT] = _vd[3].get();
80     _fd[3]->_a[QUADTREE] = _vd[2].get();
81     _fd[3]->_a[PARENT_L] = _vd[5].get();
82     _fd[3]->_a[PARENT_R] = _vd[4].get();
83 
84     // the 8 "edge diamonds" (first with geometry)
85     _ed[0] = new Diamond(mesh, TileKey(1,0,0,_profile.get()), 1, "ed0");
86     _ed[0]->setCoord( -135, 45, 0 );
87     _ed[0]->_a[GDPARENT] = _vd[0].get();
88     _ed[0]->_a[QUADTREE] = _vd[4].get();
89     _ed[0]->_a[PARENT_L] = _fd[2].get();
90     _ed[0]->_a[PARENT_R] = _fd[0].get();
91     _ed[0]->_orientation = 0;
92 
93     _ed[1] = new Diamond(mesh, TileKey(1,1,0,_profile.get()), 1, "ed1");
94     _ed[1]->setCoord( -45, 45, 0 );
95     _ed[1]->_a[GDPARENT] = _vd[0].get();
96     _ed[1]->_a[QUADTREE] = _vd[5].get();
97     _ed[1]->_a[PARENT_L] = _fd[0].get();
98     _ed[1]->_a[PARENT_R] = _fd[2].get();
99     _ed[1]->_orientation = 2;
100 
101     _ed[2] = new Diamond(mesh, TileKey(1,0,1,_profile.get()), 1, "ed2");
102     _ed[2]->setCoord( -135, -45, 0 );
103     _ed[2]->_a[GDPARENT] = _vd[2].get();
104     _ed[2]->_a[QUADTREE] = _vd[4].get();
105     _ed[2]->_a[PARENT_L] = _fd[0].get();
106     _ed[2]->_a[PARENT_R] = _fd[3].get();
107     _ed[2]->_orientation = 6;
108 
109     _ed[3] = new Diamond(mesh, TileKey(1,1,1,_profile.get()), 1, "ed3");
110     _ed[3]->setCoord( -45, -45, 0 );
111     _ed[3]->_a[GDPARENT] = _vd[2].get();
112     _ed[3]->_a[QUADTREE] = _vd[5].get();
113     _ed[3]->_a[PARENT_L] = _fd[3].get();
114     _ed[3]->_a[PARENT_R] = _fd[0].get();
115     _ed[3]->_orientation = 4;
116 
117     _ed[4] = new Diamond(mesh, TileKey(1,2,0,_profile.get()), 1, "ed4");
118     _ed[4]->setCoord( 45, 45, 0 );
119     _ed[4]->_a[GDPARENT] = _vd[1].get();
120     _ed[4]->_a[QUADTREE] = _vd[5].get();
121     _ed[4]->_a[PARENT_L] = _fd[2].get();
122     _ed[4]->_a[PARENT_R] = _fd[1].get();
123     _ed[4]->_orientation = 0;
124 
125     _ed[5] = new Diamond(mesh, TileKey(1,3,0,_profile.get()), 1, "ed5");
126     _ed[5]->setCoord( 135, 45, 0 );
127     _ed[5]->_a[GDPARENT] = _vd[1].get();
128     _ed[5]->_a[QUADTREE] = _vd[4].get();
129     _ed[5]->_a[PARENT_L] = _fd[1].get();
130     _ed[5]->_a[PARENT_R] = _fd[2].get();
131     _ed[5]->_orientation = 2;
132 
133     _ed[6] = new Diamond(mesh, TileKey(1,2,1,_profile.get()), 1, "ed6");
134     _ed[6]->setCoord( 45, -45, 0 );
135     _ed[6]->_a[GDPARENT] = _vd[3].get();
136     _ed[6]->_a[QUADTREE] = _vd[5].get();
137     _ed[6]->_a[PARENT_L] = _fd[1].get();
138     _ed[6]->_a[PARENT_R] = _fd[3].get();
139     _ed[6]->_orientation = 6;
140 
141     _ed[7] = new Diamond(mesh, TileKey(1,3,1,_profile.get()), 1, "ed7");
142     _ed[7]->setCoord( 135, -45, 0 );
143     _ed[7]->_a[GDPARENT] = _vd[3].get();
144     _ed[7]->_a[QUADTREE] = _vd[4].get();
145     _ed[7]->_a[PARENT_L] = _fd[3].get();
146     _ed[7]->_a[PARENT_R] = _fd[1].get();
147     _ed[7]->_orientation = 7;
148 
149     // set child pointers:
150     _fd[0]->setChild( 0, _ed[3].get() );
151     _fd[0]->setChild( 1, _ed[1].get() );
152     _fd[0]->setChild( 2, _ed[0].get() );
153     _fd[0]->setChild( 3, _ed[2].get() );
154 
155     _fd[1]->setChild( 0, _ed[4].get() );
156     _fd[1]->setChild( 1, _ed[6].get() );
157     _fd[1]->setChild( 2, _ed[7].get() );
158     _fd[1]->setChild( 3, _ed[5].get() );
159 
160     _fd[2]->setChild( 0, _ed[5].get() );
161     _fd[2]->setChild( 1, _ed[0].get() );
162     _fd[2]->setChild( 2, _ed[1].get() );
163     _fd[2]->setChild( 3, _ed[4].get() );
164 
165     _fd[3]->setChild( 0, _ed[2].get() );
166     _fd[3]->setChild( 1, _ed[7].get() );
167     _fd[3]->setChild( 2, _ed[6].get() );
168     _fd[3]->setChild( 3, _ed[3].get() );
169 
170 
171     // seed the bouding spheres of the manifold diamonds:
172     for( unsigned short f=0; f<4; ++f )
173         _fd[f]->activate();
174 
175     for( unsigned short e=0; e<8; ++e )
176         _ed[e]->activate();
177 
178     // generate Level 3 (the first renderable quadtree decendants).
179     seed( 3 );
180 
181     // hopefully, that's it!
182 }
183 
184 //osg::Vec3d
185 //GeodeticManifold::project( const osg::Vec3d& coord ) const
186 //{
187 //    osg::Vec3d out;
188 //
189 //    _ellipsoid->convertLatLongHeightToXYZ(
190 //        osg::DegreesToRadians( coord.y() ),
191 //        osg::DegreesToRadians( coord.x() ), 0,
192 //        out.x(), out.y(), out.z() );
193 //
194 //    return out;
195 //}
196 
197 osg::Vec3d
midpoint(const osg::Vec3d & p0,const osg::Vec3d & p1) const198 GeodeticManifold::midpoint( const osg::Vec3d& p0, const osg::Vec3d& p1 ) const
199 {
200     //TODO account for date line crossing
201     return (p0+p1)*0.5;
202 }
203 
204 //osg::Vec3d
205 //GeodeticManifold::normal( const osg::Vec3d& vert ) const
206 //{
207 //    //TODO: this is spherical. adjust for ellipsoid if necessary.
208 //    osg::Vec3d n = vert;
209 //    n.normalize();
210 //    return n;
211 //}
212 
213 MeshNode
createNode(const osg::Vec3d & manCoord) const214 GeodeticManifold::createNode( const osg::Vec3d& manCoord ) const
215 {
216     MeshNode node;
217 
218     node._manifoldCoord = manCoord;
219 
220     node._geodeticCoord.set(
221         osg::DegreesToRadians(manCoord.x()), osg::DegreesToRadians(manCoord.y()), manCoord.z() );
222 
223     osg::Vec3d temp;
224     _ellipsoid->convertLatLongHeightToXYZ(
225         node._geodeticCoord.y(), node._geodeticCoord.x(), node._geodeticCoord.z(),
226         temp.x(), temp.y(), temp.z() );
227 
228     node._vertex = temp;
229 
230     node._normal = _ellipsoid->computeLocalUpVector(
231         temp.x(), temp.y(), temp.z() );
232 
233     return node;
234 }
235 
236 osg::BoundingSphere
initialBound() const237 GeodeticManifold::initialBound() const
238 {
239     return osg::BoundingSphere( osg::Vec3d(0,0,0), _ellipsoid->getRadiusEquator() * 1.2 );
240 }
241 
242 void
seed(Level maxLevel)243 GeodeticManifold::seed( Level maxLevel )
244 {
245     for( unsigned short e=0; e<8; ++e )
246     {
247         _ed[e]->seed( maxLevel );
248     }
249 }
250 
251 void
cull(osgUtil::CullVisitor * cv)252 GeodeticManifold::cull( osgUtil::CullVisitor* cv )
253 {
254     for( unsigned short e=0; e<8; ++e )
255     {
256         _ed[e]->cull( cv );
257     }
258 }
259