SDK for iOS Developer's Guide

Objects and Interaction

HERE SDK allows the addition of a variety of objects, each with a specific purpose, to a map view. The types of available object include map markers, routes, polylines, and overlays. These objects are described in more detail below.

Map Objects Example on GitHub

You can find an example that demonstrates this feature at https://github.com/heremaps/ (Obj-C) and https://github.com/heremaps/ (Swift).

NMAMapObject Class

NMAMapObject class provides a generic base class from which most types of specialized map object are inherited. Functionality common to all these object types is encapsulated in NMAMapObject. The following is a list of important properties and methods in NMAMapObject.

  • zIndex - determines the objects stacking order, which controls how the object is displayed on the map relative to other objects that may overlap it
  • visible - determines whether or not the object is drawn when the map is rendered
  • type - contains the type of map object such as marker, polyline, and route. For the full list see the NMAMapObject API reference
  • parent - the NMAMapContainer instance holding this object, if any
  • mapLayerType - NMAMapLayerType representing the display layer where this map object is rendered. By default map objects are assigned to the foreground
  • uniqueId - uniquely identifies the object for the duration of application launch
Note:
  • NMAMapObject serves as a base class to other map object types and should not be instantiated directly.
  • Any change in a map object visual appearance causes the entire map view to be redrawn since map objects are drawn as part of the map itself. For optimal performance map objects should not be frequently updated unless it is necessary.
  • If an NMAMapObject is assigned with an NMAGeoCoordinates object that contains a positive altitude value, then this map object is rendered as floating above the map. Since map objects are always rendered as facing the camera, it may not be obvious to the user that an object is floating until the map is tilted. When a map is tilted, map objects with high altitude values may become hard to locate. For the best results always set the altitude to 0 or a low positive value.

NMAMapContainer class

Map containers are a special type of map object that can be used to group together other map objects of certain types. The types of objects allowed are NMAMapMarker, NMAMapCircle, NMAMapPolygon, and NMAMapPolyline. Containers provide a convenient way to control the stacking order and visibility of a large group of objects.

To use a map container, create one or more map objects and add them to the container using addMapObject method. To show the objects on a map, add the map container to the map with addMapObject method of NMAMapView.

Note: A container may also hold other instances of NMAMapContainer.

NMAMapCircle class

NMAMapCircle class is used to draw a circle on the map at a fixed geographical location; custom border and fill colors may be defined.

Figure 1. A MapCircle object

NMAMapPolyline class

NMAMapPolyline class is used to draw one or more connected line segments on the map. The segment vertices are specified by a series of NMAGeoCoordinates. The visual appearance of the polyline can be customized.

Figure 2. A MapPolyline object

NMAMapPolygon interface

NMAMapPolygon class is similar to NMAMapPolyline but the first and last points of the line are automatically joined to create a closed shape. Polygon objects can have different border and fill colors.

Figure 3. A MapPolygon object with transparent fill and a border
Note: Polygons that have a path that crosses over itself are not supported. For example, it is not possible to create a "bowtie" shape using four line segments where one line segment crosses another. However, you can create the shape using two triangles.

NMAMapMarker class

NMAMapMarker class is used to display a custom icon at a fixed geographical position on the map.

Custom icons can be one of the following file formats:
  • BMP
  • SVG
  • JPEG
  • PNG
Please see the NMAImage API Reference for more information on working with these file formats.
Figure 4. An NMAMapMarker object

You can set NMAMapMarker to be draggable by setting draggable property to YES. To listen for drag events, such as marker position changes, use respondToEvents:withBlock: method in NMAMapView.

NMAMapLocalModel

NMAMapLocalModel is an arbitrary 3D map object that is drawn using a local coordinate (as opposed to a geocoordinate) mesh. You can create a custom NMAMapLocalModel by setting the model mesh, texture, and geographical location before adding it to the map. For example:


NMAFloatMesh *mesh = [[NMAFloatMesh alloc] init];
float size = 40.f;
float vertices[6 * 3] = {0.0f,  0.0f,   0.0f,
  -size,  -size,  2 * size,
  size,   -size,  2 * size,
  size,   size,   2 * size,
  -size,  size,   2 * size,
  0.0f,   0.0f,   4 * size};
