Esempio n. 1
0
float
ElevationQuery::getElevation(const GeoPoint& point,
                             double          desiredResolution,
                             double*         out_actualResolution)
{
    float result = NO_DATA_VALUE;

    sync();
    if ( point.altitudeMode() == ALTMODE_ABSOLUTE )
    {
        getElevationImpl( point, result, desiredResolution, out_actualResolution );
    }
    else
    {
        GeoPoint point_abs( point.getSRS(), point.x(), point.y(), 0.0, ALTMODE_ABSOLUTE );
        getElevationImpl( point_abs, result, desiredResolution, out_actualResolution );
    }

    return result;
}
Esempio n. 2
0
void
MouseCoordsLabelCallback::set( const GeoPoint& mapCoords, osg::View* view, MapNode* mapNode )
{
    if ( _label.valid() )
    {
        if ( _formatter )
        {
            _label->setText( Stringify()
                <<  _formatter->format( mapCoords )
                << ", " << mapCoords.z() );
        }
        else
        {
            _label->setText( Stringify()
                << std::fixed
                << mapCoords.x()
                << ", " << mapCoords.y()
                << ", " << mapCoords.z() );
        }
    }
}
Esempio n. 3
0
GeoPoint
RectangleNode::getCorner( Corner corner ) const
{
    GeoPoint center = getPosition();

    double earthRadius = center.getSRS()->getEllipsoid()->getRadiusEquator();
    double lat = osg::DegreesToRadians(center.y());
    double lon = osg::DegreesToRadians(center.x());
    double halfWidthMeters  =  _width.as(Units::METERS) / 2.0;
    double halfHeightMeters  = _height.as(Units::METERS) / 2.0;   

    double eastLon, eastLat;
    double westLon, westLat;
    double northLon, northLat;
    double southLon, southLat;
        
    GeoMath::destination( lat, lon, osg::DegreesToRadians( 90.0 ), halfWidthMeters, eastLat, eastLon, earthRadius );
    GeoMath::destination( lat, lon, osg::DegreesToRadians( -90.0 ), halfWidthMeters, westLat, westLon, earthRadius );
    GeoMath::destination( lat, lon, osg::DegreesToRadians( 0.0 ),  halfHeightMeters, northLat, northLon, earthRadius );
    GeoMath::destination( lat, lon, osg::DegreesToRadians( 180.0 ), halfHeightMeters, southLat, southLon, earthRadius );

    if (corner == CORNER_LOWER_LEFT)
    {
        return GeoPoint(center.getSRS(), osg::RadiansToDegrees(westLon), osg::RadiansToDegrees(southLat), 0, ALTMODE_RELATIVE);
    }
    else if (corner == CORNER_LOWER_RIGHT)
    {
        return GeoPoint(center.getSRS(), osg::RadiansToDegrees(eastLon), osg::RadiansToDegrees(southLat), 0, ALTMODE_RELATIVE);
    }
    else if (corner == CORNER_UPPER_LEFT)
    {
        return GeoPoint(center.getSRS(), osg::RadiansToDegrees(westLon), osg::RadiansToDegrees(northLat), 0, ALTMODE_RELATIVE);
    }
    else if (corner == CORNER_UPPER_RIGHT)
    {
        return GeoPoint(center.getSRS(), osg::RadiansToDegrees(eastLon), osg::RadiansToDegrees(northLat), 0, ALTMODE_RELATIVE);
    }
    return GeoPoint();
}
void LOSCreationDialog::centerMapOnNode(osg::Node* node)
{
  if (node && _map.valid() && _manager.valid() && _views)
  {
    AnnotationNode* annoNode = dynamic_cast<AnnotationNode*>(node);
    if (annoNode && annoNode->getAnnotationData() && annoNode->getAnnotationData()->getViewpoint())
    {
      _manager->doAction(this, new SetViewpointAction(osgEarth::Viewpoint(*annoNode->getAnnotationData()->getViewpoint()), *_views));
    }
    else
    {
      osg::Vec3d center = node->getBound().center();

      GeoPoint output;
      output.fromWorld( _map->getSRS(), center );
      //_map->worldPointToMapPoint(center, output);

      _manager->doAction(this, new SetViewpointAction(osgEarth::Viewpoint(
          "center", output.x(), output.y(), output.z(), 0.0, -90.0, 1e5), *_views));
    }
  }
}
Esempio n. 5
0
bool
ElevationQuery::getElevationImpl(const GeoPoint& point,
                                 double&         out_elevation,
                                 double          desiredResolution,
                                 double*         out_actualResolution)
{
    osg::Timer_t start = osg::Timer::instance()->tick();

    if ( _mapf.elevationLayers().empty() )
    {
        // this means there are no heightfields.
        out_elevation = 0.0;
        return true;        
    }

    // tile size (resolution of elevation tiles)
    unsigned tileSize = std::max(_mapf.getMapOptions().elevationTileSize().get(), 2u);

    //This is the max resolution that we actually have data at this point
    unsigned int bestAvailLevel = getMaxLevel( point.x(), point.y(), point.getSRS(), _mapf.getProfile());

    if (desiredResolution > 0.0)
    {
        unsigned int desiredLevel = _mapf.getProfile()->getLevelOfDetailForHorizResolution( desiredResolution, tileSize );
        if (desiredLevel < bestAvailLevel) bestAvailLevel = desiredLevel;
    }

    OE_DEBUG << LC << "Best available data level " << point.x() << ", " << point.y() << " = "  << bestAvailLevel << std::endl;

    // transform the input coords to map coords:
    GeoPoint mapPoint = point;
    if ( point.isValid() && !point.getSRS()->isHorizEquivalentTo( _mapf.getProfile()->getSRS() ) )
    {
        mapPoint = point.transform(_mapf.getProfile()->getSRS());
        if ( !mapPoint.isValid() )
        {
            OE_WARN << LC << "Fail: coord transform failed" << std::endl;
            return false;
        }
    }    

    // get the tilekey corresponding to the tile we need:
    TileKey key = _mapf.getProfile()->createTileKey( mapPoint.x(), mapPoint.y(), bestAvailLevel );
    if ( !key.valid() )
    {
        OE_WARN << LC << "Fail: coords fall outside map" << std::endl;
        return false;
    }
        
    bool result = false;      
    while (!result)
    {      
        GeoHeightField geoHF;
        TileCache::Record record;
        // Try to get the hf from the cache
        if ( _cache.get( key, record ) )
        {                        
            geoHF = record.value();
        }
        else
        {
            // Create it            
            osg::ref_ptr<osg::HeightField> hf = new osg::HeightField();
            hf->allocate( tileSize, tileSize );

            // Initialize the heightfield to nodata
            for (unsigned int i = 0; i < hf->getFloatArray()->size(); i++)
            {
                hf->getFloatArray()->at( i ) = NO_DATA_VALUE;
            }   

            if (_mapf.populateHeightField( hf, key ) )
            {                
                geoHF = GeoHeightField( hf.get(), key.getExtent() );
                _cache.insert( key, geoHF );
            }
        }

        if (geoHF.valid())
        {            
            float elevation = 0.0f;                 
            result = geoHF.getElevation( mapPoint.getSRS(), mapPoint.x(), mapPoint.y(), _mapf.getMapInfo().getElevationInterpolation(), mapPoint.getSRS(), elevation);                              
            if (result && elevation != NO_DATA_VALUE)
            {                        
                // see what the actual resolution of the heightfield is.
                if ( out_actualResolution )
                    *out_actualResolution = geoHF.getXInterval(); 
                out_elevation = (double)elevation;                
                break;
            }
            else
            {                               
                result = false;
            }
        }

        if (!result)
        {
            key = key.createParentKey();                        
            if (!key.valid())
            {
                break;
            }
        }         
    }

         

    osg::Timer_t end = osg::Timer::instance()->tick();
    _queries++;
    _totalTime += osg::Timer::instance()->delta_s( start, end );

    return result;
}
Esempio n. 6
0
bool
OGR_SpatialReference::transformInPlace( GeoPoint& input ) const
{
    if ( !handle || !input.isValid() ) {
        osgGIS::notify( osg::WARN ) << "Spatial reference or input point is invalid" << std::endl;
        return false;
    }

	OGR_SpatialReference* input_sr = (OGR_SpatialReference*)input.getSRS();
    if ( !input_sr ) {
        osgGIS::notify( osg::WARN ) << "SpatialReference: input point has no SRS" << std::endl;
        return false;
    }

    // first check whether the input point is geocentric - and if so, pre-convert it to geographic:
    if ( input_sr->isGeocentric() )
    {
        input.set( input * input_sr->getInverseReferenceFrame() );
        osg::Vec3d temp = input_sr->getEllipsoid().geocentricToLatLong( input );
        input = GeoPoint( temp, input_sr->getGeographicSRS() ); 
        input_sr = static_cast<OGR_SpatialReference*>( input.getSRS() );
    }

    osg::Vec3d input_vec = input;
    bool crs_equiv = false;
    bool mat_equiv = false;
    testEquivalence( input_sr, /*out*/crs_equiv, /*out*/mat_equiv );

    // pull it out of its source frame:
    if ( !mat_equiv )
    {
        input.set( input * input_sr->inv_ref_frame );
    }    

    bool result = false;

    if ( !crs_equiv )
    {
        OGR_SCOPE_LOCK();

        //TODO: some kind of per-thread cache

        void* xform_handle = OCTNewCoordinateTransformation( input_sr->handle, this->handle );
        if ( !xform_handle ) {
            osgGIS::notify( osg::WARN ) << "Spatial Reference: SRS xform not possible" << std::endl
                << "    From => " << input_sr->getWKT() << std::endl
                << "    To   => " << this->getWKT() << std::endl;
            return false;
        }

        //TODO: figure out why xforming GEOCS x=-180 to another GEOCS doesn't work
        if ( OCTTransform( xform_handle, 1, &input.x(), &input.y(), &input.z() ) )
        {
            result = true;
        }
        else
        {
            osgGIS::notify( osg::WARN ) << "Spatial Reference: Failed to xform a point from "
                << input_sr->getName() << " to " << this->getName()
                << std::endl;
        }

        OCTDestroyCoordinateTransformation( xform_handle );
    }
    else
    {
        result = true;
    }

    // put it into the new ref frame:
    if ( !mat_equiv )
    {
        input.set( input * ref_frame );
    }

    if ( result == true )
    {
        applyTo( input );
    }

    return result;
}
Esempio n. 7
0
void GraticuleNode::traverse(osg::NodeVisitor& nv)
{
    if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
    {
        updateLabels();
    }
    else if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
    {
        osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);

        osg::Vec3d vp = cv->getViewPoint();

        osg::Matrixd viewMatrix = *cv->getModelViewMatrix();

        // Only update if the view matrix has changed.
        if (viewMatrix != _viewMatrix)
        {            
            GeoPoint eyeGeo;
            eyeGeo.fromWorld( _mapNode->getMapSRS(), vp );
            _lon = eyeGeo.x();
            _lat = eyeGeo.y();            

            osg::Viewport* viewport = cv->getViewport();

            float centerX = viewport->x() + viewport->width() / 2.0;
            float centerY = viewport->y() + viewport->height() / 2.0;

            float offsetCenterX = centerX;
            float offsetCenterY = centerY;

            bool hitValid = false;

            // Try the center of the screen.
            if(_mapNode->getTerrain()->getWorldCoordsUnderMouse(cv->getCurrentCamera()->getView(), centerX, centerY, _focalPoint))
            {
                hitValid = true;
            }

            if (hitValid)
            {
                GeoPoint focalGeo;
                focalGeo.fromWorld( _mapNode->getMapSRS(), _focalPoint );
                _lon = focalGeo.x();
                _lat = focalGeo.y();
                // We only store the previous view matrix if we actually got a hit.  Otherwise we still need to update.
                _viewMatrix = viewMatrix;
            }


            double targetResolution = (_viewExtent.height() / 180.0) / _options.gridLines().get();

            double resolution = _resolutions[0];
            for (unsigned int i = 0; i < _resolutions.size(); i++)
            {
                resolution = _resolutions[i];
                if (resolution <= targetResolution)
                {
                    break;
                }
            }

            // Trippy
            //resolution = targetResolution;

            _viewExtent = getViewExtent( cv );

            // Try to compute an approximate meters to pixel value at this view.
            double fovy, aspectRatio, zNear, zFar;
            cv->getProjectionMatrix()->getPerspective(fovy, aspectRatio, zNear, zFar);
            double dist = osg::clampAbove(eyeGeo.z(), 1.0);
            double halfWidth = osg::absolute( tan(osg::DegreesToRadians(fovy/2.0)) * dist );
            _metersPerPixel = (2.0 * halfWidth) / (double)viewport->height();

            if (_resolution != resolution)
            {
                setResolution(resolution);
            }
        }
    }
    osg::Group::traverse(nv);
}
bool
ElevationQuery::getElevationImpl(const GeoPoint& point,
                                 float&          out_elevation,
                                 double          desiredResolution,
                                 double*         out_actualResolution)
{
    // assertion.
    if ( !point.isAbsolute() )
    {
        OE_WARN << LC << "Assertion failure; input must be absolute" << std::endl;
        return false;
    }

    osg::Timer_t begin = osg::Timer::instance()->tick();

    // first try the terrain patches.
    if ( _terrainModelLayers.size() > 0 )
    {
        osgUtil::IntersectionVisitor iv;

        if ( _ivrc.valid() )
            iv.setReadCallback(_ivrc.get());

        for(LayerVector::iterator i = _terrainModelLayers.begin(); i != _terrainModelLayers.end(); ++i)
        {
            // find the scene graph for this layer:
            Layer* layer = i->get();
            osg::Node* node = layer->getNode();
            if ( node )
            {
                // configure for intersection:
                osg::Vec3d surface;
                point.toWorld( surface );

                // trivial bounds check:
                if ( node->getBound().contains(surface) )
                {
                    osg::Vec3d nvector;
                    point.createWorldUpVector(nvector);

                    osg::Vec3d start( surface + nvector*5e5 );
                    osg::Vec3d end  ( surface - nvector*5e5 );

                    // first time through, set up the intersector on demand
                    if ( !_lsi.valid() )
                    {
                        _lsi = new osgUtil::LineSegmentIntersector(start, end);
                        _lsi->setIntersectionLimit( _lsi->LIMIT_NEAREST );
                    }
                    else
                    {
                        _lsi->reset();
                        _lsi->setStart( start );
                        _lsi->setEnd  ( end );
                    }

                    // try it.
                    iv.setIntersector( _lsi.get() );
                    node->accept( iv );

                    // check for a result!!
                    if ( _lsi->containsIntersections() )
                    {
                        osg::Vec3d isect = _lsi->getIntersections().begin()->getWorldIntersectPoint();

                        // transform back to input SRS:
                        GeoPoint output;
                        output.fromWorld( point.getSRS(), isect );
                        out_elevation = (float)output.z();
                        if ( out_actualResolution )
                            *out_actualResolution = 0.0;

                        return true;
                    }
                }
                else
                {
                    //OE_INFO << LC << "Trivial rejection (bounds check)" << std::endl;
                }
            }
        }
    } 

    if (_elevationLayers.empty())
    {
        // this means there are no heightfields.
        out_elevation = NO_DATA_VALUE;
        return true;
    }

    // secure map pointer:
    osg::ref_ptr<const Map> map;
    if (!_map.lock(map))
    {
        return false;
    }    

    // tile size (resolution of elevation tiles)
    unsigned tileSize = 257; // yes?

    // default LOD:
    unsigned lod = 23u;

    // attempt to map the requested resolution to an LOD:
    if (desiredResolution > 0.0)
    {
        int level = map->getProfile()->getLevelOfDetailForHorizResolution(desiredResolution, tileSize);
        if ( level > 0 )
            lod = level;
    }

    // do we need a new ElevationEnvelope?
    if (!_envelope.valid() ||
        !point.getSRS()->isHorizEquivalentTo(_envelope->getSRS()) ||
        lod != _envelope->getLOD())
    {        
        _envelope = map->getElevationPool()->createEnvelope(point.getSRS(), lod);
    }

    // sample the elevation, and if requested, the resolution as well:
    if (out_actualResolution)
    {
        std::pair<float, float> result = _envelope->getElevationAndResolution(point.x(), point.y());
        out_elevation = result.first;
        *out_actualResolution = result.second;
    }
    else
    {
        out_elevation = _envelope->getElevation(point.x(), point.y());
    }

    return out_elevation != NO_DATA_VALUE;
}
Esempio n. 9
0
    /**
     * Create and return an image for the given TileKey.
     */
    osg::Image* createImage( const TileKey& key, ProgressCallback* progress )
    {
        if (_debugDirect)
        {
            //osg::Image* image = new osg::Image;
            //image->allocateImage(256,256,1, GL_RGB, GL_UNSIGNED_BYTE);
            //return image;

            return osgDB::readImageFile( getDirectURI(key) );
            //return URI(getDirectURI(key)).getImage(_dbOptions.get(), progress);
        }

        // center point of the tile (will be in spherical mercator)
        double x, y;
        key.getExtent().getCentroid(x, y);

        // transform it to lat/long:
        GeoPoint geo;

        GeoPoint( getProfile()->getSRS(), x, y ).transform(
            getProfile()->getSRS()->getGeographicSRS(),
            geo );

        // contact the REST API. Docs are here:
        // http://msdn.microsoft.com/en-us/library/ff701716.aspx

        // construct the request URI:
        std::string request = Stringify()
            << std::setprecision(12)
            << _options.imageryMetadataAPI().get()     // base REST API
            << "/"    << _options.imagerySet().get()   // imagery set to use
            << "/"    << geo.y() << "," << geo.x()     // center point in lat/long
            << "?zl=" << key.getLOD() + 1              // zoom level
            << "&o=json"                               // response format
            << "&key=" << _options.key().get();        // API key

        // check the URI cache.
        URI                  location;
        TileURICache::Record rec;

        if ( _tileURICache.get(request, rec) )
        {
            location = URI(rec.value());
            //CacheStats stats = _tileURICache.getStats();
            //OE_INFO << "Ratio = " << (stats._hitRatio*100) << "%" << std::endl;
        }
        else
        {
            unsigned c = ++_apiCount;
            if ( c % 25 == 0 )
                OE_INFO << LC << "API calls = " << c << std::endl;
            
            // fetch it:
            ReadResult metadataResult = URI(request).readString(_dbOptions, progress);

            if ( metadataResult.failed() )
            {
                // check for a REST error:
                if ( metadataResult.code() == ReadResult::RESULT_SERVER_ERROR )
                {
                    OE_WARN << LC << "REST API request error!" << std::endl;

                    Config metadata;
                    std::string content = metadataResult.getString();
                    metadata.fromJSON( content );
                    ConfigSet errors = metadata.child("errorDetails").children();
                    for(ConfigSet::const_iterator i = errors.begin(); i != errors.end(); ++i )
                    {
                        OE_WARN << LC << "REST API: " << i->value() << std::endl;
                    }
                    return 0L;
                }
                else
                {
                    OE_WARN << LC << "Request error: " << metadataResult.getResultCodeString() << std::endl;
                }
                return 0L;
            }

            // decode it:
            Config metadata;
            if ( !metadata.fromJSON(metadataResult.getString()) )
            {
                OE_WARN << LC << "Error decoding REST API response" << std::endl;
                return 0L;
            }

            // check the vintage field. If it's empty, that means we got a "no data" tile.
            Config* vintageEnd = metadata.find("vintageEnd");
            if ( !vintageEnd || vintageEnd->value().empty() )
            {
                OE_DEBUG << LC << "NO data image encountered." << std::endl;
                return 0L;
            }

            // find the tile URI:
            Config* locationConf= metadata.find("imageUrl");
            if ( !locationConf )
            {
                OE_WARN << LC << "REST API JSON parsing error (imageUrl not found)" << std::endl;
                return 0L;
            }

            location = URI( locationConf->value() );
            _tileURICache.insert( request, location.full() );
        }

        // request the actual tile
        //OE_INFO << "key = " << key.str() << ", URL = " << location->value() << std::endl;

        //osg::Image* image = location.getImage(_dbOptions.get(), progress);
        osg::Image* image = osgDB::readImageFile( location.full() );

        if ( image &&  _geom.valid() )
        {
            GeometryRasterizer rasterizer( image->s(), image->t() );
            rasterizer.draw( _geom.get(), osg::Vec4(1,1,1,1) );
            osg::ref_ptr<osg::Image> overlay = rasterizer.finalize();
            ImageUtils::PixelVisitor<AlphaBlend> blend;
            blend.accept( overlay.get(), image );
        }

        return image;
    }
