Frequently Asked Questions

This is an excerpt from the Carmenta Engine SDK documentation. If you find it interesting, we encourage you to request a Carmenta Engine evaluation to access the rest of the documentation.

Navigating the map

How do I let my users pan and zoom the map?

The easiest way is to activate the StandardTool on the MapControl, it has panning and zooming built-in. It is the interaction tool that is used in Carmenta Explorer for navigation. Another common technique to do zooming is to have two buttons in the user interface, zoom in and zoom out, that when clicked will double the current View.NominalScale to zoom out or halve it to zoom in. After setting the nominal scale you also need to update the view (to repaint the map).

How do I center the map on a specific location?

To re-center the map, all you have to do is to set the property center on the View object to a new point. And then update the view (to repaint the map).

The view is the root node in your map configuration that you have created in Carmenta Studio. If you are using the MapControl, you can get a reference to the view by calling MapControl.View. So setting a new center on the view would then be (C#):

 

The unit for the X and Y depends on which Crs (Coordinate Reference System) that is currently set on the View. For example, if the View Crs is Wgs84LongLat, then X is longitude and Y is latitude in degrees, but if the View Crs uses a UTM projection, then X is easting and Y is northing in meters.

If your point is not in the same Crs as the View, you can re-project the coordinates from one Crs to another using the Crs.ProjectTo method.

Making Map Configurations

Can I avoid hard-coded paths and use relative paths inside map configurations files?

Setting relative paths is one of the best ways of preparing for good and easy deployment, i.e. “copying map configuration and data to a different location without changing anything”.

Relative paths inside a map configuration file are relative to the location of the map configuration file (.px).

For example:

To access files in “c:\maps\geodata\images” from inside “c:\maps\mymapconfig.px”, you could simply set path properties to “.\geodata\images”. This works for all types of paths: geodata, symbols and other resources.

By the way, in Carmenta Studio, if you write the path directly into the right hand column of the object editor, do not write the quote marks:

How can I handle the same value on multiple objects in Carmenta Studio, for instance, having a common root path for DataSets?

There are some utility objects in Carmenta Studio that can be used to encapsulate strings and paths (and other types). That way you can refer to the same object from multiple objects, and if you need to change the path you only have to change the value at one place. You find these objects in Carmenta Studio Classes → Utility.

I have set up a geodata root path in the Windows Registry, can I set up my map configuration to use it?

Yes, there are utility objects in Carmenta Studio that is available for reading string values from Registry or Environment variables. This way your users or your installation programs can set registry or environment variables that defines where they have put their data. You find these objects in Carmenta Studio Classes → Utility (EnvironmentVariable and RegistryValue).

Application data

This section addresses some of the most common questions regarding how to display your own, usually dynamic, data on the map. We refer to this kind of data as application data or application objects.

How do I display my own objects on the map?

The most common way to display your own data on the map is by adding a new Layer that is drawn on top of the background layers. You can either add this to your map configuration file (.px) using Carmenta Studio, or use the API to construct the layer programmatically at runtime. This layer typically has a VisualizationOperator with one or more Visualizer objects with the visualization parameters that you need. The layer should also contain a ReadOperator with a MemoryDataSet attached to it.

Next, in your application code, create Feature objects that represent your application data and insert them into the MemoryDataSet in the layer. On the next map window update, the features should appear on top of the map.

Another way of displaying your application data on top of the map is to draw the data in the View.CustomDraw event on the View using the drawing methods on Drawable. Use the View.crsToPixel() method to convert View.Crs coordinates to pixel coordinates.

Can my objects have different colors, symbols etc?

In order to differentiate between different application objects in the map, the features must be given attributes which make them distinguishable from each other. These attributes can be referenced by visualizers, whose color, font or symbol can be an attribute variable that depend on an attribute of the feature. (In Carmenta Studio, attribute variables are known as maps, like ColorMap, FontMap and SymbolMap). Attributes can also be used for filtering, perhaps with the goal of hiding certain objects at certain scale levels, or to filter different object groups into different layers.

How can I test new visualization settings, without restarting my application?

It is often useful to test the visualization using Carmenta Explorer. This can be accomplished by creating the layer and operator structure as defined above to the .px-file and at the same time adding some Features (that is typical for your data) to the MemoryDataSet using Carmenta Studio. This usually saves a lot of development time, since starting Carmenta Explorer is usually faster than starting the real application.

How do I move objects on the map using the API?

To move an application object Feature on the map using the API, you simply change its coordinates. The next time the map window is re-painted the object will move to the new location. The coordinates are found in the Geometry of the Feature. The Geometry.Move method may also be used to move a Feature.

How do I let my users interact with my objects on the map using the mouse?

Activate the StandardTool on your MapControl. The StandardTool can select and edit objects. If you want to know when an object is selected or have been edited you can use the events on the StandardTool and MemoryDataSet. Make sure that the layer containing the objects and all its parent layers are selectable (have their selectable property set to true).

How do I let my users draw objects like symbols, lines and polygons using the mouse?

Activate the CreateTool on your MapControl. The CreateTool can draw points, lines and polygon Features as well as advanced tactical graphics.

How do I get to a specific Feature?

When you create a Feature and put it into a DataSet you will get an unique id. If you want to get to the feature later, you can ask the dataset for it using the id. Or, more efficiently, you can keep an object reference in a variable that refers to created Feature, and then later use the variable to access the Feature.

How do I dynamically change the appearance of an object, for instance rotating it in the direction of travel?

To rotate the text or symbol or 3D model that is displayed for a feature, add a numeric attribute to the feature that defines its rotation (in degrees), and make the PointVisualizer.Rotation property be an IndirectAttributeVariable whose key is the attribute name.

How do I update a text label for an application object?

To update a text label for a feature, for instance a position string, ensure that the TextVisualizer.Text is an IndirectAttributeVariable whose key is the name of a text attribute of the features. Then you only need to change the value of the attribute between updates, and the label will update accordingly.

How can I place labels?

A text label can be aligned in various ways; see AlignX and AlignY. It is also possible to add some additional offsets; see PointVisualizer.OffsetX and PointVisualizer.OffsetY.

To make a street name follow a curved street, use TextVisualizer.FollowLine = True.

You can find examples in the configuration sample text_visualization.px.

A label containing a two-column table is slightly more complex.

We want the left hand column to be left-aligned, but the right hand column to be right-aligned since it contains numbers. See PointVisualizerSet to learn how this table was created. (A similar example can be found in the configuration sample point_visualizer_set.px.)

How do I display tactical symbology?

Carmenta Engine Tactical Extension provides support for adding MIL-STD-2525 symbology to your application. By adding a TacticalVisualizer to your configuration and assigning a MilStd2525BParameters to this visualizer, Feature objects will be visualized as warfighting symbology according to its specified attributes (refer to MilStd2525BAttributes for a list of these attributes). The Feature objects are most commonly held by a MemoryDataSet. See Tactical Extension in Carmenta Engine SDK Documentation for more detail.

Can the visualization depend on user manipulation?

It is easy to display selected features in a special way: you construct the special visualizers and insert them into the VisualizationOperator.SelectionVisualizers.

For a feature that is not selected, but over which the cursor hovers, there is no built-in way to use special hovering visualizers. But if you use the StandardTool, you can let StandardTool.HotTrackingEnabled = True, which will replace the default Cursor by the SelectFeature variant when the cursor hovers over a selectable feature.

Can I change the visualization per feature?

The color of a feature visualization can be dynamic depending on the feature attributes. It is possible to set a text representation of a color, see Encoding Colors in Strings in Carmenta Engine SDK Documentation, as a feature attribute and have the Visualizer use a specific color for each feature that is drawn on the map. Different colors can also be used for visualization depending on other feature attributes. A line describing a road can have a different color depending on the type of the road. In this case a KeyedAttributeTable should be used, where the type attribute of the road should correspond to a specific color.

Can I change the visualization globally?

Update attributes can be set on each View. The update attributes will be available for all operators and layers below the view during a map update. They can be used to affect the global visualization in a view, for example by turning on and off layers and operators, or to change the color or transparency of all or a group of layers. If you have CustomOperators doing demanding calculations, you can use update attributes to only do the calculations when needed.

There is a number of predefined update attributes. The quickUpdate attribute is used to disable specific layers during a series of updates that needs to be quick, for example during panning or zooming of the map and is used by the StandardTool.

Can I modify the configuration in runtime?

During the applications lifetime, you often want to change what is displayed in the map. This can be done in several ways, for example by:

  • Enabling and disabling individual layers
  • Adding additional background maps or changing the background map
  • Adding or removing layers with application data

Can I enable and disable layers during runtime?

All layers have an enabled property that tells whether the layer will be drawn when the map is updated. The preferred way to turn a layer on or off during runtime is to change this property, for example through a layer control.

The layer properties MinScale, MaxScale and Condition are also used to determine if the layer will be drawn in the map.

Can I add and remove layers during runtime?

It is possible to add new layers to the View after the configuration has already been loaded. To do this, you can either load a Configuration file that contains a public Layer or create a layer chain in code and then attach it to the View or a LayerSet beneath the view.

The layer can for example contain a ReadOperator with application objects generated in runtime in a MemoryDataSet, or a new raster background map.

Layers can also be removed from the view by removing them from their parent’s View.Layers or LayerSet.Layers collection.

Can I save the configuration in runtime?

The Configuration class have methods to save parts of a configuration to a Carmenta Engine configuration XML string or file. This can be used to save a configuration that has been built or modified in runtime, with the current layers and settings of the configuration.

The SaveMode enumeration can be used to even save point, line and polygon features in all MemoryDataSets. This can be used to save the state of the application for debug purposes, or for having test features to use when configuring the feature visualization in Carmenta Studio.

Background map layers

This section is about the static data and maps that is background for your application features.

How do I improve the performance of background layers in my map?

First we recommend that you test the map configuration in Carmenta Explorer and use the built-in profiler to see where the actual bottle necks are. From the Profiler results you can see which layers that are causing the problems and which processing parts of these layers that you should focus your optimization attempts on.

It could be that the map simply tries to display too much data at the same time. If so, you need to apply some filtering techniques in your map configuration file.You need to apply some filtering techniques in your map configuration file. One base technique is to turn off a layer when you are zooming out by using the Layer.MaxScale functionality. You could also try to apply on-the-fly line thinning using the LineThinningOperator if the data are lines or polygons.

It could also be that the data is read from a slow format (text based formats are usually quite slow) or that there are too many features per data file.

If the data is slow to read from disk one solution might be to turn on Feature Index on the DataSet if it is available for that dataset (it is available for ShapefileDataSet for instance). You turn the feature index on by setting the FeatureIndexPath property to a valid path. Turning on the index will generate index files the next time the map configuration is loaded.

Have you put your layers into a TileLayer so that the data is loaded asynchronously and is cached on the graphics card?

Another variant using the TileLayer is to turn on the built-in bitmap file cache feature in TileLayer to store the tiles as image files on disk. This is a brute-force approach that works with all kind of high density data, since when the tile has been processed once, the next times it will only be handled as a simple image.

If the layer contains raster data, perhaps the poor performance is because you are forcing a re-projection (warping) of the raster data. To avoid re-projection of raster data, try to have the same Crs (coordinate reference system) on the View as on the data. If you do not know the Crs of the data you can use a SpyOperator to save information about the data to a text file.

 

Another common reason for poor performance when handling raster data is that the data is read in its original resolution for all map scales. For instance, GdalDataSet supports generation of low resolution variants of the data, called overviews, that will automatically be read when zoomed out.

How can I dim the background?

The background layers should usually be shown with dim colors, so that your application features stand out. The easiest way to dim the background layers is to lower their Layer.Opacity.

Tip
In Carmenta Explorer, you can directly modify a layer opacity. Select a layer in the layer tree, and choose Tools → Color control…

See also the Raster Data Guide in Carmenta Engine SDK Documentation.

Raster background

Background maps are often in the form of raster maps, since these can be displayed efficiently. Raster maps can be classified into

  • Image rasters (which consist of colors), and
  • Data rasters (which consist of numbers).

The numbers in a data raster may represent a physical quantity like elevation, or may represent thematic categories like WATER, FOREST, CITY, … Carmenta Engine can interpolate between colors and between true numbers, but it makes no sense to interpolate between discrete integers that represent WATER or FOREST. To signal that interpolation is allowed, the continuous property – available on some datasets – should be True.

Raster data

How can I avoid poor display of images when zooming out in a raster map?

Use a bicubic filter via the VisualizationOperator, see Raster Data Guide in Carmenta Engine SDK Documentation for more information.

How can I visualize numeric data rasters, such as elevation models?

Carmenta Engine provides several options for you, for example ShadeOperator or IsolineOperator. See the Raster Data Guide in Carmenta Engine SDK Documentation for more information.

The configuration sample topographic_map.px should also be helpful.

How can I avoid poor performance when zooming out in a raster map?

Use overviews; see the Raster Data Guide in Carmenta Engine SDK Documentation for more details.

Vector data

How do I use vector data efficiently?

See the Vector Data Guide in Carmenta Engine SDK Documentation.

Coordinates

How can I parse and format latitude and longitude?

There are many different format conventions for latitude and longitude.

Position of Carmenta headquarters, in various latitude/longitude formats (using Wgs84).

There are more variants than we can support, so it is your own responsibility to handle the concrete syntax in your application. But Carmenta Engine has some auxiliary methods that can help you with the abstract syntax; the methods convert between degrees (as numbers) and multi-string representations of either degrees/minutes/hemisphere or degrees/minutes/seconds/hemisphere, with English abbreviations for the hemispheres (N, S, W, E). Then, you can write your own application code to print and parse the separators you want. See Crs.ParseLatitude, Crs.ParseLongitude, Crs.FormatLatitudeAsDegreesMinutes, Crs.FormatLatitudeAsDegreesMinutesSeconds, Crs.FormatLongitudeAsDegreesMinutes and Crs.FormatLongitudeAsDegreesMinutesSeconds. There is a sample application that uses these methods, see Height Calculator in Carmenta Engine SDK Documentation.

The GridGenerator can display the latitudes and longitudes of a graticule in a few standard formats.

How can I parse and format MGRS (Military Grid Reference System)?

For MGRS, the alphanumeric way to write UTM and UPS coordinates, you can use the methods Crs.ParseMgrs and Crs.FormatMgrs. Also, the UtmGridGenerator can annotate a UTM grid in the MGRS style.

How can I parse and format UTM (Universal Transverse Mercator)?

There are various ways to write UTM coordinates. Proper UTM notation is right-handed: the easting is written before the northing.

There are various ways to write UTM coordinates. Proper UTM notation is right-handed: the easting is written before the northing.

Caution
Be careful in Europe. The coordinate reference systems “ETRS89 / TM26” to “ETRS89 / TM39” (EPSG codes 3038 to 3051) may appear to use the UTM zones 26N to 39N, but they are left-handed: the northing is written before the easting. To get proper right-handed UTM based on ETRS89, use the coordinate reference systems “ETRS89 / UTM zone 28N” to “ETRS89 / UTM zone 38N” (EPSG codes 25828 to 25838).

If there are no decimals, the easting will have six digits and the northing seven. (The northing will be less than 1 000 000 meters between latitudes 0° and about 9°N, but is then often written with leading zeros.)

In addition to easting and northing, you need to specify UTM zone number and either hemisphere (North/South) or latitude band letter (C to X, exluding I and O). These can be written either before or after the easting and northing.

In addition to easting and northing, you need to specify UTM zone number and either hemisphere (North/South) or latitude band letter (C to X, exluding I and O). These can be written either before or after the easting and northing.

Position of Carmenta headquarters, in various UTM formats (based on Wgs84).

Without a hemisphere (or latitude band letter), a UTM position is ambiguous, since the same range of northings are used on the north and the south hemisphere. It is sometimes assumed that the hemisphere is clear from context, since the two possible interpretations would be 10 000 km apart, but in these days of global operations, it is a risky assumption.

The latitude band letter, which is sometimes given instead of hemisphere, is not part of pure UTM, but comes from the MGRS in Carmenta Engine SDK Documentation notation (which is an alphanumeric way to write UTM and UPS positions). Each letter (except X) denotes an 8-degree latitude band, so C denotes the band 80°S to 72°S, and D denotes the band 72°S to 64°S, and so on, skipping I and O, until X denotes the 12-degree band 72°N to 84°N.

Sometimes, the hemispheres are abbreviated to N and S. The N cannot be misunderstood, since latitude band N happens to be on the north hemisphere, but the hemisphere S can be misunderstood as the latitude band S, which is also on the north hemisphere. For this reason, it is better to spell out the full North or South(but there is no international standard).

So, how can Carmenta Engine help you with parsing and formatting?

To parse UTM, your application must find out the zone, hemisphere, easting and northing. If there is a latitude band letter instead of a hemisphere symbol, remember that N is the first band letter for the north hemisphere, so band letters before N in the alphabet means the south hemisphere. (If you are ambitious, your application could check that the latitude band letter is consistent with the UTM easting and northing.) To create a point Feature, you first create a PointGeometry whose point coordinates are the easting and northing. The PointGeometry is then used for the point feature, whose Crs can be constructed directly by the static method Crs.Wgs84Utm(zone, hemisphere), assuming that the GeodeticDatum used for the UTM notation is Wgs84. Otherwise, first use the static method Projection.Utm(zone, hemisphere), to get the Utm projection, and then combine it with the geodetic datum of your choice, to get a new Crs (use the constructor Crs(projection, datum)). This point feature can then be reprojected to another coordinate reference system like Wgs84LongLat.

To print a point Feature as UTM, let us assume that you want to use Wgs84 as the datum for the UTM notation (this makes things simpler). If you know that the Crs of the point feature is already based on Wgs84 and a UtmProjection, and that the point is inside the zone limits, then printing is easy: the easting and northing are the point coordinates of the PointGeometry of the feature, and you can get the UTM zone and hemisphere from the UtmProjection. Otherwise, you can first reproject the point feature to Wgs84LongLat. Let w be the point of the PointGeometry expressed in Wgs84LongLat, and use the static method Crs.FromUtmProjectionForPoint(w) to get a Crs (call it Wgs84UtmXXX) that is based on Wgs84 and the UtmProjection whose zone contains w. Reproject w to Wgs84UtmXXX, and then extract the UTM easting and northing from the reprojected PointGeometry. To find out the zone and the hemisphere, get the projection of Wgs84UtmXXX, and cast it to the UtmProjection class. You can then get the zone and the hemisphere from the UtmProjection.

Caution
If the latitude of w is south of 80°S or north of 84°N, then the projection will be a UPS projection instead, so casting to the UtmProjection class will fail.

If you want to print the latitude band letter instead of the hemisphere, the letter is easiest to find by callingCrs.FormatMgrs(geodeticDatum, MgrsLetteringScheme.MgrsNew, False, -2, w). The -2 means that you will only get the UTM zone and the latitude band letter.

How can I transform coordinates between different coordinate systems?

See Coordinate Systems in Carmenta Engine SDK Documentation.

What are the units of numbers?

The unit of a numeric property or parameter should be given in its documentation. There are some general principles for angles and lengths, though:

Angle units

For geographers, angles are usually in degrees, and if it is a direction from a point, the angle usually goes clockwise starting from north (or grid north). Most of the angles in Carmenta Engine should be expressed in the geographer’s convention. But there are some low-level properties and parameters that should be expressed in the mathematician’s convention: radians counterclockwise (and zero direction rightward). Furthermore, the angles in a HelmertDatumShift or a LongLatOffsetDatumShiftmust be expressed in arc seconds. There is a class AngleUnit that allows you to define your own angle unit, like arc minute or milliradian, but such a unit can be used only by the EquidistantCylindricalAngularProjection.

Length units

In Carmenta Engine, lengths are usually given in screen pixels, in meters, or in some Crs unit that could be meter or foot etc. but also degree if the Crs uses LongLat. Sometimes, only one choice is possible:

  • A Drawable is attached to a View that has a Crs, but the drawable itself is not aware of the Crs and knows only about pixels, so the length parameters of drawable methods are in pixels.
  • In a similar way, an instance of Geometry is usually attached to a Feature that has a Crs, but the geometry itself is not aware of the Crs, so length parameters to geometry methods must be expressed in the length unit of the feature Crs. The geometry does not know what the length unit is, but the application programmer can get it by calling feature.Crs.getLengthUnit(), and can then convert to or from meters via the FromMeter(d) and ToMeter(d) methods.
  • Lengths that has to do with 3D visualization, for example the various horizon properties of View3D and TileLayer3D, should be given in meters. (This is because in 3D, the vertical unit used for the elevation data should also be used as the horizontal unit of the Crs of the View3D, and as the unit for horizon properties etc. And the vertical unit for elevation data is nearly always meters.)
  • Some lengths (for example RasterizeOperator.CellWidth or FeatureQuery.Resolution) must be expressed in the unit of some particular Crs, usually one that appears somewhere near the number (in the configuration file or in the application code). But usually, a length must be expressed in meters.

However, more choices are possible in a Visualizer; it has a LengthUnit property containing a value from the VisualizerLengthUnit enumeration, that controls whether other visualizer properties are in screen pixels, meters, or the unit of the View.Crs.

There is also another class, LengthUnit, that allows you to define ordinary units like meter, foot, or yard, but not screen pixels. This class can be used when defining a map Projection, and it can also be used by some operators, likeEllipseOperator andBufferZoneOperator.

More generally, the UnitConversionOperator can be used to convert attributes of features from one unit to another. It can also convert angles between true north and grid north, or between meters and the length unit of the View.Crs.

Miscellaneous

When should I have my data in a TileLayer, and when should I have them in a layer directly in the view?

For layers that handle dynamic data (editable objects or objects that are moving), it is usually better to have them placed outside any presentation-caching layers like TileLayer or BitmapLayer, i.e. directly in the view.

Layers that handle static objects usually work better in a TileLayer or a BitmapLayer.

If you put dynamic data in a TileLayer you must call Layer.FlushCache every time you have added or changed the data inside it to force a re-read of data in the TileLayer cache.

How do I build a layer control?

It is common in map applications to display a layer control so that the user can turn on and off different layers in the map.

To extract all the layers that should be displayed in a layer control, it is possible to find all layers in the View by iterating over the View.Layers collection. The collection contains the layers that are inserted directly below the view. To get all layers that are shown in the map you need to iterate over the children of these layers too. All layers that can contain sub layers can be cast to a LayerSet.

If you have a check box beside the layers describing if they are enabled or not, its value should be collected from the Layer.Enabled property. If the Layer.Enabled property changes, the Layer.EnabledChanged event is emitted, which the layer control should listen to so that the state of the check boxes can be updated.

It is not always the case that you want to display all layers in the layer control. If a LayerSet contains several sublayers to describe the same type of feature it might be enough to only display the LayerSet in the layer control. One way around this is to set a property in the IUserProperties.UserProperties that describes whether the layer should be displayed in the layer control or not.

How do I draw a transparent interface on top of a map? (C++ with Qt)

Normally Carmenta Engine instantiates its own OpenGL context for a Drawable with Renderer.OpenGL, which can make it hard to draw additional information on top of the map window. The ExternalDrawable can be used to give Qt control of the OpenGL context.

In order set up the use of an ExternalDrawable, do the following:

  1. Create a class that inherits from QGraphicsView and MapControl. This class will draw both your overlay Qt interface and the map.
  2. Call the setViewport function with a QGLWidget.
  3. Use the OpenGL context and drawable of the QGLWidget to replace the Drawable of your View with an ExternalDrawable. The ExternalDrawable class enables Carmenta Engine to draw the map on an OpenGL context set up externally.

The constructor of your class should now look approximately like this:

You also have to make sure that the QGraphicsView is updated when the map is redrawn. This can be done by subclassing QGraphicsScene and use its scene in your QMapGraphicsView. Call View.ExternalUpdate in its drawBackground function.

This is all that is needed! You can now use standard Qt functionality to draw on top of your map.

An example of a map overlay using Qt QML.