SurfaceNode::SurfaceNode(const TileKey& tilekey, const MapInfo& mapinfo, const RenderBindings& bindings, TileDrawable* drawable) { _tileKey = tilekey; _drawable = drawable; _surfaceGeode = new osg::Geode(); _surfaceGeode->addDrawable( drawable ); // Create the final node. addChild( _surfaceGeode.get() ); // Establish a local reference frame for the tile: GeoPoint centroid; tilekey.getExtent().getCentroid(centroid); osg::Matrix local2world; centroid.createLocalToWorld( local2world ); setMatrix( local2world ); _matrix = new osg::RefMatrix( local2world ); // Initialize the cached bounding box. setElevationRaster( 0L, osg::Matrixf::identity() ); }
void PolyhedralLineOfSightNode::recalculateExtent() { // get a local2world matrix for the map position: GeoPoint absMapPos = _mapPosition; absMapPos.makeAbsolute( getMapNode()->getTerrain() ); osg::Matrix local2world; absMapPos.createLocalToWorld( local2world ); // local offsets (east and north) osg::Vec3d x( _distance.as(Units::METERS), 0.0, 0.0 ); osg::Vec3d y( 0.0, _distance.as(Units::METERS), 0.0 ); // convert these to map coords: GeoPoint easting, northing; easting.fromWorld( getMapNode()->getMapSRS(), x * local2world ); northing.fromWorld( getMapNode()->getMapSRS(), y * local2world ); // calculate the offsets: double d_easting = easting.x() - absMapPos.x(); double d_northing = northing.y() - absMapPos.y(); // update the extent. _extent = GeoExtent( getMapNode()->getMapSRS(), absMapPos.x() - d_easting, absMapPos.y() - d_northing, absMapPos.x() + d_easting, absMapPos.y() + d_northing ); OE_INFO << LC << "Cached extent = " << _extent.toString() << std::endl; }
SurfaceNode::SurfaceNode(const TileKey& tilekey, const MapInfo& mapinfo, const RenderBindings& bindings, TileDrawable* drawable) : _debugNodeVisible(false) { _tileKey = tilekey; _drawable = drawable; _surfaceGeode = new osg::Geode(); _surfaceGeode->addDrawable( drawable ); // Create the final node. addChild( _surfaceGeode.get() ); // Establish a local reference frame for the tile: osg::Vec3d centerWorld; GeoPoint centroid; tilekey.getExtent().getCentroid(centroid); centroid.toWorld(centerWorld); osg::Matrix local2world; centroid.createLocalToWorld( local2world ); setMatrix( local2world ); _worldCorners.resize(8); _childrenCorners.resize(4); for(size_t i = 0; i < _childrenCorners.size(); ++i) { _childrenCorners[i].resize(8); } // Initialize the cached bounding box. setElevationExtrema(osg::Vec2f(0, 0)); }
osg::BoundingSphere LocalGeometryNode::computeBound() const { osg::BoundingSphere bs = AnnotationNode::computeBound(); // NOTE: this is the same code found in Feature.cpp. Consolidate? _boundingPT.clear(); // add planes for the four sides of the BS. Normals point inwards. _boundingPT.add( osg::Plane(osg::Vec3d( 1, 0,0), osg::Vec3d(-bs.radius(),0,0)) ); _boundingPT.add( osg::Plane(osg::Vec3d(-1, 0,0), osg::Vec3d( bs.radius(),0,0)) ); _boundingPT.add( osg::Plane(osg::Vec3d( 0, 1,0), osg::Vec3d(0, -bs.radius(),0)) ); _boundingPT.add( osg::Plane(osg::Vec3d( 0,-1,0), osg::Vec3d(0, bs.radius(),0)) ); const SpatialReference* srs = getPosition().getSRS(); if ( srs ) { // for a projected feature, we're done. For a geocentric one, transform the polytope // into world (ECEF) space. if ( srs->isGeographic() && !srs->isPlateCarre() ) { const osg::EllipsoidModel* e = srs->getEllipsoid(); // add a bottom cap, unless the bounds are sufficiently large. double minRad = std::min(e->getRadiusPolar(), e->getRadiusEquator()); double maxRad = std::max(e->getRadiusPolar(), e->getRadiusEquator()); double zeroOffset = bs.center().length(); if ( zeroOffset > minRad * 0.1 ) { _boundingPT.add( osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,-maxRad+zeroOffset)) ); } } // transform the clipping planes ito ECEF space GeoPoint refPoint; refPoint.fromWorld( srs, bs.center() ); osg::Matrix local2world; refPoint.createLocalToWorld( local2world ); _boundingPT.transform( local2world ); } return bs; }
void Dragger::updateTransform(osg::Node* patch) { osg::Matrixd matrix; GeoPoint mapPoint; _mapNode->getMap()->toMapPoint( _position, mapPoint ); //Get the height if (_position.altitudeMode() == ALTMODE_RELATIVE) { double hamsl; if (_mapNode->getTerrain()->getHeight(mapPoint.x(), mapPoint.y(), &hamsl, 0L, patch)) { mapPoint.z() += hamsl; } mapPoint.altitudeMode() = ALTMODE_ABSOLUTE; } mapPoint.createLocalToWorld( matrix ); setMatrix( matrix ); }
bool Feature::getWorldBoundingPolytope(const SpatialReference* srs, osg::Polytope& out_polytope) const { osg::BoundingSphered bs; if ( getWorldBound(srs, bs) && bs.valid() ) { out_polytope.clear(); // add planes for the four sides of the BS. Normals point inwards. out_polytope.add( osg::Plane(osg::Vec3d( 1, 0,0), osg::Vec3d(-bs.radius(),0,0)) ); out_polytope.add( osg::Plane(osg::Vec3d(-1, 0,0), osg::Vec3d( bs.radius(),0,0)) ); out_polytope.add( osg::Plane(osg::Vec3d( 0, 1,0), osg::Vec3d(0, -bs.radius(),0)) ); out_polytope.add( osg::Plane(osg::Vec3d( 0,-1,0), osg::Vec3d(0, bs.radius(),0)) ); // for a projected feature, we're done. For a geocentric one, transform the polytope // into world (ECEF) space. if ( srs->isGeographic() && !srs->isPlateCarre() ) { const osg::EllipsoidModel* e = srs->getEllipsoid(); // add a bottom cap, unless the bounds are sufficiently large. double minRad = std::min(e->getRadiusPolar(), e->getRadiusEquator()); double maxRad = std::max(e->getRadiusPolar(), e->getRadiusEquator()); double zeroOffset = bs.center().length(); if ( zeroOffset > minRad * 0.1 ) { out_polytope.add( osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,-maxRad+zeroOffset)) ); } } // transform the clipping planes ito ECEF space GeoPoint refPoint; refPoint.fromWorld( srs, bs.center() ); osg::Matrix local2world; refPoint.createLocalToWorld( local2world ); out_polytope.transform( local2world ); return true; } return false; }
void PolyhedralLineOfSightNode::updateSamples() { if ( _geode->getNumDrawables() == 0 ) rebuildGeometry(); osg::Geometry* geom = _geode->getDrawable(0)->asGeometry(); osg::Vec3Array* verts = dynamic_cast<osg::Vec3Array*>( geom->getVertexArray() ); double distance = _distance.as(Units::METERS); // get the world coords and a l2w transform for the origin: osg::Vec3d originWorld; osg::Matrix local2world, world2local; Terrain* t = getMapNode()->getTerrain(); GeoPoint origin = getPosition(); origin.makeAbsolute( t ); origin.toWorld( originWorld, t ); origin.createLocalToWorld( local2world ); world2local.invert( local2world ); // set up an intersector: osgUtil::LineSegmentIntersector* lsi = new osgUtil::LineSegmentIntersector( originWorld, originWorld ); osgUtil::IntersectionVisitor iv( lsi ); // intersect the verts (skip the origin point) with the map node. for( osg::Vec3Array::iterator v = verts->begin()+1; v != verts->end(); ++v ) { osg::Vec3d unit = *v; unit.normalize(); unit *= distance; osg::Vec3d world = unit * local2world; if ( osg::equivalent(unit.length(), 0.0) ) { OE_WARN << "problem." << std::endl; } lsi->reset(); lsi->setStart( originWorld ); lsi->setEnd( world ); OE_DEBUG << LC << "Ray: " << originWorld.x() << "," << originWorld.y() << "," << originWorld.z() << " => " << world.x() << "," << world.y() << "," << world.z() << std::endl; getMapNode()->getTerrain()->accept( iv ); osgUtil::LineSegmentIntersector::Intersections& hits = lsi->getIntersections(); if ( !hits.empty() ) { const osgUtil::LineSegmentIntersector::Intersection& hit = *hits.begin(); osg::Vec3d newV = hit.getWorldIntersectPoint() * world2local; if ( newV.length() > 1.0 ) *v = newV; else *v = unit; } else { *v = unit; } //OE_NOTICE << "Radial point = " << v->x() << ", " << v->y() << ", " << v->z() << std::endl; } verts->dirty(); geom->dirtyBound(); }
bool BillboardExtension::connect(MapNode* mapNode) { if ( !mapNode ) { OE_WARN << LC << "Illegal: MapNode cannot be null." << std::endl; return false; } OE_INFO << LC << "Connecting to MapNode.\n"; if ( !_options.imageURI().isSet() ) { OE_WARN << LC << "Illegal: image URI is required" << std::endl; return false; } if ( !_options.featureOptions().isSet() ) { OE_WARN << LC << "Illegal: feature source is required" << std::endl; return false; } _features = FeatureSourceFactory::create( _options.featureOptions().value() ); if ( !_features.valid() ) { OE_WARN << LC << "Illegal: no valid feature source provided" << std::endl; return false; } //if ( _features->getGeometryType() != osgEarth::Symbology::Geometry::TYPE_POINTSET ) //{ // OE_WARN << LC << "Illegal: only points currently supported" << std::endl; // return false; //} _features->initialize( _dbOptions ); osg::Vec3dArray* verts; if ( _features->getFeatureProfile() ) { verts = new osg::Vec3dArray(); OE_NOTICE << "Reading features...\n"; osg::ref_ptr<FeatureCursor> cursor = _features->createFeatureCursor(); while ( cursor.valid() && cursor->hasMore() ) { Feature* f = cursor->nextFeature(); if ( f && f->getGeometry() ) { if ( f->getGeometry()->getComponentType() == Geometry::TYPE_POLYGON ) { FilterContext cx; cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) ); ScatterFilter scatter; scatter.setDensity( _options.density().get() ); scatter.setRandom( true ); FeatureList featureList; featureList.push_back(f); scatter.push( featureList, cx ); } // Init a filter to tranform feature in desired SRS if (!mapNode->getMapSRS()->isEquivalentTo(_features->getFeatureProfile()->getSRS())) { FilterContext cx; cx.setProfile( new FeatureProfile(_features->getFeatureProfile()->getExtent()) ); TransformFilter xform( mapNode->getMapSRS() ); FeatureList featureList; featureList.push_back(f); cx = xform.push(featureList, cx); } GeometryIterator iter(f->getGeometry()); while(iter.hasMore()) { const Geometry* geom = iter.next(); osg::ref_ptr<osg::Vec3dArray> fVerts = geom->createVec3dArray(); verts->insert(verts->end(), fVerts->begin(), fVerts->end()); } } } } else { OE_WARN << LC << "Illegal: feature source has no SRS" << std::endl; return false; } if ( verts && verts->size() > 0 ) { OE_NOTICE << LC << "Read " << verts->size() << " points.\n"; //localize all the verts GeoPoint centroid; _features->getFeatureProfile()->getExtent().getCentroid(centroid); centroid = centroid.transform(mapNode->getMapSRS()); OE_NOTICE << "Centroid = " << centroid.x() << ", " << centroid.y() << "\n"; osg::Matrixd l2w, w2l; centroid.createLocalToWorld(l2w); w2l.invert(l2w); osg::MatrixTransform* mt = new osg::MatrixTransform; mt->setMatrix(l2w); OE_NOTICE << "Clamping elevations...\n"; osgEarth::ElevationQuery eq(mapNode->getMap()); eq.setFallBackOnNoData( true ); eq.getElevations(verts->asVector(), mapNode->getMapSRS(), true, 0.005); OE_NOTICE << "Building geometry...\n"; osg::Vec3Array* normals = new osg::Vec3Array(verts->size()); osg::Vec4Array* colors = new osg::Vec4Array(verts->size()); Random rng; for (int i=0; i < verts->size(); i++) { GeoPoint vert(mapNode->getMapSRS(), (*verts)[i], osgEarth::ALTMODE_ABSOLUTE); osg::Vec3d world; vert.toWorld(world); (*verts)[i] = world * w2l; osg::Vec3 normal = world; normal.normalize(); (*normals)[i] = osg::Matrix::transform3x3(normal, w2l); double n = rng.next(); (*colors)[i].set( n, n, n, 1 ); } //create geom and primitive sets osg::Geometry* geometry = new osg::Geometry(); geometry->setVertexArray( verts ); geometry->setNormalArray( normals ); geometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX ); geometry->setColorArray(colors); geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX ); geometry->addPrimitiveSet( new osg::DrawArrays( GL_POINTS, 0, verts->size() ) ); //create image and texture to render to osg::Texture2D* tex = new osg::Texture2D(_options.imageURI()->getImage(_dbOptions)); tex->setResizeNonPowerOfTwoHint(false); tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR ); tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR ); tex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); tex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); geometry->setName("BillboardPoints"); osg::Geode* geode = new osg::Geode; geode->addDrawable(geometry); //osg::ref_ptr<StateSetCache> cache = new StateSetCache(); //Registry::shaderGenerator().run(geode, cache.get()); //set the texture related uniforms osg::StateSet* geode_ss = geode->getOrCreateStateSet(); geode_ss->setTextureAttributeAndModes( 2, tex, 1 ); geode_ss->getOrCreateUniform("billboard_tex", osg::Uniform::SAMPLER_2D)->set( 2 ); float bbWidth = (float)tex->getImage()->s() / 2.0f; float bbHeight = (float)tex->getImage()->t(); float aspect = (float)tex->getImage()->s() / (float)tex->getImage()->t(); if (_options.height().isSet()) { bbHeight = _options.height().get(); if (!_options.width().isSet()) { bbWidth = bbHeight * aspect / 2.0f; } } if (_options.width().isSet()) { bbWidth = _options.width().get() / 2.0f; if (!_options.height().isSet()) { bbHeight = _options.width().get() / aspect; } } geode_ss->getOrCreateUniform("billboard_width", osg::Uniform::FLOAT)->set( bbWidth ); geode_ss->getOrCreateUniform("billboard_height", osg::Uniform::FLOAT)->set( bbHeight ); geode_ss->setMode(GL_BLEND, osg::StateAttribute::ON); //for now just using an osg::Program //TODO: need to add GeometryShader support to the shader comp setup VirtualProgram* vp = VirtualProgram::getOrCreate(geode_ss); vp->setName( "osgEarth Billboard Extension" ); ShaderPackage shaders; shaders.add( "Billboard geometry shader", billboardGeomShader ); shaders.add( "Billboard fragment shader", billboardFragShader ); shaders.loadAll( vp ); geode_ss->setMode( GL_CULL_FACE, osg::StateAttribute::OFF ); geode->setCullingActive(false); mt->addChild(geode); mapNode->getModelLayerGroup()->addChild(mt); return true; } return false; }
bool GeoTransform::setPosition(const GeoPoint& position) { if ( !position.isValid() ) return false; _position = position; // relative Z or reprojection require a terrain: osg::ref_ptr<Terrain> terrain; _terrain.lock(terrain); // relative Z requires a terrain: if (position.altitudeMode() == ALTMODE_RELATIVE && !terrain.valid()) { OE_TEST << LC << "setPosition failed condition 1\n"; return false; } GeoPoint p; // transform into terrain SRS if neccesary: if (terrain.valid() && !terrain->getSRS()->isEquivalentTo(position.getSRS())) p = position.transform(terrain->getSRS()); else p = position; // bail if the transformation failed: if ( !p.isValid() ) { OE_TEST << LC << "setPosition failed condition 2\n"; return false; } // convert to absolute height: if ( !p.makeAbsolute(_terrain.get()) ) { OE_TEST << LC << "setPosition failed condition 3\n"; return false; } // assemble the matrix: osg::Matrixd local2world; p.createLocalToWorld( local2world ); this->setMatrix( local2world ); // install auto-recompute? if (_autoRecompute && _position.altitudeMode() == ALTMODE_RELATIVE && !_autoRecomputeReady) { // by using the adapter, there's no need to remove // the callback then this object destructs. terrain->addTerrainCallback( new TerrainCallbackAdapter<GeoTransform>(this) ); _autoRecomputeReady = true; } return true; }