bool Bounds::contains(const Bounds& rhs) const { return isValid() && rhs.isValid() && xMin() <= rhs.xMin() && xMax() >= rhs.xMax() && yMin() <= rhs.yMin() && yMax() >= rhs.yMax(); }
bool CubeSpatialReference::transformExtentToMBR(const SpatialReference* to_srs, double& in_out_xmin, double& in_out_ymin, double& in_out_xmax, double& in_out_ymax ) const { // input bounds: Bounds inBounds(in_out_xmin, in_out_ymin, in_out_xmax, in_out_ymax); Bounds outBounds; // for each CUBE face, find the intersection of the input bounds and that face. for (int face = 0; face < 6; ++face) { Bounds faceBounds( (double)(face), 0.0, (double)(face+1), 1.0); Bounds intersection = faceBounds.intersectionWith(inBounds); // if they intersect (with a non-zero area; abutting doesn't count in this case) // transform the intersection and include in the result. if (intersection.isValid() && intersection.area2d() > 0.0) { double xmin = intersection.xMin(), ymin = intersection.yMin(), xmax = intersection.xMax(), ymax = intersection.yMax(); if (transformInFaceExtentToMBR(to_srs, face, xmin, ymin, xmax, ymax)) { outBounds.expandBy(Bounds(xmin, ymin, xmax, ymax)); } } } if (outBounds.valid()) { in_out_xmin = outBounds.xMin(); in_out_ymin = outBounds.yMin(); in_out_xmax = outBounds.xMax(); in_out_ymax = outBounds.yMax(); return true; } else { return false; } }
osg::Vec3d Geometry::localize() { osg::Vec3d offset; Bounds bounds = getBounds(); if ( bounds.isValid() ) { osg::Vec2d center = bounds.center2d(); offset.set( center.x(), center.y(), 0 ); GeometryIterator i( this ); while( i.hasMore() ) { Geometry* part = i.next(); for( Geometry::iterator j = part->begin(); j != part->end(); ++j ) { *j = *j - offset; } } } return offset; }
/** Packages an image layer as a TMS folder. */ int makeTMS( osg::ArgumentParser& args ) { // see if the user wants to override the type extension (imagery only) std::string extension; args.read( "--ext", extension ); // verbosity? bool verbose = !args.read( "--quiet" ); // find a .earth file on the command line std::string earthFile = findArgumentWithExtension( args, ".earth" ); /* if ( earthFile.empty() ) return usage( "Missing required .earth file" ); */ // folder to which to write the TMS archive. std::string rootFolder; if( !args.read( "--out", rootFolder ) ) rootFolder = Stringify() << earthFile << ".tms_repo"; // whether to overwrite existing tile files bool overwrite = false; if( args.read( "--overwrite" ) ) overwrite = true; // write out an earth file std::string outEarth; args.read( "--out-earth", outEarth ); std::string dbOptions; args.read( "--db-options", dbOptions ); std::string::size_type n = 0; while( (n = dbOptions.find( '"', n )) != dbOptions.npos ) { dbOptions.erase( n, 1 ); } osg::ref_ptr<osgDB::Options> options = new osgDB::Options( dbOptions ); std::vector< Bounds > bounds; // restrict packaging to user-specified bounds. double xmin = DBL_MAX, ymin = DBL_MAX, xmax = DBL_MIN, ymax = DBL_MIN; while( args.read( "--bounds", xmin, ymin, xmax, ymax ) ) { Bounds b; b.xMin() = xmin, b.yMin() = ymin, b.xMax() = xmax, b.yMax() = ymax; bounds.push_back( b ); } // max level to which to generate unsigned maxLevel = ~0; args.read( "--max-level", maxLevel ); // whether to keep 'empty' tiles bool keepEmpties = args.read( "--keep-empties" ); bool continueSingleColor = args.read( "--continue-single-color" ); // max level to which to generate unsigned elevationPixelDepth = 32; args.read( "--elevation-pixel-depth", elevationPixelDepth ); // load up the map osg::ref_ptr<MapNode> mapNode = MapNode::load( args ); if( !mapNode.valid() ) return usage( "Failed to load a valid .earth file" ); // create a folder for the output osgDB::makeDirectory( rootFolder ); if( !osgDB::fileExists( rootFolder ) ) return usage( "Failed to create root output folder" ); Map* map = mapNode->getMap(); // fire up a packager: TMSPackager packager( map->getProfile(), options ); packager.setVerbose( verbose ); packager.setOverwrite( overwrite ); packager.setKeepEmptyImageTiles( keepEmpties ); packager.setSubdivideSingleColorImageTiles( continueSingleColor ); packager.setElevationPixelDepth( elevationPixelDepth ); if( maxLevel != ~0 ) packager.setMaxLevel( maxLevel ); if( bounds.size() > 0 ) { for( unsigned int i = 0; i < bounds.size(); ++i ) { Bounds b = bounds[i]; if( b.isValid() ) packager.addExtent( GeoExtent( map->getProfile()->getSRS(), b ) ); } } // new map for an output earth file if necessary. osg::ref_ptr<Map> outMap = 0L; if( !outEarth.empty() ) { // copy the options from the source map first outMap = new Map( map->getInitialMapOptions() ); } // establish the output path of the earth file, if applicable: std::string outEarthFile = osgDB::concatPaths( rootFolder, osgDB::getSimpleFileName( outEarth ) ); // package any image layers that are enabled: ImageLayerVector imageLayers; map->getImageLayers( imageLayers ); unsigned counter = 0; for( ImageLayerVector::iterator i = imageLayers.begin(); i != imageLayers.end(); ++i, ++counter ) { ImageLayer* layer = i->get(); if( layer->getImageLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if( layerFolder.empty() ) layerFolder = Stringify() << "image_layer_" << counter; if( verbose ) { OE_NOTICE << LC << "Packaging image layer \"" << layerFolder << "\"" << std::endl; } osg::ref_ptr< ConsoleProgressCallback > progress = new ConsoleProgressCallback(); std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); TMSPackager::Result r = packager.package( layer, layerRoot, progress, extension ); if( r.ok ) { // save to the output map if requested: if( outMap.valid() ) { // new TMS driver info: TMSOptions tms; tms.url() = URI( osgDB::concatPaths( layerFolder, "tms.xml" ), outEarthFile ); ImageLayerOptions layerOptions( layer->getName(), tms ); layerOptions.mergeConfig( layer->getInitialOptions().getConfig( true ) ); layerOptions.cachePolicy() = CachePolicy::NO_CACHE; outMap->addImageLayer( new ImageLayer( layerOptions ) ); } } else { OE_WARN << LC << r.message << std::endl; } } else if( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } // package any elevation layers that are enabled: counter = 0; ElevationLayerVector elevationLayers; map->getElevationLayers( elevationLayers ); for( ElevationLayerVector::iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i, ++counter ) { ElevationLayer* layer = i->get(); if( layer->getElevationLayerOptions().enabled() == true ) { std::string layerFolder = toLegalFileName( layer->getName() ); if( layerFolder.empty() ) layerFolder = Stringify() << "elevation_layer_" << counter; if( verbose ) { OE_NOTICE << LC << "Packaging elevation layer \"" << layerFolder << "\"" << std::endl; } std::string layerRoot = osgDB::concatPaths( rootFolder, layerFolder ); TMSPackager::Result r = packager.package( layer, layerRoot ); if( r.ok ) { // save to the output map if requested: if( outMap.valid() ) { // new TMS driver info: TMSOptions tms; tms.url() = URI( osgDB::concatPaths( layerFolder, "tms.xml" ), outEarthFile ); ElevationLayerOptions layerOptions( layer->getName(), tms ); layerOptions.mergeConfig( layer->getInitialOptions().getConfig( true ) ); layerOptions.cachePolicy() = CachePolicy::NO_CACHE; outMap->addElevationLayer( new ElevationLayer( layerOptions ) ); } } else { OE_WARN << LC << r.message << std::endl; } } else if( verbose ) { OE_NOTICE << LC << "Skipping disabled layer \"" << layer->getName() << "\"" << std::endl; } } // Finally, write an earth file if requested: if( outMap.valid() ) { MapNodeOptions outNodeOptions = mapNode->getMapNodeOptions(); osg::ref_ptr<MapNode> outMapNode = new MapNode( outMap.get(), outNodeOptions ); if( !osgDB::writeNodeFile( *outMapNode.get(), outEarthFile ) ) { OE_WARN << LC << "Error writing earth file to \"" << outEarthFile << "\"" << std::endl; } else if( verbose ) { OE_NOTICE << LC << "Wrote earth file to \"" << outEarthFile << "\"" << std::endl; } } return 0; }
FilterContext CropFilter::push( FeatureList& input, FilterContext& context ) { if ( !context.extent().isSet() ) { OE_WARN << LC << "Extent is not set (and is required)" << std::endl; return context; } const GeoExtent& extent = *context.extent(); GeoExtent newExtent( extent.getSRS() ); if ( _method == METHOD_CENTROID ) { for( FeatureList::iterator i = input.begin(); i != input.end(); ) { bool keepFeature = false; Feature* feature = i->get(); Geometry* featureGeom = feature->getGeometry(); if ( featureGeom && featureGeom->isValid() ) { Bounds bounds = featureGeom->getBounds(); if ( bounds.isValid() ) { osg::Vec3d centroid = bounds.center(); if ( extent.contains( centroid.x(), centroid.y() ) ) { keepFeature = true; newExtent.expandToInclude( bounds.xMin(), bounds.yMin() ); } } } if ( keepFeature ) ++i; else i = input.erase( i ); } } else // METHOD_CROPPING (requires GEOS) { #ifdef OSGEARTH_HAVE_GEOS // create the intersection polygon: osg::ref_ptr<Symbology::Polygon> poly; for( FeatureList::iterator i = input.begin(); i != input.end(); ) { bool keepFeature = false; Feature* feature = i->get(); Symbology::Geometry* featureGeom = feature->getGeometry(); if ( featureGeom && featureGeom->isValid() ) { // test for trivial acceptance: const Bounds bounds = featureGeom->getBounds(); if ( !bounds.isValid() ) { //nop } else if ( extent.contains( bounds ) ) { keepFeature = true; newExtent.expandToInclude( bounds ); } // then move on to the cropping operation: else { if ( !poly.valid() ) { poly = new Symbology::Polygon(); poly->push_back( osg::Vec3d( extent.xMin(), extent.yMin(), 0 )); poly->push_back( osg::Vec3d( extent.xMax(), extent.yMin(), 0 )); poly->push_back( osg::Vec3d( extent.xMax(), extent.yMax(), 0 )); poly->push_back( osg::Vec3d( extent.xMin(), extent.yMax(), 0 )); } osg::ref_ptr<Geometry> croppedGeometry; if ( featureGeom->crop( poly.get(), croppedGeometry ) ) { if ( croppedGeometry->isValid() ) { feature->setGeometry( croppedGeometry.get() ); keepFeature = true; newExtent.expandToInclude( croppedGeometry->getBounds() ); } } } } if ( keepFeature ) ++i; else i = input.erase( i ); } #else // OSGEARTH_HAVE_GEOS OE_WARN << "CropFilter - METHOD_CROPPING not available - please compile osgEarth with GEOS" << std::endl; return context; #endif } FilterContext newContext = context; newContext.extent() = newExtent; return newContext; }
int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); if (argc < 2) { return usage(""); } //The first level unsigned int firstLevel = 0; while (arguments.read("--first-level", firstLevel)); //The max level unsigned int maxLevel = 6; while (arguments.read("--max-level", maxLevel)); unsigned int maxFeatures = 300; while (arguments.read("--max-features", maxFeatures)); //The destination directory std::string destination = "out"; while (arguments.read("--out", destination)); //The name of the layer std::string layer = "layer"; while (arguments.read("--layer", layer)); //The description of the layer std::string description = ""; while (arguments.read("--description", description)); std::string queryExpression = ""; while (arguments.read("--expression", queryExpression)); std::string queryOrderBy = ""; while (arguments.read("--order-by", queryOrderBy)); CropFilter::Method cropMethod = CropFilter::METHOD_CENTROID; if (arguments.read("--crop")) { cropMethod = CropFilter::METHOD_CROPPING; } std::string destSRS; while(arguments.read("--dest-srs", destSRS)); // Custom bounding box Bounds bounds; double xmin=DBL_MAX, ymin=DBL_MAX, xmax=DBL_MIN, ymax=DBL_MIN; while (arguments.read("--bounds", xmin, ymin, xmax, ymax )) { bounds.xMin() = xmin; bounds.yMin() = ymin; bounds.xMax() = xmax; bounds.yMax() = ymax; } std::string filename; //Get the first argument that is not an option for(int pos=1;pos<arguments.argc();++pos) { if (!arguments.isOption(pos)) { filename = arguments[ pos ]; break; } } if (filename.empty()) { return usage( "Please provide a filename" ); } //Open the feature source OGRFeatureOptions featureOpt; featureOpt.url() = filename; osg::ref_ptr< FeatureSource > features = FeatureSourceFactory::create( featureOpt ); if (!features.valid()) { OE_NOTICE << "Failed to open " << filename << std::endl; return 1; } features->initialize(); const FeatureProfile* profile = features->getFeatureProfile(); if (!profile) { OE_NOTICE << "Failed to create a valid profile for " << filename << std::endl; return 1; } std::string method = cropMethod == CropFilter::METHOD_CENTROID ? "Centroid" : "Cropping"; OE_NOTICE << "Processing " << filename << std::endl << " FirstLevel=" << firstLevel << std::endl << " MaxLevel=" << maxLevel << std::endl << " MaxFeatures=" << maxFeatures << std::endl << " Destination=" << destination << std::endl << " Layer=" << layer << std::endl << " Description=" << description << std::endl << " Expression=" << queryExpression << std::endl << " OrderBy=" << queryOrderBy << std::endl << " Method= " << method << std::endl << " DestSRS= " << destSRS << std::endl << std::endl; Query query; if (!queryExpression.empty()) { query.expression() = queryExpression; } if (!queryOrderBy.empty()) { query.orderby() = queryOrderBy; } osg::Timer_t startTime = osg::Timer::instance()->tick(); //buildTFS( features.get(), firstLevel, maxLevel, maxFeatures, destination, layer, description, query, cropMethod); TFSPackager packager; packager.setFirstLevel( firstLevel ); packager.setMaxLevel( maxLevel ); packager.setMaxFeatures( maxFeatures ); packager.setQuery( query ); packager.setMethod( cropMethod ); packager.setDestSRS( destSRS ); if (bounds.isValid()) { packager.setLod0Extent(GeoExtent(osgEarth::SpatialReference::create( destSRS ), bounds)); } packager.package( features, destination, layer, description ); osg::Timer_t endTime = osg::Timer::instance()->tick(); OE_NOTICE << "Completed in " << osg::Timer::instance()->delta_s( startTime, endTime ) << " s " << std::endl; return 0; }