Skip to content

Commit

Permalink
add doc references
Browse files Browse the repository at this point in the history
  • Loading branch information
louisgreiner committed Jun 25, 2024
1 parent aff5399 commit de8df81
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 57 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# Library for Linear Reference System

[Linear Reference](https://en.wikipedia.org/wiki/Linear_referencing) allows to identify a position along a curve (a road, a canal, a railroad…) relative to fixed reference points.
[Linear Reference](https://en.wikipedia.org/wiki/Linear_referencing) allows to identify a position along a curve (a road, a canal, a railroad…) relative to fixed reference points.

We call:

- **anchor** a reference point: it can be milestones, a landmark, an intersection…
- **scale** the list of _anchors_ and the theoretical distance between them,
- **curve** the physical description of the object to reference,
- **linear referencing method** (LRM) the combination of a _scale_ and a _curve_,
- **linear referencing system** (LRS) the complete set of data.


While the logic is quite simple, multiple small subtleties make the LRS difficult to use.
Distances between milestone change (construction of a bypass around a town), the origin of curve is displaced (the railwail station moved), there is only one scale for a river and its parallel running canal…

This library aims to handle many edge cases and makes little assumptions about the data:

- anchors are not always numbers,
- anchors don’t need to be on the curve,
- distance between anchors are not fixed,
Expand All @@ -25,7 +26,7 @@ This library aims to handle many edge cases and makes little assumptions about t

The core library is written in rust. We expose javascript binding through [WebAssembly](https://webassembly.org/). Those binding can be built in the `wasm` directory.

```
```bash
cd wasm
npm install
npm build
Expand All @@ -35,7 +36,7 @@ npm build

A simple HTML demonstrator allows to test the data and the functions:

```
```bash
cd wasm
npm run serve
```
Expand All @@ -44,7 +45,7 @@ And open your browser at `http://localhost:8080`

You can customize the map background if you provide your own [maplibre](https://maplibre.org/) style:

```
```bash
MAPLIBRE_STYLE="https://your_tile_provider/style.json?key=42" npm run serve
```

Expand Down
6 changes: 3 additions & 3 deletions python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ lrms = {plm.get_lrm_scale_id(i): i for i in range(plm.lrm_len())}
via_aurelia_handle = [v for k,v in lrms.items() if k.startswith("Via Aurelia")][0]

# We define two measures meaning “100 passus after milestone 50”
# (passus = step in latin, could be any measurement unit)
a = lrs.LrmScaleMeasure("50", 100)
b = lrs.LrmScaleMeasure("60", 200)

Expand All @@ -36,8 +37,7 @@ pip install
maturin develop
```


https://gist.github.com/Tristramg/32a2fff35eb8e0bb065eed25d987a2c7
[https://gist.github.com/Tristramg/32a2fff35eb8e0bb065eed25d987a2c7](https://gist.github.com/Tristramg/32a2fff35eb8e0bb065eed25d987a2c7)

Bindings with PyO3 to liblrs

Expand All @@ -47,4 +47,4 @@ We publish the library to PYPI running:

```sh
docker run --rm -e MATURIN_PYPI_TOKEN=PYPI_key -w /io/python -v $(pwd)/..:/io ghcr.io/pyo3/maturin publish
```
```
39 changes: 20 additions & 19 deletions python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use liblrs::lrs_ext::*;
use pyo3::{exceptions::PyTypeError, prelude::*};

/// Holds the whole Linear Referencing System
/// Hold the whole Linear Referencing System.
#[pyclass]
pub struct Lrs {
lrs: ExtLrs,
Expand All @@ -20,13 +20,13 @@ fn liblrs_python<'py>(_py: Python, m: &Bound<'py, PyModule>) -> PyResult<()> {
}

#[derive(Clone, Copy)]
/// A geographical point, it can be either a projected or spherical coordinates
/// A geographical [`Point`], it can be either a projected or spherical coordinates.
#[pyclass]
pub struct Point {
/// x or longitude
/// Position on x-axis or `longitude`.
#[pyo3(get, set)]
pub x: f64,
/// y or latitude
/// Position on y-axis or `latitude`.
#[pyo3(get, set)]
pub y: f64,
}
Expand All @@ -50,13 +50,13 @@ impl From<geo_types::Coord> for Point {
}

#[pyclass]
/// Represents a position on an Lrm Scale relative as an offset to an anchor
/// Represent a position on an [`LrmScale`] relative as an `offset` to an [`Anchor`].
pub struct LrmScaleMeasure {
#[pyo3(get, set)]
/// The name of the reference anchor
/// `name` of the reference [`Anchor`].
anchor_name: String,
#[pyo3(get, set)]
/// Offset to the reference anchor
/// `offset` to the reference [`Anchor`].
scale_offset: f64,
}

Expand All @@ -81,6 +81,7 @@ impl Into<liblrs::lrm_scale::LrmScaleMeasure> for &LrmScaleMeasure {
#[pymethods]
impl LrmScaleMeasure {
#[new]
/// Build a new [`LrmMeasure`] from an [`Anchor`] `name` and the `offset` on the [`LrmScale`].
fn new(anchor_name: String, scale_offset: f64) -> Self {
Self {
anchor_name,
Expand All @@ -90,19 +91,19 @@ impl LrmScaleMeasure {
}

#[pyclass]
/// An anchor is a reference point for a given curve.
/// An `Anchor` is a reference point for a given [`Curve`].
/// It can be a milestone, a bridge…
pub struct Anchor {
/// Name
/// `name` of the [`Anchor`].
#[pyo3(get, set)]
pub name: String,
/// Projected position on the curve (the reference point isn’t always on the curve)
/// Projected position on the [`Curve`] (the reference point isn’t always on the curve).
#[pyo3(get, set)]
pub position: Point,
/// Position on the curve
/// Position on the [`Curve`].
#[pyo3(get, set)]
pub curve_position: f64,
/// Position on the scale
/// Position on the scale.
#[pyo3(get, set)]
pub scale_position: f64,
}
Expand All @@ -120,49 +121,49 @@ impl From<PositionnedAnchor> for Anchor {

#[pymethods]
impl Lrs {
/// Load the data
/// Load the data.
#[new]
pub fn load(data: &[u8]) -> PyResult<Lrs> {
ExtLrs::load(data)
.map(|lrs| Self { lrs })
.map_err(|e| PyTypeError::new_err(e.to_string()))
}

/// How many lrms are there
/// How many LRMs compose the LRS.
pub fn lrm_len(&self) -> usize {
self.lrs.lrm_len()
}

/// Returns the geometry of the lrm
/// Return the geometry of the LRM.
pub fn get_lrm_geom(&self, index: usize) -> PyResult<Vec<Point>> {
self.lrs
.get_lrm_geom(index)
.map(|coords| coords.into_iter().map(|coord| coord.into()).collect())
.map_err(|e| PyTypeError::new_err(e.to_string()))
}

/// `id` of the [`LrmScale`]
/// `id` of the [`LrmScale`].
pub fn get_lrm_scale_id(&self, index: usize) -> String {
self.lrs.get_lrm_scale_id(index)
}

/// All the [`Anchor`]s of a LRM
/// All the [`Anchor`]s of a LRM.
pub fn get_anchors(&self, lrm_index: usize) -> PyResult<Vec<Anchor>> {
self.lrs
.get_anchors(lrm_index)
.map(|anchor| anchor.into_iter().map(Anchor::from).collect())
.map_err(|e| PyTypeError::new_err(e.to_string()))
}

/// Get the position given a [`LrmScaleMeasure`]
/// Get the position given a [`LrmScaleMeasure`].
pub fn resolve(&self, lrm_index: usize, measure: &LrmScaleMeasure) -> PyResult<Point> {
self.lrs
.resolve(lrm_index, &measure.into())
.map(Point::from)
.map_err(|e| PyTypeError::new_err(e.to_string()))
}

/// Given two [`LrmScaleMeasure`]s, returns a range of [`LineString`]
/// Given two [`LrmScaleMeasure`]s, return a range of [`LineString`].
pub fn resolve_range(
&self,
lrm_index: usize,
Expand Down
26 changes: 13 additions & 13 deletions src/lrs_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ use crate::lrs::{LrsBase, LrsError};

type Lrs = lrs::Lrs<SphericalLineStringCurve>;

/// Struct exposed to js
/// Struct exposed to js.
pub struct ExtLrs {
lrs: Lrs,
}

/// And [`Anchor`] with its coordinates
/// An [`Anchor`] with its [`Coord`].
pub struct PositionnedAnchor {
/// Name
/// Name of the [`Anchor`].
pub name: String,
/// Projected position on the curve
/// Projected position on the [`Curve`].
pub position: Coord,
/// Position on the curve
/// Position on the [`Curve`].
pub curve_position: f64,
/// Position on the scale
/// Position on the scale.
pub scale_position: f64,
}

Expand All @@ -40,32 +40,32 @@ impl PositionnedAnchor {
}

impl ExtLrs {
/// Load the data
/// Load the data.
pub fn load(data: &[u8]) -> Result<ExtLrs, String> {
Lrs::from_bytes(data)
.map(|lrs| Self { lrs })
.map_err(|err| err.to_string())
}

/// How many lrms are there
/// How many LRMs compose the LRS.
pub fn lrm_len(&self) -> usize {
self.lrs.lrm_len()
}

/// Returns the geometry of the lrm
/// Return the geometry of the LRM.
pub fn get_lrm_geom(&self, index: usize) -> Result<Vec<geo::Coord>, String> {
self.lrs
.get_linestring(TraversalHandle(index))
.map_err(|err| err.to_string())
.map(|linestring| linestring.0)
}

/// `id` of the [`LrmScale`]
/// `id` of the [`LrmScale`].
pub fn get_lrm_scale_id(&self, index: usize) -> String {
self.lrs.lrms[index].scale.id.clone()
}

/// All the [`Anchor`]s of a LRM
/// All the [`Anchor`]s of a LRM.
pub fn get_anchors(&self, lrm_index: usize) -> Result<Vec<PositionnedAnchor>, CurveError> {
let lrm = &self.lrs.lrms[lrm_index];
let curve = &self.lrs.traversals[lrm.reference_traversal.0].curve;
Expand All @@ -76,7 +76,7 @@ impl ExtLrs {
.collect()
}

/// Get the position given a [`LrmScaleMeasure`]
/// Get the position given a [`LrmScaleMeasure`].
pub fn resolve(&self, lrm_index: usize, measure: &LrmScaleMeasure) -> Result<Point, LrsError> {
let curve_position = self.lrs.lrms[lrm_index].scale.locate_point(measure)?;

Expand All @@ -87,7 +87,7 @@ impl ExtLrs {
self.lrs.locate_traversal(traversal_position)
}

/// Given two [`LrmScaleMeasure`]s, returns a range of [`LineString`]
/// Given two [`LrmScaleMeasure`]s, return a range of [`LineString`].
pub fn resolve_range(
&self,
lrm_index: usize,
Expand Down
Loading

0 comments on commit de8df81

Please sign in to comment.