# Developer’s Guide

## 1. Introduction

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.

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 instance `com.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

1. Unzip `LuciadMobile_Pro.zip` . A `LuciadMobile_x.x.x` directory is automatically created for you.

2. Unzip `LuciadMobile_Pro_Documentation.zip` and `LuciadMobile_Pro_Data.zip`. If your ZIP program creates an additional `LuciadMobile_x.x.x 2` directory, manually copy the contents in this directory into the `LuciadMobile_x.x.x` directory.

3. Copy the developer license file (`luciadmobile_development.txt`) to the `LuciadMobile_x.x.x/samples/assets` folder.

4. 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 `adb` commands, see the Android developer documentation. You may also find the Android Debug Monitor tool included with the Android SDK useful, as it lets you explore and manage the files on a device from a GUI.

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:

Program: Installing an APK
``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:

Program: Copying files to your device
``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`.

Program: Creating a LuciadMobile 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.

Program: Creating a map view
``````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.

Program: Creating a model with `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.

Program: Adding a raster layer to the map view
``````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 );
}
}``````

The application now displays a raster image of the Earth, as shown in Figure 1, “A basic application”.

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.

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 an `ILcdDataObjectCursor` with `Cursor` methods such as `isFirst()`, `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 are `null`, 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.

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`.

Program: Creating a model by loading an LVDB file
``````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 larger imagery from a GeoPackage file or LuciadMobile Raster Database (LRDB)

• Loading large raster data via a live connection to a LuciadFusion server

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()` :

Program: Creating a model from a raw bitmap resource (from `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.

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.

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.

Program: Loading LRDB data from local storage.
``````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. .

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.

Program: Creating a model from DTED data
``````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.

Program: Creating a custom data type by extending `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);

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 `ILcdShape` and `ALcdFeatureModel`. Even though there are no concrete classes implementing or extending from these, developers do not typically have to provide their own implementations. Factory classes are provided in the API such as `TLcdShapeFactory` and `TLcdVolatileFeatureModelFactory` that can create the appropriate instances.

## 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`.

Figure 2. `ALcdLayer` and its derived classes

The 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`.

 `Drawable` objects can paint both bitmap and vector features. Performance can become an issue for vector Drawables when large point sets are being displayed. If performance is compromised, consider converting the vector Drawable to a bitmap Drawable.
Figure 3. `TLcdFeatureLayer` paints points using Drawables

Program: 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”).

Program: Configuring a `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.getPaint().setColor(aColor);
return BitmapUtil.convertToBitmapDrawable(getResources(), drawable);
}
}``````
 When you paint a `Drawable`, its width and height are set to its intrinsic width and height. It is therefore important to only use Drawables that have a positive intrinsic width and height.

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.

Program: `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.

Program: Defining polygon and polyline styling for a `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;
}
}``````

.

Figure 4. `TLcdBasicFeaturePainter` styles polygons and polylines using `TLcdAreaStyle` and `TLcdLineStyle` objects
 `TLcdAreaStyle` can be configured with a `ELcdLineInterpolation` mode that allows you to paint polylines and polygons as smooth quadratic Bezier curves. It also uses `TLcdLineMarker` to add decorations to the start and end of a polyline. Currently, only arrow markers are supported.

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.

Program: Using the `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;
}
}``````
Figure 5. Custom `ALcdFeaturePainter` implementation that performs specialized drawing on an `ALcdGeoCanvas`
 `TLcdPaintState` specifies whether your painter should paint default objects, or selected objects. You can adapt the styling based on this parameter.

#### 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.

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 the `ALcdDataLoadingStrategy` class.

• Set the created strategy on the layer by calling `setDataLoadingStrategy` on `ALcdFeatureLayer`.

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”).

Program: Creating a `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`.

Figure 6. A `TLcdRasterTileSetLayer` displaying high-resolution imagery in the Los Angeles region

#### 6.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.

Program: Creating a `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);

// 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);
Figure 7. A latitude/longitude grid.

#### 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.

Program: Creating an MGRS grid. (from `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);
Figure 8. An MGRS grid

### 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.

Program: Decoding local KML data and adding it to a `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`.

Program: Using `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.
Figure 9. Graphically editing an arrow shape
##### 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`.

Figure 10. Custom Unit Type action added to the Edit dialog of a `TLcdFeatureLayer`.

#### 7.1.3. Deleting vector features

You can delete vector features by removing them from their container model. As a convenience, LuciadMobile provides the `TLcdDeleteObjectAction` class which does exactly that.

### 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.

Program: Handling a gesture event. (from `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.

Program: Custom `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 `ALcdController.invalidate()` whenever the previously painted information becomes outdated. This serves as a signal that the controller wishes to redraw its contents, and ensures that `ALcdController.onDraw(ALcdGeoCanvas)` is called during the next map repaint. Otherwise, there is no guarantee that the `onDraw` method will be invoked.

#### 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.

Program: Adding a property change listener to the location manager
``ALcdLocationManager.getInstance().addLocationListener( new LocationManagerListener() );``
Program: A listener for use with `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.

Program: Registering an orientation listener
``ALcdOrientationManager.getInstance().addOrientationListener( new OrientationListener() );``
Program: A custom orientation listener
``````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() );
}

}``````

## 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 `ILcdModel`, the container for a set of domain objects as described in Chapter 5, Loading data into models.

### 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.

Program: Displaying all element types that are defined for a certain 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.

Figure 11. ILcdDataObject

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.

Program: Printing all properties of an object
``````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.

Program: Translating the data inside an 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.

Program: Creating instances with `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.

Program: Finding child types
``````public List<TLcdDataType> findSubTypes( TLcdDataModel dataModel, TLcdType type ) {
List<TLcdDataType> result = new ArrayList<TLcdDataType>();
for ( TLcdDataType t : dataModel.getDeclaredTypes() ) {
if ( type.isAssignableFrom( 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.

Program: Creating the data model
``````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.

Figure 12. The meta model

#### 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.

Program: Traversing a data object
``````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 method `traverseObject` uses the Java `instanceof` 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`.

Program: Traversing an object
``````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.

Figure 13. The Labeling Sample demonstrates how to draw labels for points, polylines and polygons.

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.

Program: Enabling labels for your layer. (from `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.

Program: Painting a label on the `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.

Program: Example text style for rendering labels. (from `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.

Figure 14. From left to right: labeling around a point, on a path and in a path.

#### 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.

Figure 15. All available positions for placing a label around a point.
Program: Setting label properties on a `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.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.

Program: Setting label properties on a `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);

#### 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`.

Program: Setting label properties on a `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;

#### 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` or `TLcdPointLabelStyle` objects, in the `paintLabel` 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`.

Program: Retrieving a military symbology.
``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.

Figure 16. The Military Symbols Sample demonstrates a few of the military symbols that are available.

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`.

 `ALcdMilitaryIconSymbol` instances are resolution-independent vector representations of an icon. When passed directly to `ALcdGeoCanvas#drawDrawable`, the icon is converted to pixels each frame. This can have a considerable performance cost. To resolve this issue, your `ALcdFeaturePainter` implementation should render the `ALcdMilitaryIconSymbol` to a `Bitmap` and draw the feature using this bitmap instead.
Program: `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`.

Program: `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.

Figure 17. A line-of-sight algorithm result.

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°.

Figure 18. The vertical viewing angle.

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.

Figure 19. From left to right: viewshed, point-to-point and point-to-line.

### 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.

Figure 20. Top-down view of the properties of the line-of-sight coverage.

#### 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()`.

Figure 21. Top-down view of the properties of the line-of-sight coverage.

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.

Program: Different color maps can lead to different interpretations for the line-of-sight. (from `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.

Figure 22. Ellipsoidal versus orthometric heights

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 .

Program: Obtaining a WGS84 reference from `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.

Program: Creating a coordinate reference and a geodesy object (from `samples/com/luciad/samples/geodesy/GeodesySample`)
``````ALcdGeoReference reference = TLcdGeoReferenceProvider.getReference("EPSG:4326");
ALcdGeodesy geodesy = TLcdGeodesyFactory.createEllipsoidalGeodesy(reference);``````
Program: Computing the distance (in meters), forward azimuth (in degrees) and an interpolated point between two points. (from `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;
}
}``````

## 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:

Program: Setting the version number
`` 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.

Program: Creating metadata tables
``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 1. Tables created by InitSpatialMetadata
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.

Program: Creating a simple feature table
``````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.

Program: Creating a table with geometry data
``````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.

Program: geometry_columns schema
``````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);``````
Program: views_geometry_columns schema
``````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);``````
Program: virts_geometry_columns schema
``````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:

Program: spatial_ref_sys 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.

Table 3. spatial_ref_sys columns
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:

Table 4. spatial_ref_sys contents for EPSG:4326
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.

Program: Creating a spatial index
``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:

Program: Spatial index schema
``````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).

Program: Querying via the spatial index
``````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.

Program: style_columns schema
``````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.

Table 5. Table Columns for style_columns.
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:

Table 6. General styling attributes
Key Description Default

type

The style type. Possible values are "line" and "area"

This key is required

Keys applicable to the "line" type :

Table 7. Line styling attributes
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 :

Table 8. Area styling attributes
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

Program: Example style value
``````{
"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.

Program: marshalled_columns schema
``````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.

Table 9. Table Columns for marshalled_columns.
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.

Table 10. Military symbol styling attributes
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:

Table 11. Modifier attributes
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:

Table 12. Modifier fill attributes
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:

Table 13. Modifier attributes
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.

Program: Creating an LVDB file
``````PRAGMA user_version = 2;

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:

Figure 23. Detail levels in a pyramid

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:

Program: Setting the version number
`` 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:

Program: Creating metadata tables
``````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”.

Table 14. LRDB general metadata keys
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:

Table 15. LRDB imagery metadata keys
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.

Program: Creating the tile tables
``````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.

Table 16. tiles columns
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:

Program: Encoding elevation data
``````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:

Program: Decoding elevation data
``````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.

Table 17. Example meta table contents
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

Table 18. Example tiles table contents
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.

fully supported

fully supported

fully supported

fully supported

fully supported

fully supported

fully supported

fully supported

fully supported

fully supported

## 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

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

also called contextual, shortcut, and popup or pop-up menu. A menu in a graphical user interface (GUI) that appears upon user interaction. A context menu offers a limited set of choices that are available in the current state, or context, of the operating system or application. Usually the available choices are actions related to the selected object

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