Developer’s Guide
1. Introduction
1.1. About LuciadMobile
LuciadMobile is an easy-to-use, object-oriented API designed to build geographical data visualization applications, targeted at mobile devices running the Android operating system. LuciadMobile’s component architecture is based on the Model-View-Controller (MVC) design pattern. LuciadMobile provides application developers with a set of components that they can use and customize to their own needs.
1.1.1. LuciadMobile documentation
The following documentation is available in the LuciadMobile installation directory:
-
API reference provides detailed descriptions of each package and its interfaces and classes. Some descriptions are illustrated with graphics and code snippets.
-
Developer’s guide is the document you are reading now. It provides a high-level overview of the LuciadMobile components and describes how to build application components using the components. Most of the descriptions are illustrated with graphics and code snippets.
-
Samples are small applications that illustrate the functionality of (parts of) the LuciadMobile API.
-
Release notes list the enhancements, bug fixes, and upgrade considerations for the current and previous release versions of LuciadMobile.
1.2. About this guide
The purpose of this guide is to introduce LuciadMobile and to provide developers with a set of guidelines for building applications with LuciadMobile. This guide is for developers who are familiar with programming in Java and who preferably have some knowledge of the Android platform. References to general Java and Android concepts are used throughout this guide without further explanation. Although no specific knowledge of working with geographical data is required, it is useful for developers to have a good understanding of the requirements of the application that they want to build with LuciadMobile.
This guide describes the tasks that are required for building an application with LuciadMobile. It does not list all interfaces and classes of LuciadMobile and it does not contain detailed package and class descriptions. A complete overview of the LuciadMobile API and additional information about the usage of interfaces and classes is available in the API reference. For an overview of all LuciadMobile documentation, refer to Section 1.1.1, “LuciadMobile documentation”.
1.2.1. Main sections
The main sections in this guide are:
-
Part I: The LuciadMobile API explains the various aspects of LuciadMobile, including how to create map views and add data to them, how to let users interact with the map, and how to customize various parts of LuciadMobile.
-
Part II: Advanced topics goes into detail about more complex subject matters such as LuciadMobile 's unified methods for accessing domain objects, the visualization of symbology sets, and geographic reference systems.
-
Part III: Appendices covers a range of topics such as the LuciadMobile vector and raster database formats.
1.2.2. Conventions
This section describes the typographical conventions that are used in this guide and the naming conventions that are used in LuciadMobile and in this guide.
Typographical conventions
This guide uses the following typographical conventions:
-
Bold text is used to highlight a term. Note that when a term is used multiple times in a paragraph, only the first occurrence of the term is bold. Bold text is also used for names of GUI elements.
-
Italic text is used to quote text or to refer to a document or sample.
-
Typewriter
text is used for API elements such as names of interfaces, classes, and methods, and for file names and extensions.
Information paragraphs contain important information or useful tips. |
Naming conventions
LuciadMobile uses the following naming conventions:
-
Names starting with:
-
ILcd are interfaces
-
ALcd are abstract classes
-
TLcd are concrete classes
-
ELcd are enumerations
-
-
Names outside LuciadMobile (for example names of sample classes) never start with ILcd, ALcd, TLcd, or ELcd.
-
Names of Java packages have the following format:
com.luciad.*
, for instancecom.luciad.model
.
This guide refers to interfaces and classes using their complete name. To enhance readability however, the following shorthand references are used:
-
The word type refers to interfaces or their extensions. For instance, the type ILcdModel refers to the interface
ILcdModel
or extensions of it. -
The name of the class refers to an instance of that class. For instance, a TLcdFeatureLayer means an instance of the class
TLcdFeatureLayer
. In plural this guide uses: TLcdFeatureLayer objects. -
The name of the interface refers to an instance of a class as an implementation of that interface. For example, an ILcdPoint means an instance of a class that implements the interface
ILcdPoint
. In plural this guide uses: ILcdPoint objects. -
To refer to a class or interface itself, the class or interface is explicitly mentioned. For example, the class TLcdDrawableProvider implements the interface ILcdDrawableProvider.
1.3. Contact information
If you have any questions after reading this guide you can contact the Hexagon Support Desk services by mailing to support.luciad.gsp@hexagon.com or dialing +32 (0)16 26 28 30.
The LuciadMobile API
2. Getting Started
2.1. Prerequisites
Before beginning development with LuciadMobile, you should make sure that you have access to the following resources:
-
The Google Android Software Development Kit (SDK) version 5.0 or higher. The SDK can be downloaded as a part of Android Studio, the official integrated development environment (IDE) for Android. You can download it from http://developer.android.com/.
-
An Android 5.0 (or higher) compatible device for testing, or an equivalent Android virtual device, also referred to as an Android emulator.
2.2. LuciadMobile packaging structure
The LuciadMobile distribution contains the following files:
-
LuciadMobile_Pro.zip
contains everything you need to get started with the creation of an application with LuciadMobile. It includes the LuciadMobile library packaged as Android Archive (aar), a sample project you can open in Android Studio, and a small server that works with the COP sample. -
LuciadMobile_Pro_Samples.apk
contains a precompiled version of the sample code that can be installed directly onto an Android device -
LuciadMobile_Pro_Documentation.zip
contains the documentation (developer guide and Javadoc) for LuciadMobile . -
LuciadMobile_Pro_Data.zip
contains the data needed for running the samples.
2.3. Installing, compiling and running the samples
2.3.1. Creating a development project containing the LuciadMobile samples
-
Unzip
LuciadMobile_Pro.zip
. ALuciadMobile_x.x.x
directory is automatically created for you. -
Unzip
LuciadMobile_Pro_Documentation.zip
andLuciadMobile_Pro_Data.zip
. If your ZIP program creates an additionalLuciadMobile_x.x.x 2
directory, manually copy the contents in this directory into theLuciadMobile_x.x.x
directory. -
Copy the developer license file (
luciadmobile_development.txt
) to theLuciadMobile_x.x.x/samples/assets
folder. -
Start Android Studio and open the build.gradle file inside the
LuciadMobile_x.x.x/samples
folder. Depending on the gradle and android build tools you are using you might have to make adjustments to the gradle file.
To find out how to install the Android Studio SDK or how to set up emulators, consult the Android developer documentation at http://developer.android.com. |
2.3.2. Installing the precompiled samples on a device
To manage files and folders on Android devices, you can use the ADB tool that comes with the Android SDK. For more information about the ADB tool and the available |
LuciadMobile comes with a set of precompiled samples that you can try out on your Android device.
Before you can run the LuciadMobile samples, you need to install LuciadMobile_Pro_Samples.apk
on the device. To do so, use the adb install command. With the command, you must
specify the path to the .apk file that you want to install:
adb install <path_to_apk>
After installing the APK file, copy your license file luciadmobile_development.txt
to the /sdcard/MapData
folder on your device. See Section 2.3.3, “Copying the sample data on a device” for more information about the contents and usage of the MapData
folder.
To copy a file or directory (recursively) to the emulator or device, use:
adb push <local> <remote>
2.3.3. Copying the sample data on a device
LuciadMobile provides sample map data, which can be found
in LuciadMobile_x.x.x/samples/MapData
. The data in this directory is used by various samples.
To copy the MapData
folder to the external storage directory of the Android device or the emulator, mount the device as a disk drive, or use adb
.
3. LuciadMobile architecture
3.1. The Model-View-Controller architecture
LuciadMobile is based on the Model-View-Controller (MVC) architecture. The underlying concept of the MVC architecture is to separate the data (model), representation of the data (view), and the user interaction (controller) from each other. This separation results in a simpler design of the application and a higher flexibility and reusability of code.
The MVC parts of the LuciadMobile API are defined as follows:
-
A LuciadMobile model stores and describes geographical data irrespective of how to visualize and interact with the data. For example, a model contains the location of a number of hospitals together with additional information such as capacity.
-
A LuciadMobile view contains all information for the representation of data contained in LuciadMobile models. A view does not contain data itself. For example, in the case of the hospitals, a view represents the location of a hospital with a red cross.
-
A LuciadMobile controller interprets user interaction and performs the required action on LuciadMobile models and views irrespective of the type of model and view. For example, in the case of the hospitals, tapping on a red cross pops up information such as location and capacity.
Separating the different parts of the application allows you to reuse objects for different purposes and redefine objects without changing other objects. You can, for example, change a view without making changes to the models represented in the view. Similarly, you can redefine user interaction on a view without changing the view. The reuse of objects shortens the time for writing the application. Additionally it enhances a consistent functionality and design of all your applications.
Using the MVC architecture enables you to focus on the definition of the objects instead of solving design issues. |
3.2. LuciadMobile models
A LuciadMobile model (ILcdModel
) is a collection of geographical data of the same
type, for example cities, roads, elevation data or flight plans. There are two types of geographical data:
-
vector features, which consist of geometries such as points, lines and polygons. Examples of vector features are streets, buildings, airports and radars. A vector feature is stored in an
ALcdFeatureModel
. -
Raster data, which consists of a grid of cells. Examples of raster data are aerial photographs, satellite images, weather data and elevation data. Raster data is stored in an
ALcdRasterTileSetModel
.
To define the model data, or domain object, in a uniform way, each ILcdModel
is
associated with:
-
A spatial reference (
ALcdGeoReference
) that specifies the coordinate reference system that is used for locating the model data on earth. Note that all models need to be associated with a reference system, as otherwise it is not possible to determine the location of the data. -
A model descriptor (
ILcdModelDescriptor
) that provides additional information, or metadata, about the model data. The metadata usually specifies the source of the data, the data type, and a name that can be used to label the data in the view. Depending on the type of data, the model descriptor may include information about the content and/or the structure of the data or make data accessible that is stored with the source data.
3.3. LuciadMobile views
A LuciadMobile view (TLcdMapView
) is an Android View
in which the data
of one or more ILcdModel
objects are visualized in graphical form. Use the map view as part of your Android
Activity
to display a map on the device.
A LuciadMobile view is associated with:
-
A map reference: a spatial reference system used to represent geographical data in a 2D view. The reference system contains a map projection to transform the curved surface of the earth to the flat surface of the view. It is represented by an
ALcdGeoReference
. -
One or more layer: to properly visualize the model data in a LuciadMobile view, each model is put in a layer (
ALcdLayer
). Various layer implementations exist for different types of data.
To ensure optimal performance, it is recommended that the map reference of the view and the reference of each model added to a view are the same. For your convenience, the map view sets its reference to the reference of the first model added to the map view, unless it was explicitly set earlier on. |
3.4. LuciadMobile controllers
A LuciadMobile controller defines the action that a user can perform on a view, or on an object visualized in the view. On Android devices, controller actions are typically triggered by user interaction via the device’s touch screen. Examples of controller actions include navigation in the view, such as panning and zooming, and the selection of objects.
The controller maps user gestures to navigation or other operations. By default, each TLcdMapView
provides
controllers that enable moving around and zooming on the map, as well as the selection of objects. The LuciadMobile also allows
you to define more sophisticated user interaction by creating an extension of ALcdController
and setting it on the TLcdMapView
. This is explained in more
detail in Chapter 7, Managing user input with controllers.
4. Building a basic LuciadMobile application
This chapter describes how to build a basic application with LuciadMobile. The application displays a map view with some background data, and allows the user to pan and zoom using the touch screen. Subsequent chapters explain how to add other data and functionality to your application.
The design of this basic application reflects the Model-View-Controller architecture. As this is a basic application,
it only uses LuciadMobile’s built-in user interaction functionalities. The controller component of the Model-View-Controller
architecture is therefore implicit. To expand on the basic user interaction functions, you can extend the
ALcdController
class. For more information, see Section 4.5, “Controlling the map” and Chapter 7, Managing user input with controllers.
4.1. Creating an Activity
The first step in building any Android application is to create an android.app.Activity
.
Program: Creating a LuciadMobile activity shows an otherwise empty extension of Activity
.
public class BasicApplication extends Activity {
@Override
public void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
}
}
Launching this activity results in a black screen, but you are now ready to add a map view to your activity.
4.2. Creating a map view
Getting your activity ready to display geographical data is as simple as calling the initialize()
method to
start the LuciadMobile API, and then setting the activity content view to a
TLcdMapView
. Program: Creating a map view shows how to do that.
public class BasicApplication extends Activity {
@Override
public void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
// Initialize the LuciadMobile API.
TLcdMobile.initialize( this );
// Set the content view to a TLcdMapView
TLcdMapView view = new TLcdMapView( this );
setContentView( view );
}
}
Now the device screen turns light blue rather than black when you start the application. This color is the default
background color of TLcdMapView
. Because there are no layers in the view yet, it is
also the only thing the view displays.
4.3. Creating a model
Before you can add data to the view, you need to create an ILcdModel
that
contains the data. LuciadMobile provides
various ModelFactory
classes that provide a number of methods for creating models from data sources.
Program: Creating a model with `TLcdBitmapTileSetModelFactory` shows how a bitmap resource can be loaded into a model. Chapter 5, Loading data into models goes into further detail about loading data into models.
TLcdBitmapTileSetModelFactory
ALcdGeoReference wgs84 = TLcdGeoReferenceProvider.getReference( "EPSG:4326" );
ILcd2DEditableBounds bounds = TLcdShapeFactory.create2DBounds( wgs84 );
bounds.setTo( -180, -90, 360, 180 );
ALcdRasterTileSetModel model = TLcdBitmapTileSetModelFactory.decodeBitmapModel( R.raw.earth, bounds );
4.4. Creating a layer
Finally, to get the data in an ILcdModel
to show in the map view, you need to place the model on a layer, and
add it to the view. You can use an implementation of ALcdLayer
for this.
Different implementations of ALcdLayer
are available for different types of model data. The raster model
created from the bitmap in the previous step requires a TLcdRasterTileSetLayer
.
Program: Adding a raster layer to the map view shows the final application.
public class BasicApplication extends Activity {
@Override
public void onCreate( Bundle aSavedInstanceState ) {
super.onCreate( aSavedInstanceState );
// Initialize the LuciadMobile API.
TLcdMobile.initialize( this );
// Set the content view to a TLcdMapView
TLcdMapView view = new TLcdMapView( this );
setContentView( view );
ALcdGeoReference wgs84 = TLcdGeoReferenceProvider.getReference( "EPSG:4326" );
ILcd2DEditableBounds bounds = TLcdShapeFactory.create2DBounds( wgs84 );
bounds.setTo( -180, -90, 360, 180 );
ALcdRasterTileSetModel earthModel = TLcdBitmapTileSetModelFactory.decodeBitmapModel( R.raw.earth, bounds );
// Create a layer for the model and add that to the view
TLcdRasterTileSetLayer earthLayer = new TLcdRasterTileSetLayer( "Earth", earthModel );
aMapView.getLayerTree().getRoot().addChild( earthLayer );
}
}
The application now displays a raster image of the Earth, as shown in Figure 1, “A basic application”.

