When you are visualizing a line between two points, you may need to provide a richer visualization at one or more intermediate points on that line.

Common examples include:

  • Displaying a text annotation at one or more intermediate locations of a line, to show the length of a line segment measured with a ruler.

  • Showing one or more icons at one or more intermediate locations of the line, such as an airplane icon along a trajectory.

  • Showing a label at a fixed location on the line. Instead of relying on the automatic placement of a label along the line, you want to fix the label position.

How to do it?

The high-level steps for marking intermediate points on a line are:

  1. Compute one or more intermediate points between two points of the line you are visualizing.

  2. Draw the original line

  3. Draw the extra visualization at the intersection point computed in step 1.

To accomplish those steps , you need to combine two components of the LuciadRIA API.

  • Use the Geodesy component to calculate the correct position of one or more intermediate points. Here you need to select the type of line you will be visualizing.

    • LineType.SHORTEST_DISTANCE: traces the shortest distance on the surface of the earth between two points. This is a geodetic line.

    • LineType.CONSTANT_BEARING: traces a line of constant bearing on the surface of the earth between two points. This is a rhumb line, meaning that the line crosses all meridians at the same angle.

  • Define the visualization of the object. Your approach depends on the goal you want to achieve:

    • If you are visualizing data in a FeatureLayer, implement FeaturePainter.paint[Body|Label].

    • If you are defining the visualization of a Controller, implement the Controller.onDraw()` method.

Example 1. Drawing annotations at intermediate line locations

In the example code below, we are modifying the sample code of the samples/view/controller/RulerController/js/rulercontroller/RulerController.js to draw a text label showing the distance of each line segment.

  1. Create the Geodesy utility.

    this._geodesy = GeodesyFactory.createEllipsoidalGeodesy(this._shapeReference);
  2. Compute the halfway point and draw text at the line in the RulerController.onDraw() method.

    var halfwayPoint, i, distance;
    for (i = 0; i < this._polyLine.pointCount - 1; i += 1) {
      halfwayPoint = this._geodesy.interpolate(this._polyLine.getPoint(i), this._polyLine.getPoint(i + 1), 0.5, LineType.SHORTEST_DISTANCE);
      distance = this._geodesy.distance(this._polyLine.getPoint(i), this._polyLine.getPoint(i + 1), LineType.SHORTEST_DISTANCE);
      geoCanvas.drawText(halfwayPoint, this._formatDistance(distance), {
        textAnchor: "center",
        font: "bold 14px sans-serif",
        fill: "rgb(255,255,255)",
        halo: "rgb(0,0,0)",
        haloWidth: 3
      });
    }

The result will look similar to this image of several measurements taken with a ruler:

intermediate distances

Example 2. Drawing an icon at an intermediate point

The following example is a variation on the example above. Instead of drawing a controller annotation, we now draw an airplane icon midway on a flight trajectory segment. To draw the icon midway on a line:

  1. We modify the FeaturePainter.paintBody() method.

  2. We draw an airplane icon in the middle of the line, using the same technique as in the previous example to compute the midpoint.

  3. We split the original line segment in two, to ensure that the line perfectly connects to the icon. To optimize performance, the arc of a trajectory line is calculated as an approximation, which may not pass through the midpoint calculated with the accurate GeodesyFactory.interpolate() method. By splitting the line segment in half and connecting the two halves to the precisely calculated midpoint, we ensure that the icon is perfectly aligned with the trajectory line.

  4. We determine the azimuth at that given point using the GeodesyFactory.azimuth() calculation, and rotate the icon according to that azimuth.

var linePainter = new FeaturePainter();
linePainter.paintBody = function(geoCanvas, feature, shape, map, layer, state) {
  var geodesy = GeodesyFactory.createEllipsoidalGeodesy(shape.reference);
  var i, midway, azimuth;
  for (i = 0; i < shape.pointCount - 1; i += 1) {
    midway = geodesy.interpolate(shape.getPoint(i), shape.getPoint(i + 1), 0.5, LineType.SHORTEST_DISTANCE);
    geoCanvas.drawShape(ShapeFactory.createPolyline(shape.reference, [shape.getPoint(i), midway]), {
      stroke: {
        color: "rgb(0,0,255)"
      }
    });
    geoCanvas.drawShape(ShapeFactory.createPolyline(shape.reference, [midway, shape.getPoint(i + 1)]), {
      stroke: {
        color: "rgb(0,0,255)"
      }
    });
    azimuth = geodesy.forwardAzimuth(midway, shape.getPoint(i + 1), LineType.SHORTEST_DISTANCE);
    geoCanvas.drawIcon(midway,{
      url: "airplane.png",
      width:"32px",
      height: "32px",
      rotation: azimuth
    })
  }
};

The result will look similar to this image of several line trajectories displaying an airplane icon in the middle:

midway flights