void ModelViewer::focus( ) { float fov = ( 5.0f / 12.0f ) * glm::pi<float>( ); uint meshCount = m_model.numMeshes( ); if ( !meshCount ) { return; } // Calculate complete bounds Bounds bounds = m_model.bounds( ); float height = bounds.max.z - bounds.min.z; if ( height <= 0 ) { return; } float distance = bounds.min.y - ( ( height * 0.5f ) / ::tanf( fov * 0.5f ) ); if ( distance < 0 ) { distance *= -1; } // Update camera and render XMFLOAT3 dxBounds; glm::vec3 glmBounds = bounds.center( ); dxBounds.x = glmBounds.x; dxBounds.y = glmBounds.y; dxBounds.z = glmBounds.z; m_camera.setPivot( dxBounds ); //m_camera.setPivot( bounds.center( ) ); m_camera.setDistance( distance ); this->render( ); }
bool Frustum::Intersects( const Bounds &bounds ) const { // Has the frustum planes been built? if (!initialized_) { ASSERT(false); return false; } // Are the frustum planes up to date? if (needs_rebuild_) { // TODO Warn them! } // Null boxes always invisible if (bounds.is_null()) { return false; } // Infinite boxes always visible if (bounds.is_infinite()) { return true; } // Get center of the box Vector3 center = bounds.center(); // Get the half-size of the box Vector3 half = bounds.half_size(); // For each plane, see if all points are on the negative side // If so, object is not visible for (int32 plane = 0; plane < 6; ++plane) { // Skip far plane if infinite view frustum if ((plane == FRUSTUM_PLANE_FAR) && far_distance_ == 0) { continue; } int32 side = frustum_planes_[plane].Side(center, half); if (side == Plane::NEGATIVE_SIDE) { return false; } } return true; }
osg::HeightField* createHeightField( const TileKey& key, ProgressCallback* progress) { if (key.getLevelOfDetail() > _maxDataLevel) { //OE_NOTICE << "Reached maximum data resolution key=" << key.getLevelOfDetail() << " max=" << _maxDataLevel << std::endl; return NULL; } int tileSize = _options.tileSize().value(); //Allocate the heightfield osg::ref_ptr<osg::HeightField> hf = new osg::HeightField; hf->allocate(tileSize, tileSize); for (unsigned int i = 0; i < hf->getHeightList().size(); ++i) hf->getHeightList()[i] = NO_DATA_VALUE; if (intersects(key)) { //Get the extents of the tile double xmin, ymin, xmax, ymax; key.getExtent().getBounds(xmin, ymin, xmax, ymax); const SpatialReference* featureSRS = _features->getFeatureProfile()->getSRS(); GeoExtent extentInFeatureSRS = key.getExtent().transform( featureSRS ); const SpatialReference* keySRS = key.getProfile()->getSRS(); // populate feature list // assemble a spatial query. It helps if your features have a spatial index. Query query; query.bounds() = extentInFeatureSRS.bounds(); FeatureList featureList; osg::ref_ptr<FeatureCursor> cursor = _features->createFeatureCursor(query); while ( cursor.valid() && cursor->hasMore() ) { Feature* f = cursor->nextFeature(); if ( f && f->getGeometry() ) featureList.push_back(f); } // We now have a feature list in feature SRS. bool transformRequired = !keySRS->isHorizEquivalentTo(featureSRS); if (!featureList.empty()) { // Iterate over the output heightfield and sample the data that was read into it. double dx = (xmax - xmin) / (tileSize-1); double dy = (ymax - ymin) / (tileSize-1); for (int c = 0; c < tileSize; ++c) { double geoX = xmin + (dx * (double)c); for (int r = 0; r < tileSize; ++r) { double geoY = ymin + (dy * (double)r); float h = NO_DATA_VALUE; for (FeatureList::iterator f = featureList.begin(); f != featureList.end(); ++f) { osgEarth::Symbology::Polygon* boundary = dynamic_cast<osgEarth::Symbology::Polygon*>((*f)->getGeometry()); if (!boundary) { OE_WARN << LC << "NOT A POLYGON" << std::endl; } else { GeoPoint geo(keySRS, geoX, geoY, 0.0, ALTMODE_ABSOLUTE); if ( transformRequired ) geo = geo.transform(featureSRS); if ( boundary->contains2D(geo.x(), geo.y()) ) { h = (*f)->getDouble(_options.attr().value()); if ( keySRS->isGeographic() ) { // for a round earth, must adjust the final elevation accounting for the // curvature of the earth; so we have to adjust it in the feature boundary's // local tangent plane. Bounds bounds = boundary->getBounds(); GeoPoint anchor( featureSRS, bounds.center().x(), bounds.center().y(), h, ALTMODE_ABSOLUTE ); if ( transformRequired ) anchor = anchor.transform(keySRS); // For transforming between ECEF and local tangent plane: osg::Matrix localToWorld, worldToLocal; anchor.createLocalToWorld(localToWorld); worldToLocal.invert( localToWorld ); // Get the ECEF location of the anchor point: osg::Vec3d ecef; geo.toWorld( ecef ); // Move it into Local Tangent Plane coordinates: osg::Vec3d local = ecef * worldToLocal; // Reset the Z to zero, since the LTP is centered on the "h" elevation: local.z() = 0.0; // Back into ECEF: ecef = local * localToWorld; // And back into lat/long/alt: geo.fromWorld( geo.getSRS(), ecef); h = geo.z(); } break; } } } hf->setHeight(c, r, h-0.1); } } } } return hf.release(); }
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; }