osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthSymbology/GeometryExtrudeSymbolizer.cpp

Go to the documentation of this file.
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 <osgEarthSymbology/GeometryExtrudeSymbolizer>
00021 #include <osgEarthSymbology/ExtrudedSymbol>
00022 #include <osgUtil/Tessellator>
00023 #include <osg/Geometry>
00024 #include <osg/Point>
00025 #include <osg/LineWidth>
00026 #include <osg/Material>
00027 #include <osg/Geode>
00028 
00029 using namespace osgEarth::Symbology;
00030 
00031 GeometryExtrudeSymbolizer::GeometryExtrudeSymbolizer()
00032 {
00033 }
00034 
00035 
00036 void GeometryExtrudeSymbolizer::tessellate( osg::Geometry* geom )
00037 {
00038     osgUtil::Tessellator tess;
00039     tess.setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY );
00040     tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD );
00041 //    tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_POSITIVE );
00042     tess.retessellatePolygons( *geom );
00043 }
00044 
00045 bool 
00046 GeometryExtrudeSymbolizer::compile(State<GeometryContent>* state,
00047                                    osg::Group* attachPoint)
00048 {
00049     if ( !state || !attachPoint || !state->getContent() || !state->getStyle() )
00050         return false;
00051 
00052     osg::ref_ptr<osg::Group> newSymbolized = new osg::Group;
00053 
00054     const GeometryList& geometryList = state->getContent()->getGeometryList();
00055     for (GeometryList::const_iterator it = geometryList.begin(); it != geometryList.end(); ++it)
00056     {
00057         Geometry* geometry = *it;
00058         if (!geometry)
00059             continue;
00060 
00061         GeometryIterator geomIterator( geometry );
00062         geomIterator.traverseMultiGeometry() = true;
00063         geomIterator.traversePolygonHoles() = true;
00064         while( geomIterator.hasMore() )
00065         {
00066             Geometry* part = geomIterator.next();
00067             if (!part)
00068                 continue;
00069 
00070             osg::Vec4 color = osg::Vec4(1.0, 0.0, 1.0, 1.);
00071             float height = 1.0;
00072             float offset = 1.0;
00073 
00074             switch( part->getType())
00075             {
00076             case Geometry::TYPE_LINESTRING:
00077             case Geometry::TYPE_RING:
00078             {
00079                 const ExtrudedLineSymbol* line = state->getStyle()->getSymbol<ExtrudedLineSymbol>();
00080                 if (line) 
00081                 {
00082                     color = line->stroke()->color();
00083                     height = line->extrude()->height();
00084                     offset = line->extrude()->offset();
00085                 }
00086             }
00087             break;
00088 
00089             case Geometry::TYPE_POLYGON:
00090             {
00091                 const ExtrudedPolygonSymbol* polygon = state->getStyle()->getSymbol<ExtrudedPolygonSymbol>();
00092                 if (polygon)
00093                 {
00094                     color  = polygon->fill()->color();
00095                     height = polygon->extrude()->height();
00096                     offset = polygon->extrude()->offset();
00097                 }
00098             }
00099             break;
00100             default:
00101                 continue;
00102                 break;
00103             }
00104 
00105             osg::Geode* geode = extrude(part, offset, height, state->getContext() );
00106             if (geode && geode->getNumDrawables()) 
00107             {
00108                 osg::Material* material = new osg::Material;
00109                 material->setDiffuse(osg::Material::FRONT_AND_BACK, color);
00110                 geode->getOrCreateStateSet()->setAttributeAndModes(material);
00111                 newSymbolized->addChild(geode);
00112             }
00113         }
00114     }
00115 
00116     if (newSymbolized->getNumChildren())
00117     {
00118         attachPoint->removeChildren(0, attachPoint->getNumChildren());
00119         attachPoint->addChild(newSymbolized.get());
00120         return true;
00121     }
00122 
00123     return false;
00124 }
00125 
00126 osg::Geode* GeometryExtrudeSymbolizer::extrude(Geometry* geom, double offset, double height, SymbolizerContext* context )
00127 {
00128     if ( !geom ) return 0L;
00129 
00130     int numRings = 0;
00131 
00132     // start by offsetting the input data.
00133     {
00134         GeometryIterator i( geom );
00135         i.traverseMultiGeometry() = true;
00136         i.traversePolygonHoles() = true;
00137         while( i.hasMore() )
00138         {
00139             Geometry* part = i.next();
00140             if (offset != 0.0)
00141             {
00142                 for( osg::Vec3dArray::iterator j = part->begin(); j != part->end(); j++ )
00143                 {
00144                     {
00145                         (*j).z() += offset;
00146                     }
00147                 }
00148             }
00149 
00150             // in the meantime, count the # of closed geoms. We will need to know this in 
00151             // order to pre-allocate the proper # of verts.
00152             if ( part->getType() == Geometry::TYPE_POLYGON || part->getType() == Geometry::TYPE_RING )
00153             {
00154                 numRings++;
00155             }
00156         }
00157     }
00158 
00159     // now, go thru and remove any coplanar segments from the geometry. The tesselator will
00160     // not work include a vert connecting two colinear segments in the tesselation, and this
00161     // will break the stenciling logic.
00162 #define PARALLEL_EPSILON 0.01
00163     GeometryIterator i( geom );
00164     i.traverseMultiGeometry() = true;
00165     i.traversePolygonHoles() = true;
00166     while( i.hasMore() )
00167     {
00168         Geometry* part = i.next();
00169         if ( part->size() >= 3 )
00170         {
00171             osg::Vec3d prevVec = part->front() - part->back();
00172             prevVec.normalize();
00173 
00174             for( osg::Vec3dArray::iterator j = part->begin(); part->size() >= 3 && j != part->end(); )
00175             {
00176                 osg::Vec3d& p0 = *j;
00177                 osg::Vec3d& p1 = j+1 != part->end() ? *(j+1) : part->front();
00178                 osg::Vec3d vec = p1-p0; vec.normalize();
00179 
00180                 // if the vectors are essentially parallel, remove the extraneous vertex.
00181                 if ( (prevVec ^ vec).length() < PARALLEL_EPSILON )
00182                 {
00183                     j = part->erase( j );
00184                     //OE_NOTICE << "removed colinear segment" << std::endl;
00185                 }
00186                 else
00187                 {
00188                     ++j;
00189                     prevVec = vec;
00190                 }
00191             }
00192         }
00193     }
00194 
00195 
00196     bool made_geom = true;
00197 
00198     // total up all the points so we can pre-allocate the vertex arrays.
00199     int num_cap_verts = geom->getTotalPointCount();
00200     int num_wall_verts = 2 * (num_cap_verts + numRings); // add in numRings b/c we need to close each wall
00201 
00202     osg::Geometry* walls = new osg::Geometry();
00203     osg::Vec3Array* verts = new osg::Vec3Array( num_wall_verts );
00204     walls->setVertexArray( verts );
00205 
00206     osg::Geometry* top_cap = new osg::Geometry();
00207     osg::Vec3Array* top_verts = new osg::Vec3Array( num_cap_verts );
00208     top_cap->setVertexArray( top_verts );
00209 
00210     osg::Geometry* bottom_cap = new osg::Geometry();
00211     osg::Vec3Array* bottom_verts = new osg::Vec3Array( num_cap_verts );
00212     bottom_cap->setVertexArray( bottom_verts );
00213 
00214     int wall_vert_ptr = 0;
00215     int top_vert_ptr = 0;
00216     int bottom_vert_ptr = 0;
00217 
00218     //double target_len = height;
00219 
00220     // now generate the extruded geometry.
00221     GeometryIterator k( geom );
00222     while( k.hasMore() )
00223     {
00224         Geometry* part = k.next();
00225 
00226         unsigned int wall_part_ptr = wall_vert_ptr;
00227         unsigned int top_part_ptr = top_vert_ptr;
00228         unsigned int bottom_part_ptr = bottom_vert_ptr;
00229         double part_len = 0.0;
00230 
00231         GLenum prim_type = part->getType() == Geometry::TYPE_POINTSET ? GL_LINES : GL_TRIANGLE_STRIP;
00232 
00233         for( osg::Vec3dArray::const_iterator m = part->begin(); m != part->end(); ++m )
00234         {
00235             osg::Vec3d extrude_vec;
00236             {
00237                 extrude_vec.set( m->x(), m->y(), height );
00238             }
00239 
00240             (*top_verts)[top_vert_ptr++] = extrude_vec;
00241             (*bottom_verts)[bottom_vert_ptr++] = *m;
00242              
00243             part_len += wall_vert_ptr > wall_part_ptr?
00244                 (extrude_vec - (*verts)[wall_vert_ptr-2]).length() :
00245                 0.0;
00246 
00247             int p;
00248 
00249             p = wall_vert_ptr++;
00250             (*verts)[p] = extrude_vec;
00251 
00252             p = wall_vert_ptr++;
00253             (*verts)[p] = *m;
00254         }
00255 
00256         // close the wall if it's a ring/poly:
00257         if ( part->getType() == Geometry::TYPE_RING || part->getType() == Geometry::TYPE_POLYGON )
00258         {
00259             part_len += wall_vert_ptr > wall_part_ptr?
00260                 ((*verts)[wall_part_ptr] - (*verts)[wall_vert_ptr-2]).length() :
00261                 0.0;
00262 
00263             int p;
00264 
00265             p = wall_vert_ptr++;
00266             (*verts)[p] = (*verts)[wall_part_ptr];
00267 
00268             p = wall_vert_ptr++;
00269             (*verts)[p] = (*verts)[wall_part_ptr+1];
00270         }
00271 
00272         walls->addPrimitiveSet( new osg::DrawArrays(
00273                                     prim_type,
00274                                     wall_part_ptr, wall_vert_ptr - wall_part_ptr ) );
00275 
00276         top_cap->addPrimitiveSet( new osg::DrawArrays(
00277                                       osg::PrimitiveSet::LINE_LOOP,
00278                                       top_part_ptr, top_vert_ptr - top_part_ptr ) );
00279 
00280         // reverse the bottom verts so the front face is down:
00281         std::reverse( bottom_verts->begin()+bottom_part_ptr, bottom_verts->begin()+bottom_vert_ptr );
00282 
00283         bottom_cap->addPrimitiveSet( new osg::DrawArrays(
00284                                          osg::PrimitiveSet::LINE_LOOP,
00285                                          bottom_part_ptr, bottom_vert_ptr - bottom_part_ptr ) );
00286     }
00287 
00288     // build solid surfaces for the caps:
00289     tessellate( top_cap );
00290     tessellate( bottom_cap );
00291 
00292     osg::Geode* geode = new osg::Geode();
00293     geode->addDrawable( walls );
00294     geode->addDrawable( top_cap );
00295     geode->addDrawable( bottom_cap );
00296 
00297     return geode;
00298 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines