I wrote a sample application using OsgQtQuick that shows the Earth in two views:
with the following QML, that I copied from OsgQtQuick samples:
ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") id: window menuBar: MenuBar { Menu { title: qsTr("File") MenuItem { text: qsTr("&Open3") iconSource: ":/images/Test32x32.png" onTriggered: console.log("Open action triggered"); } MenuItem { text: qsTr("Exit") onTriggered: Qt.quit(); } } } OSG.Notify { id: notifier notifyLevel: OSG.Notify.WARN onNotify: console.log(message); } OSGDB.Loader { id: loader objectName: "loader" source: "file:///home/dmitry/examples/osgearth/tests/openstreetmap.earth" onNodeChanged: { console.log("loader.node: " + getNode()) leftView.cameraManipulator.home() rightView.cameraManipulator.home() } onStatusChanged: { switch(status) { case OSGDB.Loader.Null: statusLabel.text = ""; break; case OSGDB.Loader.Loading: statusLabel.text = "Loading..."; break; case OSGDB.Loader.Ready: statusLabel.text = "Ready"; statusLabel.visible = false; break; case OSGDB.Loader.Error: statusLabel.text = "Error"; break; } } } GridLayout { columns: 2 rowSpacing: 2 columnSpacing: 2 anchors.fill: parent anchors.margins: 2 OSGViewer.View { id: leftView objectName: "leftView" Text { text: "View 1" color: "white" anchors.bottom: parent.bottom } cameraManipulator: OSGEarthUtil.EarthManipulator {} sceneData: loader Layout.fillHeight: true Layout.fillWidth: true } OSGViewer.View { id: rightView objectName: "rightView" Text { text: "View 2" color: "white" anchors.bottom: parent.bottom } cameraManipulator: OSGEarthUtil.EarthManipulator {} sceneData: loader Layout.fillHeight: true Layout.fillWidth: true } } Text { id: statusLabel text: "Starting..." color: "white" font.pointSize: 24 anchors { centerIn: parent horizontalCenter: parent.horizontalCenter } } Text { text: "Both view should be identical" color: "white" anchors { top: parent.top horizontalCenter: parent.horizontalCenter } } // Component.onCompleted: { // leftView.cameraManipulator.home() // rightView.cameraManipulator.home() // } }
It loads the Earth file from QML and adds some polygon with an annotation over the map in C++:
#include <osg/Node> #include <osgEarth/MapNode> #include <osgEarthSymbology/LineSymbol> #include <osgEarthAnnotation/LabelNode> #include <osgEarthAnnotation/FeatureNode> #include <osgEarthFeatures/Feature> #include <osg/NodeQtQml> #include <osgDB/LoaderQtQml> void addAnnotation(osgEarth::MapNode * mapNode) { using namespace osgEarth; using namespace osgEarth::Symbology; using namespace osgEarth::Annotation; using namespace osgEarth::Features; auto root = mapNode; // Group to hold all our annotation elements. osg::Group* annoGroup = new osg::Group(); root->addChild( annoGroup ); // Make a group for labels osg::Group* labelGroup = new osg::Group(); annoGroup->addChild( labelGroup ); // Style our labels: Style labelStyle; labelStyle.getOrCreate<TextSymbol>()->alignment() = TextSymbol::ALIGN_CENTER_CENTER; labelStyle.getOrCreate<TextSymbol>()->fill()->color() = Color::Yellow; // A lat/long SRS for specifying points. const SpatialReference* geoSRS = mapNode->getMapSRS()->getGeographicSRS(); // a box that follows lines of latitude (rhumb line interpolation, the default) { Geometry* geom = new Polygon(); geom->push_back( osg::Vec3d(0, 40, 0) ); geom->push_back( osg::Vec3d(-60, 40, 0) ); geom->push_back( osg::Vec3d(-60, 60, 0) ); geom->push_back( osg::Vec3d(0, 60, 0) ); Feature* feature = new Feature(geom, geoSRS); feature->geoInterp() = GEOINTERP_RHUMB_LINE; Style geomStyle; geomStyle.getOrCreate<LineSymbol>()->stroke()->color() = Color::Cyan; geomStyle.getOrCreate<LineSymbol>()->stroke()->width() = 5.0f; geomStyle.getOrCreate<LineSymbol>()->tessellationSize() = 75000; geomStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN; geomStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_GPU; FeatureNode* fnode = new FeatureNode(mapNode, feature, geomStyle); annoGroup->addChild( fnode ); labelGroup->addChild( new LabelNode(mapNode, GeoPoint(geoSRS,-30, 50), "Rhumb line polygon", labelStyle) ); } } int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QApplication::setWindowIcon(QIcon(":/images/app.ico")); QQmlApplicationEngine engine; engine.addImportPath("/home/dmitry/examples/install/qml"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); QObject * topObject = engine.rootObjects().value(0); QQuickWindow * window = qobject_cast<QQuickWindow *>(topObject); if (window != nullptr) { qDebug("Main window has been created successfully."); osgDB::LoaderQtQml * loader = window->findChild<osgDB::LoaderQtQml *>("loader"); if (loader != nullptr) { qDebug("loader found!."); QObject::connect(loader, &osgDB::LoaderQtQml::nodeChanged, &app, [](osg::NodeQtQml* qmlNode) { osg::Node * node = qmlNode->node(); qDebug() << "Node has been changed:" << node->className(); osgEarth::MapNode * mapNode = dynamic_cast<osgEarth::MapNode *>(node); if (mapNode != nullptr) { qDebug() << "Map Node found!:"; addAnnotation(mapNode); } }); return app.exec(); } else { qDebug("loader not found!."); } } }
It works not quite correct, because if I rotate the Earth in a view so that the text label (annotation) becomes invisible, the Earth in other view becomes black. See video demonstrating this effect. OSG version is 3.4 and OsgEarth version is 2.8. It is noteworthy that the original OsgEarth sample osgearth_overlayviewer with the same nodes added over the map works fine:
#include <osg/Notify> #include <osg/Depth> #include <osg/LineWidth> #include <osg/LineStipple> #include <osgGA/StateSetManipulator> #include <osgGA/AnimationPathManipulator> #include <osgViewer/CompositeViewer> #include <osgViewer/ViewerEventHandlers> #include <osgEarth/OverlayDecorator> #include <osgEarth/MapNode> #include <osgEarthUtil/EarthManipulator> #include <osgEarthUtil/ExampleResources> #include <osgEarthUtil/Controls> #include <osgEarthSymbology/Color> #include <osgEarthSymbology/LineSymbol> #include <osgEarthAnnotation/LabelNode> #include <osgEarthAnnotation/FeatureNode> #include <osgEarthFeatures/Feature> using namespace osgEarth::Util; using namespace osgEarth::Util::Controls; using namespace osgEarth::Symbology; //------------------------------------------------------------------------ namespace { void addAnnotation(osgEarth::MapNode * mapNode) { using namespace osgEarth; using namespace osgEarth::Symbology; using namespace osgEarth::Annotation; using namespace osgEarth::Features; osg::Group * root = mapNode; // Group to hold all our annotation elements. osg::Group* annoGroup = new osg::Group(); root->addChild( annoGroup ); // Make a group for labels osg::Group* labelGroup = new osg::Group(); annoGroup->addChild( labelGroup ); // Style our labels: Style labelStyle; labelStyle.getOrCreate<TextSymbol>()->alignment() = TextSymbol::ALIGN_CENTER_CENTER; labelStyle.getOrCreate<TextSymbol>()->fill()->color() = Color::Yellow; // A lat/long SRS for specifying points. const SpatialReference* geoSRS = mapNode->getMapSRS()->getGeographicSRS(); // a box that follows lines of latitude (rhumb line interpolation, the default) { Geometry* geom = new Polygon(); geom->push_back( osg::Vec3d(0, 40, 0) ); geom->push_back( osg::Vec3d(-60, 40, 0) ); geom->push_back( osg::Vec3d(-60, 60, 0) ); geom->push_back( osg::Vec3d(0, 60, 0) ); Feature* feature = new Feature(geom, geoSRS); feature->geoInterp() = GEOINTERP_RHUMB_LINE; Style geomStyle; geomStyle.getOrCreate<LineSymbol>()->stroke()->color() = Color::Cyan; geomStyle.getOrCreate<LineSymbol>()->stroke()->width() = 5.0f; geomStyle.getOrCreate<LineSymbol>()->tessellationSize() = 75000; geomStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_TO_TERRAIN; geomStyle.getOrCreate<AltitudeSymbol>()->technique() = AltitudeSymbol::TECHNIQUE_GPU; FeatureNode* fnode = new FeatureNode(mapNode, feature, geomStyle); annoGroup->addChild( fnode ); labelGroup->addChild( new LabelNode(mapNode, GeoPoint(geoSRS,-30, 50), "Rhumb line polygon", labelStyle) ); } } } int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); osgViewer::CompositeViewer viewer(arguments); viewer.setThreadingModel( osgViewer::CompositeViewer::SingleThreaded ); // query the screen size. osg::GraphicsContext::ScreenIdentifier si; si.readDISPLAY(); if ( si.displayNum < 0 ) si.displayNum = 0; osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); unsigned width, height; wsi->getScreenResolution( si, width, height ); unsigned b = 50; osgViewer::View* mainView = new osgViewer::View(); mainView->getCamera()->setNearFarRatio(0.00002); EarthManipulator* em = new EarthManipulator(); em->getSettings()->setMinMaxPitch(-90, 0); mainView->setCameraManipulator( em ); //mainView->setUpViewInWindow( 50, 50, 600, 600 ); mainView->setUpViewInWindow( b, b, (width/2)-b*2, (height-b*4) ); viewer.addView( mainView ); osgViewer::View* overlayView = new osgViewer::View(); overlayView->getCamera()->setNearFarRatio(0.00002); //overlayView->getCamera()->setProjectionMatrixAsOrtho2D(-1,1,-1,1); overlayView->setCameraManipulator( new EarthManipulator() ); //overlayView->setUpViewInWindow( 700, 50, 600, 600 ); overlayView->setUpViewInWindow( (width/2), b, (width/2)-b*2, (height-b*4) ); //overlayView->addEventHandler(new osgGA::StateSetManipulator(overlayView->getCamera()->getOrCreateStateSet())); viewer.addView( overlayView ); std::string pathfile; double animationSpeed = 1.0; if (arguments.read("-p", pathfile)) { mainView->setCameraManipulator( new osgGA::AnimationPathManipulator(pathfile) ); } osg::Node* node = MapNodeHelper().load( arguments, mainView ); if ( node ) { mainView->setSceneData( node ); MapNode* mapNode = MapNode::get(node); OE_WARN << "Adding annotation." << std::endl; addAnnotation( mapNode ); //osg::Group* group = new osg::Group(); //group->addChild( mapNode ); overlayView->setSceneData( mapNode ); //setupOverlayView( overlayView, group, MapNode::get(node) ); return viewer.run(); } else return -1; }
Hello,
I’ve just come across this and was wondering if you found a solution?
I have this in an application I’m working on and haven’t had a chance to investigate it fully.
Thank,
Steve.