osg::Node* makePlaceNode(FilterContext& context, Feature* feature, const Style& style, NumericExpression& priorityExpr ) { osg::Vec3d center = feature->getGeometry()->getBounds().center(); AltitudeMode mode = ALTMODE_ABSOLUTE; const AltitudeSymbol* alt = style.getSymbol<AltitudeSymbol>(); if (alt && (alt->clamping() == AltitudeSymbol::CLAMP_TO_TERRAIN || alt->clamping() == AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN) && alt->technique() == AltitudeSymbol::TECHNIQUE_SCENE) { mode = ALTMODE_RELATIVE; } GeoPoint point(feature->getSRS(), center.x(), center.y(), center.z(), mode); PlaceNode* node = new PlaceNode(0L, point, style, context.getDBOptions()); if ( !priorityExpr.empty() ) { AnnotationData* data = new AnnotationData(); data->setPriority( feature->eval(priorityExpr, &context) ); node->setAnnotationData( data ); } return node; }
virtual void onClick( AnnotationNode* node, const EventArgs& details ) { PlaceNode* place = dynamic_cast<PlaceNode*>(node); if (place == NULL) { OE_NOTICE << "Thanks for clicking this annotation" << std::endl; } else { OE_NOTICE << "Thanks for clicking the PlaceNode: " << place->getText() << std::endl; } }
osg::Node* makePlaceNode(const FilterContext& context, const Feature* feature, const Style& style, NumericExpression& priorityExpr ) { osg::Vec3d center = feature->getGeometry()->getBounds().center(); GeoPoint point(feature->getSRS(), center.x(), center.y()); PlaceNode* placeNode = new PlaceNode(0L, point, style, context.getDBOptions()); if ( !priorityExpr.empty() ) { AnnotationData* data = new AnnotationData(); data->setPriority( feature->eval(priorityExpr, &context) ); placeNode->setAnnotationData( data ); } return placeNode; }
PlaceNode* ClusterNode::getOrCreateLabel() { PlaceNode* node = 0; if (_labelPool.size() <= _nextLabel) { // set up a style to use for placemarks: Style placeStyle; placeStyle.getOrCreate<TextSymbol>()->declutter() = false; node = new PlaceNode("", placeStyle, _defaultImage.get()); node->setMapNode(_mapNode.get()); node->setDynamic(true); _labelPool.push_back(node); } else { node = _labelPool[_nextLabel].get(); } ++_nextLabel; return node; }
int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); if ( arguments.read("--stencil") ) osg::DisplaySettings::instance()->setMinimumNumStencilBits( 8 ); //Setup a CompositeViewer osgViewer::CompositeViewer viewer(arguments); //Setup our main view that will show the loaded earth file. osgViewer::View* mainView = new osgViewer::View(); mainView->getCamera()->setNearFarRatio(0.00002); mainView->setCameraManipulator( new EarthManipulator() ); mainView->setUpViewInWindow( 50, 50, 800, 800 ); viewer.addView( mainView ); //Setup a MiniMap View that will be embedded in the main view int miniMapWidth = 400; int miniMapHeight = 200; osgViewer::View* miniMapView = new osgViewer::View(); miniMapView->getCamera()->setNearFarRatio(0.00002); miniMapView->getCamera()->setViewport( 0, 0, miniMapWidth, miniMapHeight); miniMapView->setCameraManipulator( new EarthManipulator() ); miniMapView->getCamera()->setClearColor( osg::Vec4(0,0,0,0)); miniMapView->getCamera()->setProjectionResizePolicy( osg::Camera::FIXED ); miniMapView->getCamera()->setProjectionMatrixAsPerspective(30.0, double(miniMapWidth) / double(miniMapHeight), 1.0, 1000.0); //Share a graphics context with the main view miniMapView->getCamera()->setGraphicsContext( mainView->getCamera()->getGraphicsContext()); viewer.addView( miniMapView ); // load an earth file, and support all or our example command-line options // and earth file <external> tags osg::Node* node = MapNodeHelper().load( arguments, mainView ); if ( node ) { MapNode* mapNode = MapNode::findMapNode(node); //Set the main view's scene data to the loaded earth file mainView->setSceneData( node ); //Setup a group to hold the contents of the MiniMap osg::Group* miniMapGroup = new osg::Group; MapNode* miniMapNode = makeMiniMapNode(); miniMapGroup->addChild( miniMapNode ); //Get the main MapNode so we can do tranformations between it and our minimap MapNode* mainMapNode = MapNode::findMapNode( node ); //Set the scene data for the minimap miniMapView->setSceneData( miniMapGroup ); //Add a marker we can move around with the main view's eye point Style markerStyle; markerStyle.getOrCreate<IconSymbol>()->url()->setLiteral( "../data/placemark32.png" ); PlaceNode* eyeMarker = new PlaceNode(miniMapNode, GeoPoint(miniMapNode->getMapSRS(), 0, 0), "", markerStyle); miniMapGroup->addChild( eyeMarker ); miniMapGroup->getOrCreateStateSet()->setRenderBinDetails(100, "RenderBin"); osg::Node* bounds = 0; while (!viewer.done()) { //Reset the viewport so that the camera's viewport is static and doesn't resize with window resizes miniMapView->getCamera()->setViewport( 0, 0, miniMapWidth, miniMapHeight); //Get the eye point of the main view osg::Vec3d eye, up, center; mainView->getCamera()->getViewMatrixAsLookAt( eye, center, up ); //Turn the eye into a geopoint and transform it to the minimap's SRS GeoPoint eyeGeo; eyeGeo.fromWorld( mainMapNode->getMapSRS(), eye ); eyeGeo.transform( miniMapNode->getMapSRS()); //We want the marker to be positioned at elevation 0, so zero out any elevation in the eye point eyeGeo.z() = 0; //Set the position of the marker eyeMarker->setPosition( eyeGeo ); if (bounds) { miniMapGroup->removeChild( bounds ); } GeoExtent extent = getExtent( mainView ); bounds = drawBounds( miniMapNode, extent ); miniMapGroup->addChild( bounds ); viewer.frame(); } } else { OE_NOTICE << "\nUsage: " << argv[0] << " file.earth" << std::endl << MapNodeHelper().usage() << std::endl; } return 0; }
int main(int argc, char** argv) { osg::Group* root = new osg::Group(); // try to load an earth file. osg::ArgumentParser arguments(&argc,argv); osgViewer::Viewer viewer(arguments); unsigned int numObjects = 200; while (arguments.read("--count", numObjects)) {} bool declutter = false; if (arguments.read("--declutter")) declutter = true; // initialize the viewer: viewer.setCameraManipulator( new EarthManipulator() ); // load an earth file and parse demo arguments osg::Node* node = MapNodeHelper().load(arguments, &viewer); if ( !node ) return usage(argv); // find the map node that we loaded. MapNode* mapNode = MapNode::findMapNode(node); if ( !mapNode ) return usage(argv); root->addChild( node ); // Make a group for 2D items, and activate the decluttering engine. Decluttering // will migitate overlap between elements that occupy the same screen real estate. osg::Group* labelGroup = new osg::Group(); if (declutter) { Decluttering::setEnabled( labelGroup->getOrCreateStateSet(), true ); } root->addChild( labelGroup ); // set up a style to use for placemarks: Style placeStyle; placeStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN; // A lat/long SRS for specifying points. const SpatialReference* geoSRS = mapNode->getMapSRS()->getGeographicSRS(); //-------------------------------------------------------------------- //Create a bunch of placemarks around Mt Rainer so we can actually get some elevation { osg::Image* pin = osgDB::readImageFile( "../data/placemark32.png" ); double centerLat = 46.840866; double centerLon = -121.769846; double height = 0.2; double width = 0.2; double minLat = centerLat - (height/2.0); double minLon = centerLon - (width/2.0); OE_NOTICE << "Placing " << numObjects << " placemarks" << std::endl; for (unsigned int i = 0; i < numObjects; i++) { double lat = minLat + height * (rand() * 1.0)/(RAND_MAX-1); double lon = minLon + width * (rand() * 1.0)/(RAND_MAX-1); PlaceNode* place = new PlaceNode(mapNode, GeoPoint(geoSRS, lon, lat), pin, "Placemark", placeStyle); //Enable occlusion culling. This will hide placemarks that are hidden behind terrain. //This makes use of the OcclusionCullingCallback in CullingUtils. place->setOcclusionCulling( true ); labelGroup->addChild( place ); } } viewer.setSceneData( root ); viewer.getCamera()->addCullCallback( new AutoClipPlaneCullCallback(mapNode) ); viewer.addEventHandler(new osgViewer::StatsHandler()); viewer.addEventHandler(new osgViewer::WindowSizeHandler()); viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet())); return viewer.run(); }
void KML_Placemark::build( xml_node<>* node, KMLContext& cx ) { Style masterStyle; std::string styleUrl = getValue(node, "styleurl"); if (!styleUrl.empty()) { // process a "stylesheet" style const Style* ref_style = cx._sheet->getStyle( styleUrl, false ); if (ref_style) { masterStyle = masterStyle.combineWith(*ref_style); } } xml_node<>* style = node->first_node("style", 0, false); if ( style ) { // process an "inline" style KML_Style kmlStyle; kmlStyle.scan(style, cx); masterStyle = masterStyle.combineWith(cx._activeStyle); } // parse the geometry. the placemark must have geometry to be valid. The // geometry parse may optionally specify an altitude mode as well. KML_Geometry geometry; geometry.build(node, cx, masterStyle); Geometry* allGeom = geometry._geom.get(); if ( allGeom ) { GeometryIterator giter( allGeom, false ); while( giter.hasMore() ) { Geometry* geom = giter.next(); Style style = masterStyle; AltitudeSymbol* alt = style.get<AltitudeSymbol>(); if ( geom && geom->getTotalPointCount() > 0 ) { // resolve the proper altitude mode for the anchor point AltitudeMode altMode = ALTMODE_RELATIVE; if (alt && !alt->clamping().isSetTo( alt->CLAMP_TO_TERRAIN ) && !alt->clamping().isSetTo( alt->CLAMP_RELATIVE_TO_TERRAIN ) ) { altMode = ALTMODE_ABSOLUTE; } GeoPoint position(cx._srs.get(), geom->getBounds().center(), altMode); // check for symbols. ModelSymbol* model = style.get<ModelSymbol>(); IconSymbol* icon = style.get<IconSymbol>(); TextSymbol* text = style.get<TextSymbol>(); // for a single point placemark, apply the default icon and text symbols // if none are specified in the KML. if (geom->getTotalPointCount() == 1) { if (!model && !icon && cx._options->defaultIconSymbol().valid()) { icon = cx._options->defaultIconSymbol().get(); style.add(icon); } if (!text && cx._options->defaultTextSymbol().valid()) { text = cx._options->defaultTextSymbol().get(); style.add(text); } } // the annotation name: std::string name = getValue(node, "name"); if (!name.empty()) { OE_INFO << LC << "Placemark: " << name << std::endl; } AnnotationNode* featureNode = 0L; AnnotationNode* iconNode = 0L; AnnotationNode* modelNode = 0L; // one coordinate? It's a place marker or a label. if ( (model || icon || text) && geom->getTotalPointCount() == 1 ) { // if there's a model, render that - models do NOT get labels. if ( model ) { ModelNode* node = new ModelNode( cx._mapNode, style, cx._dbOptions.get() ); node->setPosition( position ); // model scale: if ( cx._options->modelScale() != 1.0f ) { float s = *cx._options->modelScale(); node->getPositionAttitudeTransform()->setScale(osg::Vec3d(s,s,s)); } // model local tangent plane rotation: if ( !cx._options->modelRotation()->zeroRotation() ) { node->getPositionAttitudeTransform()->setAttitude( *cx._options->modelRotation() ); } modelNode = node; } // is there a label? else if ( !name.empty() ) { if ( !text ) { text = style.getOrCreate<TextSymbol>(); text->encoding() = TextSymbol::ENCODING_UTF8; } text->content()->setLiteral( name ); } // is there an icon? if ( icon ) { PlaceNode* placeNode = new PlaceNode( position ); placeNode->setStyle(style, cx._dbOptions.get()); iconNode = placeNode; } else if ( !model && text && !name.empty() ) { // note: models do not get labels. iconNode = new LabelNode(); iconNode->setStyle(style); } } // multiple coords? feature: if ( geom->getTotalPointCount() > 1 ) { // Remove symbols that we have already processed so the geometry // compiler doesn't get confused. if ( model ) style.removeSymbol( model ); if ( icon ) style.removeSymbol( icon ); if ( text ) style.removeSymbol( text ); Feature* feature = new Feature(geom, cx._srs.get(), style); featureNode = new FeatureNode(feature ); featureNode->setMapNode( cx._mapNode ); } if ( iconNode ) { Registry::objectIndex()->tagNode( iconNode, iconNode ); } if ( modelNode ) { Registry::objectIndex()->tagNode( modelNode, modelNode ); } if ( featureNode ) { Registry::objectIndex()->tagNode( featureNode, featureNode ); } // assemble the results: if ( (iconNode || modelNode) && featureNode ) { osg::Group* group = new osg::Group(); group->addChild( featureNode ); if ( iconNode ) group->addChild( iconNode ); if ( modelNode ) group->addChild( modelNode ); cx._groupStack.top()->addChild( group ); if ( iconNode ) KML_Feature::build( node, cx, iconNode ); if ( modelNode ) KML_Feature::build( node, cx, modelNode ); if ( featureNode ) KML_Feature::build( node, cx, featureNode ); } else { if ( iconNode ) { if ( cx._options->iconAndLabelGroup().valid() ) { cx._options->iconAndLabelGroup()->addChild( iconNode ); } else { cx._groupStack.top()->addChild( iconNode ); } KML_Feature::build( node, cx, iconNode ); } if ( modelNode ) { cx._groupStack.top()->addChild( modelNode ); KML_Feature::build( node, cx, modelNode ); } if ( featureNode ) { osg::Node* child = featureNode; // If this feature node is map-clamped, we most likely need a depth-offset // shader to prevent z-fighting with the terrain. if (alt && alt->clamping() == alt->CLAMP_TO_TERRAIN && alt->technique() == alt->TECHNIQUE_MAP) { DepthOffsetGroup* g = new DepthOffsetGroup(); g->addChild( featureNode ); child = g; } cx._groupStack.top()->addChild( child ); KML_Feature::build( node, cx, featureNode ); } } } } } }
void ClusterNode::getClusters(osgUtil::CullVisitor* cv, ClusterList& out) { _nextLabel = 0; osg::Camera* camera = cv->getCurrentCamera(); osg::Viewport* viewport = camera->getViewport(); if (!viewport) { return; } osg::Matrixd mvpw = camera->getViewMatrix() * camera->getProjectionMatrix() * camera->getViewport()->computeWindowMatrix(); std::vector<TPoint> points; osg::NodeList validPlaces; buildIndex(); for (osg::NodeList::iterator itr = _clusterIndex.begin(); itr != _clusterIndex.end(); ++itr) { osg::Group* index = static_cast<osg::Group*>(itr->get()); if (cv->isCulled(index->getBound())) { continue; } for (unsigned int i = 0; i < index->getNumChildren(); i++) { osg::Node* node = index->getChild(i); osg::Vec3d world = node->getBound().center(); if (cv->isCulled(*node)) { continue; } if (!_horizon->isVisible(world)) { continue; } osg::Vec3d screen = world * mvpw; if (screen.x() >= 0 && screen.x() <= viewport->width() && screen.y() >= 0 && screen.y() <= viewport->height()) { validPlaces.push_back(node); points.push_back(TPoint(screen.x(), screen.y())); } } } if (validPlaces.size() == 0) return; kdbush::KDBush<TPoint> index(points); std::set< unsigned int > clustered; for (unsigned int i = 0; i < validPlaces.size(); i++) { TPoint &screen = points[i]; osg::Node* node = validPlaces[i].get(); // If this thing is already part of a cluster then just continue. if (clustered.find(i) != clustered.end()) { continue; } osg::Vec3d world = node->getBound().center(); // Get any matching indices that are part of this cluster. TIds indices; index.range(screen.first - _radius, screen.second - _radius, screen.first + _radius, screen.second + _radius, indices); // Create a new cluster. Cluster cluster; unsigned int actualCount = 0; // Add all of the points to the cluster. for (unsigned int j = 0; j < indices.size(); j++) { if (clustered.find(indices[j]) == clustered.end()) { if (_canClusterCallback.valid()) { bool canCluster = (*_canClusterCallback)(node, validPlaces[indices[j]].get()); if (!canCluster) { continue; } } cluster.nodes.push_back(validPlaces[indices[j]]); actualCount++; clustered.insert(indices[j]); } } std::stringstream buf; buf << actualCount << std::endl; PlaceNode* marker = getOrCreateLabel(); GeoPoint markerPos; markerPos.fromWorld(_mapNode->getMapSRS(), world); marker->setPosition(markerPos); marker->setText(buf.str()); cluster.marker = marker; out.push_back(cluster); clustered.insert(i); } }