Esempio n. 10
0
bool
ElevationQuery::getElevationImpl(const GeoPoint& point,
                                 double&         out_elevation,
                                 double          desiredResolution,
                                 double*         out_actualResolution)
{
    osg::Timer_t start = osg::Timer::instance()->tick();

    if ( _maxDataLevel == 0 || _tileSize == 0 )
    {
        // this means there are no heightfields.
        out_elevation = 0.0;
        return true;
    }

    
    //This is the max resolution that we actually have data at this point
    unsigned int bestAvailLevel = getMaxLevel( point.x(), point.y(), point.getSRS(), _mapf.getProfile());

    if (desiredResolution > 0.0)
    {
        unsigned int desiredLevel = _mapf.getProfile()->getLevelOfDetailForHorizResolution( desiredResolution, _tileSize );
        if (desiredLevel < bestAvailLevel) bestAvailLevel = desiredLevel;
    }

    OE_DEBUG << "Best available data level " << point.x() << ", " << point.y() << " = "  << bestAvailLevel << std::endl;

    // transform the input coords to map coords:
    GeoPoint mapPoint = point;
    if ( point.isValid() && !point.getSRS()->isEquivalentTo( _mapf.getProfile()->getSRS() ) )
    {
        mapPoint = point.transform(_mapf.getProfile()->getSRS());
        if ( !mapPoint.isValid() )
        {
            OE_WARN << LC << "Fail: coord transform failed" << std::endl;
            return false;
        }
    }

    osg::ref_ptr<osg::HeightField> tile;

    // get the tilekey corresponding to the tile we need:
    TileKey key = _mapf.getProfile()->createTileKey( mapPoint.x(), mapPoint.y(), bestAvailLevel );
    if ( !key.valid() )
    {
        OE_WARN << LC << "Fail: coords fall outside map" << std::endl;
        return false;
    }

    // Check the tile cache. Note that the TileSource already likely has a MemCache
    // attached to it. We employ a secondary cache here for a couple reasons. One, this
    // cache will store not only the heightfield, but also the tesselated tile in the event
    // that we're using GEOMETRIC mode. Second, since the call the getHeightField can 
    // fallback on a lower resolution, this cache will hold the final resolution heightfield
    // instead of trying to fetch the higher resolution one each item.

    TileCache::Record record;
    if ( _tileCache.get(key, record) )
    {
        tile = record.value().get();
    }

    // if we didn't find it, build it.
    if ( !tile.valid() )
    {
        // generate the heightfield corresponding to the tile key, automatically falling back
        // on lower resolution if necessary:
        _mapf.getHeightField( key, true, tile, 0L );

        // bail out if we could not make a heightfield a all.
        if ( !tile.valid() )
        {
            OE_WARN << LC << "Unable to create heightfield for key " << key.str() << std::endl;
            return false;
        }

        _tileCache.insert(key, tile.get());
    }

    OE_DEBUG << LC << "LRU Cache, hit ratio = " << _tileCache.getStats()._hitRatio << std::endl;

    // see what the actual resolution of the heightfield is.
    if ( out_actualResolution )
        *out_actualResolution = (double)tile->getXInterval();

    bool result = true;

    const GeoExtent& extent = key.getExtent();
    double xInterval = extent.width()  / (double)(tile->getNumColumns()-1);
    double yInterval = extent.height() / (double)(tile->getNumRows()-1);
    
    out_elevation = (double) HeightFieldUtils::getHeightAtLocation( 
        tile.get(), 
        mapPoint.x(), mapPoint.y(), 
        extent.xMin(), extent.yMin(), 
        xInterval, yInterval, _mapf.getMapInfo().getElevationInterpolation() );

    osg::Timer_t end = osg::Timer::instance()->tick();
    _queries++;
    _totalTime += osg::Timer::instance()->delta_s( start, end );

    return result;
}
Esempio n. 11
0
bool
MGRSFormatter::transform( const GeoPoint& input, MGRSCoord& out ) const
{
    if ( !input.isValid() )
        return false;

    // convert to lat/long if necessary:
    GeoPoint inputGeo = input;
    if ( !inputGeo.makeGeographic() )
        return false;

    unsigned    zone;
    char        gzd;
    unsigned    x=0, y=0;
    char        sqid[3];
    std::string space;

    if ( _options & USE_SPACES )
        space = " ";

    sqid[0] = '?';
    sqid[1] = '?';
    sqid[2] = 0;

    double latDeg = inputGeo.y();
    double lonDeg = inputGeo.x();

    if ( latDeg >= 84.0 || latDeg <= -80.0 ) // polar projection
    {
        bool isNorth = latDeg > 0.0;
        zone = 0;
        gzd = isNorth ? (lonDeg < 0.0 ? 'Y' : 'Z') : (lonDeg < 0.0? 'A' : 'B');

        osg::ref_ptr<const SpatialReference> ups =
            const_cast<MGRSFormatter*>(this)->_srsCache[ s_polarZoneSpecs[isNorth?0:1] ];
        if (!ups.valid())
            ups = SpatialReference::create( s_polarZoneSpecs[isNorth?0:1] );

        if ( !ups.valid() )
        {
            OE_WARN << LC << "Failed to create UPS SRS" << std::endl;
            return false;
        }

        osg::Vec3d upsCoord;
        if ( _refSRS->transform(osg::Vec3d(lonDeg,latDeg,0), ups.get(), upsCoord) == false )
        {
            OE_WARN << LC << "Failed to transform lat/long to UPS" << std::endl;
            return false;
        }

        int sqXOffset = upsCoord.x() >= 0.0 ? (int)floor(upsCoord.x()/100000.0) : -(int)floor(1.0-(upsCoord.x()/100000.0));
        int sqYOffset = upsCoord.y() >= 0.0 ? (int)floor(upsCoord.y()/100000.0) : -(int)floor(1.0-(upsCoord.y()/100000.0));

        int alphaOffset = isNorth ? 7 : 12;

        sqid[0] = UPS_COL_ALPHABET[ (UPS_COL_ALPHABET_SIZE+sqXOffset) % UPS_COL_ALPHABET_SIZE ];
        sqid[1] = UPS_ROW_ALPHABET[alphaOffset + sqYOffset];

        x = (unsigned)(upsCoord.x() - (100000.0*(double)sqXOffset));
        y = (unsigned)(upsCoord.y() - (100000.0*(double)sqYOffset));
    }

    else // UTM
    {
        // figure out the grid zone designator
        unsigned gzdIndex = ((unsigned)(latDeg+80.0))/8;
        gzd = GZD_ALPHABET[gzdIndex];

        // figure out the UTM zone:
        zone = (unsigned)floor((lonDeg+180.0)/6.0);   // [0..59]
        bool north = latDeg >= 0.0;

        // convert the input coordinates to UTM:
        // yes, always use +north so we get Y relative to equator

        // using an SRS cache speed things up a lot..
        osg::ref_ptr<const SpatialReference>& utm =
            const_cast<MGRSFormatter*>(this)->_srsCache[s_lateralZoneSpecs[zone]];
        if ( !utm.valid() )
            utm = SpatialReference::create( s_lateralZoneSpecs[zone] );

        osg::Vec3d utmCoord;
        if ( _refSRS->transform( osg::Vec3d(lonDeg,latDeg,0), utm.get(), utmCoord) == false )
        {
            OE_WARN << LC << "Error transforming lat/long into UTM" << std::endl;
            return false;
        }

        // the alphabet set:
        unsigned set = zone % 6; // [0..5]

        // find the horizontal SQID offset (100KM increments) from the central meridian:
        unsigned xSetOffset = 8 * (set % 3);
        double xMeridianOffset = utmCoord.x() - 500000.0;
        int sqMeridianOffset = xMeridianOffset >= 0.0 ? (int)floor(xMeridianOffset/100000.0) : -(int)floor(1.0-(xMeridianOffset/100000.0));
        unsigned indexOffset = (4 + sqMeridianOffset);
        sqid[0] = UTM_COL_ALPHABET[xSetOffset + indexOffset];
        double xWest = 500000.0 + (100000.0*(double)sqMeridianOffset);
        x = (unsigned)(utmCoord.x() - xWest);

        // find the vertical SQID offset (100KM increments) from the equator:
        unsigned ySetOffset = 5 * (zone % 2); //(set % 2);
        int sqEquatorOffset = (int)floor(utmCoord.y()/100000.0);
        int absOffset = ySetOffset + sqEquatorOffset + (10 * UTM_ROW_ALPHABET_SIZE);
        if ( _useAL )
            absOffset += 10;
        sqid[1] = UTM_ROW_ALPHABET[absOffset % UTM_ROW_ALPHABET_SIZE];
        y = (unsigned)(utmCoord.y() - (100000.0*(double)sqEquatorOffset));
    }

    if ( (unsigned)_precision > PRECISION_1M )
    {
        x /= (unsigned)_precision;
        y /= (unsigned)_precision;
    }

    out.gzd  = Stringify() << (zone+1) << gzd;
    out.sqid = sqid;
    out.x    = x;
    out.y    = y;

    return true;
}
Esempio n. 12
0
void
ModelSplatter::operator()(const TileKey& key, osg::Node* node)
{
    TerrainTileNode* tile = osgEarth::findTopMostNodeOfType<TerrainTileNode>(node);
    if ( !tile )
        return;

    if ( key.getLOD() >= _minLOD && _model.valid() )
    {
        // make sure the correct model is loaded
        establish();

        // elevation texture and matrix are required
        osg::Texture* elevationTex = tile->getElevationTexture();
        if ( !elevationTex )
        {
            //OE_WARN << LC << "No elevation texture for key " << key.str() << "\n";
            return;
        }

        osg::RefMatrix* elevationTexMat = tile->getElevationTextureMatrix();
        if ( !elevationTexMat )
        {
            //OE_WARN << LC << "No elevation texture matrix for key " << key.str() << "\n";
            return;
        }
        
        tile->addChild( _model.get() );

        osg::StateSet* ss = tile->getOrCreateStateSet();

        // first, a rotation vector to make trees point up.
        GeoPoint p;
        key.getExtent().getCentroid(p);
        osg::Vec3d up;
        p.createWorldUpVector(up);
        osg::Quat q;
        q.makeRotate(osg::Vec3d(0,0,1), up);
        osg::Matrixd zup = osg::Matrixd::rotate(q);

        // matrices to resolve the weird terrain localization into a usable LTP.
        osg::Matrix tile2world = tile->getMatrix();
        osg::Matrix world2ltp;
        p.createWorldToLocal(world2ltp);
        osg::Matrix local2ltp = tile2world * world2ltp;
        osg::Matrix ltp2local;
        ltp2local.invert(local2ltp);

        // after inverting the matrix, combine the ZUP (optimization)
        local2ltp.preMult( zup );

        ss->addUniform( new osg::Uniform("oe_trees_local2ltp", osg::Matrixf(local2ltp)) );
        ss->addUniform( new osg::Uniform("oe_trees_ltp2local", osg::Matrixf(ltp2local)) );

        // calculate the scatter area:
        float h = key.getExtent().height() * 111320.0f;
        float w = key.getExtent().width() * 111320.0f * cos(fabs(osg::DegreesToRadians(p.y())));
        ss->addUniform( new osg::Uniform("oe_trees_span", osg::Vec2f(w,h)) );
        
        ss->setTextureAttributeAndModes(2, tile->getElevationTexture(), 1);
        ss->addUniform( new osg::Uniform("oe_terrain_tex_matrix", osg::Matrixf(*elevationTexMat)) );        
    }
}
Esempio n. 13
0
    void update( float x, float y, osgViewer::View* view )
    {
        bool yes = false;

        // look under the mouse:
        osg::Vec3d world;
        osgUtil::LineSegmentIntersector::Intersections hits;
        if ( view->computeIntersections(x, y, hits) )
        {
            world = hits.begin()->getWorldIntersectPoint();

            // convert to map coords:
            GeoPoint mapPoint;
            mapPoint.fromWorld( s_mapNode->getMapSRS(), world );

            // Depending on the level of detail key you request, you will get a mesh that should line up exactly with the highest resolution mesh that the terrain engine will draw.
            // At level 15 that is a 257x257 heightfield.  If you select a higher lod, the mesh will be less dense.
            TileKey key = s_mapNode->getMap()->getProfile()->createTileKey(mapPoint.x(), mapPoint.y(), 15);
            OE_NOTICE << "Creating tile " << key.str() << std::endl;
            osg::ref_ptr<osg::Node> node = s_mapNode->getTerrainEngine()->createTile(key);
            if (node.valid())
            {
                // Extract the triangles from the node that was created and do our own rendering.  Simulates what you would do when passing in the triangles to a physics engine.
                OE_NOTICE << "Created tile for " << key.str() << std::endl;
                CollectTrianglesVisitor v;
                node->accept(v);
                node = v.buildNode();

                if (_node.valid())
                {
                    s_root->removeChild( _node.get() );
                }

                osg::Group* group = new osg::Group;

                // Show the actual mesh.
                group->addChild( node.get() );

                _node = group;

                // Clamp the marker to the intersection of the triangles created by osgEarth.  This should line up with the mesh that is actually rendered.
                double z = 0.0;
                s_mapNode->getTerrain()->getHeight( node, s_mapNode->getMapSRS(), mapPoint.x(), mapPoint.y(), &z);

                GeoTransform* xform = new GeoTransform();
                xform->setPosition( osgEarth::GeoPoint(s_mapNode->getMapSRS(),mapPoint.x(),  mapPoint.y(), z, ALTMODE_ABSOLUTE) );
                xform->addChild( marker.get() );
                group->addChild( xform );

                s_root->addChild( _node.get() );
            }
            else
            {
                OE_NOTICE << "Failed to create tile for " << key.str() << std::endl;
            }
        }
    }
