Marble/Runners/DisplayGeoDataPlacemark: Difference between revisions

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


series=Marble C++ Tutorial|{{Template:I18n/Language Navigation Bar|Editing Projects/Marble/PaintingGeoDataLineString}}
{{TutorialBrowser|
{{TutorialBrowser|


Line 9: Line 6:
name=Search|
name=Search|


pre=[[Projects/Marble/Runners/PaintingGeoDataLineString|Tutorial 10 - Using the GeoPainter in order to paint GeoDataLineString objects]]|
pre=[[Projects/Marble/Runners/LoadingOSM|Tutorial 5 - Loading OSM files in MarbleWidget]]|


next=[[Projects/Marble/Runners/YetMissing|Tutorial 12 - Yet missing]]|
next=[[Projects/Marble/Runners/VehicleTracking|Tutorial 7 - Vehicle Tracking]]|
}}
}}




Now,  
In this tutorial we'll show how you can create a nice shiny '''placemark''' with an ''icon'' and associated '''geometries''' (such as ''LineStrings, LinearRings, Polygons or MultiGeometries''). We also cover basic '''styling''' of placemarks and geometries.


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.  
[https://developers.google.com/kml/documentation/kmlreference#placemark GeoDataPlacemark] is a class which implements the features of [https://developers.google.com/kml/documentation/kmlreference#placemark KML's Placemark]. Basically, it represents an interest point (a simple point or a more complex geometry) on the map, with some information attached.  


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.
In order to add a GeoDataPlacemark to our widget, we will use the [https://developers.google.com/kml/documentation/kmlreference#document GeoDataDocument] class, which is a container for [https://developers.google.com/kml/documentation/kmlreference#feature features] (including placemarks) and [https://developers.google.com/kml/documentation/kmlreference#feature styles]. To make the Document visible, we need to add it to Marble's TreeModel, as shown in the first example below:


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.


<source lang="cpp-qt">
#include <QtGui/QApplication>
#include <QtGui/QTreeView>
#include <QtCore/QDataStream>
#include <QtCore/QFile>
#include <QtCore/QIODevice>


<source lang="cpp">
#include <QtGui/QApplication>
#include <marble/MarbleWidget.h>
#include <marble/MarbleWidget.h>
#include <marble/GeoPainter.h>
#include <marble/GeoDataDocument.h>
#include <marble/GeoDataPlacemark.h>
#include <marble/GeoDataLineString.h>
#include <marble/GeoDataLineString.h>
#include <marble/GeoDataTreeModel.h>
#include <marble/MarbleModel.h>
#include <cstdio>
   
   
using namespace Marble;
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 );
GeoDataCoordinates Canada( -77.02, 48.52, 0.0, GeoDataCoordinates::Degree );
//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) {


Line 78: Line 43:
   
   
// Create a Marble QWidget without a parent
// Create a Marble QWidget without a parent
MarbleWidget *mapWidget = new MyMarbleWidget();
MarbleWidget *mapWidget = new MarbleWidget();
     
     
// Load the OpenStreetMap map
// Load the OpenStreetMap map
mapWidget->setMapThemeId("earth/openstreetmap/openstreetmap.dgml");
mapWidget->setMapThemeId("earth/plain/plain.dgml");
 
GeoDataPlacemark *place = new GeoDataPlacemark( "Bucharest" );
place->setCoordinate( 25.97, 44.43, 0.0, GeoDataCoordinates::Degree );
place->setPopulation( 1877155 );
place->setCountryCode ( "Romania" );
 
 
GeoDataDocument *document = new GeoDataDocument;
document->append( place );
 
// Add the document to MarbleWidget's tree model
mapWidget->model()->treeModel()->addDocument( document );
mapWidget->show();
mapWidget->show();
   
   
Line 89: Line 66:
</source>
</source>


Save the code above as <tt>my_marble.cpp</tt> and compile it:
Copy and paste the code above into a text editor. Then save it as <tt>my_marble.cpp</tt> and compile it by entering the following command on the command line:


<source lang="bash">
<source lang="bash">
  g++ -I /usr/include/qt4/ -o my_marble my_marble.cpp -lmarblewidget -lQtGui
  g++ -I /usr/include/qt4/ -o my_marble my_marble.cpp -lmarblewidget -lQtGui -lQtCore
</source>
</source>


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 are going to see the placemark of our newly created Bucharest point.


[[Image:GeoDataLineString_paint.png]]
[[Image:PlacemarkTask_bis.png]]


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.
The data we have set for our city (Population and Country) also appear, when clicking on the placemark.  


[[Image:PlacemarkTask2.png]]


name=Painting GeoDataLineString: Using the GeoPainter in order to paint a GeoDataLineString object|
As we said earlier in this tutorial, it is possible to add more complex geometry to a placemark, meaning objects belonging to [https://developers.google.com/kml/documentation/kmlreference#geometry GeoDataGeometry] or to one of the classes which inherit it.


pre=[[Projects/Marble/Runners/Parse|Tutorial 9 - Opening .kml, .gpx, ... files]]|
[https://developers.google.com/kml/documentation/kmlreference#style Styles] are another important property of placemarks. They are used in order to customize the appearance of the placemark on the map (e.g. by adding an icon). Geometries such as LineStrings, LinearRings or Polygons can be styled as well: You can change properties such as the pen color, the brush color and the line width.


next=[[Projects/Marble/Runners/YetMissing|Tutorial 11 - Yet missing]]|
The next example shows how more complex geometry and styles can be added, by creating Bucharest's city boundary, and by adding an interest point (touristic objective) with a photo replacing the regular  placemark icon. (in order for the example to work properly you will need to download the [http://techbase.kde.org/File:Bucharest_small.jpg icon] and place it in the same folder as the source code)
}}


<source lang="cpp-qt">
#include <QtGui/QApplication>
#include <QtGui/QTreeView>


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.  
#include <marble/MarbleWidget.h>
#include <marble/MarbleModel.h>


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.  
#include <marble/GeoDataDocument.h>
#include <marble/GeoDataCoordinates.h>
#include <marble/GeoDataPlacemark.h>
#include <marble/GeoDataLineString.h>
#include <marble/GeoDataLinearRing.h>
#include <marble/GeoDataTreeModel.h>
#include <marble/GeoDataStyle.h>
#include <marble/GeoDataIconStyle.h>
#include <marble/GeoDataLineStyle.h>
#include <marble/GeoDataPolyStyle.h>


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:
#include <cstdio>
 
* 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.
 
 
<source lang="cpp">
#include <QtGui/QApplication>
#include <marble/MarbleWidget.h>
#include <marble/GeoPainter.h>
#include <marble/GeoDataLineString.h>
   
   
using namespace Marble;
using namespace Marble;


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


void MyMarbleWidget::customPaint(GeoPainter* painter) {
linearRing << GeoDataCoordinates(25.97226722704463, 44.43497647488007, 0, GeoDataCoordinates::Degree )
GeoDataCoordinates France( 2.2, 48.52, 0.0, GeoDataCoordinates::Degree );
<< GeoDataCoordinates(26.04711276456992, 44.4420741223712, 0, GeoDataCoordinates::Degree )
GeoDataCoordinates Canada( -77.02, 48.52, 0.0, GeoDataCoordinates::Degree );
<< GeoDataCoordinates(25.99712510557899, 44.48015825036597, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(26.11268978668501, 44.53902366720936, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(26.12777496065434, 44.48972441010599, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(26.17769825773425, 44.47685689461117, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(26.16489863910029, 44.45366647920105, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(26.23394105442375, 44.43247765101769, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(26.23388161223319, 44.40720014793351, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(26.18689640043445, 44.40683215952335, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(26.1462530009004, 44.36252655873379, 0, GeoDataCoordinates::Degree )
<< GeoDataCoordinates(25.97226722704463, 44.43497647488007, 0, GeoDataCoordinates::Degree );


//A line from France to Canada without tessellation
}


GeoDataLineString shapeNoTessellation( NoTessellation );
void createStyleBucharest( GeoDataStyle &style ) {
shapeNoTessellation << France << Canada;
GeoDataLineStyle lineStyle( QColor( 255, 0, 0, 90 ) );
lineStyle.setWidth ( 8 );


painter->setPen( oxygenSkyBlue4 );
GeoDataPolyStyle polyStyle( QColor( 255, 0, 0, 40 ) );
painter->drawPolyline( shapeNoTessellation );
polyStyle.setFill( true );


//The same line, but with tessellation
style.setLineStyle( lineStyle );
style.setPolyStyle( polyStyle );
GeoDataLineString shapeTessellate( Tessellate );
}
shapeTessellate << France << Canada;


painter->setPen( oxygenBrickRed4 );
void createStyleArch( GeoDataStyle &style ) {
painter->drawPolyline( shapeTessellate );
GeoDataIconStyle iconStyle;
iconStyle.setIconPath( "bucharest_small.jpg" );
style.setIconStyle( iconStyle );
}


//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) {


Line 171: Line 147:
   
   
// Create a Marble QWidget without a parent
// Create a Marble QWidget without a parent
MarbleWidget *mapWidget = new MyMarbleWidget();
MarbleWidget *mapWidget = new MarbleWidget();
     
     
// Load the OpenStreetMap map
// Load the OpenStreetMap map
mapWidget->setMapThemeId("earth/openstreetmap/openstreetmap.dgml");
mapWidget->setMapThemeId("earth/openstreetmap/openstreetmap.dgml");
 
//Create the Linear Ring (polygon) representing Bucharest's boundaries and include it in a placemark
GeoDataLinearRing *Bucharest = new GeoDataLinearRing;
addPoints( *Bucharest );
 
GeoDataPlacemark *placemarkBucharest = new GeoDataPlacemark;
placemarkBucharest->setGeometry( Bucharest );
 
//Create the placemark representing the Arch of Triumph
GeoDataPlacemark *placemarkArch = new GeoDataPlacemark( "Arch of Triumph" );
placemarkArch->setCoordinate( 26.0783, 44.4671, 0, GeoDataCoordinates::Degree );
 
 
//Add styles (icons, colors, etc.) to the two placemarks
GeoDataStyle *styleBucharest = new GeoDataStyle;
        GeoDataStyle *styleArch = new GeoDataStyle;
 
createStyleBucharest( *styleBucharest );
placemarkBucharest->setStyle( styleBucharest );
 
createStyleArch ( *styleArch );
placemarkArch->setStyle( styleArch );
 
 
//Create the document and add the two placemarks (the point representing the Arch of Triumph and the polygon with Bucharest's boundaries)
GeoDataDocument *document = new GeoDataDocument;
document->append( placemarkBucharest );
document->append( placemarkArch );
 
// Add the document to MarbleWidget's tree model
mapWidget->model()->treeModel()->addDocument( document );
 
        // Center the map on Bucharest and set the zoom
mapWidget->centerOn( GeoDataCoordinates( 26.0783, 44.4671, 0, GeoDataCoordinates::Degree ) );
mapWidget->zoomView( 2400 );
 
mapWidget->show();
mapWidget->show();
   
   
Line 182: Line 194:
</source>
</source>


Save the code above as <tt>my_marble.cpp</tt> and compile it:
This is the expected outcome after compiling, running and zooming into Bucharest:  
 
<source lang="bash">
g++ -I /usr/include/qt4/ -o my_marble my_marble.cpp -lmarblewidget -lQtGui
</source>
 
If things go fine, execute <tt>./my_marble</tt> and you end up with a globe view similar to this:
 
[[Image:GeoDataLineString_paint.png]]


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.
[[Image:Bucharest.png]]

Latest revision as of 21:01, 10 March 2016

Search
Tutorial Series   Marble C++ Tutorial
Previous   Tutorial 5 - Loading OSM files in MarbleWidget
What's Next   Tutorial 7 - Vehicle Tracking
Further Reading   n/a


In this tutorial we'll show how you can create a nice shiny placemark with an icon and associated geometries (such as LineStrings, LinearRings, Polygons or MultiGeometries). We also cover basic styling of placemarks and geometries.

GeoDataPlacemark is a class which implements the features of KML's Placemark. Basically, it represents an interest point (a simple point or a more complex geometry) on the map, with some information attached.

In order to add a GeoDataPlacemark to our widget, we will use the GeoDataDocument class, which is a container for features (including placemarks) and styles. To make the Document visible, we need to add it to Marble's TreeModel, as shown in the first example below:


#include <QtGui/QApplication>
#include <QtGui/QTreeView>
#include <QtCore/QDataStream>
#include <QtCore/QFile>
#include <QtCore/QIODevice>

#include <marble/MarbleWidget.h>
#include <marble/GeoDataDocument.h>
#include <marble/GeoDataPlacemark.h>
#include <marble/GeoDataLineString.h>
#include <marble/GeoDataTreeModel.h>
#include <marble/MarbleModel.h>

#include <cstdio>
 
using namespace Marble;


int main(int argc, char** argv) {

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

	GeoDataPlacemark *place = new GeoDataPlacemark( "Bucharest" );
	place->setCoordinate( 25.97, 44.43, 0.0, GeoDataCoordinates::Degree );
	place->setPopulation( 1877155 );
	place->setCountryCode ( "Romania" );


	GeoDataDocument *document = new GeoDataDocument;
	document->append( place );

	// Add the document to MarbleWidget's tree model
	mapWidget->model()->treeModel()->addDocument( document );
	
	mapWidget->show();
								  
	return app.exec();
}

Copy and paste the code above into a text editor. Then save it as my_marble.cpp and compile it by entering the following command on the command line:

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

If things go fine, execute ./my_marble and you are going to see the placemark of our newly created Bucharest point.

The data we have set for our city (Population and Country) also appear, when clicking on the placemark.

As we said earlier in this tutorial, it is possible to add more complex geometry to a placemark, meaning objects belonging to GeoDataGeometry or to one of the classes which inherit it.

Styles are another important property of placemarks. They are used in order to customize the appearance of the placemark on the map (e.g. by adding an icon). Geometries such as LineStrings, LinearRings or Polygons can be styled as well: You can change properties such as the pen color, the brush color and the line width.

The next example shows how more complex geometry and styles can be added, by creating Bucharest's city boundary, and by adding an interest point (touristic objective) with a photo replacing the regular placemark icon. (in order for the example to work properly you will need to download the icon and place it in the same folder as the source code)

#include <QtGui/QApplication>
#include <QtGui/QTreeView>

#include <marble/MarbleWidget.h>
#include <marble/MarbleModel.h>

#include <marble/GeoDataDocument.h>
#include <marble/GeoDataCoordinates.h>
#include <marble/GeoDataPlacemark.h>
#include <marble/GeoDataLineString.h>
#include <marble/GeoDataLinearRing.h>
#include <marble/GeoDataTreeModel.h>
#include <marble/GeoDataStyle.h>
#include <marble/GeoDataIconStyle.h>
#include <marble/GeoDataLineStyle.h>
#include <marble/GeoDataPolyStyle.h>

#include <cstdio>
 
using namespace Marble;

void addPoints( GeoDataLinearRing &linearRing ) {

	linearRing << GeoDataCoordinates(25.97226722704463, 44.43497647488007, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.04711276456992, 44.4420741223712, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(25.99712510557899, 44.48015825036597, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.11268978668501, 44.53902366720936, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.12777496065434, 44.48972441010599, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.17769825773425, 44.47685689461117, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.16489863910029, 44.45366647920105, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.23394105442375, 44.43247765101769, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.23388161223319, 44.40720014793351, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.18689640043445, 44.40683215952335, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(26.1462530009004, 44.36252655873379, 0, GeoDataCoordinates::Degree )
					<< GeoDataCoordinates(25.97226722704463, 44.43497647488007, 0, GeoDataCoordinates::Degree );

}

void createStyleBucharest( GeoDataStyle &style ) {
	GeoDataLineStyle lineStyle( QColor( 255, 0, 0, 90 ) );
	lineStyle.setWidth ( 8 );

	GeoDataPolyStyle polyStyle( QColor( 255, 0, 0, 40 ) );
	polyStyle.setFill( true );

	style.setLineStyle( lineStyle );
	style.setPolyStyle( polyStyle );
}

void createStyleArch( GeoDataStyle &style ) {
	GeoDataIconStyle iconStyle;
	iconStyle.setIconPath( "bucharest_small.jpg" );
	style.setIconStyle( iconStyle );
}

int main(int argc, char** argv) {

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

	//Create the Linear Ring (polygon) representing Bucharest's boundaries and include it in a placemark
	GeoDataLinearRing *Bucharest = new GeoDataLinearRing;
	addPoints( *Bucharest );

	GeoDataPlacemark *placemarkBucharest = new GeoDataPlacemark;
	placemarkBucharest->setGeometry( Bucharest );

	//Create the placemark representing the Arch of Triumph
	GeoDataPlacemark *placemarkArch = new GeoDataPlacemark( "Arch of Triumph" );
	placemarkArch->setCoordinate( 26.0783, 44.4671, 0, GeoDataCoordinates::Degree );


	//Add styles (icons, colors, etc.) to the two placemarks
	GeoDataStyle *styleBucharest = new GeoDataStyle;
        GeoDataStyle *styleArch = new GeoDataStyle;

	createStyleBucharest( *styleBucharest );
	placemarkBucharest->setStyle( styleBucharest );

	createStyleArch ( *styleArch );
	placemarkArch->setStyle( styleArch );


	//Create the document and add the two placemarks (the point representing the Arch of Triumph and the polygon with Bucharest's boundaries)
	GeoDataDocument *document = new GeoDataDocument;
	document->append( placemarkBucharest );
	document->append( placemarkArch );

	// Add the document to MarbleWidget's tree model
	mapWidget->model()->treeModel()->addDocument( document );

        // Center the map on Bucharest and set the zoom 
	mapWidget->centerOn( GeoDataCoordinates( 26.0783, 44.4671, 0, GeoDataCoordinates::Degree ) );
	mapWidget->zoomView( 2400 );

	
	mapWidget->show();
								  
	return app.exec();
}

This is the expected outcome after compiling, running and zooming into Bucharest: