Marble/Runners/PaintingGeoDataLineString: Difference between revisions

From KDE TechBase
No edit summary
 
(18 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Template:I18n/Language Navigation Bar|Editing Projects/Marble/PaintingGeoDataLineString}}
 
{{TutorialBrowser|
{{TutorialBrowser|


Line 6: Line 6:
name=Painting GeoDataLineString: Using the GeoPainter in order to paint a GeoDataLineString object|
name=Painting GeoDataLineString: Using the GeoPainter in order to paint a GeoDataLineString object|


pre=[[Projects/Marble/Runners/Parse|Tutorial 9 - Opening .kml, .gpx, ... files]]|
pre=[[Projects/Marble/LayerInterface|Tutorial 14 - Drawing in Custom Layers]]|


next=[[Projects/Marble/Runners/YetMissing|Tutorial 11 - Yet missing]]|
next=[[Projects/Marble/DisplayGeoDataGroundOverlay|Tutorial 16 - Rendering Ground Overlays]]|
}}
}}


The previous tutorial showed how GeoPainter can be used in order to paint shapes and text at different coordinates of the map (through a GeoDataCoordinates parameter), in a [http://api.kde.org/4.x-api/kdeedu-apidocs/marble/html/classMarble_1_1MarbleWidget.html MarbleWidget].


In the previous tutorial you've seen how easy it is to embed a [http://api.kde.org/4.x-api/kdeedu-apidocs/marble/html/classMarble_1_1MarbleWidget.html MarbleWidget] into a Qt application: Just create a MarbleWidget, set a map theme on it and ... you're done already.
The previous tutorial proved how GeoPainter can be used in order to paint shapes and text at different coordinates of the map (through a GeoDataCoordinates parameter) in a [http://api.kde.org/4.x-api/kdeedu-apidocs/marble/html/classMarble_1_1MarbleWidget.html MarbleWidget]. Now, we'll show a new way of adding extra content to the globe: by painting GeoDataLineString's using our GeoPainter.
 
Briefly, [http://api.kde.org/4.x-api/kdeedu-apidocs/marble/html/classMarble_1_1GeoDataLineString.html GeoDataLineString] is a tool class which implements LineStrings (also referred to as "polylines"), allowing us to store a contiguous set of line segments. As you will see in the example, it consists of several nodes (GeoDataCoordinates points), which are connected through line segments.
 
GeoDataLineString allows LineStrings to be tessellated in order to make them follow the terrain and the curvature of the Earth. The tessellation options allow different ways of visualization:
 
* Not tessellated, connects each two nodes directly


Next we'll extend that example a bit and write our own little paint method to add some extra content to the globe. To facilitate this, Marble provides a painting hook called [http://api.kde.org/4.x-api/kdeedu-apidocs/marble/html/classMarble_1_1MarbleWidget.html#47e87a8639f38e9da380923453a6f35f MarbleWidget::customPaint]. It is called in between of the normal paint operations: After the background and tiles are painted, but before the top layers like float items (info boxes).
* A tessellated line, each segment is bent such that the LineString follows the curvature of the Earth and its terrain. A tessellated line segment connects each two nodes at the shortest possible distance ("along great circles").  
 
* A tessellated line which follows latitude circles whenever possible: in this case latitude circles are followed as soon as two subsequent nodes have exactly the same amount of latitude. In all other places the line segments follow great circles.  


The customPaint operation is called with a [http://api.kde.org/4.x-api/kdeedu-apidocs/marble/html/classMarble_1_1GeoPainter.html GeoPainter]: An extended [http://doc.trolltech.com/qpainter.html QPainter] which not only is able to paint at certain screen (pixel) positions, but also at certain geo (lat,lon) positions. We'll make use of that feature now. To keep things simple again, we just add a little 'Hello World' message indicated by a green circle.


<source lang="cpp">
<source lang="cpp">
Line 23: Line 29:
#include <marble/MarbleWidget.h>
#include <marble/MarbleWidget.h>
#include <marble/GeoPainter.h>
#include <marble/GeoPainter.h>
#include <marble/GeoDataLineString.h>
using namespace Marble;


using namespace Marble;
class MyMarbleWidget : public MarbleWidget  
class MyMarbleWidget : public MarbleWidget
{
{
public:
public:
    virtual void customPaint(GeoPainter* painter);
virtual void customPaint(GeoPainter* painter);
};
};


void MyMarbleWidget::customPaint(GeoPainter* painter)
void MyMarbleWidget::customPaint(GeoPainter* painter) {
{
 
    GeoDataCoordinates home(8.4, 49.0, 0.0, GeoDataCoordinates::Degree);
GeoDataCoordinates France( 2.2, 48.52, 0.0, GeoDataCoordinates::Degree );
    painter->setPen(Qt::green);
painter->setPen( QColor( 0, 0, 0 ) );
    painter->drawEllipse(home, 7, 7);
painter->drawText( France, "France" );
    painter->setPen(Qt::black);
 
    painter->drawText(home, "Hello Marble!");
GeoDataCoordinates Canada( -77.02, 48.52, 0.0, GeoDataCoordinates::Degree );
painter->setPen( QColor( 0, 0, 0 ) );
painter->drawText( Canada, "Canada" );
 
//A line from France to Canada without tessellation
 
GeoDataLineString shapeNoTessellation( NoTessellation );
shapeNoTessellation << France << Canada;
 
painter->setPen( oxygenSkyBlue4 );
painter->drawPolyline( shapeNoTessellation );
 
//The same line, but with tessellation
GeoDataLineString shapeTessellate( Tessellate );
shapeTessellate << France << Canada;
 
painter->setPen( oxygenBrickRed4 );
painter->drawPolyline( shapeTessellate );
 
//Now following the latitude circles
 
GeoDataLineString shapeLatitudeCircle( RespectLatitudeCircle | Tessellate );
shapeLatitudeCircle << France << Canada;
 
painter->setPen( oxygenForestGreen4 );
painter->drawPolyline( shapeLatitudeCircle );
}
}
 
int main(int argc, char** argv) {


int main(int argc, char** argv)
QApplication app(argc,argv);
{
 
    QApplication app(argc,argv);
// Create a Marble QWidget without a parent
    MyMarbleWidget *mapWidget = new MyMarbleWidget;
MarbleWidget *mapWidget = new MyMarbleWidget();
    mapWidget->setMapThemeId("earth/openstreetmap/openstreetmap.dgml");
   
    mapWidget->show();
// Load the OpenStreetMap map
    return app.exec();
mapWidget->setMapThemeId("earth/plain/plain.dgml");
mapWidget->show();
 
return app.exec();
}
}
</source>
</source>
Line 59: Line 98:
If things go fine, execute <tt>./my_marble</tt> and you end up with a globe view similar to this:
If things go fine, execute <tt>./my_marble</tt> and you end up with a globe view similar to this:


[[Image:Marble-geopainter.png]]
[[Image:GeoDataLineStringTutorial.png]]


There may be situations where MarbleWidget::customPaint() does not suit your needs. This can be the case when you don't want to paint at the very top position (above all other items), or when subclassing MarbleWidget is not possible for some reason. In that case, have a look at the next chapter [[Projects/Marble/LayerInterface|Drawing in Custom Layers]]
As you can see, the blue line corresponds to the straight-no-tessellation way of visualization, the red one follows the great circles, and the green one sticks to the latitude circles, since the two endpoints have the same latitude.

Latest revision as of 21:01, 10 March 2016

Painting GeoDataLineString: Using the GeoPainter in order to paint a GeoDataLineString object
Tutorial Series   Marble C++ Tutorial
Previous   Tutorial 14 - Drawing in Custom Layers
What's Next   Tutorial 16 - Rendering Ground Overlays
Further Reading   n/a


The previous tutorial proved how GeoPainter can be used in order to paint shapes and text at different coordinates of the map (through a GeoDataCoordinates parameter) in a MarbleWidget. Now, we'll show a new way of adding extra content to the globe: by painting GeoDataLineString's using our GeoPainter.

Briefly, GeoDataLineString is a tool class which implements LineStrings (also referred to as "polylines"), allowing us to store a contiguous set of line segments. As you will see in the example, it consists of several nodes (GeoDataCoordinates points), which are connected through line segments.

GeoDataLineString allows LineStrings to be tessellated in order to make them follow the terrain and the curvature of the Earth. The tessellation options allow different ways of visualization:

  • Not tessellated, connects each two nodes directly
  • A tessellated line, each segment is bent such that the LineString follows the curvature of the Earth and its terrain. A tessellated line segment connects each two nodes at the shortest possible distance ("along great circles").
  • A tessellated line which follows latitude circles whenever possible: in this case latitude circles are followed as soon as two subsequent nodes have exactly the same amount of latitude. In all other places the line segments follow great circles.


#include <QtGui/QApplication>
#include <marble/MarbleWidget.h>
#include <marble/GeoPainter.h>
#include <marble/GeoDataLineString.h>
 
using namespace Marble;

class MyMarbleWidget : public MarbleWidget 
{
	public:
	virtual void customPaint(GeoPainter* painter);
};

void MyMarbleWidget::customPaint(GeoPainter* painter) {

	GeoDataCoordinates France( 2.2, 48.52, 0.0, GeoDataCoordinates::Degree );
	painter->setPen( QColor( 0, 0, 0 ) );
	painter->drawText( France, "France" );

	GeoDataCoordinates Canada( -77.02, 48.52, 0.0, GeoDataCoordinates::Degree );
	painter->setPen( QColor( 0, 0, 0 ) );
	painter->drawText( Canada, "Canada" );

	//A line from France to Canada without tessellation

	GeoDataLineString shapeNoTessellation( NoTessellation );
	shapeNoTessellation << France << Canada;

	painter->setPen( oxygenSkyBlue4 );
	painter->drawPolyline( shapeNoTessellation );

	//The same line, but with tessellation
	
	GeoDataLineString shapeTessellate( Tessellate );
	shapeTessellate << France << Canada;

	painter->setPen( oxygenBrickRed4 );
	painter->drawPolyline( shapeTessellate );

	//Now following the latitude circles

	GeoDataLineString shapeLatitudeCircle( RespectLatitudeCircle | Tessellate );
	shapeLatitudeCircle << France << Canada;

	painter->setPen( oxygenForestGreen4 );
	painter->drawPolyline( shapeLatitudeCircle );
}
  
int main(int argc, char** argv) {

	QApplication app(argc,argv);
		   
	// Create a Marble QWidget without a parent
	MarbleWidget *mapWidget = new MyMarbleWidget();
				    
	// Load the OpenStreetMap map
	mapWidget->setMapThemeId("earth/plain/plain.dgml");
							 
	mapWidget->show();
								  
	return app.exec();
}

Save the code above as my_marble.cpp and compile it:

 g++ -I /usr/include/qt4/ -o my_marble my_marble.cpp -lmarblewidget -lQtGui

If things go fine, execute ./my_marble and you end up with a globe view similar to this:

As you can see, the blue line corresponds to the straight-no-tessellation way of visualization, the red one follows the great circles, and the green one sticks to the latitude circles, since the two endpoints have the same latitude.