Esempio n. 14
0
// Calculates a sub-extent of a larger extent, given the number of children and
// the child number. This currently assumes the subdivision ordering used by
// VirtualPlanetBuilder.
GeoExtent
TerrainUtils::getSubExtent(const GeoExtent& extent,
                           int              num_children,
                           int              child_no)
{
    GeoPoint centroid = extent.getCentroid();
    GeoExtent sub_extent;

    switch( num_children )
    {
    case 0:
    case 1:
        sub_extent = extent;
        break;

    case 2:
        if ( child_no == 0 )
        {
            sub_extent = GeoExtent(
                             extent.getXMin(),
                             extent.getYMin(),
                             centroid.x(),
                             extent.getYMax(),
                             extent.getSRS() );
        }
        else
        {
            sub_extent = GeoExtent(
                             centroid.x(),
                             extent.getYMin(),
                             extent.getXMax(),
                             extent.getYMax(),
                             extent.getSRS() );
        }
        break;

    case 4:
        if ( child_no == 2 )
        {
            sub_extent = GeoExtent(
                             extent.getXMin(),
                             centroid.y(),
                             centroid.x(),
                             extent.getYMax(),
                             extent.getSRS() );
        }
        else if ( child_no == 3 )
        {
            sub_extent = GeoExtent(
                             centroid.x(),
                             centroid.y(),
                             extent.getXMax(),
                             extent.getYMax(),
                             extent.getSRS() );
        }
        else if ( child_no == 0 )
        {
            sub_extent = GeoExtent(
                             extent.getXMin(),
                             extent.getYMin(),
                             centroid.x(),
                             centroid.y(),
                             extent.getSRS() );
        }
        else if ( child_no == 1 )
        {
            sub_extent = GeoExtent(
                             centroid.x(),
                             extent.getYMin(),
                             extent.getXMax(),
                             centroid.y(),
                             extent.getSRS() );
        }
    }

    return sub_extent;
}
Esempio n. 15
0
bool
getIsectPoint( const GeoPoint& p1, const GeoPoint& p2, const GeoPoint& p3, const GeoPoint& p4, GeoPoint& out )
{
    double denom = (p4.y()-p3.y())*(p2.x()-p1.x()) - (p4.x()-p3.x())*(p2.y()-p1.y());
    if ( denom == 0.0 )
    {
        out = GeoPoint::invalid(); // parallel lines
        return false;
    }

    double ua_num = (p4.x()-p3.x())*(p1.y()-p3.y()) - (p4.y()-p3.y())*(p1.x()-p3.x());
    double ub_num = (p2.x()-p1.x())*(p1.y()-p3.y()) - (p2.y()-p1.y())*(p1.x()-p3.x());

    double ua = ua_num/denom;
    double ub = ub_num/denom;

    if ( ua < 0.0 || ua > 1.0 ) // || ub < 0.0 || ub > 1.0 )
    {
        out = GeoPoint::invalid(); // isect point is on line, but not on line segment
        return false;
    }

    double x = p1.x() + ua*(p2.x()-p1.x());
    double y = p1.y() + ua*(p2.y()-p1.y());
    double z = p1.getDim() > 2? p1.z() + ua*(p2.z()-p1.z()) : 0.0; //right?
    out = GeoPoint( x, y, z, p1.getSRS() );
    return true;
}
Esempio n. 16
0
bool
findIsectSegmentAndPoint(const GeoPoint& p1,
                         const GeoPoint& p2,
                         const GeoPointList& input,
                         const UINT start_i,
                         int&      out_seg_i,
                         GeoPoint& out_isect_p )
{
    for( UINT i=0; i<input.size()-1; i++ )
    {
        // ignore the segments preceding and following the start index
        if ( (input.size()+start_i-1)%input.size() <= i && i <= (input.size()+start_i+1)%input.size() )
            continue;

        const GeoPoint& p3 = input[i];
        const GeoPoint& p4 = input[i+1];

        double denom = (p4.y()-p3.y())*(p2.x()-p1.x()) - (p4.x()-p3.x())*(p2.y()-p1.y());
        if ( denom != 0.0 )
        {
            double ua_num = (p4.x()-p3.x())*(p1.y()-p3.y()) - (p4.y()-p3.y())*(p1.x()-p3.x());
            double ub_num = (p2.x()-p1.x())*(p1.y()-p3.y()) - (p2.y()-p1.y())*(p1.x()-p3.x());

            double ua = ua_num/denom;
            double ub = ub_num/denom;

            if ( ua <= 1.0 ) {
                //osgGIS::notify( osg::WARN ) 
                //    << " [" 
                //    << i << "] "
                //    << "isect point was found at on source segment (ua=" << ua << ")" 
                //    << std::endl
                //    << "  source segment = (" << p1.toString() << " => " << p2.toString() << "), "
                //    << "  target segment = (" << p3.toString() << " => " << p4.toString() << ")"
                //    << std::endl;
            }

            else if ( ub < 0.0 || ub > 1.0 ) 
            {
                //osgGIS::notify( osg::WARN ) 
                //    << " [" 
                //    << i << "] "
                //    << "isect point was not found on target segment (ub=" << ub << ")" 
                //    << std::endl
                //    << "  source segment = (" << p1.toString() << " => " << p2.toString() << "), "
                //    << "  target segment = (" << p3.toString() << " => " << p4.toString() << ")"
                //    << std::endl;
            }
            else
            {
                double isect_x = p1.x() + ua*(p2.x()-p1.x());
                double isect_y = p1.y() + ua*(p2.y()-p1.y());
                out_seg_i = i;
                out_isect_p = p1.getDim() == 2?
                    GeoPoint( isect_x, isect_y, p4.getSRS() ) :
                    GeoPoint( isect_x, isect_y, p4.z(), p4.getSRS() );
                return true;
            }
        }
    }
    return false;
}
void
AutoClipPlaneCullCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
{
    if ( _active )
    {
        osgUtil::CullVisitor* cv = Culling::asCullVisitor(nv);
        if ( cv )
        {
            osgEarth::Map* map = _mapNode.valid() ? _mapNode->getMap() : 0;
            osg::Camera* cam = cv->getCurrentCamera();
            osg::ref_ptr<osg::CullSettings::ClampProjectionMatrixCallback>& clamper = _clampers.get(cam);
            if ( !clamper.valid() )
            {
                clamper = new CustomProjClamper();
                cam->setClampProjectionMatrixCallback( clamper.get() );
                OE_INFO << LC << "Installed custom projeciton matrix clamper" << std::endl;
            }
            else
            {
                CustomProjClamper* c = static_cast<CustomProjClamper*>(clamper.get());

                osg::Vec3d eye, center, up;
                cam->getViewMatrixAsLookAt( eye, center, up );

                // clamp the far clipping plane to the approximate horizon distance
                if ( _autoFarPlaneClamping )
                {
                    double d = eye.length();
                    c->_maxFar = sqrt( d*d - _rp2 );
                }
                else
                {
                    c->_maxFar = DBL_MAX;
                }

                // get the height-above-ellipsoid. If we need to be more accurate, we can use 
                // ElevationQuery in the future..
                //osg::Vec3d loc;
                GeoPoint loc;
                if ( map )
                {
                    loc.fromWorld( map->getSRS(), eye );
                    //map->worldPointToMapPoint( eye, loc );
                }
                else
                {
                    static osg::EllipsoidModel em;
                    osg::Vec3d t;
                    em.convertXYZToLatLongHeight( eye.x(), eye.y(), eye.z(), loc.y(), loc.x(), loc.z() );
                }
                
                //double hae = loc.z();
                double hae = loc.z();
                if (_mapNode.valid())
                {
                    double height = 0.0;
                    _mapNode->getTerrain()->getHeight(loc.getSRS(), loc.x(), loc.y(), &height);
                    //OE_NOTICE << "got height " << height << std::endl;
                    hae -= height;
                    //OE_NOTICE << "HAE=" << hae <<  std::endl;
                }

                // ramp a new near/far ratio based on the HAE.
                c->_nearFarRatio = Utils::remap( hae, 0.0, _haeThreshold, _minNearFarRatio, _maxNearFarRatio );
            }

#if 0
            {
                double n, f, a, v;
                cv->getProjectionMatrix()->getPerspective(v, a, n, f);
                OE_INFO << std::setprecision(16) << "near = " << n << ", far = " << f << ", ratio = " << n/f << std::endl;
            }
#endif
        }
    }
    traverse( node, nv );
}
Esempio n. 18
0
void TerrainProfileGraph::drawHoverCursor(const QPointF& position)
{
  if (_hoverLine)
  {
    _scene->removeItem(_hoverLine);
    delete _hoverLine;
    _hoverLine = 0L;
  }

  if (_graphField.width() < 2 || _graphField.height() < 2)
    return;

  double xPos = position.x() < _graphField.x() ? _graphField.x() : (position.x() > _graphField.x() + _graphField.width() ? _graphField.x() + _graphField.width() : position.x());

  QLineF vLine(xPos, _graphField.y(), xPos, _graphField.y() + _graphField.height());

  QPointF* intersect = new QPointF;
  bool foundIntersect = false;
  for (int i=0; i < _graphLines.count(); i++)
  {
    if (vLine.intersect(_graphLines[i], intersect) == QLineF::BoundedIntersection)
    {
      foundIntersect = true;
      break;
    }
  }

  if (foundIntersect)
  {
    // Draw the upper line segment.  Also serves as the parent item.
    _hoverLine = new QGraphicsLineItem(xPos, _graphField.y(), xPos, intersect->y() - 3);
    _hoverLine->setPen(_hoverPen);
    _hoverLine->setZValue(OVERLAY_Z);
    _scene->addItem(_hoverLine);

    // Draw the box around the intersect point
    QGraphicsRectItem* hoverBox = new QGraphicsRectItem(xPos - 3, intersect->y() - 3, 6, 6);
    hoverBox->setPen(_hoverPen);
    hoverBox->setBrush(Qt::NoBrush);
    hoverBox->setZValue(OVERLAY_Z);
    hoverBox->setParentItem(_hoverLine);

    // Draw the lower line segment
    QGraphicsLineItem* lowerLine = new QGraphicsLineItem(xPos, intersect->y() + 3, xPos, _graphField.y() + _graphField.height() + 5);
    lowerLine->setPen(_hoverPen);
    lowerLine->setZValue(OVERLAY_Z);
    lowerLine->setParentItem(_hoverLine);

    // Draw the text and background
    double y = (1.0 - ((intersect->y() - _graphField.y()) / _graphField.height())) * (_graphMaxY - _graphMinY) + _graphMinY;
    int textOffset = 10;

    QGraphicsSimpleTextItem* hoverText = new QGraphicsSimpleTextItem(QString::number(y) + tr("m"));
    hoverText->setBrush(QBrush(_axesColor));
    hoverText->setFont(_graphFont);
    hoverText->setZValue(OVERLAY_Z);

    if (intersect->x() + textOffset + hoverText->boundingRect().width() < _graphField.x() + _graphField.width())
      hoverText->setPos(intersect->x() + textOffset, intersect->y() - hoverText->boundingRect().height());
    else
      hoverText->setPos(intersect->x() - textOffset - hoverText->boundingRect().width(), intersect->y() - hoverText->boundingRect().height());

    QGraphicsRectItem* hoverTextBackground = new QGraphicsRectItem(hoverText->x() - 3, hoverText->y() - 1, 
                                                                   hoverText->boundingRect().width() + 6,
                                                                   hoverText->boundingRect().height() + 1);
    hoverTextBackground->setPen(_axesPen);
    hoverTextBackground->setBrush(QBrush(_graphColor));
    hoverTextBackground->setZValue(OVERLAY_Z);
    hoverTextBackground->setParentItem(_hoverLine);

    hoverText->setParentItem(_hoverLine);

    // Update callback
    if (_positionCallback.valid())
    {
      double distanceFactor = ((xPos - _graphField.x()) / (double)_graphField.width());

      osg::Vec3d worldStart, worldEnd;
      _calculator->getStart(ALTMODE_ABSOLUTE).toWorld(worldStart);
      _calculator->getEnd(ALTMODE_ABSOLUTE).toWorld(worldEnd);

      double worldX = (worldEnd.x() - worldStart.x()) * distanceFactor + worldStart.x();
      double worldY = (worldEnd.y() - worldStart.y()) * distanceFactor + worldStart.y();
      double worldZ = (worldEnd.z() - worldStart.z()) * distanceFactor + worldStart.z();

      GeoPoint mapPos;
      mapPos.fromWorld(_calculator->getStart().getSRS(), osg::Vec3d(worldX, worldY, worldZ));

      _positionCallback->updatePosition(mapPos.y(), mapPos.x(), hoverText->text().toStdString());
    }
  }
  else
  {
    // No intersect found so just draw the full line at xPos
    _hoverLine = new QGraphicsLineItem(xPos, _graphField.y(), xPos, _graphField.y() + _graphField.height() + 5);
    _hoverLine->setPen(_hoverPen);
    _hoverLine->setZValue(OVERLAY_Z);
    _scene->addItem(_hoverLine);
  }

  // Draw distance text
  double x = ((xPos - _graphField.x()) / _graphField.width()) * _totalDistance;

  BoxedSimpleTextItem* distanceText = new BoxedSimpleTextItem(QString::number(x / 1000.0, 'f', 2) + tr("km"), _backgroundColor);
  distanceText->setBrush(QBrush(_axesColor));
  distanceText->setFont(_graphFont);
  distanceText->setZValue(OVERLAY_Z);
  if(xPos - 2 - distanceText->boundingRect().width() > _graphField.x())
  {
      distanceText->setPos(xPos - 2 - distanceText->boundingRect().width(), _graphField.y() + _graphField.height() + 2);
  }
  else
  {
      distanceText->setPos(xPos + 2, _graphField.y() + _graphField.height() + 2);
  }
  distanceText->setParentItem(_hoverLine);

  // Draw selection box
  drawSelectionBox(xPos);

  delete intersect;
}
Esempio n. 19
0
void
GeodeticGraticule::cull(osgUtil::CullVisitor* cv)
{
    osg::Matrixd viewMatrix = *cv->getModelViewMatrix();

    osg::Vec3d vp = cv->getViewPoint();

    CameraData& cdata = getCameraData(cv->getCurrentCamera());

    // Only update if the view matrix has changed.
    if (viewMatrix != cdata._lastViewMatrix && _mapNode.valid())
    {
        GeoPoint eyeGeo;
        eyeGeo.fromWorld(_mapNode->getMapSRS(), vp);
        cdata._lon = eyeGeo.x();
        cdata._lat = eyeGeo.y();

        osg::Viewport* viewport = cv->getViewport();

        float centerX = viewport->x() + viewport->width() / 2.0;
        float centerY = viewport->y() + viewport->height() / 2.0;

        float offsetCenterX = centerX;
        float offsetCenterY = centerY;

        bool hitValid = false;

        // Try the center of the screen.
        osg::Vec3d focalPoint;
        if (_mapNode->getTerrain()->getWorldCoordsUnderMouse(cv->getCurrentCamera()->getView(), centerX, centerY, focalPoint))
        {
            hitValid = true;
        }

        if (hitValid)
        {
            GeoPoint focalGeo;
            focalGeo.fromWorld(_mapNode->getMapSRS(), focalPoint);
            cdata._lon = focalGeo.x();
            cdata._lat = focalGeo.y();
            // We only store the previous view matrix if we actually got a hit.  Otherwise we still need to update.
            cdata._lastViewMatrix = viewMatrix;
        }

        // Get the view extent.
        cdata._viewExtent = getViewExtent(cv);

        double targetResolution = (cdata._viewExtent.height() / 180.0) / options().gridLines().get();

        double resolution = _resolutions[0];
        for (unsigned int i = 0; i < _resolutions.size(); i++)
        {
            resolution = _resolutions[i];
            if (resolution <= targetResolution)
            {
                break;
            }
        }

        // Trippy
        //resolution = targetResolution;

        // Try to compute an approximate meters to pixel value at this view.
        double dist = osg::clampAbove(eyeGeo.z(), 1.0);
        double halfWidth;

        const osg::Matrix& proj = *cv->getProjectionMatrix();
        bool isOrtho = osg::equivalent(proj(3,3), 1.0);

        if (isOrtho)
        {
            double L, R, B, T, N, F;
            proj.getOrtho(L, R, B, T, N, F);
            halfWidth = 0.5*(R-L);
        }
        else // perspective
        {
            double fovy, aspectRatio, zNear, zFar;
            cv->getProjectionMatrix()->getPerspective(fovy, aspectRatio, zNear, zFar);
            halfWidth = osg::absolute(tan(osg::DegreesToRadians(fovy / 2.0)) * dist);
        }

        cdata._metersPerPixel = (2.0 * halfWidth) / (double)viewport->height();

        if (cdata._resolution != resolution)
        {
            cdata._resolution = (float)resolution;
            cdata._resolutionUniform->set(cdata._resolution);
        }

        OE_TEST << "EW=" << cdata._viewExtent.width() << ", ortho=" << isOrtho << ", hW=" << halfWidth << ", res=" << resolution << ", mPP=" << cdata._metersPerPixel << std::endl;
    }

    // traverse the label pool for this camera.
    cv->pushStateSet(cdata._labelStateset.get());

    for (std::vector< osg::ref_ptr< LabelNode > >::iterator i = cdata._labelPool.begin();
        i != cdata._labelPool.end();
        ++i)
    {
        i->get()->accept(*cv);
    }

    cv->popStateSet();
}
Esempio n. 20
0
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;
}
Esempio n. 21
0
std::string
GeodeticGraticule::getText(const GeoPoint& location, bool lat)
{ 
    double value = lat ? location.y() : location.x();
    return _formatter->format(value, lat);
}
    void update( float x, float y, osgViewer::View* view )
    {
        bool yes = false;

        // look under the mouse:
        osg::Vec3d world;
        osgUtil::LineSegmentIntersector::Intersections hits;
        if ( view->computeIntersections(x, y, hits) )
        {
            world = hits.begin()->getWorldIntersectPoint();

            // convert to map coords:
            GeoPoint mapPoint;
            mapPoint.fromWorld( s_mapNode->getMapSRS(), world );

            TileKey key = s_mapNode->getMap()->getProfile()->createTileKey(mapPoint.x(), mapPoint.y(), 13);
            OE_NOTICE << "Creating tile " << key.str() << std::endl;
            osg::ref_ptr<osg::Node> node = s_mapNode->getTerrainEngine()->createTile(key);
            if (node.valid())
            {
                OE_NOTICE << "Created tile for " << key.str() << std::endl;
                CollectTrianglesVisitor v;
                node->accept(v);

                osg::ref_ptr<osg::Node> output = v.buildNode();
                osgDB::writeNodeFile( *output.get(), "createtile.osgt" );
                OE_NOTICE << "Wrote tile to createtile.osgt\n";
                //osgDB::writeNodeFile(v.buildNode(
                //s_root->addChild(v.buildNode());
            }
            else
            {
                OE_NOTICE << "Failed to create tile for " << key.str() << std::endl;
            }
        }
    }
