Why do it?

When you visualize a geometry containing lines, such as a polyline or a polygon, LuciadRIA by default draws lines that have a constant width expressed in pixels. The width of those lines does not change when the map user zooms in or out, or when the map represents a 3D scene with perspective.

This article describes a number of guidelines you can follow to draw lines using world units that represent the actual size of real-world objects, such as meters or feet. As a result, the line width will adapt to a 3D perspective, or when users zoom in or out of the map.

How to do it?

When you draw your geometries, you can apply a style that identifies a unit of measure. You can choose between two styling approaches:

  1. Use the uom property in the styling API.

  2. Use a Symbology Encoding (SE) stylesheet, an XML format that conforms with the OGC Symbology Encoding specification. It specifies a unit of measure for symbolizers.

Using the Styling API

Applying unit of measure in the LineStyle API

The LineStyle API contains the unit of measure uom property that determines the interpretation for properties that express a size.

You can retrieve supported unit of measure values in this way:

  • UnitOfMeasureRegistry.getUnitOfMeasure("Pixels")

  • UnitOfMeasure of type QuantityKindRegistry.getQuantityKind("Length"), for example UnitOfMeasureRegistry.getUnitOfMeasure("Meter") or UnitOfMeasureRegistry.getUnitOfMeasure("Foot") This code shows how to style features as a dashed line with a width of 10 meters, consisting of dash segments of a length of 30 meters, gap segments of 15 meters, and an arrow marker with the head size of 80 meters.

var painter = new FeaturePainter();
painter.paintBody = function(geocanvas, feature, shape, layer, map, paintState) {
  geocanvas.drawShape(shape, {
    stroke: {
      color: "green",
      width: 10,
      uom: UnitOfMeasureRegistry.getUnitOfMeasure("Meter"),
      dash: [30, 15],
      endMarker: {
        size: 80
      }
    }
  });
};

The result is:

scaledLine

Applying unit of measure in the BorderStyle API

Similarly, the BorderStyle API contains an uom property to identify the unit of measure for borders of closed shapes.

This code paints a closed shape with an inner border with a width of 100 feet, an outer border with a width of 20 feet, and an outline with a width of 1 pixel:

var UOM_FOOT = UnitOfMeasureRegistry.getUnitOfMeasure("Foot");
geocanvas.drawShape(shape, {
  stroke: {
    color: "red",
    width: 1
  },
  innerBorder: {
    color: "rgba(0,255,0,0.5)",
    uom: UOM_FOOT,
    width: 100
  },
  outerBorder: {
    color: "rgba(255,255,0,0.5)",
    uom: UOM_FOOT,
    width: 20
  }
});
[source, javascript, linenums,indent=0]

The result of painting a circle with borders expressed in world units is:

scaledBorder

Using The Symbology Encoding Painter

LuciadRIA reads the optional gml:uom attribute included in LineSymbolizer and PolygonSymbolizer elements in XML Symbology Encoding stylesheets.

This unit of measure value applies to all elements included in a Symbolizer to style lines and outlines of closed shapes. If no unit of measure is set inside of Symbolizer, all units are measured in pixels.

This is an example of an SE style definition that paints a Polyline shape with repeated image icons. The size of the icons is expressed in meters. The Icons are displaced vertically from the center of the line by a distance that is also expressed in meters. The gap distances between the images and the stroke width are measured in meters as well.

<?xml version='1.0' encoding='UTF-8'?>
<FeatureTypeStyle xmlns="http://www.opengis.net/se" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ogc http://schemas.opengis.net/filter/1.1.0/filter.xsd http://www.w3.org/2001/XMLSchema http://www.w3.org/2001/XMLSchema.xsd http://www.opengis.net/se http://schemas.opengis.net/se/1.1.0/FeatureStyle.xsd http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/base/gml.xsd http://www.w3.org/1999/xlink http://www.w3.org/1999/xlink.xsd " version="1.1.0">
  <Description>
    <Title>US rail roads</Title>
  </Description>
  <Rule>
    <LineSymbolizer uom="http://www.opengeospatial.org/se/units/meter">
      <Stroke>
        <SvgParameter name="stroke">#FFFF00</SvgParameter>
        <SvgParameter name="stroke-width">10</SvgParameter>
       <GraphicStroke>
          <Graphic>
            <ExternalGraphic>
              <InlineContent encoding="base64">iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAHklEQVQIW2P8DwQMWAAjSKKOkRFFqgmoltoS2CwHACVQI+/9x0Y+AAAAAElFTkSuQmCC</InlineContent>
              <Format>image/png</Format>
            </ExternalGraphic>
            <Size>40</Size>
            <Rotation>45</Rotation>
            <Displacement>
              <DisplacementX>0</DisplacementX>
              <DisplacementY>-20</DisplacementY>
            </Displacement>
          </Graphic>
          <InitialGap>10</InitialGap>
          <Gap>50</Gap>
        </GraphicStroke>
      </Stroke>
     </LineSymbolizer>
  </Rule>
</FeatureTypeStyle>

In LuciadRIA, we use the ogc/se/SEPainterFactory to create a new FeaturePainter from the styling document. Once we have the painter, we can create a FeatureLayer to style the data in the model.

SEPainterFactory.createPainterFromURL("path/to/style.xml")
    .then(function(sePainter) {
          //the painter is ready. We can now create a layer.
          var featureLayer = new FeatureLayer(featureModel, {painter: sePainter});
    });

The result of drawing polylines with the SE style definition is:

seLines