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 #include <osgEarthSymbology/Geometry> 00020 #include <osgEarthSymbology/GEOS> 00021 #include <algorithm> 00022 #include <iterator> 00023 00024 using namespace osgEarth; 00025 using namespace osgEarth::Symbology; 00026 00027 #ifdef OSGEARTH_HAVE_GEOS 00028 # include <geos/geom/Geometry.h> 00029 # include <geos/geom/GeometryFactory.h> 00030 # include <geos/operation/buffer/BufferOp.h> 00031 # include <geos/operation/buffer/BufferBuilder.h> 00032 # include <geos/operation/overlay/OverlayOp.h> 00033 using namespace geos; 00034 using namespace geos::operation; 00035 #endif 00036 00037 #define LC "[Geometry] " 00038 00039 00040 Geometry::Geometry( const Geometry& rhs ) : 00041 osgEarth::MixinVector<osg::Vec3d,osg::Referenced>( rhs ) 00042 { 00043 //nop 00044 } 00045 00046 Geometry::Geometry( int capacity ) 00047 { 00048 if ( capacity > 0 ) 00049 reserve( capacity ); 00050 } 00051 00052 Geometry::Geometry( const Vec3dVector* data ) 00053 { 00054 reserve( data->size() ); 00055 insert( begin(), data->begin(), data->end() ); 00056 } 00057 00058 int 00059 Geometry::getTotalPointCount() const 00060 { 00061 return size(); 00062 } 00063 00064 Bounds 00065 Geometry::getBounds() const 00066 { 00067 Bounds bounds; 00068 for( const_iterator i = begin(); i != end(); ++i ) 00069 bounds.expandBy( i->x(), i->y(), i->z() ); 00070 return bounds; 00071 } 00072 00073 Geometry* 00074 Geometry::cloneAs( const Geometry::Type& newType ) const 00075 { 00076 //if ( newType == getType() ) 00077 // return static_cast<Geometry*>( clone() ); 00078 00079 switch( newType ) 00080 { 00081 case TYPE_POINTSET: 00082 return new PointSet( &this->asVector() ); 00083 case TYPE_LINESTRING: 00084 return new LineString( &this->asVector() ); 00085 case TYPE_RING: 00086 return new Ring( &this->asVector() ); 00087 case TYPE_POLYGON: 00088 if ( dynamic_cast<const Polygon*>(this) ) 00089 return new Polygon( *static_cast<const Polygon*>(this) ); 00090 else 00091 return new Polygon( &this->asVector() ); 00092 default: 00093 break; 00094 } 00095 return 0L; 00096 } 00097 00098 osg::Vec3Array* 00099 Geometry::toVec3Array() const 00100 { 00101 osg::Vec3Array* result = new osg::Vec3Array( this->size() ); 00102 std::copy( begin(), end(), result->begin() ); 00103 return result; 00104 } 00105 00106 osg::Vec3dArray* 00107 Geometry::toVec3dArray() const 00108 { 00109 osg::Vec3dArray* result = new osg::Vec3dArray( this->size() ); 00110 std::copy( begin(), end(), result->begin() ); 00111 return result; 00112 } 00113 00114 Geometry* 00115 Geometry::create( Type type, const Vec3dVector* toCopy ) 00116 { 00117 Geometry* output = 0L; 00118 switch( type ) { 00119 case TYPE_POINTSET: 00120 output = new PointSet( toCopy ); break; 00121 case TYPE_LINESTRING: 00122 output = new LineString( toCopy ); break; 00123 case TYPE_RING: 00124 output = new Ring( toCopy ); break; 00125 case TYPE_POLYGON: 00126 output = new Polygon( toCopy ); break; 00127 default: 00128 break; 00129 } 00130 return output; 00131 } 00132 00133 bool 00134 Geometry::hasBufferOperation() 00135 { 00136 #ifdef OSGEARTH_HAVE_GEOS 00137 return true; 00138 #else 00139 return false; 00140 #endif 00141 } 00142 00143 bool 00144 Geometry::buffer(double distance, 00145 osg::ref_ptr<Geometry>& output, 00146 const BufferParameters& params ) const 00147 { 00148 #ifdef OSGEARTH_HAVE_GEOS 00149 00150 geom::Geometry* inGeom = GEOSUtils::importGeometry( this ); 00151 if ( inGeom ) 00152 { 00153 buffer::BufferParameters::EndCapStyle geosEndCap = 00154 params._capStyle == BufferParameters::CAP_ROUND ? buffer::BufferParameters::CAP_ROUND : 00155 params._capStyle == BufferParameters::CAP_SQUARE ? buffer::BufferParameters::CAP_SQUARE : 00156 params._capStyle == BufferParameters::CAP_FLAT ? buffer::BufferParameters::CAP_FLAT : 00157 buffer::BufferParameters::CAP_SQUARE; 00158 00159 buffer::BufferParameters::JoinStyle geosJoinStyle = 00160 params._joinStyle == BufferParameters::JOIN_ROUND ? buffer::BufferParameters::JOIN_ROUND : 00161 params._joinStyle == BufferParameters::JOIN_MITRE ? buffer::BufferParameters::JOIN_MITRE : 00162 params._joinStyle == BufferParameters::JOIN_BEVEL ? buffer::BufferParameters::JOIN_BEVEL : 00163 buffer::BufferParameters::JOIN_ROUND; 00164 00165 //JB: Referencing buffer::BufferParameters::DEFAULT_QUADRANT_SEGMENTS causes link errors b/c it is defined as a static in the header of BufferParameters.h and not defined in the cpp anywhere. 00166 // This seems to only effect the Linux build, Windows works fine 00167 int geosQuadSegs = params._cornerSegs > 0 00168 ? params._cornerSegs 00169 : 8;//buffer::BufferParameters::DEFAULT_QUADRANT_SEGMENTS; 00170 00171 geom::Geometry* outGeom = NULL; 00172 00173 buffer::BufferParameters geosBufferParams; 00174 geosBufferParams.setQuadrantSegments( geosQuadSegs ); 00175 geosBufferParams.setEndCapStyle( geosEndCap ); 00176 geosBufferParams.setJoinStyle( geosJoinStyle ); 00177 buffer::BufferBuilder bufBuilder( geosBufferParams ); 00178 00179 if (params._singleSided) 00180 { 00181 outGeom = bufBuilder.bufferLineSingleSided(inGeom, distance, params._leftSide ); 00182 } 00183 else 00184 { 00185 outGeom = bufBuilder.buffer(inGeom, distance ); 00186 } 00187 00188 if ( outGeom ) 00189 { 00190 output = GEOSUtils::exportGeometry( outGeom ); 00191 outGeom->getFactory()->destroyGeometry( outGeom ); 00192 } 00193 else 00194 { 00195 OE_INFO << LC << "Buffer: no output geometry" << std::endl; 00196 } 00197 00198 inGeom->getFactory()->destroyGeometry( inGeom ); 00199 } 00200 return output.valid(); 00201 00202 #else // OSGEARTH_HAVE_GEOS 00203 00204 OE_WARN << LC << "Buffer failed - GEOS not available" << std::endl; 00205 return false; 00206 00207 #endif // OSGEARTH_HAVE_GEOS 00208 } 00209 00210 bool 00211 Geometry::crop( const Polygon* cropPoly, osg::ref_ptr<Geometry>& output ) const 00212 { 00213 #ifdef OSGEARTH_HAVE_GEOS 00214 00215 geom::GeometryFactory* f = new geom::GeometryFactory(); 00216 00217 //Create the GEOS Geometries 00218 geom::Geometry* inGeom = GEOSUtils::importGeometry( this ); 00219 geom::Geometry* cropGeom = GEOSUtils::importGeometry( cropPoly ); 00220 00221 if ( inGeom ) 00222 { 00223 geom::Geometry* outGeom = 0L; 00224 try { 00225 outGeom = overlay::OverlayOp::overlayOp( 00226 inGeom, cropGeom, 00227 overlay::OverlayOp::opINTERSECTION ); 00228 } 00229 catch( ... ) { 00230 outGeom = 0L; 00231 OE_NOTICE << LC << "::crop, GEOS overlay op exception, skipping feature" << std::endl; 00232 } 00233 00234 if ( outGeom ) 00235 { 00236 output = GEOSUtils::exportGeometry( outGeom ); 00237 f->destroyGeometry( outGeom ); 00238 if ( output.valid() && !output->isValid() ) 00239 { 00240 output = 0L; 00241 } 00242 } 00243 } 00244 00245 //Destroy the geometry 00246 f->destroyGeometry( cropGeom ); 00247 f->destroyGeometry( inGeom ); 00248 00249 delete f; 00250 return output.valid(); 00251 00252 #else // OSGEARTH_HAVE_GEOS 00253 00254 OE_WARN << LC << "Crop failed - GEOS not available" << std::endl; 00255 return false; 00256 00257 #endif // OSGEARTH_HAVE_GEOS 00258 } 00259 00260 bool 00261 Geometry::difference( const Polygon* diffPolygon, osg::ref_ptr<Geometry>& output ) const 00262 { 00263 #ifdef OSGEARTH_HAVE_GEOS 00264 00265 geom::GeometryFactory* f = new geom::GeometryFactory(); 00266 00267 //Create the GEOS Geometries 00268 geom::Geometry* inGeom = GEOSUtils::importGeometry( this ); 00269 geom::Geometry* diffGeom = GEOSUtils::importGeometry( diffPolygon ); 00270 00271 if ( inGeom ) 00272 { 00273 geom::Geometry* outGeom = 0L; 00274 try { 00275 outGeom = overlay::OverlayOp::overlayOp( 00276 inGeom, diffGeom, 00277 overlay::OverlayOp::opDIFFERENCE ); 00278 } 00279 catch( ... ) { 00280 outGeom = 0L; 00281 OE_NOTICE << LC << "::difference, GEOS overlay op exception, skipping feature" << std::endl; 00282 } 00283 00284 if ( outGeom ) 00285 { 00286 output = GEOSUtils::exportGeometry( outGeom ); 00287 f->destroyGeometry( outGeom ); 00288 if ( output.valid() && !output->isValid() ) 00289 { 00290 output = 0L; 00291 } 00292 } 00293 } 00294 00295 //Destroy the geometry 00296 f->destroyGeometry( diffGeom ); 00297 f->destroyGeometry( inGeom ); 00298 00299 delete f; 00300 return output.valid(); 00301 00302 #else // OSGEARTH_HAVE_GEOS 00303 00304 OE_WARN << LC << "Difference failed - GEOS not available" << std::endl; 00305 return false; 00306 00307 #endif // OSGEARTH_HAVE_GEOS 00308 } 00309 00310 osg::Vec3d 00311 Geometry::localize() 00312 { 00313 osg::Vec3d offset; 00314 00315 Bounds bounds = getBounds(); 00316 if ( bounds.isValid() ) 00317 { 00318 osg::Vec2d center = bounds.center2d(); 00319 offset.set( center.x(), center.y(), 0 ); 00320 00321 GeometryIterator i( this ); 00322 while( i.hasMore() ) 00323 { 00324 Geometry* part = i.next(); 00325 for( Geometry::iterator j = part->begin(); j != part->end(); ++j ) 00326 { 00327 *j = *j - offset; 00328 } 00329 } 00330 } 00331 00332 return offset; 00333 } 00334 00335 void 00336 Geometry::delocalize( const osg::Vec3d& offset ) 00337 { 00338 GeometryIterator i( this ); 00339 while( i.hasMore() ) 00340 { 00341 Geometry* part = i.next(); 00342 for( Geometry::iterator j = part->begin(); j != part->end(); ++j ) 00343 { 00344 *j = *j + offset; 00345 } 00346 } 00347 } 00348 00349 //---------------------------------------------------------------------------- 00350 00351 PointSet::PointSet( const PointSet& rhs ) : 00352 Geometry( rhs ) 00353 { 00354 //nop 00355 } 00356 00357 //---------------------------------------------------------------------------- 00358 00359 LineString::LineString( const LineString& rhs ) : 00360 Geometry( rhs ) 00361 { 00362 //nop 00363 } 00364 00365 LineString::LineString( const Vec3dVector* data ) : 00366 Geometry( data ) 00367 { 00368 //nop 00369 } 00370 00371 double 00372 LineString::getLength() const 00373 { 00374 double length = 0; 00375 for (unsigned int i = 0; i < size()-1; ++i) 00376 { 00377 osg::Vec3d current = (*this)[i]; 00378 osg::Vec3d next = (*this)[i+1]; 00379 length += (next - current).length(); 00380 } 00381 return length; 00382 } 00383 00384 bool 00385 LineString::getSegment(double length, osg::Vec3d& start, osg::Vec3d& end) 00386 { 00387 double pos = 0; 00388 for (unsigned int i = 0; i < size()-1; ++i) 00389 { 00390 osg::Vec3d current = (*this)[i]; 00391 osg::Vec3d next = (*this)[i+1]; 00392 pos += (next - current).length(); 00393 if (pos > length) 00394 { 00395 start = current; 00396 end = next; 00397 return true; 00398 } 00399 } 00400 return false; 00401 } 00402 00403 //---------------------------------------------------------------------------- 00404 00405 Ring::Ring( const Ring& rhs ) : 00406 Geometry( rhs ) 00407 { 00408 //nop 00409 } 00410 00411 Ring::Ring( const Vec3dVector* data ) : 00412 Geometry( data ) 00413 { 00414 open(); 00415 } 00416 00417 Geometry* 00418 Ring::cloneAs( const Geometry::Type& newType ) const 00419 { 00420 if ( newType == TYPE_LINESTRING ) 00421 { 00422 LineString* line = new LineString( &this->asVector() ); 00423 if ( line->size() > 1 && line->front() != line->back() ) 00424 line->push_back( front() ); 00425 return line; 00426 } 00427 else return Geometry::cloneAs( newType ); 00428 } 00429 00430 Ring::Orientation 00431 Ring::getOrientation() const 00432 { 00433 // adjust for a non-open ring: 00434 int n = size(); 00435 while( n > 0 && front() == back() ) 00436 n--; 00437 00438 if ( n < 3 ) 00439 return Ring::ORIENTATION_DEGENERATE; 00440 00441 // copy the open vec: 00442 std::vector<osg::Vec3d> v; 00443 v.reserve( n ); 00444 std::copy( begin(), begin()+n, std::back_inserter(v) ); 00445 00446 int rmin = 0; 00447 double xmin = v[0].x(); 00448 double ymin = v[0].y(); 00449 v[0].z() = 0; 00450 for( int i=1; i<n; ++i ) { 00451 double x = v[i].x(); 00452 double y = v[i].y(); 00453 v[i].z() = 0; 00454 if ( y > ymin ) 00455 continue; 00456 if ( y == ymin ) { 00457 if (x < xmin ) 00458 continue; 00459 } 00460 rmin = i; 00461 xmin = x; 00462 ymin = y; 00463 } 00464 00465 int rmin_less_1 = rmin-1 >= 0 ? rmin-1 : n-1; 00466 int rmin_plus_1 = rmin+1 < n ? rmin+1 : 0; 00467 00468 osg::Vec3 in = v[rmin] - v[rmin_less_1]; in.normalize(); 00469 osg::Vec3 out = v[rmin_plus_1] - v[rmin]; out.normalize(); 00470 osg::Vec3 cross = in ^ out; 00471 00472 return 00473 cross.z() < 0.0 ? Ring::ORIENTATION_CW : 00474 cross.z() > 0.0 ? Ring::ORIENTATION_CCW : 00475 Ring::ORIENTATION_DEGENERATE; 00476 } 00477 00478 // ensures that the first and last points are not idential. 00479 void 00480 Ring::open() 00481 { 00482 while( size() > 2 && front() == back() ) 00483 erase( end()-1 ); 00484 } 00485 00486 // gets the signed area. 00487 double 00488 Ring::getSignedArea2D() const 00489 { 00490 const_cast<Ring*>(this)->open(); 00491 00492 double sum = 0.0; 00493 00494 for( unsigned i=0; i<size(); ++i ) 00495 { 00496 const osg::Vec3d& p0 = (*this)[0]; 00497 const osg::Vec3d& p1 = i+1 < size() ? (*this)[i+1] : (*this)[0]; 00498 sum += p0.x()*p1.y() - p1.x()*p0.y(); 00499 } 00500 return .5*sum; 00501 } 00502 00503 // opens and rewinds the polygon to the specified orientation. 00504 void 00505 Ring::rewind( Orientation orientation ) 00506 { 00507 open(); 00508 Orientation current = getOrientation(); 00509 if ( current != orientation && current != ORIENTATION_DEGENERATE && orientation != ORIENTATION_DEGENERATE ) 00510 { 00511 std::reverse( begin(), end() ); 00512 } 00513 } 00514 00515 // point-in-polygon test 00516 bool 00517 Ring::contains2D( double x, double y ) const 00518 { 00519 bool result = false; 00520 const Ring& poly = *this; 00521 for( unsigned i=0, j=size()-1; i<size(); j = i++ ) 00522 { 00523 if ((((poly[i].y() <= y) && (y < poly[j].y())) || 00524 ((poly[j].y() <= y) && (y < poly[i].y()))) && 00525 (x < (poly[j].x()-poly[i].x()) * (y-poly[i].y())/(poly[j].y()-poly[i].y())+poly[i].x())) 00526 { 00527 result = !result; 00528 } 00529 } 00530 return result; 00531 } 00532 00533 //---------------------------------------------------------------------------- 00534 00535 Polygon::Polygon( const Polygon& rhs ) : 00536 Ring( rhs ) 00537 { 00538 for( RingCollection::const_iterator r = rhs._holes.begin(); r != rhs._holes.end(); ++r ) 00539 _holes.push_back( new Ring(*r->get()) ); 00540 } 00541 00542 Polygon::Polygon( const Vec3dVector* data ) : 00543 Ring( data ) 00544 { 00545 //nop 00546 } 00547 00548 int 00549 Polygon::getTotalPointCount() const 00550 { 00551 int total = Ring::getTotalPointCount(); 00552 for( RingCollection::const_iterator i = _holes.begin(); i != _holes.end(); ++i ) 00553 total += i->get()->getTotalPointCount(); 00554 return total; 00555 } 00556 00557 bool 00558 Polygon::contains2D( double x, double y ) const 00559 { 00560 // first check the outer ring 00561 if ( !Ring::contains2D(x, y) ) 00562 return false; 00563 00564 // then check each inner ring (holes). Point has to be inside the outer ring, 00565 // but NOT inside any of the holes 00566 for( RingCollection::const_iterator i = _holes.begin(); i != _holes.end(); ++i ) 00567 { 00568 if ( i->get()->contains2D(x, y) ) 00569 return false; 00570 } 00571 00572 return true; 00573 } 00574 00575 void 00576 Polygon::open() 00577 { 00578 Ring::open(); 00579 for( RingCollection::const_iterator i = _holes.begin(); i != _holes.end(); ++i ) 00580 (*i)->open(); 00581 } 00582 00583 //---------------------------------------------------------------------------- 00584 00585 MultiGeometry::MultiGeometry( const MultiGeometry& rhs ) : 00586 Geometry( rhs ) 00587 { 00588 for( GeometryCollection::const_iterator i = rhs._parts.begin(); i != rhs._parts.end(); ++i ) 00589 _parts.push_back( i->get()->clone() ); //i->clone() ); //osg::clone<Geometry>( i->get() ) ); 00590 } 00591 00592 MultiGeometry::MultiGeometry( const GeometryCollection& parts ) : 00593 _parts( parts ) 00594 { 00595 //nop 00596 } 00597 00598 Geometry::Type 00599 MultiGeometry::getComponentType() const 00600 { 00601 // dicey. 00602 return _parts.size() > 0 ? _parts.front()->getType() : TYPE_UNKNOWN; 00603 } 00604 00605 int 00606 MultiGeometry::getTotalPointCount() const 00607 { 00608 int total = 0; 00609 for( GeometryCollection::const_iterator i = _parts.begin(); i != _parts.end(); ++i ) 00610 total += i->get()->getTotalPointCount(); 00611 return total; 00612 } 00613 00614 unsigned 00615 MultiGeometry::getNumGeometries() const 00616 { 00617 unsigned total = 0; 00618 for( GeometryCollection::const_iterator i = _parts.begin(); i != _parts.end(); ++i ) 00619 total += i->get()->getNumGeometries(); 00620 return total; 00621 } 00622 00623 Bounds 00624 MultiGeometry::getBounds() const 00625 { 00626 Bounds bounds; 00627 for( GeometryCollection::const_iterator i = _parts.begin(); i != _parts.end(); ++i ) 00628 { 00629 bounds.expandBy( i->get()->getBounds() ); 00630 } 00631 return bounds; 00632 } 00633 00634 Geometry* 00635 MultiGeometry::cloneAs( const Geometry::Type& newType ) const 00636 { 00637 MultiGeometry* multi = new MultiGeometry(); 00638 for( GeometryCollection::const_iterator i = _parts.begin(); i != _parts.end(); ++i ) 00639 { 00640 Geometry* part = i->get()->cloneAs( i->get()->getType() ); 00641 if ( part ) multi->getComponents().push_back( part ); 00642 } 00643 return multi; 00644 } 00645 00646 bool 00647 MultiGeometry::isValid() const 00648 { 00649 if ( _parts.size() == 0 ) 00650 return false; 00651 00652 bool valid = true; 00653 for( GeometryCollection::const_iterator i = _parts.begin(); i != _parts.end() && valid; ++i ) 00654 { 00655 if ( !i->get()->isValid() ) 00656 valid = false; 00657 } 00658 return valid; 00659 } 00660 00661 //---------------------------------------------------------------------------- 00662 00663 GeometryIterator::GeometryIterator( Geometry* geom, bool holes ) : 00664 _next( 0L ), 00665 _traverseMulti( true ), 00666 _traversePolyHoles( holes ) 00667 { 00668 if ( geom ) 00669 { 00670 _stack.push( geom ); 00671 fetchNext(); 00672 } 00673 } 00674 00675 bool 00676 GeometryIterator::hasMore() const 00677 { 00678 return _next != 0L; 00679 } 00680 00681 Geometry* 00682 GeometryIterator::next() 00683 { 00684 Geometry* n = _next; 00685 fetchNext(); 00686 return n; 00687 } 00688 00689 void 00690 GeometryIterator::fetchNext() 00691 { 00692 _next = 0L; 00693 if ( _stack.size() == 0 ) 00694 return; 00695 00696 Geometry* current = _stack.top(); 00697 _stack.pop(); 00698 00699 if ( current->getType() == Geometry::TYPE_MULTI && _traverseMulti ) 00700 { 00701 MultiGeometry* m = static_cast<MultiGeometry*>(current); 00702 for( GeometryCollection::const_iterator i = m->getComponents().begin(); i != m->getComponents().end(); ++i ) 00703 _stack.push( i->get() ); 00704 fetchNext(); 00705 } 00706 else if ( current->getType() == Geometry::TYPE_POLYGON && _traversePolyHoles ) 00707 { 00708 Polygon* p = static_cast<Polygon*>(current); 00709 for( RingCollection::const_iterator i = p->getHoles().begin(); i != p->getHoles().end(); ++i ) 00710 _stack.push( i->get() ); 00711 _next = current; 00712 } 00713 else 00714 { 00715 _next = current; 00716 } 00717 } 00718 00719 //---------------------------------------------------------------------------- 00720 00721 ConstGeometryIterator::ConstGeometryIterator( const Geometry* geom, bool holes ) : 00722 _next( 0L ), 00723 _traverseMulti( true ), 00724 _traversePolyHoles( holes ) 00725 { 00726 if ( geom ) 00727 { 00728 _stack.push( geom ); 00729 fetchNext(); 00730 } 00731 } 00732 00733 bool 00734 ConstGeometryIterator::hasMore() const 00735 { 00736 return _next != 0L; 00737 } 00738 00739 const Geometry* 00740 ConstGeometryIterator::next() 00741 { 00742 const Geometry* n = _next; 00743 fetchNext(); 00744 return n; 00745 } 00746 00747 void 00748 ConstGeometryIterator::fetchNext() 00749 { 00750 _next = 0L; 00751 if ( _stack.size() == 0 ) 00752 return; 00753 00754 const Geometry* current = _stack.top(); 00755 _stack.pop(); 00756 00757 if ( current->getType() == Geometry::TYPE_MULTI && _traverseMulti ) 00758 { 00759 const MultiGeometry* m = static_cast<const MultiGeometry*>(current); 00760 for( GeometryCollection::const_iterator i = m->getComponents().begin(); i != m->getComponents().end(); ++i ) 00761 _stack.push( i->get() ); 00762 fetchNext(); 00763 } 00764 else if ( current->getType() == Geometry::TYPE_POLYGON && _traversePolyHoles ) 00765 { 00766 const Polygon* p = static_cast<const Polygon*>(current); 00767 for( RingCollection::const_iterator i = p->getHoles().begin(); i != p->getHoles().end(); ++i ) 00768 _stack.push( i->get() ); 00769 _next = current; 00770 } 00771 else 00772 { 00773 _next = current; 00774 } 00775 } 00776 00777 //---------------------------------------------------------------------------- 00778 00779 ConstSegmentIterator::ConstSegmentIterator( const Geometry* verts, bool closeLoop ) : 00780 _verts(&verts->asVector()), 00781 _closeLoop(closeLoop), 00782 _iter(verts->begin()) 00783 { 00784 _done = _verts->size() < 2; 00785 } 00786 00787 Segment 00788 ConstSegmentIterator::next() 00789 { 00790 osg::Vec3d p0 = *_iter++; 00791 if ( _iter == _verts->end() ) 00792 { 00793 _iter = _verts->begin(); 00794 _done = true; 00795 } 00796 else if ( _iter+1 == _verts->end() && !_closeLoop ) 00797 { 00798 _done = true; 00799 } 00800 00801 return Segment( p0, *_iter ); 00802 }