Go to Chapter 6, Visualizing models using ALcdLayer
for more information about the visualization of model data.
4.5. Controlling the map
You can pan the map by dragging your finger over the touch screen. Zoom in and out using a pinch gesture or by using
the magnifier controls that appear at the bottom of the view. You can also double-tap a location on the screen to zoom
in on the location. This user interaction functionality is built-in. LuciadMobile allows you to expand or override user
interaction possibilities by implementing custom controllers based on the ALcdController
class. For more
information, see Chapter 7, Managing user input with controllers.
4.6. LuciadMobile and the Android lifecycle
In Android, application component, such as Activities, Fragments and Services, have a specific Lifecycle. Components can be created and destroyed, started and stopped, paused and resumed. The concept of a lifecycle is explained in detail in the Android SDK documentation and refers to the various stages through which application components move from start to exit of an application.
In LuciadMobile, objects can be marked as having a life cycle by implementing ILcdLifecycle
. This interface offers methods which must be called when the corresponding
phase in the lifecycle occurs:
-
onStart()
when the lifecycle is started -
onRestart()
when the lifecycle is restarted, after it was stopped -
onResume()
when the lifecycle is resumed, after it was paused or stopped -
onPause()
when the lifecycle is paused -
onStop()
when the lifecycle is stopped -
onDestroy()
when the lifecycle is destroyed
Objects implementing ILcdLifecycle
can be registered in TLcdMapActivity
. This activity tracks the various stages of the lifecycle and calls the
corresponding ILcdLifecycle
callbacks. This makes it possible to permanently store data when the activity is
stopped, for example, or to release resources.
5. Loading data into models
This chapter discusses the possibilities of ILcdModel
in more detail.
Firstly, it explains the ILcdModel
interface and its two main implementations to store vector and raster data.
Secondly, it shows what types of elements can be stored in feature models.
5.1. Working with ILcdModel
LuciadMobile’s main model interface is ILcdModel
. A model has a common geographic reference for all its elements,
represented by ALcdGeoReference
, and contains metadata as an ILcdModelDescriptor
.
ILcdModel
itself extends from ILcdDisposable
and ILcdLifecycle
. The LuciadMobile model
implementations call dispose()
on themselves when onDestroy()
is called. So in order to make sure
models always release their resources at the right moment in the activity lifecycle, it is sufficient to register them
in a TLcdMapActivity
, or to call onDestroy()
at the right moment. See
Section 4.6, “LuciadMobile and the Android lifecycle” for more information about the activity lifecycle.
The two main LuciadMobile model implementations are ALcdFeatureModel
and ALcdRasterTileSetModel
.
5.1.1. Working with ALcdFeatureModel
This section describes how to use ALcdFeatureModel
and how to load vector features in such a model.
Querying and updating feature models
You can use ALcdFeatureModel
to store vector features such as points, polyline, and polygons. Its
interface provides methods to query, insert, update, and delete objects, similar to how a spatial database works:
-
insert(ILcdFeature)
inserts the given feature into the model. -
update(ILcdFeature)
updates the feature stored in the model. -
delete(ILcdFeature)
removes the given feature from the model. -
queryByArea(ILcdBounds)
retrieves anILcdDataObjectCursor
withCursor
methods such asisFirst()
,isLast()
,moveToNext()
, etc. The method returns the objects that are located fully within the given bounds, as well as those that partially overlap with the given bounds. If the provided bounds arenull
, all the objects will be returned. -
countByArea(ILcdBounds)
retrieves the number of objects within the given bounds. -
queryById(long)
retrieves a domain object with the given ID.
The elements in ALcdFeatureModel
implement the ILcdFeature
interface which is further discussed in
Section 5.2, “Creating features”. .
Listening for model changes
The ALcdFeatureModel
object management methods fire events. To receive these events, register an
ILcdFeatureModelListener
on the model. By listening for
these change events, the application can dynamically respond to changing data by repainting the map view, updating
other GUI components, clearing caches, and so on.
When the model is updated, it creates a TLcdFeatureModelChangedEvent
, which describes the changes to the model in more
detail. It has a code property specifying the global changes. You can retrieve these using the getCode()
method. More specific element changes can be queried using the getChangedFeatures()
method. This event is
passed to all registered listeners.
Please refer to the TLcdFeatureModelChangedEvent
documentation for more information.
Loading vector features from LuciadMobile Vector Databases
LuciadMobile uses LuciadMobile Vector Databases (LVDB) to store vector features such as points, lines, or polygons. The technical
details of the LVDB format are described in Appendix A, LuciadMobile Vector Database Format.
An LVDB file can be loaded into an ALcdFeatureModel
. Subsequent changes to that model are automatically
stored in the underlying database. To create LVDB models, use
TLcdLVDBFeatureModelFactory
.
ALcdFeatureModel model = TLcdLVDBFeatureModelFactory.decodeLVDBModel(
Uri.parse( "file:///sdcard/MapData/cities.lvdb" )
);
The resulting model contains objects that implement ILcdFeature
.
The objects have properties corresponding to the columns of the database table. Please refer to
Section 5.2, “Creating features” for more information on how to work with ILcdFeature
.
Creating empty feature models
In some situations, it may be required to create a model which is initially empty. You would like to create
an application that allows the user to draw shapes on the map, for example. You can use
TLcdVolatileFeatureModelFactory
and TLcdLVDBFeatureModelFactory
to
achieve this:
-
The
TLcdVolatileFeatureModelFactory.createVolatileModel()
method creates an empty model which is not persistent. Any data that the application adds to this model is lost when the application is terminated. -
The
TLcdGeoPackageModelFactory.createFeaturesModel()
method creates a model which is backed by a GeoPackage file. If the file does not exist, it is created and the resulting model is empty. If the file does exist, it will be opened and its contents will be added to the model. Modifications to this model are reflected in the underlying file, so you can use this method to create a new model of which the contents should be persistent between multiple application runs. -
The
TLcdLVDBFeatureModelFactory.createLVDBModel()
method creates a model which is backed by an LVDB file. If the database does not exist, it is created and the resulting model is empty. If the database does exist, it will be opened and its contents will be added to the model. Modifications to this model are reflected in the underlying database, so you can use this method to create a new model of which the contents should be persistent between multiple application runs.
Both of these methods require a TLcdDataType
argument that describes
the elements which you intend to add to the model. Chapter 9, Unified access to domain objects explains how to declare a data
type and create conforming domain objects.
For more information on how to allow the user to draw on the map, see Chapter 7, Managing user input with controllers.
5.1.2. Working with ALcdRasterTileSetModel
ALcdRasterTileSetModel
is used to store and represent multi-leveled tiled raster data, accessible by the
ILcdRasterTileSet
interface it implements. Raster models can only be queried. Once they are loaded, their
contents cannot be changed or removed.
There is more than one way to load rasters into a model. Which one you choose depends on the size of the raster data:
-
Loading a small bitmap resource
-
Loading larger imagery from a GeoPackage file or LuciadMobile Raster Database (LRDB)
-
Loading large raster data via a live connection to a LuciadFusion server
Loading a bitmap resource
Images that are small enough to fit into device memory, can be put on the device as a bitmap resource. They can be loaded
into a model using TLcdBitmapTileSetModelFactory.decodeBitmapModel()
:
samples/com/luciad/samples/common/LayerFactory
)ALcdGeoReference wgs84 = TLcdGeoReferenceProvider.getReference("EPSG:4326");
ILcd2DEditableBounds bounds = TLcdShapeFactory.create2DBounds(wgs84);
bounds.setTo(-180, -90, 360, 180);
ALcdRasterTileSetModel model = TLcdBitmapTileSetModelFactory.decodeBitmapModel(R.raw.earth, bounds);
The TLcdBitMapTileSetModelFactory
uses the supplied resource ID to load a
Bitmap
resource. It then maps this bitmap onto the defined spatial extent. In the previous example, the
image is mapped to the entire world.
Although they are limited in size, bitmap resources can be useful as background data for maps when no higher-resolution imagery is available or needed.
Loading imagery from GeoPackage files
Raster imagery that cannot be loaded entirely into memory can still be viewed by LuciadMobile if you first convert the data
to the GeoPackage format.
Once a database has been exported and copied to the Android device,
TLcdGeoPackageModelFactory.decodeTilesModel()
can create a corresponding model for it.
Loading imagery from LuciadMobile Raster Databases
Raster imagery that cannot be loaded entirely into memory can still be viewed by LuciadMobile if you first convert the data
to the LuciadMobile Raster Database (LRDB) format. Technical details of the LRDB format are described in Appendix B, LuciadMobile Raster Database Format.
Once a database has been exported and copied to the Android device,
TLcdLRDBTileSetModelFactory.decodeLRDBModel()
can create a corresponding model for it.
File database = new File(
Environment.getExternalStorageDirectory(), "MapData/fusion.lrdb"
);
ILcdModel model = TLcdLRDBTileSetModelFactory.decodeLRDBModel(
fMapActivity, Uri.fromFile( database )
);
Loading imagery from an ECW file
LuciadMobile also supports decoding ECW files directly, without the need to convert them to GeoPackage or LRDB files.
After you copied an ECW file to your Android device, you can create a TLcdRasterTileSetModel
from that
ECW file by calling TLcdECWModelFactory.decode
. Note that TLcdECWModelFactory.decode
supports also ECWP streams.
.
Loading elevation data from DTED
A model from DTED data can be created by using
TLcdDTEDModelFactory.decode()
.
It is possible to load the full data set by using the Uri
of the dmed file.
A single tile can be loaded by using the Uri
of a dt0, dt1 or dt2 file.
ALcdFeatureModel model = TLcdDTEDModelFactory.decode(
Uri.parse( "file:///sdcard/MapData/dmed" )
);
Connecting to a live LuciadFusion server
In cases where converting data to an LRDB file is undesirable or impractical, for example
because the dataset is too large to be stored on the Android device, LuciadMobile can also use a live connection to a
LuciadFusion server. This requires the device to have a working data connection, but is otherwise as simple
as calling TLcdFusionTileSetModelFactory.decodeFusionModel()
with the Uri
of the server.
Connecting to a Bing Maps server
LuciadMobile also offers support to visualize data from a Bing Maps compatible server. The TLcdBingMapsModelFactory
provides methods to connect either with Microsoft’s
tile servers or with a custom Bing Maps-compatible server. If you need to display copyright notices, use the
TLcdBingMapsParameters
class. It has a method to
add copyright notices based on coverage areas.
Before connecting to the Bing Maps servers you need to get a Bing Maps developer key. The Bing Maps portal (http://www.bingmapsportal.com) allows you to create a Bing Maps account and one or more Bing Maps keys.
The use of the BingMaps service is subject to Microsoft’s terms of use which can be found on the Bing Maps portal. The terms of use may require displaying a logo and copyright notices. At the time of writing, the raster tileset sample fulfills the necessary requirements to display this information.
Connecting to a WMTS server
LuciadMobile can connect to an OGC Web Map Tile Service (WMTS) compatible server.
The TLcdWMTSModelFactory
can be used to retrieve and parse the capabilities of the WMTS server
and create a ALcdRasterTileSetModel
that contains all information to retrieve tiles.
To connect and retrieve tiles from a WMTS server, you first need to retrieve the capabilities from the server.
This can be done using TLcdWMTSModelFactory.queryLayers()
where you pass the URL of the server as a parameter.
This function returns a list of TLcdWMTSLayer
which describe the tile matrix, supported formats, styles and
query dimensions of each layer that is served by the WMTS server.
The next step is to create a ALcdRasterTileSetModel
using TLcdWMTSModelFactory.decodeWMTSModel()
where a TLcdWMTSLayer
and other optional parameters can be passed. Optional parameters are a layer
style (TLcdWMTSLayerStyle
), a Map<String, String>
containing optional query dimensions and a
TLcdWMTSTileMatrixSet
.
5.2. Creating features
ALcdFeatureModel
stores objects of type ILcdFeature
, which is a combination of
ILcdEditableShaped
, ILcdDataObject
and ILcdIdentifiable
. The
ILcdEditableShaped
interface defines that these objects have a geometry, for example a polygon that defines
the boundary of a county. The ILcdDataObject
interface introduces the possibility of having other properties,
such as a county name, a county population, and so on. The ILcdIdentifiable
interface determines that each
domain
object is associated with a unique ID per model.
-
getShape()
/setShape()
retrieves/sets the geometry of the domain object, the county boundary for example. -
hasValue()
queries whether the domain object has a value for the given property, whether a property population is defined for example. -
getValue()
/setValue()
retrieves/sets the value for the given property, for example, the population of a county. -
getID()
retrieves the ID for this domain object. An object ID is only set after the domain object has been added to a model.
Although the LuciadMobile API does not provide concrete implementations of ILcdFeature
, you do not have to implement
this interface yourself. The LuciadMobile API provides you with the necessary tools for managing domain objects:
TLcdFeatureDataTypes
provides factory methods to
create a domain object, given an ILcdShape
and a
TLcdDataType
.
You can obtain ILcdShape
instances, such as bounds, points, polylines, and polygons from
TLcdShapeFactory
. TLcdFeatureDataTypes
provides base
data types such as SHAPE_FEATURE_TYPE
with an ID and geometry property that can be extended to add custom
properties. A county boundary can be extended with properties such as a county name and a county population, for
instance.
The program below shows how TLcdFeatureDataTypes.SHAPE_FEATURE_TYPE
is extended to add a String
property.
TLcdFeatureDataTypes.SHAPE_FEATURE_TYPE
and adding a name property (from samples/com/luciad/samples/common/DataTypes
)TLcdDataModelBuilder b = new TLcdDataModelBuilder("Shape");
TLcdDataTypeBuilder shapeBuilder = b.typeBuilder("Shape");
shapeBuilder.superType(TLcdFeatureDataTypes.SHAPE_FEATURE_TYPE);
shapeBuilder.addProperty("name", TLcdCoreDataTypes.STRING_TYPE);
SHAPE_TYPE = b.createDataModel().getDeclaredType("Shape");
SHAPE_NAME_PROPERTY = SHAPE_TYPE.getProperty("name");
Please refer to Chapter 9, Unified access to domain objects for a more in-depth description of the ILcdDataObject
and
TLcdDataType
concepts.
LuciadMobile provides many interfaces and abstract classes such as |
6. Visualizing models using ALcdLayer
Before you can visualize the models you created on the map, you must add them to a map layer. For this purpose, you can
use an implementation of ALcdLayer
.

ALcdLayer
and its derived classesThe LuciadMobile API comes with a set of predefined layer implementations for displaying points,
lines, polygons, rasters and grids. Figure 2, “ALcdLayer
and its derived classes” shows a class diagram of these layer implementations.
6.1. Visualizing feature layers
Vector features can be visualized using a TLcdFeatureLayer
.
The feature layer allows you to visualize the objects in a model, while it delegates the painting of individual objects
to ALcdFeaturePainter
. Use ALcdFeaturePainter
to
style the visualized objects. LuciadMobile provides the concrete feature painter implementation
TLcdBasicFeaturePainter
that defines a default styling for vector features. Styling is defined by
TLcdAreaStyle
and
TLcdLineStyle
objects for polygons and polylines and by
<<Drawable>>
objects for point objects.
The following sections discuss how TLcdBasicFeaturePainter
can be configured and extended to perform styling
on individual objects. Next, ALcd<<GeoCanvas>>
is introduced in a discussion on how to extend
ALcdFeaturePainter
to perform custom drawing.
6.1.1. Styling vector features
Styling point data
Point data is typically visualized with a Drawable
.
The Android API provides different Drawable
implementations. Examples include
BitmapDrawable
to paint bitmaps, ShapeDrawable
to draw Shape
objects, and so on.
Please refer to the Android API and Android Developer’s Guide for more information on Drawable
.
|

TLcdFeatureLayer
paints points using DrawablesProgram: Configuring a `TLcdBasicFeaturePainter` for point styling
taken from samples.icons.simple illustrates the visualization of a point with a Drawable
that paints
simple circles filled with a blue color for unselected objects, and a red color for selected objects (see also
Figure 3, “TLcdFeatureLayer
paints points using Drawables”).
TLcdBasicFeaturePainter
for point styling (from samples/com/luciad/samples/icons/simple/CircleIconsSample
)public class CircleIconsSample extends AIconsActivity {
// The pixel radius of the disks.
private static final int DISK_RADIUS = 10;
@Override
protected ALcdFeaturePainter getFeaturePainter() {
TLcdBasicFeaturePainter painter = new TLcdBasicFeaturePainter();
painter.setDefaultPointDrawable(
createCircleDrawable(Color.argb(220, 100, 100, 220)));
painter.setSelectedPointDrawable(
createCircleDrawable(Color.argb(220, 220, 100, 100)));
return painter;
}
private Drawable createCircleDrawable(int aColor) {
ShapeDrawable drawable = new ShapeDrawable(new OvalShape());
drawable.setIntrinsicWidth(2 * DISK_RADIUS);
drawable.setIntrinsicHeight(2 * DISK_RADIUS);
drawable.getPaint().setColor(aColor);
return BitmapUtil.convertToBitmapDrawable(getResources(), drawable);
}
}
When you paint a |
You can also customize the basic feature painter to get a different styling for each object by overriding one or more of
the protected methods. Program: `TLcdBasicFeaturePainter` extension to apply per-object styling shows an example taken from
com.luciad.samples.labeling
for custom per-object point styling.
TLcdBasicFeaturePainter
extension to apply per-object styling (from samples/com/luciad/samples/labeling/CityPainter
)@Override
public void paint(ALcdGeoCanvas aCanvas, ILcdFeature aFeature, ILcdShape aShape, ALcdLayer aLayer, TLcdMapView aMapView, TLcdPaintState aState) {
int paintLevel = aState.getLevel();
Number popNumber = (Number) aFeature.getValue("TOT_POP");
int population = popNumber != null ? popNumber.intValue() : 0;
if (population > 1000000 && paintLevel > 0) {
aCanvas.drawDrawable(aShape, fHugeCityDrawable);
} else if (population > 500000 && paintLevel > 1) {
aCanvas.drawDrawable(aShape, fLargeCityDrawable);
} else if (population > 250000 && paintLevel > 2) {
aCanvas.drawDrawable(aShape, fMediumCityDrawable);
} else if (paintLevel > 2) {
aCanvas.drawDrawable(aShape, fSmallCityDrawable);
}
}
This LuciadMobile sample uses the JavaScript Object Notation (JSON) format to describe object styling. For more information about JSON, see http://json.org/. |
Please refer to the many icon samples in the subpackages com.luciad.samples.icons.*
for more examples.
Styling polygon and polyline data
Program: Defining polygon and polyline styling for a `TLcdFeatureLayer` taken from com.luciad.samples.common
illustrates how you
can configure the polygon and polyline style on a TLcdBasicFeaturePainter
.
See Figure 4, “TLcdBasicFeaturePainter
styles polygons and polylines using TLcdAreaStyle
and TLcdLineStyle
objects” for an accompanying figure.
TLcdFeatureLayer
(from samples/com/luciad/samples/common/FeaturePainterUtil
)public final class FeaturePainterUtil {
public static ALcdFeaturePainter getDefaultPainter(
ELcdLineInterpolation aLineInterpolation,
ELcdLinePrecision aLinePrecision) {
// Default style for polygons.
TLcdAreaStyle defaultPolygonStyle = new TLcdAreaStyle();
defaultPolygonStyle.setPaintMode(ELcdPaintMode.FILL_AND_STROKE);
defaultPolygonStyle.setLineInterpolation(aLineInterpolation);
defaultPolygonStyle.setLinePrecision(aLinePrecision);
defaultPolygonStyle.setStrokeCap(ELcdCap.ROUND);
defaultPolygonStyle.setAntiAlias(true);
defaultPolygonStyle.setStrokeColor(Color.argb(255, 255, 255, 255));
defaultPolygonStyle.setStrokeWidth(3f);
defaultPolygonStyle.setFillColor(Color.argb(200, 0, 255, 0));
// Style for selected polygons.
TLcdAreaStyle selectedPolygonStyle = new TLcdAreaStyle(defaultPolygonStyle);
selectedPolygonStyle.setStrokeColor(Color.argb(255, 255, 255, 255));
selectedPolygonStyle.setStrokeWidth(5f);
selectedPolygonStyle.setFillColor(Color.argb(200, 255, 0, 0));
// Default style for polylines.
TLcdLineStyle defaultPolylineStyle = new TLcdLineStyle();
defaultPolylineStyle.setStrokeColor(Color.argb(230, 255, 255, 255));
defaultPolylineStyle.setStrokeWidth(5f);
defaultPolylineStyle.setStrokeCap(ELcdCap.ROUND);
defaultPolylineStyle.setAntiAlias(true);
defaultPolylineStyle.setLineInterpolation(aLineInterpolation);
defaultPolylineStyle.setLinePrecision(aLinePrecision);
// Style for selected polylines.
TLcdLineStyle selectedPolylineStyle = new TLcdLineStyle(defaultPolylineStyle);
selectedPolylineStyle.setStrokeColor(Color.argb(230, 255, 0, 0));
selectedPolylineStyle.setStrokeWidth(5f);
// Configuring the basic painter with the above defined styles.
TLcdBasicFeaturePainter painter = new TLcdBasicFeaturePainter();
painter.setFallbackDefaultPolygonStyle(defaultPolygonStyle);
painter.setFallbackSelectedPolygonStyle(selectedPolygonStyle);
painter.setFallbackDefaultPolylineStyle(defaultPolylineStyle);
painter.setFallbackSelectedPolylineStyle(selectedPolylineStyle);
return painter;
}
}
.

TLcdBasicFeaturePainter
styles polygons and polylines using TLcdAreaStyle
and TLcdLineStyle
objects
|
Refer to com.luciad.samples.firstsample
, com.luciad.samples.arrows
,
com.luciad.samples.creation
, com.luciad.samples.cop
for examples of polygon and polyline shapes in a
TLcdFeatureLayer
.
If the provided implementation of TLcdBasicFeaturePainter
does not suit your needs, consider creating a custom
extension of ALcdFeaturePainter
and perform custom drawing on ALcdGeoCanvas
. For more information,
see Section 6.1.2, “Using ALcdGeoCanvas
for custom drawing”
6.1.2. Using ALcdGeoCanvas
for custom drawing
Sometimes, you may want to perform not only custom styling operations, but also custom drawing operations for vector
layers. LuciadMobile provides a high-level canvas (ALcdGeoCanvas
) that allows you to draw styled objects, such as text
and Drawable
instances, and vector features, such as circles, lines and polygons. The
styling of the drawn shapes is defined by the ALcdStyle
objects discussed above. Internally,
TLcdBasicFeaturePainter
uses ALcdGeoCanvas
to perform its drawing operations.
Instances of ALcdGeoCanvas
are created and managed by LuciadMobile, and are provided as a method argument where needed.
For instance, ALcdFeaturePainter
gets an
ALcdGeoCanvas
as an argument for its paint()
method. Similarly, the controller API (see
Chapter 7, Managing user input with controllers) provides you with an ALcdGeoCanvas
via the
ALcdController.onDraw(ALcdGeoCanvas)
method.
An ALcdGeoCanvas
performs vector feature drawing operations in a geographical coordinate reference, which is
identified via the feature’s reference. If the reference cannot be determined, the objects and shapes will be drawn in
screen coordinates.
Program: Using the `ALcdGeoCanvas` in an `ALcdFeaturePainter` to create a custom drawing taken from com.luciad.samples.geocanvas
illustrates how you can perform custom painting on an ALcdGeoCanvas
for point objects. In this sample, a point
is drawn using a ShapeDrawable
. In addition, the sample draws concentric circles and text labels that depict
all locations at a distance of 1000, 2000, 3000, 4000 and 5000km from the given point. See
Figure 5, “Custom ALcdFeaturePainter
implementation that performs specialized drawing on an ALcdGeoCanvas
” for an accompanying illustration.
ALcdGeoCanvas
in an ALcdFeaturePainter
to create a custom drawing (from samples/com/luciad/samples/geocanvas/PointPainter
)class PointPainter extends ALcdFeaturePainter {
@Override
public void paint(ALcdGeoCanvas aGeoCanvas, ILcdFeature aFeature, ILcdShape aShape, ALcdLayer aLayer, TLcdMapView aMapView, TLcdPaintState aPaintState) {
Drawable drawable;
ALcdStyle circleStyle;
if (aPaintState.isSelected()) {
drawable = fSelectedDrawable;
circleStyle = fSelectedCircleStyle;
} else {
drawable = fDefaultDrawable;
circleStyle = fDefaultCircleStyle;
}
ILcdPoint focusPoint = aShape.getFocusPoint();
ALcdGeodesy geodesy = TLcdGeodesyFactory.createEllipsoidalGeodesy(aLayer.getModel().getGeoReference());
// Draw an icon at the focus point
aGeoCanvas.drawDrawable(focusPoint, drawable);
// Draw concentric circles and labels around the point
for (int i = 0; i < DISTANCES.length; i++) {
double distance = DISTANCES[i];
aGeoCanvas.drawCircle(focusPoint, distance, circleStyle);
try {
ILcdPoint result = geodesy.interpolate(focusPoint, distance, 90.0, ELcdLineType.SHORTEST_DISTANCE);
aGeoCanvas.drawText(result, (int) (distance / 1000.0) + " km", fTextStyle);
} catch (TLcdOutOfBoundsException e) {
// Skip this label
}
}
}
private Drawable createDrawable(int aColor) {
ShapeDrawable shape = new ShapeDrawable();
shape.setShape(new OvalShape());
shape.setIntrinsicHeight(15);
shape.setIntrinsicWidth(15);
shape.getPaint().setColor(aColor);
return shape;
}
private ALcdStyle createCircleStyle(float aStrokeWidth) {
TLcdAreaStyle style = new TLcdAreaStyle();
style.setPaintMode(ELcdPaintMode.STROKE);
style.setStrokeWidth(aStrokeWidth);
style.setColor(Color.WHITE);
style.setAntiAlias(true);
return style;
}
private TLcdTextStyle createTextStyle() {
TLcdTextStyle style = new TLcdTextStyle();
style.setColor(Color.WHITE);
style.setWithHalo(true);
style.setHaloColor(Color.BLACK);
style.setAntiAlias(true);
style.setTextSize(12.0f);
return style;
}
}

ALcdFeaturePainter
implementation that performs specialized drawing on an ALcdGeoCanvas
|
6.1.3. Displaying information balloons
LuciadMobile allows information balloons to be displayed for individual features. Balloons are Android View
instances that are
anchored to a spatial location on the map. When the map is moved, the balloon always remains at the same location on
screen relative to its anchor location.
To show a balloon call the showBalloon
method of TLcdMapView
. This method requires an
instance of ALcdBalloonProvider
. A balloon provider is responsible for the creation of the entire balloon
including the balloon frame, contents and any additional user interface elements such as close buttons.
Relative positioning of the balloon with respect to its anchor location is also controlled by the balloon provider.
Before returning the balloon View
a balloon provider can assign an instance of
TLcdMapView.LayoutParams
as the layout parameters property of the root view of the balloon. The values
defined in the LayoutParams
object determine the positioning of the view.
A default implementation of a balloon provider is provided by TLcdBasicBalloonProvider
. This implementation
provides a default frame with close button and default contents. The contents of the default balloons can be modified
by overriding the getContents
method.
ALcdFeatureLayer
integrates the information balloon functionality by exposing a balloon provider property. The
default implementation of ALcdFeatureLayer#onTap
will call TLcdMapView#showBalloon
provided that a non-null
balloon provider has been assigned to the layer.
6.1.4. Optimized feature loading
By default, ALcdFeatureLayer
loads an entire model into memory. To prevent memory problems when you are loading very large feature models, it is recommended to set a limit on the number of cached objects. To reduce the number of features that are loaded in memory, you need to change the loading strategy of the ALcdFeatureLayer
:
-
Create a loading strategy that limits the number of features by calling
createFeatureCountLimitedStrategy
on theALcdDataLoadingStrategy
class. -
Set the created strategy on the layer by calling
setDataLoadingStrategy
onALcdFeatureLayer
.
Limiting the number of simultaneously loaded objects also limits the number of simultaneously painted objects. The latter is closely tied to
the cache limit, but you cannot set the object painting limit directly. Whenever the painter determines that there are too many features to be painted in the view, an outline
is painted instead. You can customize the style of this outline using the setOutlineStyle
method on ALcdFeatureLayer
.
Because loading optimization relies heavily on spatial queries of the model, it is strongly encouraged to always include a spatial index in your models. In the absence of such an index, the feature loader uses slow direct querying as a fallback.
6.2. Visualizing raster layers
TLcdRasterTileSetLayer
is a layer implementation that can display tiled raster data sets. Raster data
can be loaded from local storage or from remote network services.
Use the TLcdBitmapTileSetModelFactory
,
TLcdBingMapsModelFactory
,
TLcdGeoPackageModelFactory
,
TLcdLRDBTileSetModelFactory
,
TLcdECWModelFactory
,
TLcdDTEDModelFactory
or
TLcdFusionTileSetModelFactory
to
create models for this layer type. Section 5.1.2, “Working with ALcdRasterTileSetModel
” describes the usage of these model factories in detail.
Program: Creating a `TLcdRasterTileSetLayer` for displaying an LRDB file stored on the Android device illustrates the creation of
TLcdRasterTileSetLayer
that displays an LRDB file stored on the external storage directory of the Android
device (see also Figure 6, “A TLcdRasterTileSetLayer
displaying high-resolution imagery in the Los Angeles region”).
TLcdRasterTileSetLayer
for displaying an LRDB file stored on the Android device (from samples/com/luciad/samples/tileset/LRDBSupport
)public static ALcdRasterTileSetModel decodeModel(Uri aUri) throws IOException {
return TLcdLRDBTileSetModelFactory.decodeLRDBModel(aUri);
}
public static TLcdRasterTileSetLayer createLayer(ALcdRasterTileSetModel aModel) {
return new TLcdRasterTileSetLayer("LRDB", aModel);
}
LuciadMobile Raster Databases (LRDB) can be created using the LuciadMobile exporter addons for Lucy, as detailed in the LuciadMobile Addons for Lucy User’s Guide.
Complete sample code that uses TLcdRasterTileSetLayer
objects can be found in
com.luciad.samples.tileset
.

TLcdRasterTileSetLayer
displaying high-resolution imagery in the Los Angeles region6.2.1. Elevation data
When visualizing an ALcdRasterTileSetModel
that
contains elevation data, the TLcdRasterTileSetLayer
automatically applies the default color map for
visualizing elevation data. To create your own custom color map, create a new
TLcdElevationColorMap
using its builder class. To
activate the color map, retrieve the style of the TLcdRasterTileSetLayer
and call its
setElevationColorMap()
method. To retrieve the elevation at a specific spatial position, use the
TLcdTerrainSampler
class.
6.3. Visualizing grid layers
LuciadMobile offers built-in support for the display of a latitude/longitude grid or a grid based on the Military Grid Reference System (MGRS).
6.3.1. Adding a latitude/longitude grid
A latitude/longitude grid is defined in the TLcdLonLatGrid
class. This object contains general properties of
the grid itself, such as origin and increment size between consecutive latitude and longitude lines. It is also possible
to vary the increments based on the map’s current scale. The TLcdLonLatGrid
also contains styling options that
determine how the grid is rendered on the map.
The next step is creating a TLcdGridLayer
, using the TLcdLonLatGrid
mentioned before. Program: Creating a `TLcdLonLatGrid` for use with a `TLcdGridLayer`. illustrates how to create a TLcdGridLayer
with
a TLcdLonLatGrid
. A more extensive sample can be found in the com.luciad.samples.grid.lonlat
subpackage.
TLcdLonLatGrid
for use with a TLcdGridLayer
. (from samples/com/luciad/samples/grid/lonlat/LonLatGridSample
)TLcdLineStyle zeroStyle = new TLcdLineStyle();
zeroStyle.setStrokeColor(Color.YELLOW);
TLcdTextStyle labelStyle = new TLcdTextStyle();
labelStyle.setColor(Color.WHITE);
labelStyle.setHaloColor(Color.BLACK);
// We provide four different scaling levels. As long as the scale of
// the map is smaller than scales[i], deltas[i] is used as increment
// between grid lines. This creates a dynamic grid which has different
// increments between grid lines, depending on the scale of the current map.
double[] scales = {2.0E-8, 9.0E-9, 5.0E-9, 0};
double[] deltaLons = {2.0, 5.0, 10, 20};
double[] deltaLats = {2.0, 5.0, 10, 20};
TLcdLonLatGrid.Builder gridBuilder = new TLcdLonLatGrid.Builder();
gridBuilder.origin(0, 0);
gridBuilder.addAllDeltas(scales, deltaLons, deltaLats);
// Create grid layer.
TLcdLonLatGrid grid = gridBuilder.build();
grid.setZeroStyle(zeroStyle);
grid.setLabeled(true);
grid.setLabelEdgeOffset(5);
grid.setLabelStyle(labelStyle);
grid.setLabelFormat(new TLcdLonLatPointFormat(TLcdLonLatPointFormat.DEC_DEG_0));
TLcdGridLayer lonLatGridLayer = new TLcdGridLayer("Grid", grid);
aMapView.getLayerTree().getRoot().addChild(lonLatGridLayer);

6.3.2. Adding an MGRS grid
To draw an MGRS grid, use TLcdMGRSGrid
in conjunction with a TLcdGridLayer
.
Program: Creating an MGRS grid. illustrates how to create a TLcdMGRSGrid
. See
the com.luciad.samples.grid.mgrs
subpackage for a more extensive sample.
samples/com/luciad/samples/grid/mgrs/MGRSGridSample
)// Set drawing properties.
float density = aMapView.getContext().getResources().getDisplayMetrics().density;
TLcdLineStyle gridZone = new TLcdLineStyle();
gridZone.setStrokeColor(Color.WHITE);
gridZone.setHaloColor(Color.BLACK);
gridZone.setStrokeWidth(2.0f * density);
TLcdTextStyle gridZoneLabel = new TLcdTextStyle();
gridZoneLabel.setColor(Color.WHITE);
gridZoneLabel.setHaloColor(Color.BLACK);
gridZoneLabel.setWithHalo(true);
gridZoneLabel.setAntiAlias(true);
gridZoneLabel.setTextSize(22.0f * density);
gridZoneLabel.setTextAlign(TLcdTextStyle.Align.CENTER);
TLcdLineStyle gridPrimary = new TLcdLineStyle();
gridPrimary.setStrokeColor(Color.RED);
gridPrimary.setStrokeWidth(1.0f * density);
gridPrimary.setAntiAlias(true);
TLcdLineStyle gridSecondary = new TLcdLineStyle();
gridSecondary.setStrokeColor(Color.DKGRAY);
gridSecondary.setStrokeWidth(2.0f * density);
gridSecondary.setAntiAlias(true);
TLcdTextStyle gridLabel = new TLcdTextStyle();
gridLabel.setColor(Color.BLACK);
gridLabel.setHaloColor(Color.WHITE);
gridLabel.setWithHalo(true);
gridLabel.setTextSize(15.0f * density);
gridLabel.setAntiAlias(true);
TLcdTextStyle grid100kLabel = new TLcdTextStyle();
grid100kLabel.setColor(Color.RED);
grid100kLabel.setHaloColor(Color.BLACK);
grid100kLabel.setWithHalo(true);
grid100kLabel.setAntiAlias(true);
grid100kLabel.setTextSize(20.0f * density);
grid100kLabel.setTextAlign(TLcdTextStyle.Align.CENTER);
TLcdMGRSGrid grid = new TLcdMGRSGrid();
grid.setPrimaryStyle(gridPrimary);
grid.setSecondaryStyle(gridSecondary);
grid.setLabelStyle(gridLabel);
grid.set100kLabelStyle(grid100kLabel);
grid.setGridZoneStyle(gridZone);
grid.setGridZoneLabelStyle(gridZoneLabel);
grid.setLabeled(true);
grid.setLabelRotation(true);
grid.setLabelEdgeOffset((int) (6 * density));
fGridLayer = new TLcdGridLayer("MGRS", grid);
aMapView.getLayerTree().getRoot().addChild(fGridLayer);