[mesh setVertices:vertices withCount:6];
float textureCoordinates[6 * 2] = {0.5,   0.5,
  0.5,   1,
  1,   0.5,
  0.5,   0,
  0,   0.5,
  0.5,   0.5};
[mesh setTextureCoordinates:textureCoordinates withCount:6];
short triangles[8 * 3] = {0, 2, 1,
  0, 3, 2,
  0, 4, 3,
  0, 1, 4,
  5, 1, 2,
  5, 2, 3,
  5, 3, 4,
  5, 4, 1};
[mesh setTriangles:triangles withCount:8];
NMAMapLocalModel* _diamond = [[NMAMapLocalModel alloc] initWithMesh:mesh];
NMAImage *image = [NMAImage imageWithUIImage:[UIImage imageNamed:@"flag.png"]];
[_diamond setTexture:image];
[_diamond setCoordinates:geoCoordCenter];
[self.mapView addMapObject:_diamond];

While translating the 3D model mesh to the map a unit of 1.0f represents 1 meter in the real world. For example, a set of vertices in {100, 200, 300} represents an offset of +100 meters in the x-axis (East), +200 meters in the y-axis (North), and +300 meters in the z-axis direction (Up). You can further control the size of the 3D model mesh by setting a scaling factor with scale property.

Figure 5. An NMAMapLocalModel object

Aside from setting a texture, an NMAMapLocalModel can also be customized by adding a directional light. For example, the following code sets a light source to the NMAMapLocalModel.

NMAVector3d vec3d;
vec3d.x = 0.f; vec3d.y = 0.5f; vec3d.z = -1.f;

// This light shines from above in the Z axis
NMADirectionalLight* light = [NMADirectionalLight lightWithDirection:vec3d];
// assume 'model' is an NMAMapLocalModel that is already on the map
[model addLight:light];
Note:
  • As 3D objects consume large amounts of memory, avoid using NMAMapLocalModel and NMAMapGeoModel to replace 2D map markers. Two examples of recommended uses of these classes are adding a few 3D structures to the map, or showing a realistic car model during guidance.
  • If you use NMAMapLocalModel to create a two-dimensional object, and if you use an anchor with an undefined or zero altitude value, there is a known rendering issue with OpenGL where parts of the object may conflict with the map layer causing the object to flicker. To get around this issue, use a z-coordinate offset that is greater than 0. For example, you can use a small floating point number such as 0.001, so that the user is unable to distinguish between the object altitude and the map.

NMAMapGeoModel

NMAMapGeoModel is an arbitrary 3D map object that is drawn using geocoordinate vertices. You can create an NMAMapGeoModel by using an NMAGeoMesh and a texture NMAImage. For example:


NMAGeoMesh *geoMesh = [[NMAGeoMesh alloc] init];

double vertices[5 * 3] =
  {   -123.133392, 49.265275, 0,
    -123.127813, 49.265275, 0,
    -123.133392, 49.261803, 0,
    -123.127813, 49.261803, 0,
    -123.130903, 49.263931, 1250
  };
[geoMesh setVertices:vertices withCount:5];

float textureCoordinates[5 * 2] =
{   0.0, 0.0,
  1.0, 0.0,
  0.0, 1.0,
  1.0, 1.0,
  0.5, 0.5
};
[geoMesh setTextureCoordinates:textureCoordinates withCount:5];

short triangles[4 * 3] =
{
  0, 4, 1,
  2, 3, 4,
  0, 2, 4,
  1, 4, 3};

[geoMesh setTriangles:triangles withCount:4];

NMAMapGeoModel* _textureOverArea =
  [[NMAMapGeoModel alloc] initWithMesh:geoMesh];
NMAImage *image =
  [NMAImage imageWithUIImage:[UIImage imageNamed:@"flag.png"]];
[_textureOverArea setTexture:image];

[self.mapView addMapObject:_textureOverArea];
Note: As with NMAMapLocalModel, you can set the lighting for an NMAMapGeoModel using addLight: method.
Figure 6. An NMAMapGeoModel object

Map Object Selection

All user-defined objects with a visual representation can be selected. Selection occurs when a visible object on the map is tapped. By default the map does not take any action when objects are selected. To implement selection handling, a custom class must implement the NMAMapViewDelegate protocol and its onMapObjectsSelected method. An instance of the class must then be installed as a map view observer through addMapViewObserver method. onMapObjectsSelected callback returns an array that contains instances of NMAViewObject, which is a superclass of NMAMapObject.

Object selection can also be programmatically invoked by using objectsAtPoint: or visibleObjectsAtPoint: method. Each of these methods takes a CGPoint screen coordinate and returns an NSArray of NMAMapObject at that location. visibleObjectsAtPoint method does not return any object that has visible property set as NO.

For more information see the NMAMapView API documentation.

Note: In addition to user-defined objects, certain types of internal map objects are also selectable. See Proxy Objects section for more details.

NMAMapOverlay Class

NMAMapOverlay class represents a special type of map object that does not inherit from NMAMapObject base class. Instead, it inherits from UIView class of Apple UIKit framework. Thus, it provides a way for any UIView or UIView subclass to be displayed at a fixed geographical location on the map.

For example, the following code shows how to use a UILabel on a map:


/*
 * 'location' is a CGPoint on screen
 * 'mapView' is an NMAMapView object
 */
NMAGeoCoordinates *coords = [mapView geoCoordinatesFromPoint:location];

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.textColor = [UIColor redColor];
label.text = @"overlay";
label.textAlignment = NSTextAlignmentCenter;
label.backgroundColor = [UIColor whiteColor];
label.layer.borderWidth = 2;
label.layer.borderColor = [UIColor redColor].CGColor;

label.frame = CGRectMake(0, 0, 70, 30);

NMAMapOverlay *overlay = [NMAMapOverlay mapOverlayWithSubview:label geoCoordinates:coords];

[mapView addMapOverlay:overlay];
Figure 7. Example of Map Overlay

Content can be added to a map overlay in the same manner as a normal UIView, with addSubview method. If complex view content is required, such as a view with subviews of its own, the content should be fully initialized before adding it to the map overlay.

Due to the extra performance cost of UIViews it is recommended that NMAMapOverlay only be used in situations where the additional functionality provided by UIView, such as animation, is needed. If the map object only needs to display a static image, NMAMapMarker should be used.

Note:
  • NMAMapOverlay does not inherit from NMAMapObject, and thus overlays are not selected from a tap gesture by default. To achieve this behavior, the appropriate gesture handling must be implemented either in an NMAMapOverlay subclass, or in a custom view that is added as a subview to a standard NMAMapOverlay. For more information see Map Gestures.
  • The geometry properties of NMAMapOverlay inherited from UIView, such as center and frame, should not be modified directly.

Proxy Objects

Some objects are added to the map by the system to represent real-world information such as traffic events, public transportation, or points of interest. These objects cannot be modified but many can be selected. All proxy objects are subclasses of NMAProxyObject which shares NMAViewObject class ancestor with NMAMapObject.

NMAPoiObject

Points of interest are represented by instances of NMAPoiObject proxy object class.

Figure 8. Examples of Points of Interest

In the above screenshot there are four points of interests: two shops, one restaurant, and one car dealership. Each of these points of interest may be selected by either tapping on the map, which returns the objects from mapView:didSelectObjects: callback method in NMAMapViewDelegate, or by calling objectsAtPoint: method in NMAMapView.

The following is an example of how to retrieve point of interest information from a tapped NMAPoiObject:


-(void)mapView:(NMAMapView *)mapView didSelectObjects:(NSArray *)objects
{
  for(NMAViewObject *object in objects) {
    if ([object isKindOfClass:[NMAPoiObject class]]){
      NMAPoiObject *poiObject = (NMAPoiObject*) object;
      NSString* placeName =
        [poiObject.locationInfo valueForField:NMALocationInfoFieldPlaceName];
      NSString* placeCategory =
        [poiObject.locationInfo valueForField:NMALocationInfoFieldPlaceCategory];
      NSString* placePhoneNUmber =
        [poiObject.locationInfo valueForField:NMALocationInfoFieldPlacePhoneNumber];
    }
  }
}