Source code for openlr_dereferencer.decoding.routes

"Defines data types out of which line locations consist"

from typing import NamedTuple, Tuple, Optional, List
from shapely.geometry import LineString
from shapely.ops import substring, linemerge
from openlr import Coordinates
from ..maps.abstract import Line, path_length

[docs]class PointOnLine(NamedTuple): "A point on the road network" #: The line element on which the point resides line: Line #: Specifies the relative offset of the point. #: Its value is member of the interval [0.0, 1.0]. #: A value of 0 references the starting point of the line. relative_offset: float
[docs] def position(self) -> Coordinates: "Returns the actual geo position" point = self.line.geometry.interpolate(self.relative_offset, normalized=True) return Coordinates(point.x, point.y)
[docs] def split(self) -> Tuple[Optional[LineString], Optional[LineString]]: "Splits the Line element that this point is along and returns the halfs" if self.relative_offset == 0.0: return (None, self.line.geometry) elif self.relative_offset == 1.0: return (self.line.geometry, None) line1 = substring(self.line.geometry, 0.0, self.relative_offset, True) line2 = substring(self.line.geometry, self.relative_offset, 1.0, True) return (line1, line2)
[docs]class Route(NamedTuple): "A part of a line location path. May contain partial lines." #: The point with which this location is starting start: PointOnLine #: While the first and the last line may be partial, these are the intermediate lines. path_inbetween: List[Line] #: The point on which this location is ending end: PointOnLine @property def lines(self) -> List[Line]: "Returns all lines that take part in the route" result = [self.start.line] for line in self.path_inbetween: if line.line_id != result[-1].line_id: result.append(line) if self.end.line.line_id == result[-1].line_id: result.pop() result.append(self.end.line) return result
[docs] def length(self) -> float: "Length of this line location part in meters" lines = self.lines result = path_length(lines) if self.start.relative_offset > 0.0: result -= lines[0].length * self.start.relative_offset if self.end.relative_offset < 1.0: result -= lines[-1].length * (1.0 - self.end.relative_offset) return result
@property def absolute_start_offset(self) -> float: "Offset on the starting line in meters" return self.start.line.length * self.start.relative_offset @property def absolute_end_offset(self) -> float: "Offset on the ending line in meters" return self.end.line.length * (1.0 - self.end.relative_offset) @property def shape(self) -> LineString: "Returns the shape of the route. The route is has to be continuous." if self.start.line.line_id == self.end.line.line_id: return substring( self.start.line.geometry, self.start.relative_offset, self.end.relative_offset, normalized=True ) return linemerge([ self.start.split()[1]] + [line.geometry for line in self.path_inbetween] + [self.end.split()[0] ])
[docs] def coordinates(self) -> List[Coordinates]: "Returns all Coordinates of this line location" return [Coordinates(lon, lat) for (lon, lat) in self.shape.coords]