Skip to content

Commit

Permalink
Merge pull request #1 from anorthall/v0.1.5
Browse files Browse the repository at this point in the history
Assign UUIDs to anonymous stations, improve logging
  • Loading branch information
anorthall authored Aug 9, 2023
2 parents 19502d6 + 2d7f3a9 commit 70cf657
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 97 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ readme = "README.md"
authors = ["Andrew Northall <[email protected]>"]
keywords = ["caving", "caves", "cave-survey", "survex", "bindings"]
categories = ["api-bindings", "external-ffi-bindings", "science::geo"]
version = "0.1.4"
version = "0.1.5"
edition = "2021"
include = ["**/*.rs", "lib/**/*", "Cargo.toml", "README.md", "LICENCE"]

[dependencies]
uuid = { version = "1.4.1", features = ["v4", "fast-rng"] }
petgraph = "0.6.3"
log = "0.4"

[build-dependencies]
bindgen = "0.66.1"
81 changes: 77 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,80 @@
# survex-rs
A library for reading Survex 3D files using rust, using bindings to `img.c` from
the [Survex project](https://survex.com/). For more information, see the Rust generated documentation.
Rust bindings to the Survex `img.c` library which can be used via a safe API utilising
[`SurveyData`][`data::SurveyData`] and [`Station`][`station::Station`] structs, or directly via
unsafe Rust. For more information, view the [documentation](https://docs.rs/survex-rs).

## Safe API
The safe API is able to read data from a Survex .3d file and store it in a
[`SurveyData`][`data::SurveyData`] instance. [`SurveyData`][`data::SurveyData`] instances
contain a vector of references to [`Station`][`station::Station`] structs and a graph, built
using [`petgraph`][`petgraph::graph::Graph`], of connections between those stations.

A helper function, [`load_from_path`][`crate::read::load_from_path`], is provided to read a
given Survex .3d file and return a [`SurveyData`][`data::SurveyData`] instance.

### Example
```rust
use std::path::PathBuf;
use survex_rs::read::load_from_path;
use survex_rs::station::Point;

let path = PathBuf::from("tests/data/nottsii.3d");
let data = load_from_path(path).unwrap();

println!("Loaded {} stations", data.stations.len());
// Loaded 1904 stations

println!("Loaded {} survey legs", data.graph.edge_count());
// Loaded 1782 survey legs

let station = data.get_by_label("nottsii.entrance").unwrap();
let station = station.borrow();
println!("Station '{}' is at {}", station.label, station.coords);
// Station 'nottsii.entrance' is at 66668.00, 78303.00, 319.00

let coords = Point::new(66668.00, 78303.00, 319.00);
let station = data.get_by_coords(&coords).unwrap();
let station = station.borrow();
println!("{:#?}", station);
// Station {
// label: "nottsii.entrance",
// coords: Point {
// x: 66668.0,
// y: 78303.0,
// z: 319.0,
// },
// index: NodeIndex(1901),
// lrud: LRUD {
// left: None,
// right: None,
// up: None,
// down: None,
// },
// surface: false,
// underground: false,
// entrance: true,
// exported: true,
// fixed: true,
// anonymous: false,
// wall: false,
// }
```

## Unsafe API
If you wish to simply access the Survex `img.c` library directly using unsafe Rust, you can do so
via the bindings in the [`survex`][`crate::survex`] module.

For an example of how to use the unsafe API, take a look at the source for
[`load_from_path`][`crate::read::load_from_path`] in `src/read.rs`. You can browse the functions in the
[`survex`][`crate::survex`] module and reference them to the Survex `img.c` and `img.h` files found in the `src/`
directory of the [Survex source code](https://github.com/ojwb/survex).

## Project status
This project is currently in early development and is not ready for production use. The API is subject to change at
any time and semantic versioning is not yet being used.

## Contributing
Pull requests are [welcome on GitHub](https://github.com/anorthall/survex-rs).

## License
This project is licensed under the GNU General Public License v3.0 - see the LICENCE
file for details.
This project is licensed under the GNU General Public License v3.0 - see the LICENCE file for details.
45 changes: 41 additions & 4 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use petgraph::graph::{NodeIndex, UnGraph};
use std::cell::RefCell;
use std::rc::Rc;

type Stations = Vec<RefStation>;
type RefStation = Rc<RefCell<Station>>;
type StationGraph = UnGraph<String, f64>;
pub type Stations = Vec<RefStation>;
pub type RefStation = Rc<RefCell<Station>>;
pub type StationGraph = UnGraph<String, f64>;

/// Handles the creation and management of stations, as well as holding the
/// [`graph`][`petgraph::graph::Graph`] of stations.
Expand All @@ -34,7 +34,9 @@ impl SurveyData {
}
}

/// Retrieve a reference to a [`Station`] by its label.
/// Retrieve a reference to a [`Station`] by its label. Only exact matches are returned. To
/// retrieve a station by partial label use
/// [`get_by_label_part`][`SurveyData::get_by_label_part`].
pub fn get_by_label(&self, label: &str) -> Option<RefStation> {
for station in &self.stations {
if station.borrow().label == label {
Expand All @@ -44,6 +46,31 @@ impl SurveyData {
None
}

/// Retrieve a reference to a [`Station`] by its label, allowing for partial matches. If
/// multiple stations match the given label, [`None`] is returned, unless one of the matches is
/// an exact match, in which case that station is returned.
pub fn get_by_label_part(&self, label: &str) -> Option<RefStation> {
let matches = self
.stations
.iter()
.filter(|&node| node.borrow().label.contains(label))
.collect::<Vec<_>>();

if matches.len() == 1 {
return Some(Rc::clone(matches[0]));
} else {
for station in matches.iter() {
if station.borrow().label == label {
return Some(Rc::clone(station));
}
}
}

// We have ruled out an exact match, so there is either no match or multiple matches, so
// just return None and hope the user can be more specific.
None
}

/// Retrieve a reference to a [`Station`] by its coordinates. If multiple stations exist at the
/// given coordinates, the first station found is returned.
pub fn get_by_coords(&self, coords: &Point) -> Option<RefStation> {
Expand All @@ -55,6 +82,16 @@ impl SurveyData {
None
}

/// Retrieve a reference to a [`Station`] by its index in the graph.
pub fn get_by_index(&self, index: NodeIndex) -> Option<RefStation> {
for station in &self.stations {
if station.borrow().index == index {
return Some(Rc::clone(station));
}
}
None
}

/// This helper method is used to add or update a [`Station`] to both the stations vector and
/// the graph.
///
Expand Down
75 changes: 1 addition & 74 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,77 +1,4 @@
//! # survex-rs
//! Rust bindings to the Survex `img.c` library which can be used via a safe API utilising
//! [`SurveyData`][`data::SurveyData`] and [`Station`][`station::Station`] structs, or directly via
//! unsafe Rust.
//!
//! ## Safe API
//! The safe API is able to read data from a Survex .3d file and store it in a
//! [`SurveyData`][`data::SurveyData`] instance. [`SurveyData`][`data::SurveyData`] instances
//! contain a vector of references to [`Station`][`station::Station`] structs and a graph, built
//! using [`petgraph`][`petgraph::graph::Graph`], of connections between those stations.
//!
//! A helper function, [`load_from_path`][`crate::read::load_from_path`], is provided to read a
//! given Survex .3d file and return a [`SurveyData`][`data::SurveyData`] instance.
//!
//! ## Unsafe API
//! If you wish to simply access the Survex `img.c` library directly using unsafe Rust, you can do so
//! via the bindings in the [`survex`][`crate::survex`] module.
//!
//! # Examples
//! ## Safe API
//! ```rust
//! use std::path::PathBuf;
//! use survex_rs::read::load_from_path;
//! use survex_rs::station::Point;
//!
//! let path = PathBuf::from("tests/data/nottsii.3d");
//! let data = load_from_path(path).unwrap();
//!
//! println!("Loaded {} stations", data.stations.len());
//! // Loaded 1904 stations
//!
//! println!("Loaded {} survey legs", data.graph.edge_count());
//! // Loaded 1782 survey legs
//!
//! let station = data.get_by_label("nottsii.entrance").unwrap();
//! let station = station.borrow();
//! println!("Station '{}' is at {}", station.label, station.coords);
//! // Station 'nottsii.entrance' is at 66668.00, 78303.00, 319.00
//!
//! let coords = Point::new(66668.00, 78303.00, 319.00);
//! let station = data.get_by_coords(&coords).unwrap();
//! let station = station.borrow();
//! println!("{:#?}", station);
//! // Station {
//! // label: "nottsii.entrance",
//! // coords: Point {
//! // x: 66668.0,
//! // y: 78303.0,
//! // z: 319.0,
//! // },
//! // index: NodeIndex(1901),
//! // lrud: LRUD {
//! // left: None,
//! // right: None,
//! // up: None,
//! // down: None,
//! // },
//! // surface: false,
//! // underground: false,
//! // entrance: true,
//! // exported: true,
//! // fixed: true,
//! // anonymous: false,
//! // wall: false,
//! // }
//! ```
//!
//! ## Unsafe API
//! For an example of how to use the unsafe API, take a look at the source for
//! [`load_from_path`][`crate::read::load_from_path`] in `src/read.rs`.
//!
//! You can also take a look at the functions in the [`survex`][`crate::survex`] module and
//! reference them to the Survex `img.c` and `img.h` files found in the `src/` directory of the
//! [Survex GitHub](https://github.com/ojwb/survex).
#![doc = include_str!("../README.md")]
pub mod data;
pub mod read;
pub mod station;
Expand Down
Loading

0 comments on commit 70cf657

Please sign in to comment.