osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/engine_seamless/PatchSet.cpp

Go to the documentation of this file.
00001 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00002  * Copyright 2010 Pelican Ventures, Inc.
00003  * http://osgearth.org
00004  *
00005  * osgEarth is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU Lesser General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00017  */
00018 
00019 #include <algorithm>
00020 
00021 #include "PatchSet"
00022 
00023 #include <osg/Math>
00024 #include <osg/MatrixTransform>
00025 
00026 #include "Patch"
00027 #include "PatchGroup"
00028 
00029 namespace seamless
00030 {
00031 using namespace osg;
00032 using namespace osgEarth;
00033 
00034 PatchSet::PatchSet()
00035     : _maxLevel(16), _patchOptionsPrototype(new PatchOptions), _mapf(0),
00036       _resolution(128), _verticalScale(1.0f)
00037 {
00038     setPrecisionFactor(4);
00039     initPrimitiveSets();
00040 
00041 }
00042 
00043 PatchSet::PatchSet(const Drivers::SeamlessOptions& options,
00044                    PatchOptions* poptionsPrototype)
00045     :  _maxLevel(16),
00046        _patchOptionsPrototype(poptionsPrototype ? poptionsPrototype
00047                               : new PatchOptions),
00048        _mapf(0), _options(options)
00049 {
00050     _resolution = options.resolution().value();
00051     _verticalScale = options.verticalScale().value();
00052     setPrecisionFactor(4);
00053     initPrimitiveSets();
00054 }
00055 
00056 PatchSet::PatchSet(const PatchSet& rhs, const CopyOp& copyop)
00057     : _precisionFactor(rhs._precisionFactor), _resolution(rhs._resolution),
00058       _maxLevel(rhs._maxLevel), _verticalScale(rhs._verticalScale),
00059       _patchOptionsPrototype(static_cast<PatchOptions*>(copyop(rhs._patchOptionsPrototype.get()))),
00060       _map(static_cast<Map*>(copyop(rhs._map.get())))
00061 {
00062     _patchOptionsPrototype
00063         = static_cast<PatchOptions*>(copyop(_patchOptionsPrototype.get()));
00064     for (int j = 0; j < 2; ++j)
00065         for (int i = 0; j < 4; ++i)
00066             trilePset[j][i]
00067                 = static_cast<DrawElementsUShort*>(copyop(rhs.trilePset[j][i].get()));
00068     for (int j = 0; j < 4; ++j)
00069         for (int i = 0; j < 4; ++i)
00070             stripPset[j][i]
00071                 = static_cast<DrawElementsUShort*>(copyop(rhs.stripPset[j][i].get()));
00072     if (rhs._mapf)
00073         _mapf = new MapFrame(*_mapf);
00074 }
00075 
00076 PatchSet::~PatchSet()
00077 {
00078     delete _mapf;
00079 }
00080 
00081 void PatchSet::setMap(const Map* map)
00082 {
00083     _map = map;
00084     if (map)
00085     {
00086         delete _mapf;
00087         _mapf = new MapFrame(map, Map::TERRAIN_LAYERS, "seamless");
00088     }
00089 }
00090 
00091 Node* PatchSet::createPatchGroup(const std::string& filename,
00092                                  PatchOptions* poptions)
00093 {
00094     PatchGroup* pgroup = new PatchGroup;
00095     pgroup->setOptions(poptions);
00096     Transform* patch = createPatch(filename, poptions);
00097     BoundingSphere bsphere = patch->getBound();
00098     pgroup->setCenter(bsphere.center());
00099     if (poptions->getPatchLevel() >= _maxLevel)
00100     {
00101         pgroup->addChild(patch, 0.0, 1e10);
00102     }
00103     else
00104     {
00105         pgroup->addChild(patch, 0.0, 1.0);
00106         pgroup->setRange(1, 1.0, 1e10);
00107         pgroup->setFileName(1, "foo.osgearth_engine_seamless_patch");
00108     }
00109     return pgroup;
00110 }
00111 
00112 // Default implementation that creates a flat 81920m x 81920m plane.
00113 
00114 Transform* PatchSet::createPatch(const std::string& filename, PatchOptions* poptions)
00115 {
00116     Patch* patch = new Patch;
00117     patch->setPatchSet(this);
00118     Vec2d ll, ur;
00119     poptions->getPatchExtents(ll, ur);
00120     Vec2d range = (ur - ll);
00121     ref_ptr<Patch::Data> data = new Patch::Data;
00122     int patchDim = _resolution + 1;
00123     Vec3Array* verts = new Vec3Array(patchDim * patchDim);
00124     for (int j = 0; j < patchDim; ++j)
00125         for (int i = 0; i < patchDim; ++i)
00126             (*verts)[patchDim * j + i]
00127                 = Vec3((ll.x() + i * range.x()
00128                         / static_cast<float>(_resolution)) * 81920.0,
00129                        (ll.y() + j * range.y()
00130                         / static_cast<float>(_resolution)) * 81920.0,
00131                        0.0);
00132     data->vertexData.array = verts;
00133     data->vertexData.binding = Geometry::BIND_PER_VERTEX;
00134     Vec3Array* norms = new Vec3Array(1);
00135     (*norms)[0] = Vec3d(0.0, 0.0, 1.0);
00136     data->normalData.array = norms;
00137     data->normalData.binding = Geometry::BIND_OVERALL;
00138     Vec4Array* colors = new Vec4Array(1);
00139     (*colors)[0] = Vec4(1.0, 1.0, 1.0, 1.0);
00140     data->colorData.array = colors;
00141     data->colorData.binding = Geometry::BIND_OVERALL;
00142     patch->setData(data);
00143     MatrixTransform* transform = new MatrixTransform;
00144     transform->addChild(patch);
00145     return transform;
00146 }
00147 
00148 Node* PatchSet::createPatchSetGraph(const std::string& filename)
00149 {
00150     PatchOptions* poptions = osg::clone(_patchOptionsPrototype.get());
00151     poptions->setPatchSet(this);
00152     return createPatchGroup(filename, poptions);
00153 }
00154 
00155 double PatchSet::calcPrecisionFactor(int pixelError, double horiz_fov_deg,
00156                                int screenRes, int dpi)
00157 {
00158     // Find near plane distance in meters
00159     const double pixelsPerMeter = dpi / .0254;
00160     const double halfScreen = .5 * screenRes / pixelsPerMeter;
00161     const double dNear = halfScreen / tan(DegreesToRadians(horiz_fov_deg / 2));
00162     return dNear * pixelsPerMeter / (pixelError * _resolution);
00163 }
00164 
00165 namespace
00166 {
00167 inline void getGridCoords(int psRes, unsigned short index, int& x, int& y)
00168 {
00169     y = index / (psRes + 1);
00170     x = index % (psRes + 1);
00171 }
00172 }
00173 
00174 ref_ptr<DrawElementsUShort> PatchSet::makeBasicTrile(int delta)
00175 {
00176     ref_ptr<DrawElementsUShort> pset = new DrawElementsUShort(GL_TRIANGLES);
00177     // y axis
00178     int xBegin = delta;
00179     int xEnd = _resolution - delta;
00180     for (int j = 0; j < _resolution / 2 - delta; j += delta)
00181     {
00182         for (int i = xBegin; i < xEnd; i += 2 * delta)
00183         {
00184             pset->push_back(makeIndex(i, j));
00185             pset->push_back(makeIndex(i + delta, j));
00186             pset->push_back(makeIndex(i + delta, j + delta));
00187             pset->push_back(makeIndex(i + delta, j + delta));
00188             pset->push_back(makeIndex(i + delta, j));
00189             pset->push_back(makeIndex(i + 2 * delta, j));
00190             if (i + 2 * delta == xEnd)
00191                 break;
00192             pset->push_back(makeIndex(i + delta, j + delta));
00193             pset->push_back(makeIndex(i + 2 * delta, j));
00194             pset->push_back(makeIndex(i + 2 * delta, j + delta));
00195             pset->push_back(makeIndex(i + 2 * delta, j + delta));
00196             pset->push_back(makeIndex(i + 2 * delta, j));
00197             pset->push_back(makeIndex(i + 3 * delta, j + delta));
00198         }
00199         xBegin += delta;
00200         xEnd -= delta;
00201     }
00202     return pset;
00203 }
00204 
00205 // Rotate grid indices 90 deg counter-clockwise.
00206 unsigned short PatchSet::rotateIndex(unsigned short index)
00207 {
00208     int x, y;
00209     int psRes = _resolution;
00210     getGridCoords(psRes, index, x, y);
00211     x -= psRes / 2;
00212     y -= psRes / 2;
00213     int newx = -y;
00214     int newy = x;
00215     newx += psRes / 2;
00216     newy += psRes / 2;
00217     return makeIndex(newx, newy);
00218 }
00219 
00220 // Stitching  strip between two triles of the same resolution.
00221 
00222 ref_ptr<DrawElementsUShort> PatchSet::makeSingleStrip(int delta)
00223 {
00224     ref_ptr<DrawElementsUShort> pset = new DrawElementsUShort(GL_TRIANGLES);
00225     for (int i = 0; i < _resolution / 2; i += delta)
00226     {
00227         if (i > 0)
00228         {
00229             pset->push_back(makeIndex(i - delta, i));
00230             pset->push_back(makeIndex(i, i));
00231             pset->push_back(makeIndex(i, i + delta));
00232         }
00233         pset->push_back(makeIndex(i, i));
00234         pset->push_back(makeIndex(i + delta, i + delta));
00235         pset->push_back(makeIndex(i, i + delta));
00236         pset->push_back(makeIndex(i, i));
00237         pset->push_back(makeIndex(i + delta, i));
00238         pset->push_back(makeIndex(i + delta, i + delta));
00239         if (i < _resolution / 2 - delta)
00240         {
00241             pset->push_back(makeIndex(i + delta, i + delta));
00242             pset->push_back(makeIndex(i + delta, i));
00243             pset->push_back(makeIndex(i + 2 * delta, i + delta));
00244         }
00245     }
00246     return pset;
00247 }
00248 
00249 // Stitching strip between triles of different resolutions.
00250 
00251 ref_ptr<DrawElementsUShort> PatchSet::makeDualStrip()
00252 {
00253     ref_ptr<DrawElementsUShort> pset = new DrawElementsUShort(GL_TRIANGLES);
00254     for (int i = 0, j = 2; j <= _resolution / 2; i += 2, j += 2)
00255     {
00256         pset->push_back(makeIndex(i, j));
00257         if (i == 0)
00258             pset->push_back(makeIndex(0, 0));
00259         else
00260             pset->push_back(makeIndex(i - 2, j -2));
00261         pset->push_back(makeIndex(i + 1, j - 2));
00262         pset->push_back(makeIndex(i, j));
00263         pset->push_back(makeIndex(i + 1, j - 2));
00264         pset->push_back(makeIndex(i + 2, j - 1));
00265 
00266         pset->push_back(makeIndex(i, j));
00267         pset->push_back(makeIndex(i + 2, j - 1));
00268         pset->push_back(makeIndex(i + 3, j));
00269     }
00270     return pset;
00271 }
00272 
00273 void PatchSet::initPrimitiveSets()
00274 {
00275     for (int res = 0; res < 2; res++)
00276     {
00277         // Bottom trile
00278         trilePset[res][0] = makeBasicTrile(2 - res);
00279         // The other triles are rotations of the first on the grid of
00280         // coordinate indices.
00281         for (int i = 1; i < 4; ++i)
00282         {
00283             trilePset[res][i] = new DrawElementsUShort(GL_TRIANGLES);
00284             for (DrawElementsUShort::iterator itr = trilePset[res][i - 1]->begin(),
00285                      end = trilePset[res][i - 1]->end();
00286                  itr != end;
00287                 ++itr)
00288                 trilePset[res][i]->push_back(rotateIndex(*itr));
00289         }
00290     }
00291     // First, the strips for the edge from lower left to middle
00292     stripPset[0][0] = makeSingleStrip(2); // low res
00293     stripPset[1][0] = makeDualStrip();
00294     // The other dual strip is the reflection across y = x
00295     stripPset[2][0] = new DrawElementsUShort(GL_TRIANGLES);
00296     for (DrawElementsUShort::iterator itr = stripPset[1][0]->begin(),
00297              end = stripPset[1][0]->end();
00298          itr != end;
00299         ++itr)
00300     {
00301         int x, y;
00302         getGridCoords(_resolution, *itr, x, y);
00303         stripPset[2][0]->push_back(makeIndex(y, x));
00304     }
00305     // Now switch the order on the triangles on the reflected strip
00306     for (size_t i = 1; i < stripPset[2][0]->size(); i += 3)
00307     {
00308         std::swap((*stripPset[2][0].get())[i],
00309                   (*stripPset[2][0].get())[i + 1]);
00310     }
00311 
00312     stripPset[3][0] = makeSingleStrip(1); // hi res
00313     // Now rotate the strips for the other diagonals.
00314     for (int j = 1; j < 4; ++j)
00315     {
00316         for (int i = 0; i < 4; ++i)
00317         {
00318             stripPset[i][j] = new DrawElementsUShort(GL_TRIANGLES);
00319             for (DrawElementsUShort::iterator itr = stripPset[i][j - 1]->begin(),
00320                      end = stripPset[i][j - 1]->end();
00321                  itr != end;
00322                 ++itr)
00323                 stripPset[i][j]->push_back(rotateIndex(*itr));
00324         }
00325     }
00326 }
00327 
00328 osg::Node* PatchSet::createChild(const PatchOptions* parentOptions, int childNum)
00329 {
00330     Vec2d lowerLeft(0.0, 1.0);
00331     Vec2d upperRight(1.0, 1.0);
00332 
00333     parentOptions->getPatchExtents(lowerLeft, upperRight);
00334     Vec2d range = upperRight - lowerLeft;
00335     Vec2d newRange = range * .5;
00336     double x = (childNum % 2) * .5;
00337     double y = (childNum / 2) * .5;
00338     PatchOptions* pgroupOptions = osg::clone(parentOptions);
00339     Vec2d ll = lowerLeft + componentMultiply(Vec2d(x, y), range);
00340     pgroupOptions->setPatchExtents(ll, ll + newRange);
00341     pgroupOptions->setPatchLevel(parentOptions->getPatchLevel() + 1);
00342     Node* pgroup = createPatchGroup("foobies.osgearth_engine_seamless_patch",
00343                                     pgroupOptions);
00344     return pgroup;
00345 }
00346 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines