void TessellateOperator::tessellateLinear( const osg::Vec3d& p0, const osg::Vec3d& p1, unsigned parts, Vec3dVector& out ) { osg::Vec3d vec = (p1-p0)/double(parts); out.push_back( p0 ); for( unsigned i=1; i<parts; ++i ) { out.push_back( p0 + vec*double(i) ); } }
void TessellateOperator::operator()( Feature* feature, FilterContext& context ) const { if (_numPartitions <= 1 || !feature || !feature->getGeometry() || feature->getGeometry()->getComponentType() == Geometry::TYPE_POINTSET ) { return; } bool isGeo = context.profile() ? context.profile()->getSRS()->isGeographic() : true; GeoInterpolation interp = feature->geoInterp().isSet() ? *feature->geoInterp() : _defaultInterp; GeometryIterator i( feature->getGeometry(), true ); while( i.hasMore() ) { Geometry* g = i.next(); bool isRing = dynamic_cast<Ring*>( g ) != 0L; Vec3dVector newVerts; newVerts.reserve( g->size() * _numPartitions ); for( Geometry::const_iterator v = g->begin(); v != g->end(); ++v ) { const osg::Vec3d& p0 = *v; if ( v != g->end()-1 ) // not last vert { if ( isGeo ) tessellateGeo( *v, *(v+1), _numPartitions, interp, newVerts ); else tessellateLinear( *v, *(v+1), _numPartitions, newVerts ); } else if ( isRing ) { if ( isGeo ) tessellateGeo( *v, *g->begin(), _numPartitions, interp, newVerts ); else tessellateLinear( *v, *g->begin(), _numPartitions, newVerts ); } else { // get the final vert. newVerts.push_back( *v ); } } g->swap( newVerts ); } }
void TessellateOperator::tessellateGeo( const osg::Vec3d& p0, const osg::Vec3d& p1, unsigned parts, GeoInterpolation interp, Vec3dVector& out ) { double step = 1.0/double(parts); double zdelta = p1.z() - p0.z(); out.push_back( p0 ); for( unsigned i=1; i<parts; ++i ) { double t = step*double(i); osg::Vec3d p; if ( interp == GEOINTERP_GREAT_CIRCLE ) { double lat, lon; GeoMath::interpolate( osg::DegreesToRadians(p0.y()), osg::DegreesToRadians(p0.x()), osg::DegreesToRadians(p1.y()), osg::DegreesToRadians(p1.x()), t, lat, lon ); p.set( osg::RadiansToDegrees(lon), osg::RadiansToDegrees(lat), p0.z() + t*zdelta ); } else // GEOINTERP_RHUMB_LINE { double lat1 = osg::DegreesToRadians(p0.y()), lon1 = osg::DegreesToRadians(p0.x()); double lat2 = osg::DegreesToRadians(p1.y()), lon2 = osg::DegreesToRadians(p1.x()); double totalDistance = GeoMath::rhumbDistance( lat1, lon1, lat2, lon2 ); double bearing = GeoMath::rhumbBearing( lat1, lon1, lat2, lon2 ); double interpDistance = t * totalDistance; double lat3, lon3; GeoMath::rhumbDestination(lat1, lon1, bearing, interpDistance, lat3, lon3); p.set( osg::RadiansToDegrees(lon3), osg::RadiansToDegrees(lat3), p0.z() + t*zdelta ); } out.push_back(p); } }
void TessellateOperator::operator()( Feature* feature, FilterContext& context ) const { if (_numPartitions <= 1 || !feature || !feature->getGeometry() || feature->getGeometry()->getComponentType() == Geometry::TYPE_POINTSET ) { return; } Units featureUnits = feature->getSRS() ? feature->getSRS()->getUnits() : Units::METERS; bool isGeo = feature->getSRS() ? feature->getSRS()->isGeographic() : false; GeoInterpolation geoInterp = feature->geoInterp().isSet() ? *feature->geoInterp() : _defaultInterp; double sliceSize = 0.0; int numPartitions = _numPartitions; if ( _maxDistance.isSet() ) { // copmpute the slice size in feature units. double latitude = feature->getGeometry()->getBounds().center().y(); sliceSize = SpatialReference::transformUnits( _maxDistance.value(), feature->getSRS(), latitude ); sliceSize = _maxDistance->as(Units::METERS); } GeometryIterator i( feature->getGeometry(), true ); while( i.hasMore() ) { Geometry* g = i.next(); bool isRing = dynamic_cast<Ring*>( g ) != 0L; Vec3dVector newVerts; for( Geometry::const_iterator v = g->begin(); v != g->end(); ++v ) { unsigned slices = _numPartitions; const osg::Vec3d& p0 = *v; if ( v != g->end()-1 ) // not last vert { // calculate slice count if ( sliceSize > 0.0 ) { double dist = GeoMath::distance(*v, *(v + 1), feature->getSRS()); slices = std::max( 1u, (unsigned)(dist / sliceSize) ); } if ( isGeo ) tessellateGeo( *v, *(v+1), slices, geoInterp, newVerts ); else tessellateLinear( *v, *(v+1), slices, newVerts ); } else if ( isRing ) { // calculate slice count if ( sliceSize > 0.0 ) { double dist = GeoMath::distance(*v, *g->begin(), feature->getSRS()); slices = std::max( 1u, (unsigned)(dist / sliceSize) ); } if ( isGeo ) tessellateGeo( *v, *g->begin(), slices, geoInterp, newVerts ); else tessellateLinear( *v, *g->begin(), slices, newVerts ); } else { // get the final vert. newVerts.push_back( *v ); } } g->swap( newVerts ); } }