mark-p-thomas : GIS Polyline Classes

Sections

Main Polyline Structure

Polyline classes are representations of Routes and Tracks subclassed from the polyline class in the Geometry library. Each subclass has additional methods related to additional properties and inputs, such as separate querying of elevations points via an API. Some methods are repeated, either constrained to the corresponding Point/Segment type, or to other ways of navigating the polyline.

The general pattern in this library is to have an interface that inherits from the base interface, which the class then implements, on top of also inheriting from the base class in order to preserve prior functionality. This interface also inherits from a Route or Track polyline methods interface, which is strictly the methods related to the class.

The only changes in the public functionality of the class is the types allowed for coordinates passed to the constructor, as well as a static method to be used to determine if a polyline is a Route or Track. All other changes are performed in the Points, Segments, and Path Properties, described later.

Screen Shot 2024-08-26 at 1.33.21 PM.png

Track Polyline Optimization

Tracks can be optimized in navigation by creating a map of timestamps to nodes, since each timestamp is unique. In that case, if any operation is performed by referencing a timestamp, the O(N) time to find the node is reduced to O(1), just as if we had maintained a node reference. This can be further improved where if a time is selected that does not exist, the closest time can be chosen.

Class Interfaces & Common Inheritance/Implementation

IQ/ICl in the UML diagrams on this page indicate the following interfaces:

Screen Shot 2024-08-26 at 1.38.43 PM.png

These are from a library common to all projects in the Mark.ly & Mark.se namespaces. In this case, these allow easy non-reference equality comparison as well as deep cloning potential.

The polyline class implements these interfaces, while in most other cases, a final class interface inherits from these. The class interface pulls together these common interfaces alongside other interfaces. In this way, classes can directly use property interfaces that may also be used purely for data (i.e. serialization), but have a final & simple interface that pulls together other interfaces related more to class behavior.

Points

All points ultimately subclass from the abstract Vertex class used in Polylines. Each additional subclass is performed for the different conceptual level where additional properties/methods apply.

For easily testable, extensible & simple code, each class implements a ‘class interface’ that combines equality & cloning interfaces, and interfaces of the serializable properties, with methods specific to the class when needed.

The public implementation of the classes is kept simple by merely having additional constructor arguments as needed, as well as static factory methods. The basic Point class has a number of other convenience static methods for calculations involving 2 points, such as calculating linear distance between the 2 latitude/longitude coordinates.

Screen Shot 2024-08-26 at 1.33.41 PM.png

Point Factory Methods

Each point has a set of 3 factory methods to generate it from the following lower level data types:

  1. Position - GeoJSON Position.

  2. Point* - GeoJSON Point, NOT the point defined in the GIS library.

  3. Point Properties - The most fundamental properties needed to define the point, such as latitude & longitude (and optional altitude or elevation) for the GIS Point object.

Point Properties

Point properties are just that - the most basic scalar data needed in order to construct the Point.

Elevation vs. Altitude

It is important to note here the difference between altitude and elevation (as already discussed for Points). Altitude is recorded by GPS devices or other such devices at the time. Inaccuracies are due to inaccuracies in the device recording (e.g. satellite reception, barometer calibrations, etc.)

Elevation is determined later by using latitude & longitude to look up a specified elevation on the surface of the Earth at that location determined by DEM data. Inaccuracies are due to the accuracy of the data chosen, such as a higher resolution DEM, one using LIDAR data vs. older surveying data, etc.

Segments

Just as segments join any 2 vertices, it is worth having derived interfaces and classes for segments joining 2 Points for a Route or Track. Similar to Points, these have additional properties that apply to the concept of a Route or Track.

Since Segments have an interface and non-abstract class in the Geometry library, this library inherits from each of these as a starting point of further defining the class.

For easily testable, extensible & simple code, each class implements a ‘class interface’ that combines equality & cloning interfaces, and interfaces of the serializable properties, with methods specific to the class when needed.

The public implementation of the classes is kept simple by merely having additional constructor arguments as needed, as well as static factory methods.

Screen Shot 2024-08-26 at 1.33.53 PM.png

Segment Factory Methods

Each segment is generated by providing 2 points of the appropriate class type or further subclass (i.e. you can generate Route Segments from Track Points).

Path Properties

A concept related to segments in the GIS library are Paths. These join at least 2 segments, but aren’t necessarily a full Route or Track. These are used to determine 2rd-order properties about a Point, such as speed. The interface inheritance & implementation follow the same pattern as for Points & Segments.

Screen Shot 2024-08-26 at 1.27.45 PM.png

Path Property Creation & Methods

Path properties are initialized with optional scalar data of what the properties are to be. However, the properties can also be dynamically generated later by adding the 2 adjacent segments from which the properties are derived.