6.4. Visualizing KML data
The Keyhole Markup Language(KML) file format has a very specific domain model that provides a lot of flexibility for content providers. A KML file can contain things like overlays, placemarks (geometric vector data), temporal data, behavioral data and styling data. The LuciadMobile implementation of KML visualization, however, is limited to the display of placemarks with styling options and styled balloons, loaded from local storage. LuciadMobile does not support the creation or editing of KML data.
TLcdKMLModelFactory
is used for decoding KML data, and accepts any .kml or .kmz[1] file as input and produce a
TLcdFeatureModel
as output. The model is visualized with the TLcdKMLLayer
, as shown in
Program: Decoding local KML data and adding it to a `TLcdKMLLayer`.. The layer visualizes the KML data using the
styling information provided in the data, or falls back on default styling if no custom style was defined.
TLcdKMLLayer
. (from samples/com/luciad/samples/fileloader/formats/KMLFormatHandler
)@Override
protected ALcdFeatureModel decode(Uri aUri) throws IOException {
return TLcdKMLModelFactory.decode(aUri);
}
@Override
protected ALcdLayer createLayer(ALcdFeatureModel aModel) {
String displayName = aModel.getModelDescriptor().getDisplayName();
return new TLcdKMLLayer(displayName, aModel);
}
7. Managing user input with controllers
The ability to deal with touch screen input events is an important part of your application. LuciadMobile provides
built-in controls for the most common tasks such as panning and zooming on a map. These
controls are automatically enabled when creating a new TLcdMapView
. To achieve more sophisticated interaction,
you can implement your own custom controllers. You can do this by extending the ALcdController
class.
You can activate and deactivate controllers by calling the TLcdMapView.setController()
method. When this method is called, any previously configured controller is
deactivated, and the newly configured controller is activated. The controllers in question get notified of this
state change via the ALcdController.onDeactivate()
and ALcdController.onActivate()
methods
respectively.
7.1. Handling the creation and manipulation of vector features by users
LuciadMobile supports the interactive creation and editing of vector features using extensions of ALcdController
.
By default all feature layers are editable, but you can disable this property using the setEditable
method.
7.1.1. Creating new vector features
ALcdCreateController
makes it possible to initiate an interactive session of
vector feature creation. By default, vertex can be placed by tapping the touch screen or using freehand drawing.
Depending on what the user should draw, both the drawing mode and the minimum/maximum number of points can be
configured.
As a convenience, LuciadMobile also provides a concrete implementation,
TLcdCreateController
.
This controller implements ALcdCreatecontroller.onCreateNewObject()
by creating a new shape based
on a shape type token that is passed to its constructor. If the model of the target layer contains
ILcdDataObject
instances, it will also wrap the shape in a data object instance.
Program: Using `TLcdCreateController`, taken from
com.luciad.samples.creation
, illustrates the usage of TLcdCreateController
.
TLcdCreateController
(from samples/com/luciad/samples/creation/CreateShapeMenuHandler
)private void activateController(TLcdMapView aMapView, TLcdShapeFactory.ShapeType<?> aShapeType, TLcdFeatureLayer aTargetLayer, String aMessage) {
aMapView.setController(
new TLcdCreateController(
aTargetLayer,
aShapeType
),
aMessage
);
}
Please refer to sample com.luciad.samples.creation
and com.luciad.samples.annotatedshapes
for complete illustrations.
7.1.2. Editing existing vector features
Graphical editing
LuciadMobile provides built-in support for graphical vector feature editing. A graphical editing session is initiated by
using TLcdEditController
. During a graphical editing session, the shape’s geometry or position can be modified
by dragging the shape itself or one of its vertices or control points. See Figure 9, “Graphically editing an arrow shape” for an example.
When an object is being edited, a commit is performed only at the end of an editing session. This means that frequent database updates during editing are avoided. |