Esempio n. 23
0
bool
AnnotationNode::makeAbsolute( GeoPoint& mapPoint, osg::Node* patch ) const
{
    // in terrain-clamping mode, force it to HAT=0:
    if ( _altitude.valid() && (
        _altitude->clamping() == AltitudeSymbol::CLAMP_TO_TERRAIN || 
        _altitude->clamping() == AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN) )
    {
        mapPoint.altitudeMode() = ALTMODE_RELATIVE;
        //If we're clamping to the terrain
        if (_altitude->clamping() == AltitudeSymbol::CLAMP_TO_TERRAIN)
        {
            mapPoint.z() = 0.0;
        }
    }

    // if the point's already absolute and we're not clamping it, nop.
    if ( mapPoint.altitudeMode() == ALTMODE_ABSOLUTE )
    {
        return true;
    }

    // calculate the absolute Z of the map point.
    if ( getMapNode() )
    {
        // find the terrain height at the map point:
        double hamsl;
        if (getMapNode()->getTerrain()->getHeight(patch, mapPoint.getSRS(), mapPoint.x(), mapPoint.y(), &hamsl, 0L))
        {
            // apply any scale/offset in the symbology:
            if ( _altitude.valid() )
            {
                if ( _altitude->verticalScale().isSet() )
                    hamsl *= _altitude->verticalScale()->eval();
                if ( _altitude->verticalOffset().isSet() )
                    hamsl += _altitude->verticalOffset()->eval();
            }
            mapPoint.z() += hamsl;
        }
        mapPoint.altitudeMode() = ALTMODE_ABSOLUTE;
        return true;
    }

    return false;
}
Esempio n. 24
0
void
OverlayNode::traverse( osg::NodeVisitor& nv )
{
    if ( !_overlayProxyContainer.valid() )
    {
        osg::Group::traverse( nv );
    }
    else
    {
        if ( nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR )
        {
            if ( _active )
            {
                // do nothing -- culling will happen via the OverlayProxy instead.
            }
            else
            {
                // for a non-active node, just traverse children as usual.
                osg::Group::traverse( nv );
            }
        }

        else if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR )
        {
            if ( _dirty )
            {
                applyChanges();
                _dirty = false;
                ADJUST_UPDATE_TRAV_COUNT( this, -1 );
            }
            
            // traverse children directly, regardles of active status
            osg::Group::traverse( nv );
        }

        else if (dynamic_cast<osgUtil::IntersectionVisitor*>(&nv))
        {
            /*
               In order to properly intersect with overlay geometries, attempt to find the point on the terrain where the pick occurred
               cast a second intersector vertically at that point.

               Currently this is only imlpemented for our custom PrimitiveIntersector.
            */
            osgUtil::IntersectionVisitor* iv = dynamic_cast<osgUtil::IntersectionVisitor*>(&nv);
            osgEarth::PrimitiveIntersector* pi = dynamic_cast<osgEarth::PrimitiveIntersector *>(iv->getIntersector());

            osg::ref_ptr<MapNode> mapNode;
            if (pi && !pi->getOverlayIgnore() && _mapNode.lock(mapNode))
            { 
                osg::NodePath path = iv->getNodePath();
                osg::NodePath prunedNodePath( path.begin(), path.end()-1 );
                osg::Matrix modelToWorld = osg::computeLocalToWorld(prunedNodePath);
                osg::Vec3d worldStart = pi->getStart() * modelToWorld;
                osg::Vec3d worldEnd = pi->getEnd() * modelToWorld;

                osg::ref_ptr<DPLineSegmentIntersector> lsi = new DPLineSegmentIntersector(worldStart, worldEnd);
                osgUtil::IntersectionVisitor ivTerrain(lsi.get());
                mapNode->getTerrainEngine()->accept(ivTerrain);

                if (lsi->containsIntersections())
                {
                  osg::Vec3d worldIntersect = lsi->getFirstIntersection().getWorldIntersectPoint();
                  
                  GeoPoint mapIntersect;
                  mapIntersect.fromWorld(mapNode->getMapSRS(), worldIntersect);

                  osg::Vec3d newMapStart(mapIntersect.x(), mapIntersect.y(), 25000.0);
                  osg::Vec3d newMapEnd(mapIntersect.x(), mapIntersect.y(), -25000.0);

                  osg::Vec3d newWorldStart;
                  mapNode->getMapSRS()->transformToWorld(newMapStart, newWorldStart);

                  osg::Vec3d newWorldEnd;
                  mapNode->getMapSRS()->transformToWorld(newMapEnd, newWorldEnd);

                  osg::Matrix worldToModel;
                  worldToModel.invert(modelToWorld);

                  osg::Vec3d newModelStart = newWorldStart * worldToModel;
                  osg::Vec3d newModelEnd = newWorldEnd * worldToModel;

                  osg::ref_ptr<osgEarth::PrimitiveIntersector> pi2 = new osgEarth::PrimitiveIntersector(osgUtil::Intersector::MODEL, newModelStart, newModelEnd, pi->getThickness(), true);
                  osgUtil::IntersectionVisitor iv2(pi2);
                  iv2.setTraversalMask(iv->getTraversalMask());
                  path[0]->accept(iv2);

                  if (pi2->containsIntersections())
                  {
                    // Insert newlly found intersections into the original intersector.
                    for (PrimitiveIntersector::Intersections::iterator it = pi2->getIntersections().begin(); it != pi2->getIntersections().end(); ++it)
                    {
                      PrimitiveIntersector::Intersection intersection(*it);
                      intersection.ratio = 1.0;
                      pi->insertIntersection(intersection);
                    }
                  }
                }
                else
                {
                  //OE_WARN << LC << "No hits on terrain!" << std::endl;
                }
            }
            else
            {
              osg::Group::traverse( nv );
            }
        }

        // handle other visitor types (like intersections, etc) by simply
        // traversing the child graph.
        else // if ( nv.getNodeVisitor() == osg::NodeVisitor::NODE_VISITOR )
        {
            osg::Group::traverse( nv );
        }
    }
}
Esempio n. 25
0
bool
ElevationQuery::getElevationImpl(const GeoPoint& point, /* abs */
                                 double&         out_elevation,
                                 double          desiredResolution,
                                 double*         out_actualResolution)
{
    // assertion.
    if ( !point.isAbsolute() )
    {
        OE_WARN << LC << "Assertion failure; input must be absolute" << std::endl;
        return false;
    }

    osg::Timer_t begin = osg::Timer::instance()->tick();

    // first try the terrain patches.
    if ( _patchLayers.size() > 0 )
    {
        osgUtil::IntersectionVisitor iv;

        for(std::vector<ModelLayer*>::iterator i = _patchLayers.begin(); i != _patchLayers.end(); ++i)
        {
            // find the scene graph for this layer:
            osg::Node* node = (*i)->getSceneGraph( _mapf.getUID() );
            if ( node )
            {
                // configure for intersection:
                osg::Vec3d surface;
                point.toWorld( surface );

                // trivial bounds check:
                if ( node->getBound().contains(surface) )
                {
                    osg::Vec3d nvector;
                    point.createWorldUpVector(nvector);

                    osg::Vec3d start( surface + nvector*5e5 );
                    osg::Vec3d end  ( surface - nvector*5e5 );
                
                    // first time through, set up the intersector on demand
                    if ( !_patchLayersLSI.valid() )
                    {
                        _patchLayersLSI = new DPLineSegmentIntersector(start, end);
                        _patchLayersLSI->setIntersectionLimit( _patchLayersLSI->LIMIT_NEAREST );
                    }
                    else
                    {
                        _patchLayersLSI->reset();
                        _patchLayersLSI->setStart( start );
                        _patchLayersLSI->setEnd  ( end );
                    }

                    // try it.
                    iv.setIntersector( _patchLayersLSI.get() );
                    node->accept( iv );

                    // check for a result!!
                    if ( _patchLayersLSI->containsIntersections() )
                    {
                        osg::Vec3d isect = _patchLayersLSI->getIntersections().begin()->getWorldIntersectPoint();

                        // transform back to input SRS:
                        GeoPoint output;
                        output.fromWorld( point.getSRS(), isect );
                        out_elevation = output.z();
                        if ( out_actualResolution )
                            *out_actualResolution = 0.0;

                        return true;
                    }
                }
                else
                {
                    //OE_INFO << LC << "Trivial rejection (bounds check)" << std::endl;
                }
            }
        }
    }

    if ( _mapf.elevationLayers().empty() )
    {
        // this means there are no heightfields.
        out_elevation = 0.0;
        return true;        
    }

    // tile size (resolution of elevation tiles)
    unsigned tileSize = std::max(_mapf.getMapOptions().elevationTileSize().get(), 2u);

    //This is the max resolution that we actually have data at this point
    unsigned int bestAvailLevel = getMaxLevel( point.x(), point.y(), point.getSRS(), _mapf.getProfile());

    if (desiredResolution > 0.0)
    {
        unsigned int desiredLevel = _mapf.getProfile()->getLevelOfDetailForHorizResolution( desiredResolution, tileSize );
        if (desiredLevel < bestAvailLevel) bestAvailLevel = desiredLevel;
    }

    OE_DEBUG << LC << "Best available data level " << point.x() << ", " << point.y() << " = "  << bestAvailLevel << std::endl;

    // transform the input coords to map coords:
    GeoPoint mapPoint = point;
    if ( point.isValid() && !point.getSRS()->isHorizEquivalentTo( _mapf.getProfile()->getSRS() ) )
    {
        mapPoint = point.transform(_mapf.getProfile()->getSRS());
        if ( !mapPoint.isValid() )
        {
            OE_WARN << LC << "Fail: coord transform failed" << std::endl;
            return false;
        }
    }    

    // get the tilekey corresponding to the tile we need:
    TileKey key = _mapf.getProfile()->createTileKey( mapPoint.x(), mapPoint.y(), bestAvailLevel );
    if ( !key.valid() )
    {
        OE_WARN << LC << "Fail: coords fall outside map" << std::endl;
        return false;
    }
        
    bool result = false;      
    while (!result)
    {      
        GeoHeightField geoHF;
        TileCache::Record record;
        // Try to get the hf from the cache
        if ( _cache.get( key, record ) )
        {                        
            geoHF = record.value();
        }
        else
        {
            // Create it            
            osg::ref_ptr<osg::HeightField> hf = new osg::HeightField();
            hf->allocate( tileSize, tileSize );

            // Initialize the heightfield to nodata
            for (unsigned int i = 0; i < hf->getFloatArray()->size(); i++)
            {
                hf->getFloatArray()->at( i ) = NO_DATA_VALUE;
            }   

            if (_mapf.populateHeightField(hf, key, false))
            {                
                geoHF = GeoHeightField( hf.get(), key.getExtent() );
                _cache.insert( key, geoHF );
            }
        }

        if (geoHF.valid())
        {            
            float elevation = 0.0f;                 
            result = geoHF.getElevation( mapPoint.getSRS(), mapPoint.x(), mapPoint.y(), _mapf.getMapInfo().getElevationInterpolation(), mapPoint.getSRS(), elevation);                              
            if (result && elevation != NO_DATA_VALUE)
            {                        
                // see what the actual resolution of the heightfield is.
                if ( out_actualResolution )
                    *out_actualResolution = geoHF.getXInterval(); 
                out_elevation = (double)elevation;                
                break;
            }
            else
            {                               
                result = false;
            }
        }

        if (!result)
        {
            key = key.createParentKey();                        
            if (!key.valid())
            {
                break;
            }
        }         
    }

         

    osg::Timer_t end = osg::Timer::instance()->tick();
    _queries++;
    _totalTime += osg::Timer::instance()->delta_s( begin, end );

    return result;
}