Textual editing of vector features via the context menu
The LuciadMobile API allows you to define custom actions (ALcdObjectAction
) that can be executed from the
context menu, the dialog box shown when a user long-presses (press and hold) an object. See
Figure 10, “Custom Unit Type action added to the Edit dialog of a TLcdFeatureLayer
.” for an example. You can add the action to
any TLcdFeatureLayer
using the
addContextMenuAction
method. These actions are
typically used for editing or changing textual properties of a domain object.
Refer to the samples com.luciad.samples.annotatedshapes
and
com.luciad.samples.icons.ms2525
for example implementations of ALcdObjectAction
.

TLcdFeatureLayer
.7.2. Implementing custom user interaction
Besides using default create and edit controllers, you can also create custom controllers by implementing
ALcdController
. This allows you can integrate custom user interaction in your application.
7.2.1. Handling user gestures and key strokes
Extensions of ALcdController
can respond to input events by overriding the
ALcdController.onGestureEvent(TLcdGestureEvent)
and
ALcdController.onKeyEvent(TLcdKeyEvent)
methods.
TLcdGestureEvent
is used to describe incoming gesture
events.
The TLcdGestureEvent
class serves as a wrapper for the Android
MotionEvent
class. It also converts raw motion events, such as
ACTION_CANCEL
and ACTION_DOWN
, into higher-level gestures such as
DOUBLE_TAP
and LONG_PRESS
. This makes it easier to
rapidly create custom controllers. The original Android MotionEvent
object can obtained using the
getMotionEvent()
method.
Similarly TLcdKeyEvent
provides a wrapper for Android
KeyEvent
instances. The default implementation of
ALcdController.onKeyEvent(TLcdKeyEvent)
responds to presses of the Back key by deactivating the controller.
Controller implementations can also use the TLcdMapNavigator
class to move around and zoom on the map. A TLcdMapNavigator
instance can be obtained from the
TLcdMapView
.
Program: Handling a gesture event. illustrates the usage of a
TLcdGestureEvent
to handle incoming motion events. See the sample in
com.luciad.samples.customcontrollers
for more examples of event handling.
samples/com/luciad/samples/customcontrollers/RulerController
)public int onGestureEvent(TLcdGestureEvent aEvent) {
if (aEvent == null || aEvent.getMotionEvent() == null) {
return EVENT_IGNORED;
}
if (aEvent.getType() == TLcdGestureEvent.GestureType.SINGLE_TAP_CONFIRMED) {
// Add a new point to the measurement
if (fModelPolyline == null) {
fModelPolyline = TLcdShapeFactory.create2DPolyline(fModelReference);
}
try {
// Calculate where to add a new point to the measurement
ILcd2DEditablePoint viewPoint = TLcdShapeFactory.create2DPoint(ELcdCoordinateType.CARTESIAN);
viewPoint.move2D(aEvent.getMotionEvent().getX(), aEvent.getMotionEvent().getY());
ILcd3DEditablePoint worldPoint = getMapView().getViewToMapTransformation().transform(viewPoint);
fModelXYWorldTransformation.getInverseTransformation().transformSFCT(worldPoint, fTempModelPoint);
// Insert the new point in the measurement and calculate the total distance
fModelPolyline.insert2DPoint(fModelPolyline.getPointCount(), fTempModelPoint.getX(), fTempModelPoint.getY());
updateDistance(fModelPolyline, fGeodesy);
invalidate();
} catch (TLcdOutOfBoundsException e) {
// Do not add a new point to the measured polyline
}
return EVENT_HANDLED;
}
return EVENT_IGNORED;
}
7.2.2. Performing custom painting with ALcdGeoCanvas
You can use ALcdGeoCanvas
to perform custom painting in your controller, similar to its use in
ALcdFeaturePainter
. For more information, refer to Section 6.1.2, “Using ALcdGeoCanvas
for custom drawing”.
Program: Custom `ALcdController` implementation that illustrates the usage of `ALcdGeoCanvas` shows an example of custom painting using ALcdGeoCanvas
from within the controller’s onDraw
method.
ALcdController
implementation that illustrates the usage of ALcdGeoCanvas
(from samples/com/luciad/samples/customcontrollers/RulerController
)/**
* Controller that makes it possible to measure distances along a polyline.
*/
class RulerController extends ALcdController {
@Override
public void onDraw(ALcdGeoCanvas aGeoCanvas) {
ILcd2DEditablePolyline polyline = fModelPolyline;
if (polyline == null) {
return;
}
int pointCount = polyline.getPointCount();
if (pointCount > 0) {
if (pointCount > 1) {
TLcdLineStyle style = fLineType == ELcdLineType.CONSTANT_BEARING ?
fConstantBearingLineStyle :
fShortestDistanceLineStyle;
aGeoCanvas.drawShape(polyline, style);
}
for (int i = 0; i < pointCount; i++) {
aGeoCanvas.drawDrawable(polyline.getPoint(i), fPointDrawable);
}
}
}
}
Controller implementations must call |
7.2.3. Motion events pipeline
When a motion event is registered, it is sent into a pipeline to determine where it should be consumed.
The entry point for all motion events is the onTouchEvent
method in the TLcdMapView
class.
This wraps the Android MotionEvent
object in a TLcdGestureEvent
and assign the
TLcdGestureEvent.GestureType.NO_GESTURE
type to it. An event without an assigned gesture type
is a raw input event for which no specific gesture (pan, scroll, …​ ) has been identified yet.
To allow all kinds of custom controls, the incoming raw motion events are first forwarded to your custom controller.
Remember that you have to activate this controller by calling the TLcdMapView.setController()
method to receive incoming motion events.
If the incoming motion events are not consumed by your controller (EVENT_IGNORED
), they are propagated
onwards
to the Android gesture detector classes. When a specific gesture such as panning or scrolling is detected, the
GestureType
of the related TLcdGestureEvent
is updated. For consistency, the
GestureTypes
are named after their Android counterparts. Depending on the type of gesture, the
TLcdGestureEvent
can also be downcasted to a TLcdFlingGestureEvent
, TLcdPinchGestureEvent
or
TLcdScrollGestureEvent
to retrieve more information.
Once a motion event is identified as a specific gesture, it is propagated one more time to your custom controller. If
the event is not consumed by your controller, it is sent to the default controllers that are active on the
TLcdMapView
(pan, zoom, select, …​ ). This allows you to define custom controllers while still enabling the
user to zoom and move around on the map.
8. Using device sensors
Android devices may have hardware sensors, the data of which can be used as input in an application. For example, many devices are shipped with a GPS sensor that can be used to determine the current position of the device. You can use the output of the GPS sensor to mark a person’s position on a map. Another example is the compass sensor on most Android devices. You can use the output of the compass sensor to indicate the direction faced by the person holding the device.
LuciadMobile facilitates access to these sensors using the following sensor managers:
-
Location manager (
ALcdLocationManager
) -
Orientation manager (
ALcdOrientationManager
)
8.1. Location Manager
Retrieve the location manager by calling ALcdLocationManager.getInstance()
.
The recommended usage of the ALcdLocationManager
consists of registering
ILcdLocationListener
objects
that get notified of updated Location
objects. See the Android API for more details on Location
.
Program: Adding a property change listener to the location manager illustrates how to attach a custom ILcdLocationListener
(defined in
Program: A listener for use with `ALcdLocationManager`) to the location manager.
Please refer to samples.sensor.location for a complete example.
ALcdLocationManager.getInstance().addLocationListener( new LocationManagerListener() );
ALcdLocationManager
public class LocationManagerListener implements ILcdLocationListener {
@Override
public void onLocationChange( ALcdLocationManager aManager,
Location aOldLocation, Location aLocation ) {
Log.d( "Location", "(" + aLocation.getLongitude() + ", " + aLocation.getLatitude() + ")" );
}
}
8.2. Orientation Manager
Retrieve the orientation manager by calling ALcdOrientationManager.getInstance()
.
It provides two output values:
-
The azimuth of the device with respect to the magnetic north (in degrees)
-
A value indicating in which way the device is oriented. This value can be 0, 90, 180 or 270 degrees, where 0 corresponds to an upright portrait orientation.
In a similar approach as that of the location manager, it is recommended to use the ALcdOrientationManager
through ILcdOrientationListener
objects.
Program: Registering an orientation listener shows how to attach an ILcdOrientationListener
to the orientation
manager. Program: A custom orientation listener shows how the azimuth and device orientation values
are passed to the listener.
ALcdOrientationManager.getInstance().addOrientationListener( new OrientationListener() );
public class OrientationListener implements ILcdOrientationListener {
@Override
public void onDeviceOrientationChange( ALcdOrientationManager aOrientationManager ) {
Log.d( "Device", "Orientation: " + aOrientationManager.getDeviceOrientation() );
}
@Override
public void onAzimuthChange( ALcdOrientationManager aOrientationManager ) {
Log.d( "Device", "Azimuth: " + aOrientationManager.getMagneticNorth() );
}
}
Advanced topics
9. Unified access to domain objects
LuciadMobile provides a framework to access domain objects in a unified way. With this framework it is possible to access all domain objects of a LuciadMobile model, independent of their specific domain. Additionally, the framework provides information about the static structure of the domain objects as is typically provided by a UML diagram.
This chapter uses the term domain model to refer to the set of domain objects and their relationship as used in
a specific domain. A LuciadMobile model refers to an |
9.1. Introducing the framework
The com.luciad.datamodel
package defines a common
meta model that describes the static structure of the different domain models. The meta model structures
domain objects using types, each with a different set of properties.
TLcdDataType
and
TLcdDataProperty
explicitly represent types and properties as
objects at runtime, which makes the static structure of a domain model visible. The package also defines the
ILcdDataObject
interface that enables unified access to domain
objects.
The java.lang.reflect
package provides similar introspection capabilities for Java classes
and Java objects. One advantage of the com.luciad.datamodel
package is that you can use it in situations where
new data models are created at run-time. In such cases, often different types share the same instance class (typically
an implementation of ILcdDataObject
). You cannot extract all necessary type information using
Java reflection. Also, the com.luciad.datamodel
package provides these capabilities at a higher level of
abstraction, much closer to the actual data model.
A model is an abstraction of objects in the real world; a meta model is yet another abstraction, highlighting properties of the model itself. A well-known meta model is the Unified Modeling Language (UML) that is used to specify, visualize, modify, construct, and document the artifacts of an object-oriented software system. |
9.2. Getting started
9.2.1. Handling models
The elements contained in an ILcdModel
are domain objects. In case these domain objects implement
ILcdDataObject
, the model should have an ILcdModelDescriptor
that implements
ILcdDataModelDescriptor
. This interface gives
access to the data model on which the model’s elements are based.
A data model, represented using the TLcdDataModel
class, is defined
as a collection of types. A type is always declared by exactly one data model. Data models allow you to group types in
logical units, much like Java classes are grouped in packages or XML schema types are grouped in XML schema documents.
Program: Displaying all element types that are defined for a certain model shows how you can use an ILcdDataModelDescriptor
to print out all data types
that are defined for elements within a certain model. Note that this does not require iteration over the elements of the
model.
public void print( ILcdModel model ) {
if ( model.getModelDescriptor() instanceof ILcdDataModelDescriptor ) {
ILcdDataModelDescriptor desc = ( ILcdDataModelDescriptor ) model.getModelDescriptor();
for ( TLcdDataType t : desc.getDataModel().getModelElementTypes() ) {
System.out.println( t.getDataModel() + ":" + t.getName() );
}
}
}
9.2.2. Handling domain objects
The interface ILcdDataObject
is the unified representation of a
domain object. A data object holds a set of named properties. Each property contains either a simple primitive-type
value or a reference to another data object. The interface ILcdDataObject
provides methods to manipulate these
properties. A data object also provides access to its type. The type defines which properties an object can have.
Figure 11, “ILcdDataObject” shows ILcdDataObject
in a diagram.

Using ILcdDataObject
allows you to access the data stored inside a domain object. For example,
Program: Printing all properties of an object shows how you can print the values of all properties of an object on the console.
public void print( ILcdDataObject dataObject ) {
for ( TLcdDataProperty p : dataObject.getDataType().getProperties() ) {
System.out.println( p.getName() + " => " + dataObject.getValue( p ) );
}
}
To change an object, you can use ILcdDataObject
as shown in Program: Translating the data inside an object. This code snippet shows
how to translate all string typed properties for a given data object.
public void translate( ILcdDataObject dataObject ) {
for ( TLcdDataProperty p : dataObject.getDataType().getProperties() ) {
if ( p.getType() == TLcdCoreDataTypes.STRING_TYPE ) {
dataObject.setValue( p, translate( ( String ) dataObject.getValue( p ) ) );
}
}
}
Finally, you can create new instances with a TLcdDataType
.
Program: Creating instances with `TLcdDataType` shows how to create an instance for a given type. The code also sets the value of the
name
property.
TLcdDataType
public ILcdDataObject createObject( TLcdDataType type, String name ) {
ILcdDataObject result = type.newInstance();
TLcdDataProperty p = type.getProperty( "name" );
if ( p != null ) {
result.setValue( p, name );
}
return result;
}
9.2.3. Browsing type information
Given a data model, it is possible to browse for all kinds of type information. Program: Finding child types shows for example how to find all types that are declared in a given data model and that are a subtype of a given type.
public List<TLcdDataType> findSubTypes( TLcdDataModel dataModel, TLcdType type ) {
List<TLcdDataType> result = new ArrayList<TLcdDataType>();
for ( TLcdDataType t : dataModel.getDeclaredTypes() ) {
if ( type.isAssignableFrom( t ) ) {
result.add( t );
}
}
return result;
}
9.2.4. Defining a data model
You can create a data model using a TLcdDataModelBuilder
. The code in Program: Creating the data model
shows an example usage of this builder. The code creates a data model with a single type which represents a city with
position and name attributes.
private TLcdDataModel createCityDataModel() {
TLcdDataModelBuilder builder = new TLcdDataModelBuilder( "cities" );
TLcdDataTypeBuilder typeBuilder = builder.typeBuilder( "cityType" );
typeBuilder.addProperty( "position", TLcdCoreDataTypes.POINT_TYPE );
typeBuilder.addProperty( "name", TLcdCoreDataTypes.STRING_TYPE );
TLcdDataModel datamodel = builder.createDataModel();
return datamodel;
}
The code first instantiates a data model builder. Using this builder, it creates a TLcdDataTypeBuilder
, which
can be used to define a new TLcdDataType
. The data type builder, in turn, can be used to define the properties
of the data type. TLcdCoreDataTypes
defines all possible types that a property can have. When all properties
have been declared, createDataModel()
is called to construct the final TLcdDataModel
.
9.3. Explaining the meta model
Figure 12, “The meta model” shows a UML diagram of the LuciadMobile meta model. The three main classes defined by the meta model are
TLcdDataModel
, TLcdDataType
, and TLcdDataProperty
. The following sections provide more
information on each of the main classes.

9.3.1. The static model
TLcdDataModel
A TLcdDataModel
is a collection of types that forms a logical entity. As such you can compare it to a Java or
UML package or an XML schema. A data model is identified by a unique name and can have a number of dependencies. A data
model depends on another data model when domain model objects of the data model need to refer to domain model objects of
another data model. This is for instance the case when a type of the data model declares a property of a type of another
data model. This is actually the most common case of dependency. As such, these dependencies are automatically defined
by the framework. Dependencies can be cyclic.
A special kind of data model is an anonymous data model. By definition, this is a data model that has no name and declares no types. It only has dependencies. These data models are typically used as a simple way to represent a group of data models as a single data model.
TLcdDataType
A TLcdDataType
represents the type of a data object. A data type describes the structure of a data object as a
list of properties. Each of these properties themselves are of a certain type. A type always has a super type. The only
exception to this rule is the Object
type, which has no super type. A type (recursively) inherits all
properties from its super type. Note that a type cannot redefine these inherited properties, they are always inherited
as is.
A type is either a primitive type or a data object type. Primitive types are types which have no
internal structure (no properties) and typically represent simple objects such as strings,
numbers, dates, and so on. All primitive types either extend from another primitive type or directly from
the Object
type. A data object type is structured as a list of properties. All data object types either extend
from another data object type or from the DataObject
type. Instances of data object types implement
ILcdDataObject
.
Types are always defined in the context of a TLcdDataModel
. Within a certain data model, types are uniquely
defined by their name. As such, two types are equal if their data models are equal and they have the same name.
Types are mapped on Java classes. This is a many-to-one mapping; each type maps on one Java class, but different types can map on the same Java class. This class is called the type’s instance class. Instances of a type are always instances of the type’s instance class.
A type can be defined as an enumeration. This means that there are only a fixed set of possible instances. This set is
directly available from the TLcdDataType
's interface. A prime example of such a type is a type of which the
instance class is a Java enumeration.
You can create an instance of a data object
type using the newInstance
method. Note that primitive
types do not support this method.
TLcdDataProperty
A TLcdDataProperty
represents a property of a type. A property always belongs to a certain type (called
its declaring type) and also has a certain type (called its type).
A property either has a single value or multiple values. If it has a single value, the value of the property for a
certain data object is an instance of the type of the property. If the property has multiple values, the property has a
CollectionType
that defines if property values are represented as a set, a list, or a map. The values of the
property are instances of the Set
, List
or Map
interfaces of the java.util
package. The elements of these Set
and List
objects and the values of these Map
objects
are instances of the property’s type. The keys in the Map
objects are instances of the property’s map key type.
By default, a property is defined as contained. This means that, by default, the values for properties are not shared among data objects. In other words, the graph of data objects of which the types only have contained properties is a tree. Cycles are only possible if a property is not contained.
Properties which are not nullable should always have a value that is different from null
.
9.3.2. Creating data models
You create a data model using a TLcdDataModelBuilder
.
With such a builder, you create a TLcdDataTypeBuilder
for each type you need to create. With the
TLcdDataTypeBuilder
you can build a data type. When you add a property to a data type builder, a
TLcdDataPropertyBuilder
is returned. That allows you to configure the properties.
Once all types and properties are built, you can ask the TLcdDataModelBuilder
to create a data model. All types and properties are created at the same time. From that point on, the data model builder, and all type and property
builders depending on it, no longer accept any interaction and throw exceptions to indicate that the data model has
been built. This ensures that you cannot modify a data model once it has been created.
9.4. Advanced topics
Section 9.2.1, “Handling models” gives a quick introduction to the meta model and describes a simple sample. This section covers some more advanced topics.
9.4.1. Traversing an object graph
A frequently recurring pattern when dealing with data objects is traversal through the data contained in a graph of data
objects. The ILcdDataObject
interface allows you to traverse the
object graph. Program: Traversing a data object traverses an ILcdDataObject
by looking at the values
of all its properties. If the value is not null, then depending on whether the property is a map, a collection, or just
a single value, traversal continues on the value.
public void traverseDataObject( ILcdDataObject object ) {
for ( TLcdDataProperty property : object.getDataType().getProperties() ) {
Object value = object.getValue( property );
if ( value != null ) {
if ( property.getCollectionType() == null ) {
// single-valued property
traverseChild( property.getType(), value );
} else {
switch ( property.getCollectionType() ) {
case MAP:
for ( Map.Entry<Object, Object> entry : ( Map<Object, Object> ) value ) {
traverseChild( property.getMapKeyType(), entry.getKey() );
traverseChild( property.getType(), entry.getValue() );
}
break;
case LIST:
case SET:
for ( Object elem : (Collection<?>) value ) {
traverseChild( property.getType(), elem );
}
break;
}
}
}
}
}
Program: Traversing an object traverses a single object. The type of the object is passed as argument. Note that this is merely the declared type. The object itself may be of a specialized type. This is in accordance with the standard rules on polymorphism.
-
If the type is primitive, then no further (generic) introspection is possible.
-
If the type is a data object type, then the object has to be an
ILcdDataObject
and traversal can continue as shown in Program: Traversing a data object. -
Otherwise the type is
TLcdCoreDataTypes.OBJECT_TYPE
. This is an exceptional case where you do not have enough type information available. You have to examine the object that is passed as parameter. The methodtraverseObject
uses the Javainstanceof
operator to determine how to continue the traversal.
A practical example with properties of type TLcdCoreDataTypes.OBJECT_TYPE
is the modeling of a choice from XML
schema or a union from C. Both a choice and a union property can have values of different types. You can model this by
representing the choice or union by a single property. The type of that property is the common super type of the choice
or union types. In case the choice or union types contain both data object types and primitive types, this common super
type is TLcdCoreDataTypes.OBJECT_TYPE
.
public void traverseChild( TLcdDataType type, Object object ) {
if ( type.isPrimitive() ) {
traversePrimitive( object );
} else if ( type.isDataObjectType() ) {
traverseDataObject( ( ILcdDataObject ) object );
} else {
traverseObject( Object object );
}
}
public void traverseObject( Object object ) {
if ( object instanceof Map<?,?> ) {
...
} else if ( object instanceof Collection<?> ) {
for ( Object element : ( Collection<?> object ) ) {
traverseObject( element );
}
} else if ( object instanceof ILcdDataObject ) {
traverseDataObject( ( ILcdDataObject ) object );
} else {
traversePrimitive( object );
}
}
Traversal as shown in the programs above works fine for graphs of objects in which there are no cycles. This is the case for most of the supported domain models in LuciadMobile. In case of cycles, you need to add a check when a data object is traversed to see if the object has not already been traversed before.
10. Labeling domain objects
When visualizing objects on a map, you typically want to show some text with the visualized object. Labels such as these can be used to further describe or classify objects on a map. LuciadMobile comes with built-in support for decluttered text labeling. You can visualize labels for points, polylines and polygons. Label decluttering prevents that labels are visualized on top of each other, making the label text unreadable.

Section Section 10.1, “Enabling labels for your layer” describes how to enable labeling in your application. Section Section 10.2, “Styling and configuring the label” describes the labeling API in more detail and provides instructions on how to modify the style and general properties of your label. Section Section 10.3, “Advanced labeling configuration” goes into more detail about the different options for positioning a label. To see a demonstration of what is possible with the LuciadMobile API , see the Labeling sample in the LuciadMobile samples.
10.1. Enabling labels for your layer
The first step to enable labeling is calling setLabeled(true)
on the ALcdFeatureLayer
for which you want to visualize labels.
samples/com/luciad/samples/labeling/LabelingSample
)TLcdFeatureLayer layer = new TLcdFeatureLayer(aLayerName, model);
layer.setLabeled(true);
Once labeling is enabled on the layer itself, create or re-use an implementation of ALcdFeaturePainter
. By default, your painter does not show labels out of the box. To
enable labeling, override the paintLabels
method in your implementation of ALcdFeaturePainter
and add
some code. Program Program: Painting a label on the `ALcdLabelCanvas`. shows an example of how to draw labels for cities.
ALcdLabelCanvas
.@Override
public void paintLabel( ALcdLabelCanvas aCanvas, ILcdFeature aFeature, ILcdShape aShape, ALcdLayer aLayer, TLcdMapView aMapView, TLcdPaintState aState ) {
String cityName = ( String ) aFeature.getValue( "CITY" );
aCanvas.drawLabel( cityName, aShape, textStyle, labelStyle );
}
As you can see from Program: Painting a label on the `ALcdLabelCanvas`., the ALcdLabelCanvas
object is used to draw labels on a map. Using the
drawLabel
methods, you can paint a label around a point, on a path or in a path. A path can be both a polyline
or polygon. This allows you to paint a label on the edge of a polygon or a label inside the area of a polyline.
The ALcdLabelCanvas
also allows you to draw multiple labels per feature. Simply call the drawLabel
methods multiple times, but with different parameters.
10.2. Styling and configuring the label
10.2.1. Using TLcdTextStyle
to style a label
The visual style of a label is defined by a TLcdTextStyle
object.
You can use this style object to modify the text color, font, alignment and lots of other options. Program
Section 10.2.2, “Using ALcdLabelStyle
to configure the position of a label” shows the text style that is used to paint the labels for the rivers in the LuciadMobile Labeling sample.
samples/com/luciad/samples/labeling/RiverPainter
)fTextStyle = new TLcdTextStyle();
fTextStyle.setAntiAlias(true);
fTextStyle.setWithHalo(true);
fTextStyle.setTextSize(16 * density);
fTextStyle.setColor(Color.rgb(192, 229, 255));
fTextStyle.setHaloColor(Color.argb(192, 64, 64, 64));
10.2.2. Using ALcdLabelStyle
to configure the position of a label
A label style defines where a label should be placed on the map. By default, all labels are painted in a non-overlapping way. This is called decluttered labeling. Label decluttering prevents that labels are visualized on top of each other, making the labels' text unreadable.
To define how and where a label should be placed on the map, you need to take three properties into account: priority,
group and position. Program Section 10.3.2, “Drawing a label on a path” in the next section demonstrates how to set each of these properties
on an ALcdLabelStyle
object.
- Priority
-
describes how important it is that this label is drawn. Labels are rendered in priority order. This means labels with a small priority are placed before labels with a large priority. When drawing hundreds of cities on a map for example, you could use the city population to determine label priority. This ensures that only the names of big cities are shown when all cities are in view. In order to assign a larger priority to cities with a larger population, the priority should be set to the negative of the population value.
- Group name
-
can be used to create a distinction between labels that have a different semantic meaning. Labels that are painted within the same group are decluttered, while labels across different groups are not. This allows you to have different groups of decluttered labels. The only exception to this is the
ALcdLabelStyle#NON_DECLUTTERED_GROUP
group name. If this group name is used, all labels inside this group are painted on top of each other, and labels inside this group are not decluttered. This effectively disables label decluttering for all labels inside this group. - Position
-
describes the different positions at which a label can be placed, relative to the object it is linked to. If a label cannot be placed at a certain position, a different position will be tried. When painting a label around a point for example, you can choose to position the label at the north or south side of the point. Every position is expressed as a constant value (integer). To allow multiple positions, simply combine these values using a bitwise OR. Which positions you need to define depends on whether you are painting a label around a point, on a line or inside a polygon.
10.3. Advanced labeling configuration
LuciadMobile supports labels for points, polylines and polygons. Figure Figure 14, “From left to right: labeling around a point, on a path and in a path.” illustrates the three currently supported label styles.

10.3.1. Drawing a label around a point
To draw a label around a point, the ALcdLabelCanvas
provides the drawLabel
method.
This method requires a TLcdPointLabelStyle
object to
define the possible positions for the label around the point. There are nine positions available. Figure
Figure 15, “All available positions for placing a label around a point.” illustrates the different positions and program Section 10.3.2, “Drawing a label on a path” demonstrates how
to allow multiple positions for a label. When trying to position a label on the map, the application considers each
allowed position as a possible candidate for placing the label.

TLcdPointLabelStyle
. (from samples/com/luciad/samples/labeling/CityPainter
)fLabelStyle = new TLcdPointLabelStyle();
fLabelStyle.setPriority(Integer.MAX_VALUE);
fLabelStyle.setGroupName(ALcdLabelStyle.DEFAULT_GROUP);
fLabelStyle.setAllowedPositions(TLcdPointLabelStyle.NORTH_EAST | TLcdPointLabelStyle.NORTH_WEST |
TLcdPointLabelStyle.SOUTH_EAST | TLcdPointLabelStyle.SOUTH_WEST);
fLabelStyle.setPadding(4f * density);
fLabelStyle.setOffset(4f * density);
10.3.2. Drawing a label on a path
To draw a label on a line, the ALcdLabelCanvas
provides the drawLabelOnPath
method. This method
requires a TLcdOnPathLabelStyle
object to define the
position of the label. There are three positions available: above the line, below the line and centered on top of the
line.
The TLcdOnPathLabelStyle
object also has a property to modify the rotation of the labels. By default, labels
are rotated at the same angle as the path on which the label is currently placed. By using the
ELcdPathLabelRotation.NO_ROTATION
mode, you can
simply disable rotation. Program Section 10.3.3, “Drawing a label inside a path” demonstrates how to create a TLcdOnPathLabelStyle
.
Note that the ILcdShape
parameter for the ALcdLabelCanvas#drawLabelOnPath
method supports both
polylines and polygons. In the case of a polygon, the label is positioned along the edge of the polygon.
TLcdOnPathLabelStyle
. (from samples/com/luciad/samples/labeling/RiverPainter
)fLabelStyle = new TLcdOnPathLabelStyle();
fLabelStyle.setGroupName(ALcdLabelStyle.DEFAULT_GROUP);
fLabelStyle.setPosition(TLcdOnPathLabelStyle.CENTER);
fLabelStyle.setRotation(ELcdPathLabelRotation.FIXED_LINE_ANGLE);
fLabelStyle.setPadding(4f * density);
10.3.3. Drawing a label inside a path
You can draw a label inside a path using the ALcdLabelCanvas#drawLabelInPath
method. This method requires a
TLcdInPathLabelStyle
object that defines the basic
properties of the label. Currently, LuciadMobile only supports labels at the centroid of the path. As such, no specific in-path
properties have to be set.
Note that the ILcdShape
parameter for the ALcdLabelCanvas#drawLabelInPath
method supports both
polylines and polygons. In the case of a polyline, the label is positioned at the centroid of the area defined by
the closed polyline. Program Section 10.3.4, “Maintaining performance when labeling is enabled” demonstrates how to create a TLcdInPathLabelStyle
.
TLcdInPathLabelStyle
. (from samples/com/luciad/samples/labeling/StatePainter
)fLabelStyle = new TLcdInPathLabelStyle();
fLabelStyle.setGroupName(ALcdLabelStyle.DEFAULT_GROUP);
fLabelStyle.setPriority(Integer.MAX_VALUE);
float density = aContext.getResources().getDisplayMetrics().density;
fLabelStyle.setPadding(4f * density);
10.3.4. Maintaining performance when labeling is enabled
If you want to guarantee optimal performance for your application, take the following guidelines into account when you activate labeling:
-
Do not create new style objects, such as
TLcdTextStyle
orTLcdPointLabelStyle
objects, in thepaintLabel
method of your feature painter. Instead, create the required style objects once, and store them as instance variables. -
Drawing many rotated labels on a path can slow down the application. To increase performance, disable label rotation.
-
When a label is being positioned on the map, each allowed position is considered as a possible candidate for placing the label. This also means that every position is checked until a valid, non-overlapping, position is found, or each allowed position has been checked. If there are many labels, resulting in significant decluttering, the requirement to check multiple positions per label can slow down your application. You can prevent this by limiting the number of allowed positions.
11. Symbology
A symbology is a set of named symbols that can be used for visualizing icons and shapes on a map. LuciadMobile currently supports the military symbology standards APP6 and MS2525. For the list of supported symbols, see Appendix C, Supported Military Symbology.
11.1. Retrieving a symbology
You can use the ALcdSymbologyProvider
to retrieve
a specific symbology. As an alternative, you can use
ELcdMilitarySymbology
, which contains an overview of all
available military symbologies. Call the getSymbology()
method on the enumeration constant to retrieve an
ALcdSymbology
.
ALcdHierarchicalSymbology<..., ...> symbology = ELcdMilitarySymbology.APP6A.getSymbology();
You can also use a ALcdHierarchicalSymbology
object to navigate through the symbology hierarchy . Each node in the hierarchy is an
ALcdSymbologyNode
containing detailed information about the
symbol related to that node.
11.2. Visualizing a symbol
The returned ALcdSymbology
can be queried to find specific symbols, based on their code.
Depending on the type of the symbol you want to find, you call either getIconSymbol(String)
or getShapeSymbol(String)
. The
first method returns an ALcdMilitaryIconSymbol
,
which is a Drawable that can be used to render an icon at a specific position. The second method returns an
ALcdMilitaryShapeSymbol
, which is an
ALcdStyle
object that can be applied to lines and polygons.

To visualize a symbol, implement a custom ALcdFeaturePainter
and use the ALcdGeoCanvas
to draw the symbol on the screen. An ALcdMilitaryIconSymbol
only
requires an additional point to specify the position on the map where the icon should be drawn.
Program: `ALcdFeaturePainter` using a military symbology to paint points as military icons. illustrates how to render military icons using the
ALcdGeoCanvas
.
|
ALcdFeaturePainter
using a military symbology to paint points as military icons. (from samples/com/luciad/samples/symbology/MilitarySymbolsPainter
)private void paintIcon(ALcdGeoCanvas aGeoCanvas, ILcdFeature aFeature, ILcdShape aShape,
ALcdLayer aLayer, TLcdMapView aMapView, TLcdPaintState aPaintState,
String aSymbology, String aCode) {
// Query the style that is used to draw this military symbol.
ALcdMilitaryIconSymbol symbol = SymbologyUtil.getSymbology(aSymbology).getIconSymbol(aCode);
// Use the GeoCanvas to paint the military icon.
Drawable symbolWithHalo = addHalo(aPaintState, symbol);
aGeoCanvas.drawDrawable(aShape, symbolWithHalo,
symbol.getAnchorOffsetX(), symbol.getAnchorOffsetY());
}
You can visualize ALcdMilitaryShapeSymbol
instances using the same approach. Note, however, that these types
of symbols require a polygon or polyline to render.
Program: `ALcdFeaturePainter` using a military symbology to paint polygons and polylines as military shapes. illustrates how to render military shapes using
the ALcdGeoCanvas
. See the Military Symbols Sample for more information on how to retrieve and visualize
ALcdMilitaryIconSymbols
and ALcdMilitaryShapeSymbols
.
ALcdFeaturePainter
using a military symbology to paint polygons and polylines as military shapes. (from samples/com/luciad/samples/symbology/MilitarySymbolsPainter
)private void paintShape(ALcdGeoCanvas aGeoCanvas, ILcdFeature aFeature, ILcdShape aShape,
ALcdLayer aLayer, String aSymbology, String aCode) {
// Query the style that is used to draw this military symbol.
ALcdMilitaryShapeSymbol shapeStyle = SymbologyUtil.getAsMilitaryShape(aSymbology, aCode);
// Use the GeoCanvas to paint the military shape.
aGeoCanvas.drawShape(aShape, shapeStyle);
}
11.3. Rendering symbol properties
Both the ALcdMilitaryIconSymbol
instances and ALcdMilitaryShapeSymbol
instances have visualization properties that can
be queried with the help of the getProperties()
method. These properties allow you to configure the rendering
of the symbol.
11.4. Manipulating symbol properties
In the APP6 and MS2525 standards, the visualization of a symbol depends on the type of the symbol, as well as on a variety of symbol attributes. For example, a symbol can visualize an affiliation such as "Friend", "Neutral", or "Hostile", or it can show the status of an action: an action is "Planned" or "Anticipated", for example.
To query and modify the properties of a symbol, LuciadMobile offers the ALcdMilitarySymbol
class.
The javadoc of the class includes several example snippets that show how to create a new ALcdMilitarySymbol
, modify its properties and read out the
resulting symbol code.
12. Line-of-sight
12.1. Computing line-of-sight with LuciadMobile
This chapter explains how to use the LuciadMobile API to compute the line-of-sight (LOS) between a point and its environment. LuciadMobile supports viewshed, point-to-point and point-to-line LOS. Section Section 12.2, “Line-of-sight algorithm” contains more information on how the LOS is computed and what input parameters should be provided. Section Section 12.3, “Computing the line-of-sight” demonstrates how to use the LuciadMobile API to visualize the LOS computations. It also provides additional information on how to retrieve the actual values computed by the LOS algorithm.
12.2. Line-of-sight algorithm
The figure below gives an overview on how the LOS algorithm works. The algorithm starts from a specified 3D position and points a line at a certain direction, or towards a specified target. Along this line, coverage values are computed at different spatial positions on the terrain. These coverage values represent the altitude (in meters) above which something can be seen from the start position. Thus, a coverage value of zero means that this point is visible from the start position, and a value of 10m means that an object has to be 10 meters high before it is visible from the start position. The green line is composed of the entire sequence of coverage values returned by the LuciadMobile API . Note that this line is a monotonically increasing function, and that coverage values can never be negative.

The LOS computation also takes other parameters into account such as the minimum and maximum viewing angle. Both angles start from the horizontal axis, or -90° compared to the zenith. Together they form the vertical viewing angle. A classical vertical viewing angle, for example, is from -45° to 45°.

LuciadMobile lets you use this LOS algorithm in different ways. You can use it to compute a viewshed (with 360° coverage) at a specified position, to compute point-to-point LOS, or to compute LOS from a specified position towards multiple targets on a line. The following figures illustrate the results of executing these operations.

12.3. Computing the line-of-sight
The LOS API has been kept as simple as possible. To execute a LOS operation, create an
ALcdLOSOperation
that fits your purpose and call its execute(ALcdRasterTileSetModel)
method. Note that
this method requires a model containing elevation data.
The result of calling this method is an
ALcdLOSOperationResult
. This object contains the coverage values mentioned earlier. Section
Section 12.4, “Visualizing the line-of-sight” explains how to visualize these results.
You can set the accuracy of all LOS operations using the
ELcdLOSAccuracy
parameter. The accuracy offers a trade-off between performance and precision. LuciadMobile
uses the accuracy value to automatically compute the appropriate number of samples, taking into account the density of
the terrain data.
12.3.1. Computing viewshed
The TLcdLOSViewshedOperation
class allows
computing the LOS from a center point to its entire surrounding area (360° coverage). Assuming that the maximum range of
visibility is the same in every direction, this area is defined as a circular or polar coverage with the following
parameters:
-
Center position: The point around which the area is covered.
-
Center position altitude: The altitude of the center point above ellipsoid.
-
Maximum radius: The radial extent of the coverage area.
-
Start angle: The starting angle of the arc which defines the coverage area.
-
Arc angle: The angular extent of the arc which defines the coverage area.

12.3.2. Computing point-to-point and point-to-line
The TLcdLOSPoint2PointOperation
and
TLcdLOSPoint2LineOperation
classes can be
used to compute point-to-point and point-to-line LOS respectively. Both classes take a start position and a target point
or line respectively, as parameters. While the altitude of the target object is ignored, the altitude of the start
position is important and should be at least equal to, or higher than the altitude of the terrain itself.
The TLcdLOSPoint2PointOperation
class
also has a method isVisible(ILcdPoint, ILcdPoint, ALcdRasterTileSetModel
that lets you compute whether two
points are visible to each other. The result of this operation is an
ELcdLOSVisibility
object.
12.4. Visualizing the line-of-sight
The TLcdLOSLayer
allows direct visualization of
ALcdLOSOperations
. Simply call the
setOperation(ALcdLOSOperation)
method, and the layer converts the LOS results and renders it to the screen.
By default the TLcdLOSLayer
is a default LOS TLcdElevationColorMap
. To modify this color map, create a new
TLcdElevationColorMap
and set it to the
TLcdLOSLayer
by calling getStyle().setElevationColorMap()
.

It is important to realize that the used color mapping determines how to interpret the results of the LOS algorithm. Figure 21, “Top-down view of the properties of the line-of-sight coverage.” shows the results of a viewshed operation with two different types of color mapping. In one color mapping, red means decreased visibility. In another mapping, red means increased visibility.
In the left image, the red pixels represent areas that are visible from the center position, while the green pixels represent areas that are not. The colors of the pixels are determined by the coverage values. As the coverage values increase, objects have to be increasingly higher to be visible from the center. Areas with high coverage values are represented by green pixels, while areas with lower coverage values are represented by red pixels. The red color fades to green as the coverage values increase, and therefore, the visibility from the center position decreases. As a result, the colors give you an indication of an object’s visibility in a certain area. The larger the red area, the larger the area where an object or a person can be spotted from the center position.
The right image, on the other hand, uses a color map that shows visibility information about the terrain. Green pixels indicates areas of the terrain that are visible from the center position. Red pixels indicate areas that are not visible, because for example a building or a mountain is in the way. See the Terrain Analysis sample for more information.
samples/com/luciad/samples/tea/TerrainAnalysis
)TLcdElevationColorMap.Builder colorMapB = new TLcdElevationColorMap.Builder();
colorMapB.add(Double.MAX_VALUE, Color.rgb(249, 89, 89));
colorMapB.add(2.0 * Scenario.OBJECT_HEIGHT, Color.rgb(249, 89, 89));
colorMapB.add(Scenario.OBJECT_HEIGHT, Color.rgb(249, 249, 89));
colorMapB.add(0.0, Color.rgb(102, 152, 108));
fVisibilityColorMap = colorMapB.build();
TLcdElevationColorMap.Builder colorMapBuilder = new TLcdElevationColorMap.Builder();
colorMapBuilder.add(Double.MAX_VALUE, Color.rgb(102, 152, 108));
colorMapBuilder.add(20.0, Color.rgb(102, 152, 108));
colorMapBuilder.add(10.0, Color.rgb(89, 249, 89));
colorMapBuilder.add(5.0, Color.rgb(249, 249, 89));
colorMapBuilder.add(2.5, Color.rgb(227, 152, 97));
colorMapBuilder.add(0.0, Color.rgb(249, 89, 89));
fCoverageColorMap = colorMapBuilder.build();
13. Geodesy
geodesy is the scientific discipline that deals with the measurement and representation of the earth. Many mathematical models have been proposed to approximate the shape of the earth, ranging from flat-earth models to spherical approximations, ellipsoid, and geoid. Spherical and ellipsoidal approximations are used because of their mathematical simplicity. A more accurate approximation is the earth’s geoid, a hypothetical surface that coincides with the earth’s mean sea level. Although the earth’s geoid is considerably smoother than the actual surface of the earth, it is still highly irregular and therefore more difficult to represent and to use in computations. Note that there are many ellipsoid models (for example WGS84 and NAD83) and geoid models (for example EGM96 and NAVD88) in use around the world. The following sections describe what references are supported in LuciadMobile~and how they are used to perform geodesy calculations.
13.1. What is a geodetic datum?
A Section 13.1, “What is a geodetic datum?” is a reference from which position measurements are made. A horizontal datum is a known and constant surface on which the positions of points can be precisely expressed. Because of their relative simplicity, ellipsoids are often used as the basis for horizontal datums. A vertical datum is an additional vertical reference for expressing the elevation of points. It is typically based on geoid or ellipsoid models.
Geodetic datums provide a basis for coordinate reference systems. For example, a geodetic datum based on an ellipsoid model of the earth’s surface allows to define geodetic lon-lat-height coordinates. The height coordinate may for example be computed with respect to the ellipsoid on which the lon-lat coordinates are defined (ellipsoidal height), or with respect to a geoid model (orthometric height), as shown in Figure 22, “Ellipsoidal versus orthometric heights”. Geodetic datums and the coordinate systems based on them are widely used in surveying, mapping, and navigation.

There are many datums in use today, as the basis for even more coordinate reference systems. Because referencing
geodetic coordinates to the wrong datum can result in position errors of hundreds of meters, you need to be careful when
converting between coordinates defined with respect to different datums.
Geodetic datums are implicitly supported in LuciadMobile~through the various coordinate reference systems that are supported.
The API reference provides all the necessary details in the packages reference
,
transformation
, and geodesy
. There is a vast literature on geodesy
for the interested reader. Section 13.4, “Literature on geodesy” provides a few references.
13.2. Working with coordinate references
The com.luciad.reference
package provides a TLcdGeoReferenceProvider
that can be used to obtain a suitable
ALcdGeoReference
, based on an EPSG code.
Program: Obtaining a WGS84 reference from `TLcdGeoReferenceProvider`
illustrates how a WSG84 reference is obtained from the reference provider using the EPSG:4326
code
.
TLcdGeoReferenceProvider
(from samples/com/luciad/samples/common/GeoReference
)public final class GeoReference {
/**
* Creates the default reference.
* @return a reference instance
*/
public static ALcdGeoReference getDefaultGeographicReference() {
return TLcdGeoReferenceProvider.getReference("EPSG:4326");
}
public static ALcdGeoReference getDefaultProjectedReference() {
return TLcdGeoReferenceProvider.getReference("EPSG:3857");
}
private GeoReference() {
}
}
When you create a model using one of the model factories, the reference is passed as an argument. For more information about creating models, see Chapter 5, Loading data into models.
The package com.luciad.transformation
provides the factory class TLcdTransformationFactory
. It allows for the creation of
ALcdTransformation
objects that can be used to transform ILcdPoint
and ILcdBounds
objects
from a source reference to a destination reference.
13.3. Performing geodetic calculations
The com.luciad.geodesy
package provides the factory class TLcdGeodesyFactory
that allows you to obtain a Cartesian, spherical or
ellipsoidal geodesy object (ALcdGeodesy
. This object can be used to
perform geometric calculations in Cartesian space, on the sphere, or on the ellipsoid
respectively. The main methods in ALcdGeodesy
are:
-
distance
: calculates the distance between two points in meters. -
forwardAzimuth
: calculates the forward azimuth between two points in degrees. -
interpolate
: interpolate a point along the line between two other points.
You must provide a geographic reference (ALcdGeoReference
) to the geodesy factory. This reference
determines in which spatial reference system the geodesy object performs its calculations.
Program: Creating a coordinate reference and a geodesy object illustrates how a geodesy object is obtained from a given reference to perform geodetic calculations on the ellipsoid. Program: Computing the distance (in meters), forward azimuth (in degrees) and an interpolated point between two points., taken from the same sample, illustrates how the geodesy object is used to compute the total length of a polyline in meters.
samples/com/luciad/samples/geodesy/GeodesySample
)ALcdGeoReference reference = TLcdGeoReferenceProvider.getReference("EPSG:4326");
ALcdGeodesy geodesy = TLcdGeodesyFactory.createEllipsoidalGeodesy(reference);
samples/com/luciad/samples/geodesy/GeodesySample
)private void calculateValues(ILcdPolyline aPolyline) {
ILcdPoint p0 = aPolyline.getPoint(0);
ILcdPoint p1 = aPolyline.getPoint(1);
try {
fDistance = fGeodesy.distance(p0, p1, ELcdLineType.SHORTEST_DISTANCE);
fAzimuth = fGeodesy.forwardAzimuth(p0, p1, ELcdLineType.SHORTEST_DISTANCE);
fIntermediatePoint = fGeodesy.interpolate(p0, p1, 0.5, ELcdLineType.SHORTEST_DISTANCE);
} catch (TLcdOutOfBoundsException e) {
fDistance = Double.NaN;
fAzimuth = Double.NaN;
fIntermediatePoint = null;
}
}
13.4. Literature on geodesy
-
Burkehard, Geodesy for the layman, 1985 (http://www.ngs.noaa.gov/PUBS_LIB/Geodesy4Layman/toc.htm)
-
Ewing, Mitchell, Introduction to Geodesy, 1970
-
Bomford, Geodesy, 1952
Appendix A: LuciadMobile Vector Database Format
A.1. Description
The LuciadMobile Vector Database (LVDB) format is a file format that is suited for the storage of geometric shapes and their associated attributes. Geometry, attributes and spatial referencing information are all stored in a single file, which makes the LVDB format convenient for the exchange of data sets between devices.
A.2. Disk File Format
The on-disk file format used by the LVDB format is the SQLite database file format . Detailed documentation of the SQLite database file format can be found at http://sqlite.org/fileformat2.html. The SQLite C-library, which can be obtained from http://sqlite.org/, can be used to open, read and write LVDB files. To create and manage the data in the LVDB file, use either the SpatiaLite SQLite extension or LuciadMobile. Spatialite can be obtained from https://www.gaia-gis.it/fossil/libspatialite/index.
A.3. Database Structure
A.3.1. Version Number
The SQLite user version number of an LVDB file should be set to the integer value 2. Execute the statement:
PRAGMA user_version = 2;
A.3.2. Metadata Tables
LVDB contains a number of metadata tables that are used to track data and enforce data constraints. These tables can be
created by calling the InitSpatialMetadata
Spatialite function.
SELECT InitSpatialMetadata();
This function creates the set of tables listed in table Table 1, “Tables created by InitSpatialMetadata”. Each of these tables is described in more detail in the following sections.
Table | Description |
---|---|
spatial_ref_sys |
Spatial reference system definitions. |
geometry_columns |
Geometry column metadata for regular tables. |
views_geometry_columns |
Geometry column metadata for views. |
virts_geometry_columns |
Geometry column metadata for virtual tables. |
geom_cols_ref_sys |
A convenience view that joins the geometry_columns and spatial_ref_sys tables. |
geometry_columns_auth |
Not used by LVDB. |
A.3.3. Feature Tables
An LVDB database contains one or more feature tables. Feature tables are tables containing geometric objects and their associated attributes. This type of table should be created using standard SQL CREATE statements. The example below creates a cities table containing the name of each city and the population count. This table does not yet contain geometry data. Section Section A.3.4, “Geometry Columns” describes how you must add geometry data.
CREATE TABLE cities (
name VARCHAR,
population INTEGER
);
When a feature table is loaded in LuciadMobile, SQL types are mapped to Java types. The table below lists the supported SQL types and the corresponding Java type to which they are mapped. .SQL to Java type mapping
SQL Type | Java Type |
---|---|
CHAR |
String |
CHARACTER |
|
VARCHAR |
|
LONGVARCHAR |
|
VARYING CHARACTER |
|
NCHAR |
|
NATIVE CHARACTER |
|
NVARCHAR |
|
TEXT |
|
CLOB |
|
BLOB |
byte[] |
BINARY |
|
VARBINARY |
|
LONGVARBINARY |
|
BOOLEAN |
Boolean |
BIT |
|
TINYINT |
Byte |
INT2 |
Short |
SMALLINT |
|
INT |
Integer |
MEDIUMINT |
|
INT8 |
Long |
UNSIGNED BIG INT |
|
BIGINT |
|
INTEGER |
|
LONG |
|
NUMERIC |
|
DECIMAL |
|
FLOAT |
Float |
REAL |
Double |
DOUBLE |
|
DOUBLE PRECISION |
|
DATE |
Date |
DATETIME |
|
GEOMETRY |
ILcdShape |
POINT |
ILcdPoint |
POLYGON |
ILcdPolygon |
LINESTRING |
ILcdPolyline |
CIRCULARARCSTRING |
ILcdCircularArc |
LCDELLIPTICALARC |
ILcdArc |
LCDCIRCLE |
ILcdCircle |
LCDELLIPSE |
ILcdEllipse |
GEOMETRYCOLLECTION |
ILcdShapeList |
A.3.4. Geometry Columns
Columns containing geometry should not be added to a feature table in the CREATE statement. Instead, geometry
columns should be added by calling the AddGeometryColumn
Spatialite function. The AddGeometryColumn function creates a
new geometry column, updates the geometry_columns table (see below) and creates triggers in order to enforce
constraints. It has the following signature:
int AddGeometryColumn( table String, column String, srid int, geom_type String, dimension int, not_null int ) |
|
Parameter |
Description |
table |
The name of the table to add a geometry column to |
column |
The name of the column to create |
srid |
The spatial reference ID. This value is used as a foreign key to the spatial reference table (see Section A.3.5, “Spatial Reference Systems”). |
geom_type |
The geometry type. One of POINT, POLYGON, LINESTRING, CIRCULARARCSTRING, LCDELLIPTICALARC, LCDCIRCLE, LCDELLIPSE, GEOMETRYCOLLECTION or GEOMETRY. |
dimension |
The dimension of the geometry. This should always be set to 2. 3D geometry is not supported. |
not_null |
An optional parameter that sets a NOT NULL constraint on the new column if present and not zero. |
return value |
1 if successful, 0 otherwise |
The SQL program below illustrates how to create a table with a geometry column. In this example a my_features table is created with a text column called name and a POINT column called location.
CREATE TABLE my_features (
name TEXT
);
SELECT AddGeometryColumn('my_features', 'location', 4326, 'POINT', 2);
Geometry columns are tracked by the database in the geometry_columns, views_geometry_columns and virts_geometry_columns for regular tables, views and virtual tables respectively. The schema for these tables is listed below.
CREATE TABLE geometry_columns (
f_table_name TEXT NOT NULL,
f_geometry_column TEXT NOT NULL,
type TEXT NOT NULL,
coord_dimension TEXT NOT NULL,
srid INTEGER NOT NULL,
spatial_index_enabled INTEGER NOT NULL,
CONSTRAINT pk_geom_cols PRIMARY KEY (f_table_name, f_geometry_column),
CONSTRAINT fk_gc_srs FOREIGN KEY (srid) REFERENCES spatial_ref_sys (srid)
);
CREATE INDEX idx_srid_geocols ON geometry_columns (srid);
CREATE TABLE views_geometry_columns (
view_name TEXT NOT NULL,
view_geometry TEXT NOT NULL,
view_rowid TEXT NOT NULL,
f_table_name VARCHAR(256) NOT NULL,
f_geometry_column VARCHAR(256) NOT NULL,
CONSTRAINT pk_geom_cols_views PRIMARY KEY (view_name, view_geometry),
CONSTRAINT fk_views_geom_cols FOREIGN KEY (f_table_name, f_geometry_column)
REFERENCES geometry_columns (f_table_name, f_geometry_column) ON DELETE CASCADE
);
CREATE INDEX idx_viewsjoin ON views_geometry_columns (f_table_name, f_geometry_column);
CREATE TABLE virts_geometry_columns (
virt_name TEXT NOT NULL,
virt_geometry TEXT NOT NULL,
type VARCHAR(30) NOT NULL,
srid INTEGER NOT NULL,
CONSTRAINT pk_geom_cols_virts PRIMARY KEY (virt_name, virt_geometry),
CONSTRAINT fk_vgc_srid FOREIGN KEY (srid) REFERENCES spatial_ref_sys (srid)
);
CREATE INDEX idx_virtssrid ON virts_geometry_columns (srid);
The geometry_columns table should not be manipulated directly. This is done by the AddGeometryColumn
Spatialite
function. When creating a view or virtual table containing a geometry column, you must insert a new entry manually in the
views_geometry_columns or virts_geometry_columns table .
A.3.5. Spatial Reference Systems
Spatial reference systems are stored in a table called spatial_ref_sys. This table has the following schema:
CREATE TABLE spatial_ref_sys (
srid INTEGER NOT NULL PRIMARY KEY,
auth_name TEXT NOT NULL,
auth_srid INTEGER NOT NULL,
ref_sys_name TEXT,
proj4text TEXT NOT NULL,
srs_wkt TEXT
);
Table Table 3, “spatial_ref_sys columns” lists a description for each column of this table.
Column | Description |
---|---|
srid |
an integer value that uniquely identifies a spatial reference system within a single LVDB file. This value is the |
srid that should be used with the AddGeometryColumn function (see Section A.3.4, “Geometry Columns”). |
auth_name |
the name of the standard or standards body that defined this spatial reference system |
auth_srid |
the integer ID of the spatial reference system as defined by the authority specified in the |
auth_name column. |
ref_sys_name |
a human-readable description of the spatial reference system. |
proj4text |
the definition of the spatial reference system encoded as a PROJ.4 parameter string. |
srs_wkt |
the definition of the spatial reference system encoded as an OGC WKT string. |
For example, the table for the WGS 84 reference (EPSG code 4326) can contain the following data:
Column | Value |
---|---|
srid |
1 |
auth_name |
EPSG |
auth_srid |
4326 |
ref_sys_name |
WGS 84 |
proj4text |
+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs |
srs_wkt |
GEOGCS[ "WGS 84" ,DATUM[ "WGS_1984" ,SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]] ,AUTHORITY["EPSG","6326"] ] ,PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]] ,UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] |
A.3.6. Spatial Index
Spatial indexing of geometries is provided by the SQLite R*-Tree extension. The Spatialite extension should be used to create the spatial index and to ensure it is updated when geometry columns are modified.
By default a newly created geometry column does not have a spatial index. To create the spatial index you should call
the CreateSpatialIndex
Spatialite function as illustrated below. This creates the necessary R*-Tree tables and add
triggers to the table being indexed in order to keep the R*-Tree up to date.
SELECT CreateSpatialIndex('my_features', 'location');
The CreateSpatialIndex
function creates a number of tables. The main index table is called
idx_〈table name〉_〈column name〉
. This table is a virtual SQLite table, of which
the schema is equivalent to:
CREATE TABLE idx (
pkid INTEGER,
xmin REAL,
xmax REAL,
ymin REAL,
ymax REAL,
);
These columns contain the following content:
- pkid
-
the row ID of the row in the indexed table row that corresponds to this entry
- xmin
-
the minimum X coordinate of this entry
- xmax
-
the maximum X coordinate of this entry
- ymin
-
the minimum Y coordinate of this entry
- ymax
-
the maximum Y coordinate of this entry
The spatial index is not used automatically in SQL queries. Instead, use an explicit subquery to retrieve the row IDs of rows matching a spatial query. The example below uses this type of subquery to retrieve all features in the area from (0, 0) to (10, 10).
SELECT name, location FROM my_features WHERE rowid IN (
SELECT pkid FROM idx_my_features_location WHERE xmin >= 0 AND xmax <= 10 and ymin >= 0 and ymax <= 10
);
A.3.7. Style Encoding
An LVDB file can optionally contain styling information per object in the database. Style columns are tracked similarly to geometry columns. In order to use styling information, a new metadata table called style_columns should be created.
CREATE TABLE style_columns (
table_name TEXT NOT NULL,
style_column TEXT NOT NULL,
style_encoding TEXT NOT NULL,
CONSTRAINT pk_style_cols PRIMARY KEY (table_name, style_column),
);
This table tracks which columns of which tables contain styling information. If a style column has not been registered in the style_columns table, the data in the column is interpreted as plain data rather than as styling information.
Table Table 5, “Table Columns for style_columns.” lists a description for each column of this table.
Column | Description |
---|---|
table_name |
the name of the table containing a style column. |
style_column |
the name of the column in table_name that contains the style data. |
style_encoding |
the mime type describing in which the format the style column has been encoded. |
Style columns are added to a feature table as a regular column. Depending on the encoding type that is used the style column may differ in type. The section below describes concrete encodings of style information.
JSON Style Encoding
The JSON-based style encoding format requires that the style column is of type TEXT and that the style_encoding value is set to application/json. Styling information is encoded as a single JSON object containing simple key value pairs.
LVDB v1.0 and up uses nested types to support different styling states. The supported states are
-
"default"
-
"selected"
For each styling state, LVDB v1.0 and up supports the following general styling keys:
Key | Description | Default |
---|---|---|
type |
The style type. Possible values are "line" and "area" |
This key is required |
Keys applicable to the "line" type :
Key | Description | Default |
---|---|---|
stroke |
The stroke color. RGBA value encoded as a hexadecimal string |
"000000FF" (black) |
stroke-width |
The stroke line width. An integer or floating point value in pixels |
1 |
marker-start |
The arrow head for the start of the line. Possible values are "arrow" and "none" |
"none" |
marker-end |
The arrow head for the end of the line. Possible values are "arrow" and "none" |
"none" |
interpolation |
The line interpolation method. Possible values are "shortest-distance", "constant-bearing" and "quadratic-spline" |
"shortest-distance" |
Keys applicable to the "area" type :
Key | Description | mode |
---|---|---|
Possible values are "outlined", "filled" and "outlined-filled" |
"outlined-filled" |
stroke |
The stroke color. RGBA value encoded as a hexadecimal string |
"000000FF" (black) |
stroke-width |
The stroke line width. An integer or floating point value in pixels |
1 |
fill |
The fill color. RGBA value encoded as a hexadecimal string |
"FFFFFFFF" (white) |
interpolation |
{
"default":{
type: "area"
mode: "outlined-filled"
stroke: "FFFFFFFF",
stroke-width: 2.5,
fill: "FF000000"
},
"selected":{
type: "area"
mode: "outlined"
stroke: "FFFF0000",
stroke-width: 5.0,
}
}
A.3.8. Marshalled Objects
An LVDB file can optionally contain marshalled data per object in the database. Examples of marshalled data are military
symbol properties such as
TLcdMilitaryIconProperties
and
TLcdMilitaryShapeProperties
. Marshalled
columns are tracked similarly to geometry columns. In order to use marshalled data, a new metadata table called
’marshalled_columns’ should be created.
CREATE TABLE marshalled_columns (
table_name TEXT NOT NULL,
marshalled_column TEXT NOT NULL,
marshalled_encoding TEXT NOT NULL,
marshalled_type TEXT NOT NULL,
CONSTRAINT pk_style_cols PRIMARY KEY (table_name, marshalled_column),
);
This table tracks which columns of which tables contain marshalled data. If a marshalled column has not been registered in the ’marshalled_columns’ table, the data in the column will be interpreted as plain data rather than as marshalled data.
Table Table 9, “Table Columns for marshalled_columns.” lists a description for each column of this table.
Column | Description |
---|---|
table_name |
the name of the table containing a marshalled column. |
marshalled_column |
the name of the column in table_name that contains the style data. |
marshalled_encoding |
the mime type describing in which the format the style column has been encoded. |
marshalled_type |
the type of the object that was marshalled. |
Marshalled columns are added to a feature table as a regular column. Depending on the encoding type and object that is used the marshalled column may differ. The section below describes concrete encodings of marshalled objects.
Military Symbols
Both a TLcdMilitaryIconProperties
and TLcdMilitaryShapeProperties
object can be marshalled. The
encoding that is used is application/json. The marshalled_type is military_icon_properties for a
TLcdMilitaryIconProperties
and military_shape_properties for a TLcdMilitaryShapeProperties
. Both
use the same key value pairs for describing the properties of a military symbol.
Key | Description | Default |
---|---|---|
fill |
Denotes whether the military symbol is filled or not. Possible values are "true" and "false". (Only valid for military icons.) |
"true" |
icon |
Denotes whether the icon is visible or not. Possible values are "true" and "false". (Only valid for military icons.) |
"true" |
frame |
Denotes whether the symbol frame is visible or not. Possible values are "true" and "false". (Only valid for military icons.) |
"true" |
alternate |
Denotes the alternate fill color for the symbol. Encoded as a hexadecimal RGBA value. (Only valid for military icons.) |
"FFFFFF00" |
percentage |
Denotes the fill percentage of the symbol in the range [0, 1]. (Only valid for military icons.) |
1.0 |
modifier |
Properties for the symbol modifier. The value is an object compliant with the definition of the "modifier style" described in a separate table. |
affiliation |
Keys applicable to the "modifier" properties:
Key | Description | Default |
---|---|---|
fill |
Fill information for the modifier. The value is an object compliant with the definition of the "modifier fill" property. |
frame |
Frame information for the modifier. The value is an object compliant with the definition of the "modifier frame" property. |
color |
The color of the modifier. Encoded as a hexadecimal RGBA value. |
"FFFFFF00" |
enabled |
Denotes whether the modifier is enabled or not. Possible values are "true" and "false". |
Keys applicable to the "modifier fill" property and the "modifier frame" property:
Key | Description | Default |
---|---|---|
color |
The color of the modifier fill or frame. Encoded as a hexadecimal RGBA value. |
"FFFFFF00" |
enabled |
Denotes whether the modifier fill or frame is enabled or not. Possible values are "true" and "false". |
"false" |
Keys applicable to the "affiliation" properties:
Key | Description | Default |
---|---|---|
enabled |
Denotes whether affiliation colors are enabled or not. Possible values are "true" and "false". |
"true" |
pending |
The color for the affiliation "PENDING". Encoded as a hexadecimal RGBA value. |
"FFFF8800" |
unknown |
The color for the affiliation "UNKNOWN". Encoded as a hexadecimal RGBA value. |
"FFFF8800" |
assumed_friend |
The color for the affiliation "ASSUMED_FRIEND". Encoded as a hexadecimal RGBA value. |
"88FEFF00" |
friend |
The color for the affiliation "FRIEND". Encoded as a hexadecimal RGBA value. |
"88FEFF00" |
assumed_neutral |
The color for the affiliation "ASSUMED_NEUTRAL". Encoded as a hexadecimal RGBA value. |
"ABFFAB00" |
neutral |
The color for the affiliation "NEUTRAL". Encoded as a hexadecimal RGBA value. |
"ABFFAB00" |
suspect |
The color for the affiliation "SUSPECT". Encoded as a hexadecimal RGBA value. |
"FF888800" |
hostile |
The color for the affiliation "HOSTILE". Encoded as a hexadecimal RGBA value. |
"FF888800" |
exercise_pending |
The color for the affiliation "EXERCISE_PENDING". Encoded as a hexadecimal RGBA value. |
"FFFF8800" |
exercise_unknown |
The color for the affiliation "EXERCISE_UNKNOWN". Encoded as a hexadecimal RGBA value. |
"FFFF8800" |
exercise_assumed_friend |
The color for the affiliation "EXERCISE_ASSUMED_FRIEND". Encoded as a hexadecimal RGBA value. |
"88FEFF00" |
exercise_friend |
The color for the affiliation "EXERCISE_FRIEND". Encoded as a hexadecimal RGBA value. |
"88FEFF00" |
exercise_assumed_neutral |
The color for the affiliation "EXERCISE_ASSUMED_NEUTRAL". Encoded as a hexadecimal RGBA value. |
"ABFFAB00" |
exercise_neutral |
The color for the affiliation "EXERCISE_NEUTRAL". Encoded as a hexadecimal RGBA value. |
"ABFFAB00" |
joker |
The color for the affiliation "JOKER". Encoded as a hexadecimal RGBA value. |
"FF888800" |
faker |
The color for the affiliation "FAKER". Encoded as a hexadecimal RGBA value. |
"FF888800" |
A.4. Example
The SQL script below shows a complete example of an LVDB creation script. This script can be executed using the Spatialite command line shell.
PRAGMA user_version = 2;
SELECT InitSpatialMetadata();
CREATE TABLE cities (
name VARCHAR,
population INTEGER
);
SELECT AddGeometryColumn( 'cities', 'location', 4326, 'POINT', 2 );
CREATE TABLE roads (
name VARCHAR
);
SELECT AddGeometryColumn( 'roads', 'path', 4326, 'LINESTRING', 2 );
INSERT INTO cities VALUES("London", 7429200, GeomFromText("POINT(0.083 51.53)", 4326));
INSERT INTO cities VALUES("Berlin", 3387828, GeomFromText("POINT(13.42 52.50)", 4326));
INSERT INTO cities VALUES("Madrid", 3099834, GeomFromText("POINT(-3.66 40.40)", 4326));
INSERT INTO roads VALUES("London-Berlin", GeomFromText("LINESTRING(0.083 51.53, 13.42 52.50)", 4326));
INSERT INTO roads VALUES("Berlin-Madrid", GeomFromText("LINESTRING(13.42 52.50, -3.66 40.40)", 4326));
Appendix B: LuciadMobile Raster Database Format
B.1. Description
The LuciadMobile Raster Database (LRDB) format is a file format that is suited for storage of multi-level, tiled pyramids, or pyramids for short. A pyramid provides multiple levels of detail, each of which contains a regular grid of tiles. Level 0 is the least detailed, and each subsequent level doubles the numbers of rows and columns in the tile grid. The combined levels form a multiresolution tile pyramid in which one tile on level N corresponds to a block of 2x2 tiles on level N+1. The figure below illustrates this concept:

The tile grid is defined in a 2D coordinate system, either a geodetic reference or a grid reference, and its bounds are known by the pyramid. Each level covers the exact same geographic area, but does so using an increasingly larger number of tiles. If all tiles contain approximately the same amount of data, for example a 128x128 pixel image, then it is clear that the higher levels contain more detailed data than the lower levels. This principle is the key to performing efficient visualization of the tiled data.
Note that although the pyramid defines tiles as being laid out in a regular grid, it does not require that every cell in the grid is populated. In other words, pyramids can be sparse data structures, which is useful to create high resolution insets in low resolution base data, for instance.
Finally, note that the contents of the tiles are not restricted in any way by the LRDB specification. Typically, tiles in a pyramid contain data that is of a regularly gridded nature, such as imagery and terrain elevation, but theoretically they can also contain 3D representations of other types of geographic features, such as buildings, roads, or vegetation; 2D or 3D raster data such as weather data; or even non-visual data, such as textual descriptions of the area underlying the tile. LRDB version 1.0 only supports imagery data though.
B.2. Disk File Format
The on-disk file format used by the LRDB format is the SQLite database file format. Detailed documentation of the SQLite database file format can be found at http://sqlite.org/fileformat2.html. The SQLite C-library, which can be obtained from http://sqlite.org/, can be used to open, read and write LRDB files.
B.3. Database Structure
B.3.1. Version Number
The SQLite user version number of an LRDB file should be set to the integer value 1. This can be done by executing the statement:
PRAGMA user_version = 1;
B.3.2. Metadata Tables
LRDB contains a single metadata table called meta. This table stores key-value pairs that describe the raster pyramid. The meta table should be created using the following SQL script:
CREATE TABLE "meta" (
KEY TEXT UNIQUE NOT NULL PRIMARY KEY,
VALUE TEXT NOT NULL
);
Keys strings are case-insensitive. The general metadata keys and their description are listed in table Table 14, “LRDB general metadata keys”. Keys that are specific to imagery data are listed in table Table 15, “LRDB imagery metadata keys”. A complete example is shown in section Section B.3.6, “Example”.
Key | Description |
---|---|
levels |
The number of levels in the pyramid |
rows |
The number of tile rows of the least detailed level of the pyramid. |
columns |
The number of tile columns of the least detaled level of the pyramid. |
bx, by, cw, bh |
The lower left x coordinate, lower left y coordinate, width and height of the bounding box of the pyramid. |
format |
The MIME type of each individual tile. |
name |
A human readable description of this data set. |
georeference |
An encoded version of the georeference in which the bounding box and the pyramid are expressed. The value corresponding to this key must be encoded in the encoding indicated by the georeference_type value. |
georeference_name |
A human readable string describing the value corresponding to the georeference key. |
georeference_type |
The encoding that was used to encode the georeference value. One of WKT or PROJ4. If not present the default value is WKT. |
georeference_urn |
The URN corresponding to the georeference value. |
This table lists keys that are specific to imagery data:
Key | Description |
---|---|
tilew |
The width of each imagery tile in pixels. |
tileh |
The height of each imagery tile in pixels. |
format |
The imagery MIME type. For imagery data this value is restricted to either image/jpeg or image/png. |
B.3.3. Raster Tile Data
The raster tile data itself is stored in a second table called tiles. This table is created using the SQL script below.
CREATE TABLE "tiles" (
TL INTEGER NOT NULL,
TX INTEGER NOT NULL,
TY INTEGER NOT NULL,
TD BLOB,
PRIMARY KEY (TL, TX, TY)
);
Table Table 16, “tiles columns” lists a description for each column of this table.
Column | Description |
---|---|
TL |
The pyramid level of this tile. |
TX |
The tile’s X coordinate (column). |
TY |
The tile’s Y coordinate (row). |
TD |
The tile data. Tile data must be encoded in the encoding specified by the format value in the meta table. |
B.3.4. Constraints
On top of the rules outlined in earlier sections, an LRDB file must meet the following criteria in order to be valid:
-
All metadata keys should be specified and have a valid value.
-
For each tile in the tile table of which the level is not zero, the parent tile should be present. The parent tile of a tile with coordinate \((level, x, y)\) is the tile with coordinate \((level - 1, \lfloor x / 2 \rfloor, \lfloor y / 2 \rfloor)\).
-
For imagery tiles, all tiles must have the same dimension in pixels.
B.3.5. Elevation Data
Storing elevation data imposes some extra constraints to the LRDB file. First of all, the format of the LRDB file has to be changed to image/png+elevation. This means all tiles have to be encoded in PNG. To store elevation data in a PNG file and read it back out, LuciadMobile uses the following conventions:
Encoding Elevation Data
Before the elevation data can be stored in a PNG file, all elevation values are transformed to 16-bit unsigned integer values. These values are then stored in a 16-bit grayscale PNG file. The following algorithm explains how to transform elevation data to 16-bit values:
double[] elevations; // The array containing all elevation data for this tile.
double minElevation; // The minimal elevation in this tile.
double maxElevation; // The maximal elevation in this tile.
short[] imageData; // The output array to store the 16-bit grayscale pixel values in.
double doubleToUShortScale = ( 65535 - 1 ) / ( maxElevation - minElevation );
for ( int y = 0; y < height; y++ ) {
for ( int x = 0; x < width; x++ ) {
double currValue = elevations[ y * width + x ];
if ( Double.isNaN( currValue ) ) {
// No elevation data provided for this pixel.
imageData[ ( height - 1 - y ) * width + x ] = 0;
}
else {
int rawUShort = 1 + ( int ) ( ( currValue - aMinElevation ) * doubleToUShortScale + 0.5 );
imageData[ ( height - 1 - y ) * width + x ] = ( short ) Math.max( 1, Math.min( 65535, rawUShort ) );
}
}
}
Decoding Elevation Data
The PNG color data can be decoded to elevation data by applying the following algorithm:
byte[] imageByteData; // Contains the 16-bit grayscale PNG values, two bytes per pixel.
double minElevation; // The minimal elevation in this tile.
double maxElevation; // The maximal elevation in this tile.
double elevations; // The output array containing the decoded elevation data.
double uShortToDoubleScale = ( maxElevation - minElevation ) / ( 65535 - 1 );
for ( int i = 0; i < pixels; i++ ) {
short encodedElevation = imageByteData[ i * 2 ] << 8 | imageByteData[ i * 2 + 1 ]
int uShort = ( int ) encodedElevation[ i ] & 0xFFFF;
if ( uShort == 0 ) {
elevations[ i ] = Double.NaN; // No elevation data provided for this pixel.
}
else {
elevations[ i ] = minElevation + uShortToDoubleScale * ( uShort - 1 );
}
}
Encoding Elevation Metadata
Both the encoding and decoding algorithm require additional metadata such as the minimum and maximum elevation value in a tile. For this reason, every PNG file should also contain a custom PNG chunk named lmMd that stores the required metadata in a specified format.
Due to the nature of the encoding/decoding algorithm, the decoded elevation values are not guaranteed to be exactly the same as the original elevation value. Small rounding errors are possible. In some cases this might lead to unexpected results. For this reason, the metadata format offers the possibility of a lookup table. By hard-coding the real elevation value together with its encoded value, the decoder can directly convert these encoded values to their real elevation value, and skip the decoding process that could lead to a loss of precision.
The binary representation of the lmMd PNG chunk looks like this: `Version Number, Minimum Elevation, Maximum Elevation, Lookup Table Size, (Key, Value)* `
-
Version Number The version number of the metadata format. At the moment only one version exists, so this has be equal to 1. The version number is encoded as a one byte integer using network byte order.
-
Minimum Elevation The minimum elevation value in a tile. Encoded as a double precision floating point value. The value is encoded in IEEE 754 format using network byte order.
-
Maximum Elevation The maximum elevation value in a tile. Encoded as a double precision floating point value. The value is encoded in IEEE 754 format using network byte order.
-
Lookup Table Size Indicates the number of elements in the lookup table. If the lookup table is empty or should not be used, this value has to be equal to 0. The size is encoded as a 16-bit integer using network byte order.
-
Key, Value The actual contents of the lookup table. the key is equal to the encoded elevation (using the encoding algoritm mentioned before). The value is equal to the real elevation value (the value that is used as input for the encoding algorithm). While decoding a tile, the encoded elevation values can be compared to the elements in the lookup table. If a lookup value is provided, the decoded elevation value is directly known. If no lookup value is provided, the decoding algorithm is used to retrieve the elevation value. The key is encoded as a 16-bit integer, the value as a double precision floating point value (IEEE 754 format). Both are stored in network byte order. Multiple pairs of (key, value) are stored directly after each other.
B.3.6. Example
The tables below provide a complete example of the contents an LRDB file. Note that only a small portion of the tiles is shown.
Key | Value |
---|---|
LEVELS |
24 |
ROWS |
2 |
COLUMNS |
4 |
BX |
-180.0 |
BY |
-90.0 |
BW |
360.0 |
BH |
180.0 |
FORMAT |
image/jpeg |
NAME |
LA Harbour |
GEOREFERENCE |
GEOGCS["WGS_84", DATUM["WGS_1984", SPHEROID["WGS_1984",6378137.0,298.257223563], TOWGS84[0.0,0.0,0.0,0.0,0.0,0.0,0.0] ], PRIMEM["Greenwich",0.0], UNIT["Degrees",0.017453292519943295] ] |
GEOREFERENCE_TYPE |
WKT |
GEOREFERENCE_NAME |
WGS 84 |
GEOREFERENCE_URN |
urn:ogc:def:crs:EPSG::4326 |
TILEW |
256 |
TILEH |
256 |
TL | TX | TY | TD |
---|---|---|---|
0 |
0 |
1 |
|
0 |
1 |
1 |
|
1 |
1 |
2 |
|
1 |
1 |
3 |
|
1 |
2 |
2 |
|
1 |
2 |
3 |
Appendix C: Supported Military Symbology
This appendix documents the level of support for each military symbology. Each symbology supports the complete set of tactical symbols and tactical graphics.
Glossary
- Activities
-
An Android Activity is an application component that provides a screen with which users can interact in order to do something, such as dial the phone, take a photo, send an email, or view a map. Each activity is given a window in which to draw its user interface. The window typically fills the screen, but may be smaller than the screen and float on top of other windows. An application usually consists of multiple activities that are loosely bound to each other
- ADB
-
Android Debug Bridge
- Android
-
An operating system for mobile devices such as smartphones and tablet computers. It is developed by the Open Handset Alliance led by Google
- Android emulator
-
The Android SDK includes mobile device emulators, virtual mobile devices that run on your computer. The emulators let you develop and test Android applications without using a physical device.When the emulator is running, you can interact with the emulated mobile device just as you would an actual mobile device, except that you use your mouse pointer to "touch" the touchscreen and can use some keyboard keys to invoke certain keys on the device
- Antialiasing
-
antialiasing is a software technique for diminishing jaggies - stairstep-like lines that should be smooth. Jaggies occur because the output device, the monitor or printer, does not have a high enough resolution to represent a smooth line. Antialiasing reduces the prominence of jaggies by surrounding the stairsteps with intermediate shades of gray (for gray-scaling devices) or color (for color devices). Although this reduces the jagged appearance of the lines, it also makes them fuzzier
- APP6
-
Allied Procedural Publication 6 is a NATO standard for military map marking symbols. It provides common operational symbology along with details on their display and plotting to ensure the compatibility, and to the greatest extent possible, the interoperability of NATO Land Component Command, Control, Communications, Computer, and Intelligence (C4I) systems, development, operations, and training
- Azimuth
-
An azimuth is defined as a horizontal angle measured clockwise from a north base line. This north base line could be true north, magnetic north, or grid north. The azimuth is the most common military method to express direction. When using an azimuth, the point from which the azimuth originates is the center of an imaginary circle . This circle is divided into 360 degrees or 6400 mils . NORTH IS 0/360 AZIMUTH
- Bezier curves
-
Curved lines (splines) defined by mathematical formulas. Bezier curves employ at least three points to define a curve. The two endpoints of the curve are called anchor points. The other points, which define the shape of the curve, are called handles, tangent points, or nodes. Attached to each handle are two control points. By moving the handles themselves, or the control points, you can modify the shape of the curve. In vector graphics, Bezier curves are used to model smooth curves that can be scaled indefinitely
- bitmap
-
A representation, consisting of rows and columns of dots, of a graphics image in computer memory. Bit-mapped graphics are often referred to as raster graphics. The other method for representing images is known as vector graphics or object-oriented graphics. With vector graphics, images are represented as mathematical formulas that define all the shapes in the image
- bounds
-
Represents an axis-aligned bounding box
- Bounding box
-
An invisible box surrounding a graphical object and determining its size. The minimum bounding box for a point set in N dimensions is the box with the smallest measure (area, volume, or hypervolume in higher dimensions) within which all the points lie
- Cartesian
-
Cartesian coordinates provide a method of rendering graphs and indicating the positions of points on a two-dimensional (2D) surface or in three-dimensional (3D) space. The Cartesian plane consists of two perpendicular axes that cross at a central point called the origin. Positions or coordinates are determined according to the east/west and north/south displacements from the origin. The east/west axis is often called the x axis, and the north/south axis is called the y axis. For this reason, the Cartesian plane is also known as the xy-plane. Cartesian three-space, also called xyz-space, has a third axis, oriented at right angles to the xy-plane. This axis, usually called the z axis, passes through the origin of the xy-plane
- component
-
Application components are the essential building blocks of an Android application. Each component is a different point through which the system can enter your application. Not all components are actual entry points for the user and some depend on each other, but each one exists as its own entity and plays a specific role. Each one is a unique building block that helps define your application’s overall behavior
- controller
-
application component that handles user interaction
- Dalvik Debug Monitor Server
-
Android ships with a debugging tool called the Dalvik Debug Monitor Server (DDMS), which provides port-forwarding services, screen capture on the device, thread and heap information on the device, logcat, process, and radio state information, incoming call and SMS spoofing, location data spoofing, and more
- domain object
-
A separate data element that is part of a business domain and that is contained in a model
- Drawable
-
A Drawable is a general abstraction for something that can be drawn. Most often you will deal with Drawable as the type of resource retrieved for drawing things to the screen; the Android
Drawable
- ellipsoid
-
In geodesy, a reference ellipsoid is a mathematically-defined surface that approximates the geoid, the truer figure of the earth, or other planetary body. Because of their relative simplicity, reference ellipsoids are used as a preferred surface on which geodetic network computations are performed and point coordinates such as latitude, longitude, and elevation are defined
- EPSG
-
The EPSG geodetic parameter dataset is a structured repository of data required to identify coordinates through a coordinate reference system (CRS) definition, and to define transformations and conversions that allow coordinates to be changed from one CRS to another CRS. The EPSG Geodetic Parameter Dataset is maintained by the Geodesy Subcommittee of OGP
- Fragment
-
An Android Fragment represents a behavior or a portion of user interface in an Android Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running
- GeoCanvas
-
Geographical drawing component provided by the LuciadMobile class
ALcdGeoCanvas
- geodesy
-
also named geodetics, a branch of earth sciences, is the scientific discipline that deals with the measurement and representation of the earth, including its gravitational field, in a three-dimensional time-varying space. Geodesists also study geodynamical phenomena such as crustal motion, tides, and polar motion. For this they design global and national control networks, using space and terrestrial techniques while relying on datums and coordinate systems
- geodetic datum
-
A geodetic datum is a reference from which measurements are made. In surveying and geodesy, a datum is a set of reference points on the earth’s surface against which position measurements are made, and (often) an associated model of the shape of the earth (reference ellipsoid) to define a geographic coordinate system. Horizontal datums are used for describing a point on the earth’s surface, in latitude and longitude or another coordinate system. Vertical datums measure elevations or depths
- geoid
-
Essentially the figure of the earth abstracted from its topographical features. It is an idealized equilibrium surface of sea water, the mean sea level surface in the absence of currents, air pressure variations and so forth, and continued under the continental masses
- GPS
-
Global Positioning System
- GPU
-
Graphics Processing Unit
- IDE
-
Integrated Development Environment
- interpolate
-
Insert an immediate item into a series of items by estimating or calculating it from surrounding known values
- JSON
-
(JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages. These properties make JSON a good data interchange language
- KML
-
is an XML-based file format for storing and visualizing geographic data in Earth browsers. The file format was originally developed by Keyhole Inc. for use with their Earth Viewer application, which is currently known as Google Earth.
- layer
-
Container used to visually represent model data in a view
- Lifecycle
-
Android activities are managed as an activity stack. When a new activity is started, it is placed on the top of the stack and becomes the running activity — the previous activity always remains below it in the stack, and will not come to the foreground again until the new activity exits. An activity has essentially four states: active or running when it is in the foreground of the screen, paused when it has lost focus but is still visible on the screen, stopped when it is completely obscured on the screen, and finally, destroyed by the system
- MGRS
-
The Military Grid Reference System (MGRS) is a geocoordinate standard used by NATO. The MGRS is derived from the UTM and UPS grid systems, but uses a different labeling convention. The MGRS is used for the entire earth
- model
-
A container for domain objects
- MS2525
-
MIL-STD-2525 is a common warfighting symbology, and an American equivalent standard of APP6
- multiresolution
-
a multiresolution object can be described at different levels of resolution
- object graph
-
A view of an object system at a particular point in time. Whereas a normal data model such as a UML class diagram details the relationships between classes, the object graph relates their instances
- OpenCL
-
Open Computing Language is a framework for writing programs that execute across heterogeneous platforms consisting of CPUs, GPUs, and other processors. OpenCL includes a language (based on C99) for writing kernels (functions that execute on OpenCL devices), and APIs that are used to define and then control the platforms. OpenCL provides parallel computing using task-based and data-based parallelism. OpenCL gives any application access to the graphics processing unit for non-graphical computing. Thus, OpenCL extends the power of the Graphics Processing Unit beyond graphics (general-purpose computing on graphics processing units)
- OpenGL
-
A standard specification defining a cross-language, cross-platform set of rules for writing applications that produce 2D and 3D computer graphics. It is used to draw complex three-dimensional scenes from simple building blocks and is widely used in engineering, virtual reality, scientific visualization, information visualization, and flight simulation
- panning
-
Moving the map by clicking or touching it and dragging it
- polyline
-
Continuous line composed of one or more line segments
- Raw
-
Unprocessed. The term refers to data that is passed along to an I/O device without being interpreted
- RGBA
-
Red Green Blue Alpha. RGBA is a use of the RGB color model, with extra information. The color is RGB, and may belong to any RGB color space, but an integral alpha value enables alpha blending and alpha compositing. The alpha channel is normally used as an opacity channel
- Service
-
An Android Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC)
- Shape
-
A geometrical object with a bounding box and a focus (or center) point
- Snapping
-
Snapping layer objects into position pulls the objects to one another or to ruler subdivisions, grid lines, guides, or guide points so that you can control the placement and alignment of the objects
- SpatiaLite
-
SpatiaLite is a small-sized SQLite extension. It allows the SQLite DBMS to load, store and manipulate spatial data, such as geographic data, geospatial and geometry data. SpatiaLite implements spatial extensions following the specification of the Open Geospatial Consortium (OGC). A DBMS that supports spatial data offers an SQL environment that has been extended with a set of geometry types. A geometry-valued SQL column is implemented as a column that has a geometry type. The OGC specification describe a set of SQL geometry types, as well as functions on those types to create and analyze geometry values
- SQLite
-
SQLite is an in-process library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine. The code for SQLite is in the public domain and is thus free for use for any purpose, commercial or private. SQLite is an embedded SQL database engine. Unlike most other SQL databases, it does not have a separate server process. SQLite reads and writes directly to ordinary disk files. A complete SQL database with multiple tables, indices, triggers, and views, is contained in a single disk file. The database file format is cross-platform. SQLite is a compact library. With all features enabled, the library size can be less than 300KiB, depending on compiler optimization settings. If optional features are omitted, the size of the SQLite library can be reduced below 180KiB
- UPS
-
The Universal Polar Stereographic (UPS) grid system is similar to the UTM grid system, except that only two grid zones are used in each polar region: Y and Z in the north polar region, and A and B in the south polar region
- UTM
-
The Universal Transverse Mercator (UTM) geographic coordinate system is a grid-based method of specifying locations on the surface of the earth that is a practical application of a 2-dimensional Cartesian coordinate system. It was developed by the United States Army. The UTM system divides the surface of the earth between 80°S and 84°N latitude into 60 zones, each 6° of longitude in width, and centered over a meridian of longitude
- vector features
-
A representation of a geometrical shape and its attributes
- vertex
-
a vertex (plural vertices) is a special kind of point that describes the corners or intersections of geometric shapes. Vertices are commonly used in computer graphics to define the corners of surfaces (typically triangles) in 3D models, where each such point is given as a vector
- view
-
Visual representation of model data
- virtual device
-
The Android SDK includes mobile device emulators, virtual mobile devices that run on your computer. They let you develop and test Android applications without using a physical device. When the emulator is running, you can interact with the emulated mobile device just as you would an actual mobile device, except that you use your mouse pointer to "touch" the touchscreen and can use some keyboard keys to invoke certain keys on the device
- WGS
-
The World Geodetic System is a standard for use in cartography, geodesy, and navigation. It comprises a standard coordinate frame for the earth, a standard spheroidal reference surface (the datum or reference ellipsoid) for raw altitude data, and a gravitational equipotential surface (the geoid) that defines the nominal sea level.The latest revision is WGS 84 (dating from 1984 and last revised in 2004), which will be valid up to about 2010. WGS 84 is the reference coordinate system used by the Global Positioning System
- Shader
-
A set of software instructions that is used primarily to calculate rendering effects on graphics hardware with a high degree of flexibility. Shaders are used to program the graphics processing unit (GPU) programmable rendering pipeline, which has mostly superseded the fixed-function pipeline that allowed only common geometry transformation and pixel-shading functions. With shaders, customized effects can be used