Adding documentation, some code cleanups
* Not re-exporting SpaceSetObject outside of the crate * Removed unused SpaceObject definition * Factored out Point definition. * Remove `pub` visibility on definition not actually requiring it. * Added an assert for indexing into a Position, in the case where the position has only one dimension, the index MUST BE 0. * Commented `highest_resolution()` as this is not yet used.
This commit is contained in:
28
README.md
28
README.md
@@ -22,35 +22,9 @@ This enables the index implementations to be agnostic from the underlying data s
|
|||||||
|
|
||||||
* Rust: https://www.rust-lang.org
|
* Rust: https://www.rust-lang.org
|
||||||
|
|
||||||
## Quick start
|
|
||||||
|
|
||||||
## Building from sources
|
|
||||||
|
|
||||||
To build this project, you will need to run the following:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
|
|
||||||
To install the software on the system you can use:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo install --release
|
|
||||||
```
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
The binary `db-test` provided is used only as an integration test at this point. It will convert a json input to a binary representation, before building an index over it. Once this is achieved, it will run a couple of hard-coded queries over the index.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cargo run --release
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
For more information, please refer to the [documentation](https://epfl-dias.github.io/PROJECT_NAME/).
|
For more information, please refer to the [documentation](https://epfl-dias.github.io/mercator_db/).
|
||||||
|
|
||||||
If you want to build the documentation and access it locally, you can use:
|
If you want to build the documentation and access it locally, you can use:
|
||||||
|
|
||||||
|
|||||||
@@ -9,15 +9,31 @@ use super::space_index::SpaceSetObject;
|
|||||||
use super::DataBase;
|
use super::DataBase;
|
||||||
use super::ResultSet;
|
use super::ResultSet;
|
||||||
|
|
||||||
|
/// Query Parameters.
|
||||||
pub struct CoreQueryParameters<'a> {
|
pub struct CoreQueryParameters<'a> {
|
||||||
|
/// Database to use.
|
||||||
pub db: &'a DataBase,
|
pub db: &'a DataBase,
|
||||||
|
/// Output reference space into which to convert results.
|
||||||
pub output_space: Option<&'a str>,
|
pub output_space: Option<&'a str>,
|
||||||
|
/// Volume value to use to select the index resolution.
|
||||||
|
//FIXME: IS this necessary given view_port?
|
||||||
pub threshold_volume: Option<f64>,
|
pub threshold_volume: Option<f64>,
|
||||||
|
/// Full definition of the view port, a.k.a the volume being
|
||||||
|
/// displayed.
|
||||||
pub view_port: &'a Option<(Vec<f64>, Vec<f64>)>,
|
pub view_port: &'a Option<(Vec<f64>, Vec<f64>)>,
|
||||||
|
/// Index resolution to use.
|
||||||
pub resolution: &'a Option<Vec<u32>>,
|
pub resolution: &'a Option<Vec<u32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoreQueryParameters<'_> {
|
impl CoreQueryParameters<'_> {
|
||||||
|
/// Build a minimum bounding box out of the provided viewport, and
|
||||||
|
/// rebase it in the target space.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `space`:
|
||||||
|
/// Space to use for the encoded coordinates of the minimum
|
||||||
|
/// bounding box.
|
||||||
pub fn view_port(&self, space: &Space) -> Option<Shape> {
|
pub fn view_port(&self, space: &Space) -> Option<Shape> {
|
||||||
if let Some((low, high)) = self.view_port {
|
if let Some((low, high)) = self.view_port {
|
||||||
let view_port = Shape::BoundingBox(low.into(), high.into());
|
let view_port = Shape::BoundingBox(low.into(), high.into());
|
||||||
@@ -31,14 +47,21 @@ impl CoreQueryParameters<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Definition of the volumetric objects identifiers.
|
||||||
|
///
|
||||||
|
/// We have two parts to it, first the *kind* and the actual, *id* used
|
||||||
|
/// to distinguish different objects.
|
||||||
// FIXME: Ids are expected unique, irrespective of the enum variant!
|
// FIXME: Ids are expected unique, irrespective of the enum variant!
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub enum Properties {
|
pub enum Properties {
|
||||||
|
/// Spatial Features.
|
||||||
Feature(String),
|
Feature(String),
|
||||||
|
/// Unoptimized arbitrary kind of *identifiers*.
|
||||||
Unknown(String, String),
|
Unknown(String, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Properties {
|
impl Properties {
|
||||||
|
/// Extract the *identifier* of this spatial object.
|
||||||
pub fn id(&self) -> &str {
|
pub fn id(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Properties::Feature(id) => id,
|
Properties::Feature(id) => id,
|
||||||
@@ -46,6 +69,7 @@ impl Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract the *kind* of spatial object.
|
||||||
pub fn type_name(&self) -> &str {
|
pub fn type_name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Properties::Feature(_) => "Feature",
|
Properties::Feature(_) => "Feature",
|
||||||
@@ -53,6 +77,13 @@ impl Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instantiate a new *feature*.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `id`:
|
||||||
|
/// The identifier of the object, which can be converted into a
|
||||||
|
/// `String`.
|
||||||
pub fn feature<S>(id: S) -> Properties
|
pub fn feature<S>(id: S) -> Properties
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
@@ -60,6 +91,17 @@ impl Properties {
|
|||||||
Properties::Feature(id.into())
|
Properties::Feature(id.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instantiate a new arbitrary kind of object, with the given id.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `id`:
|
||||||
|
/// The identifier of the object, which can be converted into a
|
||||||
|
/// `String`.
|
||||||
|
///
|
||||||
|
/// * `type_name`:
|
||||||
|
/// A value which can be converted into a `String`, and
|
||||||
|
/// represent the **kind** of the object.
|
||||||
pub fn unknown<S>(id: S, type_name: S) -> Properties
|
pub fn unknown<S>(id: S, type_name: S) -> Properties
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
@@ -68,6 +110,7 @@ impl Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Index over a single dataset
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Core {
|
pub struct Core {
|
||||||
title: String,
|
title: String,
|
||||||
@@ -77,6 +120,43 @@ pub struct Core {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Core {
|
impl Core {
|
||||||
|
/// Instantiate a new index for a dataset.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `title`:
|
||||||
|
/// The title to use for the new dataset.
|
||||||
|
///
|
||||||
|
/// * `version`:
|
||||||
|
/// The revision of the new dataset.
|
||||||
|
///
|
||||||
|
/// * `spaces`:
|
||||||
|
/// The list of reference spaces used within the dataset.
|
||||||
|
///
|
||||||
|
/// * `properties`:
|
||||||
|
/// The *identifiers*, has an ordered list, which is referenced
|
||||||
|
/// by the `space_objects` by offset within this list.
|
||||||
|
///
|
||||||
|
/// * `space_objects`:
|
||||||
|
/// A list of links between volumetric positions and
|
||||||
|
/// identifiers.
|
||||||
|
///
|
||||||
|
/// * `scales`:
|
||||||
|
/// A list of resolutions for which to build indices. Each value
|
||||||
|
/// represent the number of bits of precision to **remove** from
|
||||||
|
/// the coordinates to build the index.
|
||||||
|
///
|
||||||
|
/// * `max_elements`:
|
||||||
|
/// The minimum number of positions to use as a stopping
|
||||||
|
/// condition while building automatically multiple resolutions
|
||||||
|
/// of the index.
|
||||||
|
///
|
||||||
|
/// Each consecutive index will contains at most half the number
|
||||||
|
/// of data points than the next finer-grained index.
|
||||||
|
///
|
||||||
|
/// The minimum number of elements contained within an index is
|
||||||
|
/// this value or the number of *identifiers*, whichever is
|
||||||
|
/// greater.
|
||||||
pub fn new<S>(
|
pub fn new<S>(
|
||||||
title: S,
|
title: S,
|
||||||
version: S,
|
version: S,
|
||||||
@@ -125,14 +205,17 @@ impl Core {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Title of the dataset.
|
||||||
pub fn name(&self) -> &String {
|
pub fn name(&self) -> &String {
|
||||||
&self.title
|
&self.title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Revision of the dataset.
|
||||||
pub fn version(&self) -> &String {
|
pub fn version(&self) -> &String {
|
||||||
&self.version
|
&self.version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// List of *identifiers* contained in this dataset.
|
||||||
pub fn keys(&self) -> &Vec<Properties> {
|
pub fn keys(&self) -> &Vec<Properties> {
|
||||||
&self.properties
|
&self.properties
|
||||||
}
|
}
|
||||||
@@ -164,13 +247,26 @@ impl Core {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search by positions defining a volume.
|
/// Retrieve everything located at specific positions.
|
||||||
// Positions ARE DEFINED IN F64 VALUES IN THE SPACE. NOT ENCODED!
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `parameters`:
|
||||||
|
/// Search parameters, see [CoreQueryParameters](struct.CoreQueryParameters.html).
|
||||||
|
///
|
||||||
|
/// * `positions`:
|
||||||
|
/// Volume to use to filter data points.
|
||||||
|
///
|
||||||
|
/// * `space_id`:
|
||||||
|
/// *positions* are defined as decoded coordinates in this
|
||||||
|
/// reference space.
|
||||||
|
///
|
||||||
|
/// [shape]: space/enum.Shape.html
|
||||||
pub fn get_by_positions(
|
pub fn get_by_positions(
|
||||||
&self,
|
&self,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &CoreQueryParameters,
|
||||||
positions: &[Position],
|
positions: &[Position],
|
||||||
from: &str,
|
space_id: &str,
|
||||||
) -> ResultSet {
|
) -> ResultSet {
|
||||||
let CoreQueryParameters {
|
let CoreQueryParameters {
|
||||||
db, output_space, ..
|
db, output_space, ..
|
||||||
@@ -178,7 +274,7 @@ impl Core {
|
|||||||
|
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
let count = positions.len();
|
let count = positions.len();
|
||||||
let from = db.space(from)?;
|
let from = db.space(space_id)?;
|
||||||
|
|
||||||
// Filter positions based on the view port, if present
|
// Filter positions based on the view port, if present
|
||||||
let filtered = match parameters.view_port(from) {
|
let filtered = match parameters.view_port(from) {
|
||||||
@@ -211,12 +307,21 @@ impl Core {
|
|||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search by shape defining a volume:
|
/// Search using a [shape] which defines a volume.
|
||||||
// * Hyperrectangle (MBB),
|
///
|
||||||
// * HyperSphere (radius around a point),
|
/// # Parameters
|
||||||
// * Point (Specific position)
|
///
|
||||||
|
/// * `parameters`:
|
||||||
// SHAPE IS DEFINED IN F64 VALUES IN THE SPACE. NOT ENCODED!
|
/// Search parameters, see [CoreQueryParameters](struct.CoreQueryParameters.html).
|
||||||
|
///
|
||||||
|
/// * `shape`:
|
||||||
|
/// Volume to use to filter data points.
|
||||||
|
///
|
||||||
|
/// * `space_id`:
|
||||||
|
/// *shape* is defined as decoded coordinates in this
|
||||||
|
/// reference space.
|
||||||
|
///
|
||||||
|
/// [shape]: space/enum.Shape.html
|
||||||
pub fn get_by_shape(
|
pub fn get_by_shape(
|
||||||
&self,
|
&self,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &CoreQueryParameters,
|
||||||
@@ -251,7 +356,16 @@ impl Core {
|
|||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search by Id, a.k.a values
|
/// Search by Id, a.k.a retrieve all the positions linked to this id.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `parameters`:
|
||||||
|
/// Search parameters, see [CoreQueryParameters](struct.CoreQueryParameters.html).
|
||||||
|
///
|
||||||
|
/// * `id`:
|
||||||
|
/// Identifier for which to retrieve is positions.
|
||||||
|
///
|
||||||
pub fn get_by_id<S>(
|
pub fn get_by_id<S>(
|
||||||
&self,
|
&self,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &CoreQueryParameters,
|
||||||
@@ -305,8 +419,17 @@ impl Core {
|
|||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search by Label, a.k.a within a volume defined by the positions of an Id.
|
/// Search by label, a.k.a use an identifier to define the search
|
||||||
// FIXME: NEED TO KEEP TRACK OF SPACE IDS AND DO CONVERSIONS
|
/// volume.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `parameters`:
|
||||||
|
/// Search parameters, see [CoreQueryParameters](struct.CoreQueryParameters.html).
|
||||||
|
///
|
||||||
|
/// * `id`:
|
||||||
|
/// Identifier to use to define the search volume.
|
||||||
|
///
|
||||||
pub fn get_by_label<S>(&self, parameters: &CoreQueryParameters, id: S) -> ResultSet
|
pub fn get_by_label<S>(&self, parameters: &CoreQueryParameters, id: S) -> ResultSet
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
mod db_core;
|
mod db_core;
|
||||||
pub mod space;
|
pub mod space;
|
||||||
mod space_db;
|
mod space_db;
|
||||||
mod space_index;
|
pub(crate) mod space_index;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ironsea_index::Indexed;
|
use ironsea_index::Indexed;
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use super::storage;
|
use super::storage;
|
||||||
pub use db_core::Core;
|
pub use db_core::Core;
|
||||||
@@ -14,27 +13,36 @@ pub use db_core::CoreQueryParameters;
|
|||||||
pub use db_core::Properties;
|
pub use db_core::Properties;
|
||||||
use space::Position;
|
use space::Position;
|
||||||
use space::Space;
|
use space::Space;
|
||||||
pub use space_index::SpaceFields;
|
|
||||||
pub use space_index::SpaceSetObject;
|
|
||||||
|
|
||||||
// (Space Name, Position, Fields)
|
/// Selected tuples matching a query.
|
||||||
|
///
|
||||||
|
/// This is either:
|
||||||
|
/// * `Err` with a reason stored as a `String`
|
||||||
|
/// * `Ok`, with a vector of tuples defined as:
|
||||||
|
/// `(Space Name, [(Position, Properties)])`
|
||||||
pub type ResultSet<'r> = Result<Vec<(&'r String, Vec<(Position, &'r Properties)>)>, String>;
|
pub type ResultSet<'r> = Result<Vec<(&'r String, Vec<(Position, &'r Properties)>)>, String>;
|
||||||
pub type ReferenceSpaceIndex = ironsea_index_hashmap::Index<Space, String>;
|
|
||||||
|
type ReferenceSpaceIndex = ironsea_index_hashmap::Index<Space, String>;
|
||||||
type CoreIndex = ironsea_index_hashmap::Index<Core, String>;
|
type CoreIndex = ironsea_index_hashmap::Index<Core, String>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize)]
|
/// Collection of datasets and their reference spaces.
|
||||||
pub struct SpaceObject {
|
|
||||||
pub space_id: String,
|
|
||||||
pub position: Position,
|
|
||||||
pub value: Properties,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DataBase {
|
pub struct DataBase {
|
||||||
reference_spaces: ReferenceSpaceIndex,
|
reference_spaces: ReferenceSpaceIndex,
|
||||||
cores: CoreIndex,
|
cores: CoreIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataBase {
|
impl DataBase {
|
||||||
|
/// Instantiate a `DataBase` struct.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `spaces`:
|
||||||
|
/// List of reference spaces.
|
||||||
|
///
|
||||||
|
/// * `cores`:
|
||||||
|
/// List of datasets (cores) which will be queried through this
|
||||||
|
/// `DataBase` struct.
|
||||||
|
// TODO: Replace vectors with iterators?
|
||||||
pub fn new(spaces: Vec<Space>, cores: Vec<Core>) -> Self {
|
pub fn new(spaces: Vec<Space>, cores: Vec<Core>) -> Self {
|
||||||
DataBase {
|
DataBase {
|
||||||
reference_spaces: ReferenceSpaceIndex::new(spaces.into_iter()),
|
reference_spaces: ReferenceSpaceIndex::new(spaces.into_iter()),
|
||||||
@@ -42,6 +50,12 @@ impl DataBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load a list of indices.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `indices`:
|
||||||
|
/// The list of index file names to load.
|
||||||
pub fn load(indices: &[&str]) -> Result<Self, String> {
|
pub fn load(indices: &[&str]) -> Result<Self, String> {
|
||||||
let mut spaces = HashMap::new();
|
let mut spaces = HashMap::new();
|
||||||
let mut cores = vec![];
|
let mut cores = vec![];
|
||||||
@@ -99,12 +113,17 @@ impl DataBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup a space within the reference spaces registered
|
/// Returns an ordered list of the reference space names registered.
|
||||||
pub fn space_keys(&self) -> &Vec<String> {
|
pub fn space_keys(&self) -> &Vec<String> {
|
||||||
self.reference_spaces.keys()
|
self.reference_spaces.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup a space within the reference spaces registered
|
/// Lookup a space within the reference spaces registered.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `name`:
|
||||||
|
/// The name of the reference space to search for.
|
||||||
pub fn space(&self, name: &str) -> Result<&Space, String> {
|
pub fn space(&self, name: &str) -> Result<&Space, String> {
|
||||||
if name == space::Space::universe().name() {
|
if name == space::Space::universe().name() {
|
||||||
Ok(space::Space::universe())
|
Ok(space::Space::universe())
|
||||||
@@ -115,12 +134,17 @@ impl DataBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup a space within the reference spaces registered
|
/// Returns an ordered list of dataset (Core) names registered.
|
||||||
pub fn core_keys(&self) -> &Vec<String> {
|
pub fn core_keys(&self) -> &Vec<String> {
|
||||||
self.cores.keys()
|
self.cores.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup a dataset within the datasets registered
|
/// Lookup a dataset within the datasets registered.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `name`:
|
||||||
|
/// The name of the dataset (core) to search for.
|
||||||
pub fn core(&self, name: &str) -> Result<&Core, String> {
|
pub fn core(&self, name: &str) -> Result<&Core, String> {
|
||||||
let r = self.cores.find(&name.to_string());
|
let r = self.cores.find(&name.to_string());
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,16 @@ use serde::Serialize;
|
|||||||
use super::coordinate::Coordinate;
|
use super::coordinate::Coordinate;
|
||||||
use super::position::Position;
|
use super::position::Position;
|
||||||
|
|
||||||
|
/// Mathematical set numbers.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub enum NumberSet {
|
pub enum NumberSet {
|
||||||
|
/// [Natural numbers](https://en.wikipedia.org/wiki/Natural_number), here including **0**.
|
||||||
N,
|
N,
|
||||||
|
/// [Integers](https://en.wikipedia.org/wiki/Integer).
|
||||||
Z,
|
Z,
|
||||||
|
/// [Rational](https://en.wikipedia.org/wiki/Rational_number) numbers.
|
||||||
Q,
|
Q,
|
||||||
|
/// [Real](https://en.wikipedia.org/wiki/Real_number) numbers.
|
||||||
R,
|
R,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,12 +42,19 @@ impl From<&NumberSet> for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Definition of a fixed-precision, finite length axis.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct Graduation {
|
pub struct Graduation {
|
||||||
|
/// Set of numbers allowed on the axis.
|
||||||
pub set: NumberSet,
|
pub set: NumberSet,
|
||||||
|
/// Minimum value *inclusive*.
|
||||||
pub minimum: f64,
|
pub minimum: f64,
|
||||||
|
/// Maximum value *inclusive*.
|
||||||
pub maximum: f64,
|
pub maximum: f64,
|
||||||
|
/// Number of *ticks* or discrete values between `minimum` and
|
||||||
|
/// `maximum`.
|
||||||
pub steps: u64,
|
pub steps: u64,
|
||||||
|
/// Length between two distinct *ticks* on the axis.
|
||||||
pub epsilon: f64,
|
pub epsilon: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +72,7 @@ impl Graduation {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub enum UnitSI {
|
enum UnitSI {
|
||||||
// Partial list, which is tailored to the use case needs. Prevents possible
|
// Partial list, which is tailored to the use case needs. Prevents possible
|
||||||
// confusions between Mm and mm, for example.
|
// confusions between Mm and mm, for example.
|
||||||
m,
|
m,
|
||||||
@@ -113,16 +125,45 @@ impl From<&str> for UnitSI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Definition of an axis of a base.
|
||||||
|
///
|
||||||
|
/// This links together valid values on this axis, as well as the
|
||||||
|
/// direction in the Universe of the axis and the base length unit of
|
||||||
|
/// the `1.0` value.
|
||||||
// TODO: In the future this might become an Enum with AffineAxis, ArbitraryAxis, etc...
|
// TODO: In the future this might become an Enum with AffineAxis, ArbitraryAxis, etc...
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct Axis {
|
pub struct Axis {
|
||||||
measurement_unit: UnitSI,
|
measurement_unit: UnitSI,
|
||||||
graduation: Graduation,
|
graduation: Graduation,
|
||||||
// Coordinates in Universe, expressed in f64, and in the Universe number of dimensions.
|
// Coordinates in Universe, expressed in f64, and in the Universe
|
||||||
pub unit_vector: Position,
|
// number of dimensions.
|
||||||
|
unit_vector: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Axis {
|
impl Axis {
|
||||||
|
/// Instanciate a new Axis definition.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `unit`:
|
||||||
|
/// SI Unit to use on this axis for the `1.0` value.
|
||||||
|
/// See [measurement_unit](#method.measurement_unit).
|
||||||
|
///
|
||||||
|
/// * `unit_vector`:
|
||||||
|
/// A vector providing the direction in the Universe space of
|
||||||
|
/// this axis.
|
||||||
|
///
|
||||||
|
/// * `set`:
|
||||||
|
/// The valid numbers on this axis.
|
||||||
|
///
|
||||||
|
/// * `minimum`:
|
||||||
|
/// The minimum value described by this axis *included*.
|
||||||
|
///
|
||||||
|
/// * `maximum`:
|
||||||
|
/// The maximum value described by this axis *included*.
|
||||||
|
///
|
||||||
|
/// * `steps`:
|
||||||
|
/// The number of steps, or discrete *ticks* on this axis.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
unit: &str,
|
unit: &str,
|
||||||
unit_vector: Vec<f64>,
|
unit_vector: Vec<f64>,
|
||||||
@@ -142,20 +183,48 @@ impl Axis {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The unit, as in [SI unit] used on this axis, more specifically,
|
||||||
|
/// a [metric prefix] of the **meter**.
|
||||||
|
///
|
||||||
|
/// Currently the following values are supported:
|
||||||
|
/// * `m`
|
||||||
|
/// * `dm`
|
||||||
|
/// * `cm`
|
||||||
|
/// * `mm`
|
||||||
|
/// * `um`
|
||||||
|
/// * `nm`
|
||||||
|
/// * `pm`
|
||||||
|
///
|
||||||
|
/// [SI unit]: https://en.wikipedia.org/wiki/International_System_of_Units
|
||||||
|
/// [metric prefix]: https://en.wikipedia.org/wiki/Metric_prefix
|
||||||
pub fn measurement_unit(&self) -> &str {
|
pub fn measurement_unit(&self) -> &str {
|
||||||
self.measurement_unit.to_str()
|
self.measurement_unit.to_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The unit vector of the axis.
|
||||||
|
///
|
||||||
|
/// This vector is expressed in the Universe coordinate system.
|
||||||
pub fn unit_vector(&self) -> &Position {
|
pub fn unit_vector(&self) -> &Position {
|
||||||
&self.unit_vector
|
&self.unit_vector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The valid number range and properties on this axis.
|
||||||
pub fn graduation(&self) -> &Graduation {
|
pub fn graduation(&self) -> &Graduation {
|
||||||
&self.graduation
|
&self.graduation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Project a point expressed in Universe coordinates from the origin of this
|
/// Project a position on this axis.
|
||||||
// axis on this axis.
|
///
|
||||||
|
/// The resulting coordinate is expressed as an encoded coordinate
|
||||||
|
/// on this axis.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// The position to project on this axis. It must be defined in
|
||||||
|
/// Universe coordinates, but with any translations already
|
||||||
|
/// applied so that the origin of the vector is the origin of
|
||||||
|
/// this axis.
|
||||||
pub fn project_in(&self, position: &Position) -> Result<Coordinate, String> {
|
pub fn project_in(&self, position: &Position) -> Result<Coordinate, String> {
|
||||||
let max = self.graduation.maximum;
|
let max = self.graduation.maximum;
|
||||||
let min = self.graduation.minimum;
|
let min = self.graduation.minimum;
|
||||||
@@ -192,7 +261,19 @@ impl Axis {
|
|||||||
self.encode(d)
|
self.encode(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a value on this axis to Universe coordinates, based from the origin of this axis.
|
/// Convert an encoded coordinate expressed on this axis into a
|
||||||
|
/// position.
|
||||||
|
///
|
||||||
|
/// The resulting position is expressed in the Universe reference
|
||||||
|
/// space, but from the origin of this axis. Any required
|
||||||
|
/// translation must be applied to this resulting position to obtain
|
||||||
|
/// an absolute value in the Universe space.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `coordinate`:
|
||||||
|
/// The coordinate to project out of this axis. It must be
|
||||||
|
/// defined as an encoded coordinate on this axis.
|
||||||
pub fn project_out(&self, coordinate: &Coordinate) -> Result<Position, String> {
|
pub fn project_out(&self, coordinate: &Coordinate) -> Result<Position, String> {
|
||||||
let d = self.decode(coordinate)?;
|
let d = self.decode(coordinate)?;
|
||||||
|
|
||||||
@@ -202,7 +283,13 @@ impl Axis {
|
|||||||
Ok(&self.unit_vector * d)
|
Ok(&self.unit_vector * d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value is expressed on the current Axis, not in absolute coordinates!
|
/// Encode a coordinate expressed on this axis.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `val`:
|
||||||
|
/// The coordinate to encode. It must be defined as a
|
||||||
|
/// coordinate on this axis.
|
||||||
pub fn encode(&self, val: f64) -> Result<Coordinate, String> {
|
pub fn encode(&self, val: f64) -> Result<Coordinate, String> {
|
||||||
let max = self.graduation.maximum;
|
let max = self.graduation.maximum;
|
||||||
let min = self.graduation.minimum;
|
let min = self.graduation.minimum;
|
||||||
@@ -229,7 +316,13 @@ impl Axis {
|
|||||||
Ok(v.into())
|
Ok(v.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value is expressed on the current Axis, not in absolute coordinates!
|
/// Decode a coordinate expressed on this axis.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `val`:
|
||||||
|
/// The coordinate to decode. It must be defined as an encoded
|
||||||
|
/// coordinate on this axis.
|
||||||
pub fn decode(&self, val: &Coordinate) -> Result<f64, String> {
|
pub fn decode(&self, val: &Coordinate) -> Result<f64, String> {
|
||||||
let max = self.graduation.maximum;
|
let max = self.graduation.maximum;
|
||||||
let min = self.graduation.minimum;
|
let min = self.graduation.minimum;
|
||||||
|
|||||||
@@ -11,18 +11,36 @@ use std::ops::Sub;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
|
/// Store efficiently a coordinate.
|
||||||
|
///
|
||||||
|
/// While you can manually create a `Coordinate` value directly, using
|
||||||
|
/// the `From` trait will automatically choose the most efficient enum
|
||||||
|
/// member to store the value. This it the recommended way of using this
|
||||||
|
/// struct.
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||||
pub enum Coordinate {
|
pub enum Coordinate {
|
||||||
|
/// Encoded coordinates whose value is in the range `[0; 2^8[`.
|
||||||
CoordinateU8(u8),
|
CoordinateU8(u8),
|
||||||
|
/// Encoded coordinates whose value is in the range `[0; 2^16[`,
|
||||||
|
/// but should be used only for the range `[2^8; 2^16[`.
|
||||||
CoordinateU16(u16),
|
CoordinateU16(u16),
|
||||||
|
/// Encoded coordinates whose value is in the range `[0; 2^32[`,
|
||||||
|
/// but should be used only for the range `[2^16; 2^32[`.
|
||||||
CoordinateU32(u32),
|
CoordinateU32(u32),
|
||||||
|
/// Encoded coordinates whose value is in the range `[0; 2^64[`,
|
||||||
|
/// but should be used only for the range `[2^32; 2^64[`.
|
||||||
CoordinateU64(u64),
|
CoordinateU64(u64),
|
||||||
// We currently assume that 2^64 is enough to store encoded position values per axis.
|
// We currently assume that 2^64 is enough to store encoded position values per axis.
|
||||||
//CoordinateU128(u128),
|
//CoordinateU128(u128),
|
||||||
|
/// Decoded coordinate value expressed as a floating point value over 64 bits.
|
||||||
|
/// For details on the precision, please see the
|
||||||
|
/// [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) reference.
|
||||||
CoordinateF64(f64),
|
CoordinateF64(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Coordinate {
|
impl Coordinate {
|
||||||
|
/// Return the value as a `f64`, this may introduce a loss of
|
||||||
|
/// precision for encoded values.
|
||||||
pub fn f64(&self) -> f64 {
|
pub fn f64(&self) -> f64 {
|
||||||
match *self {
|
match *self {
|
||||||
Coordinate::CoordinateU8(v) => f64::from(v),
|
Coordinate::CoordinateU8(v) => f64::from(v),
|
||||||
@@ -33,6 +51,7 @@ impl Coordinate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the value as `u64`, this is valid only on encoded values.
|
||||||
pub fn u64(&self) -> u64 {
|
pub fn u64(&self) -> u64 {
|
||||||
match *self {
|
match *self {
|
||||||
Coordinate::CoordinateU8(v) => u64::from(v),
|
Coordinate::CoordinateU8(v) => u64::from(v),
|
||||||
@@ -43,6 +62,8 @@ impl Coordinate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the value as `usize`, this is valid only on encoded
|
||||||
|
/// values.
|
||||||
pub fn as_usize(&self) -> usize {
|
pub fn as_usize(&self) -> usize {
|
||||||
self.u64() as usize
|
self.u64() as usize
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,39 @@ use super::coordinate::Coordinate;
|
|||||||
use super::position::Position;
|
use super::position::Position;
|
||||||
use super::MAX_K;
|
use super::MAX_K;
|
||||||
|
|
||||||
|
/// Kinds of space coordinate systems, or bases
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub enum CoordinateSystem {
|
pub enum CoordinateSystem {
|
||||||
Universe { origin: Position },
|
/// Absolute base, which allows to generate transformation between
|
||||||
// Coordinates in Universe, expressed in f64, and in the Universe number of dimensions.
|
/// spaces by anchoring them relative to each other.
|
||||||
AffineSystem { origin: Position, axes: Vec<Axis> },
|
Universe {
|
||||||
|
/// A position which contains zeroes for all its coordinates,
|
||||||
|
/// but has a coordinate per dimensions of the highest
|
||||||
|
/// dimensions space referenced.
|
||||||
|
origin: Position,
|
||||||
|
},
|
||||||
|
/// Base which needs only an affine transformation to map into the Universe.
|
||||||
|
AffineSystem {
|
||||||
|
/// Coordinates in Universe, expressed in f64, or decoded, and
|
||||||
|
/// in the Universe number of dimensions.
|
||||||
|
origin: Position,
|
||||||
|
|
||||||
|
/// The definition of the coordinate system, through its axes.
|
||||||
|
axes: Vec<Axis>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoordinateSystem {
|
impl CoordinateSystem {
|
||||||
|
/// Instantiate a new coordinate system.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `origin`:
|
||||||
|
/// The translation vector in Universe coordinates of this
|
||||||
|
/// base.
|
||||||
|
///
|
||||||
|
/// * `axes`:
|
||||||
|
/// The list of axes defining the coordinate system.
|
||||||
pub fn new(origin: Vec<f64>, axes: Vec<Axis>) -> Self {
|
pub fn new(origin: Vec<f64>, axes: Vec<Axis>) -> Self {
|
||||||
CoordinateSystem::AffineSystem {
|
CoordinateSystem::AffineSystem {
|
||||||
origin: origin.into(),
|
origin: origin.into(),
|
||||||
@@ -21,6 +46,7 @@ impl CoordinateSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The translation vector, in Universe coordinates.
|
||||||
pub fn origin(&self) -> &Position {
|
pub fn origin(&self) -> &Position {
|
||||||
match self {
|
match self {
|
||||||
CoordinateSystem::Universe { origin, .. } => origin,
|
CoordinateSystem::Universe { origin, .. } => origin,
|
||||||
@@ -28,6 +54,7 @@ impl CoordinateSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The axes definition of this base.
|
||||||
pub fn axes(&self) -> &Vec<Axis> {
|
pub fn axes(&self) -> &Vec<Axis> {
|
||||||
match self {
|
match self {
|
||||||
CoordinateSystem::Universe { .. } => {
|
CoordinateSystem::Universe { .. } => {
|
||||||
@@ -38,6 +65,7 @@ impl CoordinateSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number of dimensions of positions within this base.
|
||||||
pub fn dimensions(&self) -> usize {
|
pub fn dimensions(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
CoordinateSystem::Universe { .. } => MAX_K,
|
CoordinateSystem::Universe { .. } => MAX_K,
|
||||||
@@ -45,6 +73,10 @@ impl CoordinateSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The smallest bounding box containing the whole base, expressed
|
||||||
|
/// in decoded Universe coordinates.
|
||||||
|
///
|
||||||
|
// FIXME: Add the translation vector!
|
||||||
pub fn bounding_box(&self) -> (Position, Position) {
|
pub fn bounding_box(&self) -> (Position, Position) {
|
||||||
let mut low = Vec::with_capacity(self.dimensions());
|
let mut low = Vec::with_capacity(self.dimensions());
|
||||||
let mut high = Vec::with_capacity(self.dimensions());
|
let mut high = Vec::with_capacity(self.dimensions());
|
||||||
@@ -67,6 +99,9 @@ impl CoordinateSystem {
|
|||||||
(low.into(), high.into())
|
(low.into(), high.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The volume of this space.
|
||||||
|
///
|
||||||
|
// FIXME: This assumes orthogonal spaces!
|
||||||
pub fn volume(&self) -> f64 {
|
pub fn volume(&self) -> f64 {
|
||||||
let (low, high) = self.bounding_box();
|
let (low, high) = self.bounding_box();
|
||||||
let difference: Vec<_> = (high - low).into();
|
let difference: Vec<_> = (high - low).into();
|
||||||
@@ -80,8 +115,19 @@ impl CoordinateSystem {
|
|||||||
volume
|
volume
|
||||||
}
|
}
|
||||||
|
|
||||||
// The position is expressed in coordinates in the universe,
|
/// Rebase a position in this coordinate space.
|
||||||
// return a position in the current coordinate system.
|
///
|
||||||
|
/// Each coordinate is encoded individually, and a new `Position`
|
||||||
|
/// is generated.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// expressed in decoded Universe coordinates.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// The encoded coordinates within this coordinate system.
|
||||||
pub fn rebase(&self, position: &Position) -> Result<Position, String> {
|
pub fn rebase(&self, position: &Position) -> Result<Position, String> {
|
||||||
match self {
|
match self {
|
||||||
CoordinateSystem::Universe { origin } => {
|
CoordinateSystem::Universe { origin } => {
|
||||||
@@ -106,8 +152,16 @@ impl CoordinateSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The position is expressed in coordinates in the current coordinate system,
|
/// Express the position in the Universe coordinate system.
|
||||||
// return a position in Universe coordinates.
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// expressed as an encoded coordinates in the coordinate system.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// The position expressed in Universe decoded coordinates.
|
||||||
pub fn absolute_position(&self, position: &Position) -> Result<Position, String> {
|
pub fn absolute_position(&self, position: &Position) -> Result<Position, String> {
|
||||||
match self {
|
match self {
|
||||||
CoordinateSystem::Universe { origin } => {
|
CoordinateSystem::Universe { origin } => {
|
||||||
@@ -132,8 +186,19 @@ impl CoordinateSystem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The position is expressed in the current system
|
/// Encode a position expressed in the current coordinate system.
|
||||||
// Encode each coordinate separately and return an encoded Position
|
///
|
||||||
|
/// Each coordinate is encoded individually, and a new `Position`
|
||||||
|
/// is generated.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// expressed in the current coordinate system.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// The encoded coordinates within this coordinate system.
|
||||||
pub fn encode(&self, position: &[f64]) -> Result<Position, String> {
|
pub fn encode(&self, position: &[f64]) -> Result<Position, String> {
|
||||||
let mut encoded = vec![];
|
let mut encoded = vec![];
|
||||||
|
|
||||||
@@ -155,8 +220,20 @@ impl CoordinateSystem {
|
|||||||
Ok(encoded.into())
|
Ok(encoded.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// The position is expressed in the current system as an encoded value,
|
/// Decode a position expressed in the current coordinate system as
|
||||||
// return a position in the current system as f64 values.
|
/// an encoded value.
|
||||||
|
///
|
||||||
|
/// Each coordinate is decoded individually.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// expressed in the current coordinate system, as encoded
|
||||||
|
/// values.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// The decoded coordinates within this coordinate system.
|
||||||
pub fn decode(&self, position: &Position) -> Result<Vec<f64>, String> {
|
pub fn decode(&self, position: &Position) -> Result<Vec<f64>, String> {
|
||||||
let mut decoded = vec![];
|
let mut decoded = vec![];
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
//! Reference space definitions.
|
||||||
|
//!
|
||||||
|
//! This include notions such as shapes, positions, axes, etc…
|
||||||
|
|
||||||
mod axis;
|
mod axis;
|
||||||
mod coordinate;
|
mod coordinate;
|
||||||
mod coordinate_system;
|
mod coordinate_system;
|
||||||
@@ -18,7 +22,14 @@ pub use coordinate_system::CoordinateSystem;
|
|||||||
pub use position::Position;
|
pub use position::Position;
|
||||||
pub use shape::Shape;
|
pub use shape::Shape;
|
||||||
|
|
||||||
pub const MAX_K: usize = 3;
|
// Maximum number of dimensions currently supported.
|
||||||
|
//
|
||||||
|
// **Note:** This will be deprecated as soon as support is implemented
|
||||||
|
// in some dependencies. This is linked to limitations in
|
||||||
|
// [ironsea_index_sfc_dbc].
|
||||||
|
//
|
||||||
|
// [ironsea_index_sfc_dbc]: https://github.com/epfl-dias/ironsea_index_sfc_dbc
|
||||||
|
const MAX_K: usize = 3;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref UNIVERSE: Space = Space {
|
static ref UNIVERSE: Space = Space {
|
||||||
@@ -29,6 +40,7 @@ lazy_static! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A reference space, defined by its name and coordinate system.
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct Space {
|
pub struct Space {
|
||||||
name: String,
|
name: String,
|
||||||
@@ -36,6 +48,15 @@ pub struct Space {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Space {
|
impl Space {
|
||||||
|
/// Instantiate a new space.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `name`:
|
||||||
|
/// Id of the reference space.
|
||||||
|
///
|
||||||
|
/// * `system`:
|
||||||
|
/// Coordinate system defintion of the reference space
|
||||||
pub fn new<S>(name: S, system: CoordinateSystem) -> Self
|
pub fn new<S>(name: S, system: CoordinateSystem) -> Self
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
@@ -46,54 +67,93 @@ impl Space {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the Universe Space.
|
||||||
|
///
|
||||||
|
/// This space contains all of the spaces, and allows us to connect
|
||||||
|
/// them between each others.
|
||||||
pub fn universe() -> &'static Self {
|
pub fn universe() -> &'static Self {
|
||||||
&UNIVERSE
|
&UNIVERSE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transform a position from space `from` into a position in space `to`.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// Position to transform, expressed as encoded coordinates.
|
||||||
|
///
|
||||||
|
/// * `from`:
|
||||||
|
/// Space in which `position` is defined.
|
||||||
|
///
|
||||||
|
/// * `to`:
|
||||||
|
/// Target space in which `position` should be expressed.
|
||||||
pub fn change_base(position: &Position, from: &Space, to: &Space) -> Result<Position, String> {
|
pub fn change_base(position: &Position, from: &Space, to: &Space) -> Result<Position, String> {
|
||||||
to.rebase(&from.absolute_position(position)?)
|
to.rebase(&from.absolute_position(position)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Id of the reference space.
|
||||||
pub fn name(&self) -> &String {
|
pub fn name(&self) -> &String {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Origin of the space, expressed in Universe.
|
||||||
pub fn origin(&self) -> &Position {
|
pub fn origin(&self) -> &Position {
|
||||||
self.system.origin()
|
self.system.origin()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Axes definition of the space.
|
||||||
pub fn axes(&self) -> &Vec<Axis> {
|
pub fn axes(&self) -> &Vec<Axis> {
|
||||||
self.system.axes()
|
self.system.axes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the bounding box enclosing the whole space.
|
||||||
pub fn bounding_box(&self) -> (Position, Position) {
|
pub fn bounding_box(&self) -> (Position, Position) {
|
||||||
self.system.bounding_box()
|
self.system.bounding_box()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Total volume of the reference space.
|
||||||
pub fn volume(&self) -> f64 {
|
pub fn volume(&self) -> f64 {
|
||||||
self.system.volume()
|
self.system.volume()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The position is expressed in coordinates in the universe,
|
// `position` is expressed in the Universe, this return encoded
|
||||||
// return a position in the current space.
|
// coordinates in the current space.
|
||||||
pub fn rebase(&self, position: &Position) -> Result<Position, String> {
|
fn rebase(&self, position: &Position) -> Result<Position, String> {
|
||||||
self.system.rebase(position)
|
self.system.rebase(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The position is expressed in coordinates in the current space,
|
// The position is expressed in encoded coordinates in the current space,
|
||||||
// return an absolute position in Universe.
|
// return an absolute position in Universe.
|
||||||
pub fn absolute_position(&self, position: &Position) -> Result<Position, String> {
|
fn absolute_position(&self, position: &Position) -> Result<Position, String> {
|
||||||
self.system.absolute_position(position)
|
self.system.absolute_position(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The position is expressed in the current space as an encoded value,
|
/// Decode coordinates expressed in the current space, to their
|
||||||
// return a position in the current system as f64 values
|
/// values within the axes definitions.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// expressed in encoded coordinates within the current space.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// The decoded position within the space.
|
||||||
pub fn decode(&self, position: &Position) -> Result<Vec<f64>, String> {
|
pub fn decode(&self, position: &Position) -> Result<Vec<f64>, String> {
|
||||||
self.system.decode(position)
|
self.system.decode(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The position is expressed in the current space,
|
/// Encode a position expressed in the current space within the axes
|
||||||
// return a position expressed in the current space as an encoded value.
|
/// value ranges.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// expressed in the current space.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// The encoded coordinates within the space.
|
||||||
pub fn encode(&self, position: &[f64]) -> Result<Position, String> {
|
pub fn encode(&self, position: &[f64]) -> Result<Position, String> {
|
||||||
self.system.encode(position)
|
self.system.encode(position)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,24 +18,31 @@ use serde::Serialize;
|
|||||||
|
|
||||||
use super::coordinate::Coordinate;
|
use super::coordinate::Coordinate;
|
||||||
|
|
||||||
|
/// Store a position as efficiently as possible in terms of space.
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, Serialize)]
|
||||||
pub enum Position {
|
pub enum Position {
|
||||||
|
/// 1 dimension positions.
|
||||||
Position1(Coordinate),
|
Position1(Coordinate),
|
||||||
|
/// 2 dimensions positions.
|
||||||
Position2([Coordinate; 2]),
|
Position2([Coordinate; 2]),
|
||||||
|
/// 3 dimensions positions.
|
||||||
Position3([Coordinate; 3]),
|
Position3([Coordinate; 3]),
|
||||||
|
/// 4 dimensions positions.
|
||||||
Position4([Coordinate; 4]),
|
Position4([Coordinate; 4]),
|
||||||
|
/// 5 dimensions positions.
|
||||||
Position5([Coordinate; 5]),
|
Position5([Coordinate; 5]),
|
||||||
|
/// 6 dimensions positions.
|
||||||
Position6([Coordinate; 6]),
|
Position6([Coordinate; 6]),
|
||||||
|
/// 7 dimensions positions.
|
||||||
Position7([Coordinate; 7]),
|
Position7([Coordinate; 7]),
|
||||||
|
/// 8 dimensions positions.
|
||||||
Position8([Coordinate; 8]),
|
Position8([Coordinate; 8]),
|
||||||
|
/// N dimensions positions.
|
||||||
PositionN(Vec<Coordinate>),
|
PositionN(Vec<Coordinate>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
pub fn new(coordinates: Vec<Coordinate>) -> Self {
|
/// Returns the number of dimensions or size of the vector.
|
||||||
coordinates.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dimensions(&self) -> usize {
|
pub fn dimensions(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Position::Position1(_) => 1,
|
Position::Position1(_) => 1,
|
||||||
@@ -50,7 +57,7 @@ impl Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns ||self||
|
/// Compute `||self||`.
|
||||||
pub fn norm(&self) -> f64 {
|
pub fn norm(&self) -> f64 {
|
||||||
if let Position::Position1(coordinates) = self {
|
if let Position::Position1(coordinates) = self {
|
||||||
// the square root of a single number to the square is its positive value, so ensure it is.
|
// the square root of a single number to the square is its positive value, so ensure it is.
|
||||||
@@ -68,32 +75,48 @@ impl Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unit / Normalized vector from self.
|
/// Compute the unit vector pointing in the same direction as `self`.
|
||||||
pub fn unit(&self) -> Self {
|
pub fn unit(&self) -> Self {
|
||||||
self * (1f64 / self.norm())
|
self * (1f64 / self.norm())
|
||||||
}
|
}
|
||||||
|
|
||||||
// This multiplies self^T with other, producing a scalar value
|
/// Multiplies `self` with `rhs`, producing a scalar value.
|
||||||
pub fn dot_product(&self, other: &Self) -> f64 {
|
///
|
||||||
assert_eq!(self.dimensions(), other.dimensions());
|
/// `self • rhs = product`
|
||||||
|
///
|
||||||
|
/// **Note:** The two vector sizes must be equal, a.k.a the two
|
||||||
|
/// vectors must have the same number of dimensions.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// `rhs`:
|
||||||
|
/// The right-hand side vector.
|
||||||
|
pub fn dot_product(&self, rhs: &Self) -> f64 {
|
||||||
|
assert_eq!(self.dimensions(), rhs.dimensions());
|
||||||
|
|
||||||
let mut product = 0f64;
|
let mut product = 0f64;
|
||||||
|
|
||||||
for k in 0..self.dimensions() {
|
for k in 0..self.dimensions() {
|
||||||
product += (self[k] * other[k]).f64();
|
product += (self[k] * rhs[k]).f64();
|
||||||
}
|
}
|
||||||
|
|
||||||
product
|
product
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove bits of precision.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `scale`:
|
||||||
|
/// Number of bits of precision to remove from each coordinates.
|
||||||
pub fn reduce_precision(&self, scale: u32) -> Self {
|
pub fn reduce_precision(&self, scale: u32) -> Self {
|
||||||
let mut position = Vec::with_capacity(self.dimensions());
|
let mut position = Vec::with_capacity(self.dimensions());
|
||||||
|
|
||||||
for i in 0..self.dimensions() {
|
for i in 0..self.dimensions() {
|
||||||
position.push((self[i].u64() >> scale).into())
|
position.push(self[i].u64() >> scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
Position::new(position)
|
position.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +176,10 @@ impl Index<usize> for Position {
|
|||||||
|
|
||||||
fn index(&self, k: usize) -> &Self::Output {
|
fn index(&self, k: usize) -> &Self::Output {
|
||||||
match self {
|
match self {
|
||||||
Position::Position1(coordinate) => coordinate,
|
Position::Position1(coordinate) => {
|
||||||
|
assert_eq!(k, 0);
|
||||||
|
coordinate
|
||||||
|
}
|
||||||
Position::Position2(coordinates) => &coordinates[k],
|
Position::Position2(coordinates) => &coordinates[k],
|
||||||
Position::Position3(coordinates) => &coordinates[k],
|
Position::Position3(coordinates) => &coordinates[k],
|
||||||
Position::Position4(coordinates) => &coordinates[k],
|
Position::Position4(coordinates) => &coordinates[k],
|
||||||
@@ -169,7 +195,10 @@ impl Index<usize> for Position {
|
|||||||
impl IndexMut<usize> for Position {
|
impl IndexMut<usize> for Position {
|
||||||
fn index_mut(&mut self, k: usize) -> &mut Self::Output {
|
fn index_mut(&mut self, k: usize) -> &mut Self::Output {
|
||||||
match self {
|
match self {
|
||||||
Position::Position1(coordinate) => coordinate,
|
Position::Position1(coordinate) => {
|
||||||
|
assert_eq!(k, 0);
|
||||||
|
coordinate
|
||||||
|
}
|
||||||
Position::Position2(coordinates) => &mut coordinates[k],
|
Position::Position2(coordinates) => &mut coordinates[k],
|
||||||
Position::Position3(coordinates) => &mut coordinates[k],
|
Position::Position3(coordinates) => &mut coordinates[k],
|
||||||
Position::Position4(coordinates) => &mut coordinates[k],
|
Position::Position4(coordinates) => &mut coordinates[k],
|
||||||
|
|||||||
@@ -5,16 +5,33 @@ use super::Coordinate;
|
|||||||
use super::Position;
|
use super::Position;
|
||||||
use super::Space;
|
use super::Space;
|
||||||
|
|
||||||
|
/// Known shapes descriptions
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
|
/// A singular point in space.
|
||||||
Point(Position),
|
Point(Position),
|
||||||
//HyperRectangle([Position; MAX_K]),
|
//HyperRectangle([Position; MAX_K]),
|
||||||
|
/// A sphere in space.
|
||||||
HyperSphere(Position, Coordinate),
|
HyperSphere(Position, Coordinate),
|
||||||
|
|
||||||
|
/// Hyperrectangle whose faces have one of the axis as a normal.
|
||||||
BoundingBox(Position, Position),
|
BoundingBox(Position, Position),
|
||||||
//Nifti(nifti_data??),
|
//Nifti(nifti_data??),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shape {
|
impl Shape {
|
||||||
|
/// Convert the encoded coordinates between two reference spaces.
|
||||||
|
///
|
||||||
|
/// The resulting shape is expressed in encoded coordinates in the
|
||||||
|
/// target space.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `from`:
|
||||||
|
/// Current reference space of the shape.
|
||||||
|
///
|
||||||
|
/// * `to`:
|
||||||
|
/// Target reference space.
|
||||||
pub fn rebase(&self, from: &Space, to: &Space) -> Result<Shape, String> {
|
pub fn rebase(&self, from: &Space, to: &Space) -> Result<Shape, String> {
|
||||||
match self {
|
match self {
|
||||||
Shape::Point(position) => Ok(Shape::Point(Space::change_base(position, from, to)?)),
|
Shape::Point(position) => Ok(Shape::Point(Space::change_base(position, from, to)?)),
|
||||||
@@ -36,6 +53,20 @@ impl Shape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decode the coordinates of the shape.
|
||||||
|
///
|
||||||
|
/// The encoded coordinates of the shapes are expressed in the
|
||||||
|
/// provided space.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `space`:
|
||||||
|
/// Reference space of the shape. It is used to decode the
|
||||||
|
/// encoded coordinates into positions.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// The shape with decoded positions within the space.
|
||||||
pub fn decode(&self, space: &Space) -> Result<Shape, String> {
|
pub fn decode(&self, space: &Space) -> Result<Shape, String> {
|
||||||
let s = match self {
|
let s = match self {
|
||||||
Shape::Point(position) => Shape::Point(space.decode(position)?.into()),
|
Shape::Point(position) => Shape::Point(space.decode(position)?.into()),
|
||||||
@@ -51,6 +82,19 @@ impl Shape {
|
|||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encode the positions of the shape.
|
||||||
|
///
|
||||||
|
/// The positions of the shapes are expressed in the provided space.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `space`:
|
||||||
|
/// Reference space of the shape. It is used to encode the
|
||||||
|
/// positions into encoded coordinates.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// The shape with encoded coordinates within the space.
|
||||||
pub fn encode(&self, space: &Space) -> Result<Shape, String> {
|
pub fn encode(&self, space: &Space) -> Result<Shape, String> {
|
||||||
let s = match self {
|
let s = match self {
|
||||||
Shape::Point(position) => {
|
Shape::Point(position) => {
|
||||||
@@ -72,6 +116,10 @@ impl Shape {
|
|||||||
Ok(s)
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the minimum bounding box of the shape.
|
||||||
|
///
|
||||||
|
/// This is an hyperrectangle whose faces are perpendicular to an
|
||||||
|
/// axis of the space, and which minimally covers the shape.
|
||||||
pub fn get_mbb(&self) -> (Position, Position) {
|
pub fn get_mbb(&self) -> (Position, Position) {
|
||||||
match self {
|
match self {
|
||||||
Shape::Point(position) => (position.clone(), position.clone()),
|
Shape::Point(position) => (position.clone(), position.clone()),
|
||||||
@@ -88,6 +136,12 @@ impl Shape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the shape overlaps with the given position.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `position`:
|
||||||
|
/// The position to check.
|
||||||
pub fn contains(&self, position: &Position) -> bool {
|
pub fn contains(&self, position: &Position) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Shape::Point(reference) => reference == position,
|
Shape::Point(reference) => reference == position,
|
||||||
@@ -178,9 +232,8 @@ impl Shape {
|
|||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform a Shape into a list of Position which approximate the shape.
|
/// Transform a Shape into a list of `Position` which approximate
|
||||||
// Note:
|
/// the shape.
|
||||||
// * All output positions are expressed within the space.
|
|
||||||
// TODO: Return an iterator instead, for performance!
|
// TODO: Return an iterator instead, for performance!
|
||||||
pub fn rasterise(&self) -> Result<Vec<Position>, String> {
|
pub fn rasterise(&self) -> Result<Vec<Position>, String> {
|
||||||
match self {
|
match self {
|
||||||
@@ -200,10 +253,14 @@ impl Shape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform a Shape into a list of Position which approximate the shape.
|
/// Transform a Shape into a list of `Position` which approximate
|
||||||
// Note:
|
/// the shape, in absolute, or Universe positions.
|
||||||
// * All input positions are expressed within the space.
|
///
|
||||||
// * All output positions are expressed in absolute positions in Universe
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `space`:
|
||||||
|
/// Reference space in which the shape is expressed.
|
||||||
|
///
|
||||||
// TODO: Return an iterator instead, for performance!
|
// TODO: Return an iterator instead, for performance!
|
||||||
pub fn rasterise_from(&self, space: &Space) -> Result<Vec<Position>, String> {
|
pub fn rasterise_from(&self, space: &Space) -> Result<Vec<Position>, String> {
|
||||||
Ok(self
|
Ok(self
|
||||||
@@ -216,6 +273,7 @@ impl Shape {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the volume.
|
||||||
pub fn volume(&self) -> f64 {
|
pub fn volume(&self) -> f64 {
|
||||||
match self {
|
match self {
|
||||||
Shape::Point(_) => std::f64::EPSILON, // Smallest non-zero volume possible
|
Shape::Point(_) => std::f64::EPSILON, // Smallest non-zero volume possible
|
||||||
|
|||||||
@@ -193,11 +193,13 @@ impl SpaceDB {
|
|||||||
&self.reference_space
|
&self.reference_space
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Comment this for now, as this is not yet used.
|
||||||
// The smallest volume threshold, which is the highest resolution, will
|
// The smallest volume threshold, which is the highest resolution, will
|
||||||
// be at position 0
|
// be at position 0
|
||||||
fn highest_resolution(&self) -> usize {
|
fn highest_resolution(&self) -> usize {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// The highest volume threshold, which is the lowest resolution, will
|
// The highest volume threshold, which is the lowest resolution, will
|
||||||
// be at position len - 1
|
// be at position len - 1
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ impl SpaceIndex {
|
|||||||
self.index.find_by_value(id)
|
self.index.find_by_value(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inputs and Results are also in encoded space coordinates.
|
// Inputs and Results are also in encoded space coordinates.
|
||||||
pub fn find_by_shape(
|
pub fn find_by_shape(
|
||||||
&self,
|
&self,
|
||||||
shape: &Shape,
|
shape: &Shape,
|
||||||
|
|||||||
30
src/lib.rs
30
src/lib.rs
@@ -1,3 +1,33 @@
|
|||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
|
//! # Mercator DB
|
||||||
|
//!
|
||||||
|
//! Database model for the Mercator spatial index.
|
||||||
|
//!
|
||||||
|
//! ## Mercator: Spatial Index
|
||||||
|
//!
|
||||||
|
//! **Mercator** is a spatial *volumetric* index for the
|
||||||
|
//! [Human Brain Project]. It is a component of the [Knowledge Graph]
|
||||||
|
//! service, which provides the spatial anchoring for the metadata
|
||||||
|
//! registered as well as processes the volumetric queries.
|
||||||
|
//!
|
||||||
|
//! It is build on top of the Iron Sea database toolkit.
|
||||||
|
//!
|
||||||
|
//! ## Iron Sea: Database Toolkit
|
||||||
|
//! **Iron Sea** provides a set of database engine bricks, which can be
|
||||||
|
//! combined and applied on arbitrary data structures.
|
||||||
|
//!
|
||||||
|
//! Unlike a traditional database, it does not assume a specific
|
||||||
|
//! physical structure for the tables nor the records, but relies on the
|
||||||
|
//! developer to provide a set of extractor functions which are used by
|
||||||
|
//! the specific indices provided.
|
||||||
|
//!
|
||||||
|
//! This enables the index implementations to be agnostic from the
|
||||||
|
//! underlying data structure, and re-used.
|
||||||
|
//!
|
||||||
|
//! [Human Brain Project]: http://www.humanbrainproject.eu
|
||||||
|
//! [Knowledge Graph]: http://www.humanbrainproject.eu/en/explore-the-brain/search/
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//! Bincode support
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufWriter;
|
use std::io::BufWriter;
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
@@ -9,6 +11,12 @@ use serde::Serialize;
|
|||||||
|
|
||||||
use super::model;
|
use super::model;
|
||||||
|
|
||||||
|
/// Deserialize a data structure.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `from`:
|
||||||
|
/// File to read, which contains Bincode data.
|
||||||
pub fn load<T>(from: &str) -> Result<T, Error>
|
pub fn load<T>(from: &str) -> Result<T, Error>
|
||||||
where
|
where
|
||||||
T: DeserializeOwned,
|
T: DeserializeOwned,
|
||||||
@@ -26,6 +34,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialize a data structure.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `data`:
|
||||||
|
/// Data to serialize.
|
||||||
|
///
|
||||||
|
/// * `to`:
|
||||||
|
/// File to use to store the serialized data.
|
||||||
pub fn store<T>(data: T, to: &str) -> Result<(), Error>
|
pub fn store<T>(data: T, to: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: Serialize,
|
T: Serialize,
|
||||||
@@ -44,6 +61,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build an index from the input files.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `name`:
|
||||||
|
/// Index name, this value will also be used to generate file names
|
||||||
|
/// as such:
|
||||||
|
/// * `.spaces.bin` and `.objects.bin` will be appended for the
|
||||||
|
/// input files.
|
||||||
|
/// * `.index` will be appended for the index file.
|
||||||
|
///
|
||||||
|
/// * `version`:
|
||||||
|
/// Parameter to distinguish revisions of an index.
|
||||||
|
///
|
||||||
|
/// * `scales`:
|
||||||
|
/// An optional list of specific index resolutions to generates on
|
||||||
|
/// top of the full resolution one.
|
||||||
|
///
|
||||||
|
/// * `max_elements`:
|
||||||
|
/// If this is specified, automatically generates scaled indices, by
|
||||||
|
/// halving the number elements between resolutions, and stop
|
||||||
|
/// generating indices either when the number of points remaining is
|
||||||
|
/// equal to the number of distinct Ids, or smaller or equal to this
|
||||||
|
/// value.
|
||||||
|
///
|
||||||
|
/// **Note**: `max_elements` is ignored when `scales` is not `None`.
|
||||||
pub fn build(
|
pub fn build(
|
||||||
name: &str,
|
name: &str,
|
||||||
version: &str,
|
version: &str,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//! JSON support
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufWriter;
|
use std::io::BufWriter;
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
@@ -29,6 +31,14 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserialise a JSON file.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `name`:
|
||||||
|
/// Base name of the file,
|
||||||
|
/// * `.xyz` will be automatically appended for the source file, while
|
||||||
|
/// * `.bin` will be appended for the output file.
|
||||||
pub fn from<T>(name: &str) -> Result<(), Error>
|
pub fn from<T>(name: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: Serialize + DeserializeOwned,
|
T: Serialize + DeserializeOwned,
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
//! Persistent data functions and types.
|
||||||
|
//!
|
||||||
|
//! Serialisation / deserialisation functions and structures used to
|
||||||
|
//! store and manipulate indices and data.
|
||||||
|
|
||||||
pub mod bincode;
|
pub mod bincode;
|
||||||
pub mod json;
|
pub mod json;
|
||||||
pub mod model;
|
pub mod model;
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
//! Model definitions for serialisation.
|
||||||
|
//!
|
||||||
|
//! The following definitions are used as part of the serialisation
|
||||||
|
//! process to exchange objects either through network or to storage.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -5,32 +10,59 @@ use serde::Serialize;
|
|||||||
|
|
||||||
use crate::database;
|
use crate::database;
|
||||||
use database::space;
|
use database::space;
|
||||||
|
use database::space_index::SpaceSetObject;
|
||||||
use database::Core;
|
use database::Core;
|
||||||
use database::SpaceSetObject;
|
|
||||||
|
|
||||||
|
/// Reference space definition.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Space {
|
pub struct Space {
|
||||||
|
/// **Id** of the space.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
|
/// Position of the origin of axis expressed in Universe coordinates.
|
||||||
pub origin: Vec<f64>,
|
pub origin: Vec<f64>,
|
||||||
|
|
||||||
|
/// List of axes of the space.
|
||||||
pub axes: Vec<Axis>,
|
pub axes: Vec<Axis>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reference space axis definition.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Axis {
|
pub struct Axis {
|
||||||
|
/// Length unit for the value `1.0`.
|
||||||
pub measurement_unit: String,
|
pub measurement_unit: String,
|
||||||
|
|
||||||
|
/// Define the valid range of number on this axis.
|
||||||
pub graduation: Graduation,
|
pub graduation: Graduation,
|
||||||
|
|
||||||
|
/// Vector which defines the direction of the axis in the Universe
|
||||||
pub unit_vector: Vec<f64>,
|
pub unit_vector: Vec<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Valid range of numbers on the axis.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Graduation {
|
pub struct Graduation {
|
||||||
|
/// Mathematical Number Set of numbers allowed.
|
||||||
pub set: String,
|
pub set: String,
|
||||||
|
|
||||||
|
/// Minimum value allowed, included.
|
||||||
pub minimum: f64,
|
pub minimum: f64,
|
||||||
|
|
||||||
|
/// Maximum value allowed, excluded.
|
||||||
pub maximum: f64,
|
pub maximum: f64,
|
||||||
|
|
||||||
|
/// Number of distinct positions between `[min; max[`
|
||||||
pub steps: u64,
|
pub steps: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A single spatial location.
|
||||||
|
///
|
||||||
|
/// This has a value per dimension of the space it is expressed in.
|
||||||
|
pub type Point = Vec<f64>;
|
||||||
|
|
||||||
pub mod v1 {
|
pub mod v1 {
|
||||||
|
//! REST API objects, v1.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -39,25 +71,41 @@ pub mod v1 {
|
|||||||
use crate::database;
|
use crate::database;
|
||||||
use database::space;
|
use database::space;
|
||||||
|
|
||||||
|
use super::Point;
|
||||||
use super::Properties;
|
use super::Properties;
|
||||||
|
|
||||||
|
/// Links Properties to a list of spatial volumes.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct SpatialObject {
|
pub struct SpatialObject {
|
||||||
|
/// Definition of the `properties` to tag in space.
|
||||||
pub properties: Properties,
|
pub properties: Properties,
|
||||||
|
|
||||||
|
/// List of volumes associated with `properties`.
|
||||||
pub shapes: Vec<Shape>,
|
pub shapes: Vec<Shape>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Define a Shape, within a specific reference space.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Shape {
|
pub struct Shape {
|
||||||
|
/// Type of the shape, which is used to interpret the list of `vertices`.
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub type_name: String,
|
pub type_name: String,
|
||||||
|
|
||||||
|
/// Id of the reference space the points are defined in.
|
||||||
#[serde(rename = "space")]
|
#[serde(rename = "space")]
|
||||||
pub reference_space: String,
|
pub reference_space: String,
|
||||||
|
|
||||||
|
/// List of spatial positions.
|
||||||
pub vertices: Vec<Point>,
|
pub vertices: Vec<Point>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Point = Vec<f64>;
|
/// Convert a list of properties grouped by space id, then positions to a
|
||||||
|
/// list of Spatial Objects for the rest API v1.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `list`:
|
||||||
|
/// A list of (**Space Id**, [ ( *Spatial position*, `&Properties` ) ]) tuples.
|
||||||
pub fn to_spatial_objects(
|
pub fn to_spatial_objects(
|
||||||
list: Vec<(&String, Vec<(space::Position, &database::Properties)>)>,
|
list: Vec<(&String, Vec<(space::Position, &database::Properties)>)>,
|
||||||
) -> Vec<SpatialObject> {
|
) -> Vec<SpatialObject> {
|
||||||
@@ -95,6 +143,8 @@ pub mod v1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod v2 {
|
pub mod v2 {
|
||||||
|
//! REST API objects, v2.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -103,30 +153,68 @@ pub mod v2 {
|
|||||||
use crate::database;
|
use crate::database;
|
||||||
use database::space;
|
use database::space;
|
||||||
|
|
||||||
|
use super::Point;
|
||||||
use super::Properties;
|
use super::Properties;
|
||||||
|
|
||||||
|
/// Links Properties to a list of spatial volumes.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct SpatialObject {
|
pub struct SpatialObject {
|
||||||
|
/// Definition of the `properties` to tag in space.
|
||||||
pub properties: Properties,
|
pub properties: Properties,
|
||||||
|
|
||||||
|
/// List of volumes associated with `properties`.
|
||||||
pub volumes: Vec<Volume>,
|
pub volumes: Vec<Volume>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines a volume as the union of geometric shapes.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Volume {
|
pub struct Volume {
|
||||||
|
/// Reference space id.
|
||||||
pub space: String,
|
pub space: String,
|
||||||
|
|
||||||
|
/// List of geometric shapes defined in the reference space
|
||||||
|
/// `space`.
|
||||||
pub shapes: Vec<Shape>,
|
pub shapes: Vec<Shape>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describes an homogeneous list of geometric shapes.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
|
/// List of points.
|
||||||
Points(Vec<Point>),
|
Points(Vec<Point>),
|
||||||
|
|
||||||
|
/// List of Bounding boxes or *hyper rectangles* for which each
|
||||||
|
/// face is perpendicular to one of the axis of the reference
|
||||||
|
/// space.
|
||||||
|
///
|
||||||
|
/// That property allows us to describe such a hyperrectangle
|
||||||
|
/// with two corners:
|
||||||
|
///
|
||||||
|
/// * one for which all the coordinates are the smallest among
|
||||||
|
/// all the corners, per dimension, which is called here
|
||||||
|
/// *lower corner*
|
||||||
|
///
|
||||||
|
/// * one for which all the coordinates are the greatest among
|
||||||
|
/// all the corners, per dimension, which is called
|
||||||
|
/// *higher corner*.
|
||||||
|
///
|
||||||
|
/// The list simply stores tuples of (`lower corner`,
|
||||||
|
/// `higher corner`), as this is enough to reconstruct all the
|
||||||
|
/// corners of the bounding box.
|
||||||
BoundingBoxes(Vec<(Point, Point)>),
|
BoundingBoxes(Vec<(Point, Point)>),
|
||||||
|
|
||||||
|
/// List of hyperspheres, stored as (`center`, radius) tuples.
|
||||||
HyperSpheres(Vec<(Point, f64)>),
|
HyperSpheres(Vec<(Point, f64)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
type Point = Vec<f64>;
|
/// Convert a list of properties grouped by space id, then positions to a
|
||||||
|
/// list of Spatial Objects for the rest API v2.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `list`:
|
||||||
|
/// A list of (**Space Id**, [ ( *Spatial position*, `&Properties` ) ]) tuples.
|
||||||
pub fn to_spatial_objects(
|
pub fn to_spatial_objects(
|
||||||
list: Vec<(&String, Vec<(space::Position, &database::Properties)>)>,
|
list: Vec<(&String, Vec<(space::Position, &database::Properties)>)>,
|
||||||
) -> Vec<SpatialObject> {
|
) -> Vec<SpatialObject> {
|
||||||
@@ -163,10 +251,15 @@ pub mod v2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// **Properties** which are registered at one or more spatial locations.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct Properties {
|
pub struct Properties {
|
||||||
|
/// The **type** of *Id*, this allows for different kinds of objects
|
||||||
|
/// to have the same *Id*, but handled distinctly.
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub type_name: String,
|
pub type_name: String,
|
||||||
|
|
||||||
|
/// An arbitrary string.
|
||||||
pub id: String,
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +337,35 @@ impl From<&&database::Properties> for Properties {
|
|||||||
|
|
||||||
pub use v1::SpatialObject;
|
pub use v1::SpatialObject;
|
||||||
|
|
||||||
|
/// Generate an index.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `name`:
|
||||||
|
/// Name to give to the index.
|
||||||
|
///
|
||||||
|
/// * `version`:
|
||||||
|
/// Parameter to distinguish revisions of an index.
|
||||||
|
///
|
||||||
|
/// * `spaces`:
|
||||||
|
/// A list of the reference spaces. Only objects whose reference
|
||||||
|
/// space is known will be indexed.
|
||||||
|
///
|
||||||
|
/// * `objects`:
|
||||||
|
/// The data points to index.
|
||||||
|
///
|
||||||
|
/// * `scales`:
|
||||||
|
/// An optional list of specific index resolutions to generates on
|
||||||
|
/// top of the full resolution one.
|
||||||
|
///
|
||||||
|
/// * `max_elements`:
|
||||||
|
/// If this is specified, automatically generates scaled indices, by
|
||||||
|
/// halving the number elements between resolutions, and stop
|
||||||
|
/// generating indices either when the number of points remaining is
|
||||||
|
/// equal to the number of distinct Ids, or smaller or equal to this
|
||||||
|
/// value.
|
||||||
|
///
|
||||||
|
/// **Note**: `max_elements` is ignored when `scales` is not `None`.
|
||||||
pub fn build_index(
|
pub fn build_index(
|
||||||
name: &str,
|
name: &str,
|
||||||
version: &str,
|
version: &str,
|
||||||
|
|||||||
@@ -1,3 +1,113 @@
|
|||||||
|
//! # XYZ file format
|
||||||
|
//!
|
||||||
|
//! This module support reading files read by [MeshView] tool used at
|
||||||
|
//! the [University of Oslo].
|
||||||
|
//!
|
||||||
|
//! # File structure
|
||||||
|
//!
|
||||||
|
//! Each files begins with:
|
||||||
|
//!
|
||||||
|
//! ```txt
|
||||||
|
//! RGBA [Red] [Green] [Blue] [Alpha] # RGBA
|
||||||
|
//! [X],[Y],[Z] # WHS Origin
|
||||||
|
//! [X],[Y],[Z] # Bregma
|
||||||
|
//!
|
||||||
|
//! SCALE [F]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! * `RGBA [Red] [Green] [Blue] [Alpha]`: defines the color to use for
|
||||||
|
//! the following points
|
||||||
|
//! * `[X],[Y],[Z] # WHS Origin`: defines where the Waxholm Origin is
|
||||||
|
//! in Voxel coordinates.
|
||||||
|
//! * `[X],[Y],[Z] # Bregma`: same as above, for another reference
|
||||||
|
//! space.
|
||||||
|
//! * `SCALE [F]`: **TBC** Size of the voxels.
|
||||||
|
//!
|
||||||
|
//! The rest of the file contains (one per line):
|
||||||
|
//! * coordinate triplets (x, y and z), each representing one point
|
||||||
|
//! coordinate.
|
||||||
|
//! * `RGB [Red] [Green] [Blue]`: Which applies from that line
|
||||||
|
//! until further notice.
|
||||||
|
//! * A comment Line, starting with `#`
|
||||||
|
//!
|
||||||
|
//! ## File Coordinate system
|
||||||
|
//!
|
||||||
|
//! Coordinates in MeshView follow RAS (Right-Anterior-Superior)
|
||||||
|
//! orientation and are expressed in voxels:
|
||||||
|
//! * First axis `x` starts from the left side of the volume, and
|
||||||
|
//! points towards the right.
|
||||||
|
//! * Second axis `y` starts from the backmost position in the volume,
|
||||||
|
//! and points towards the front.
|
||||||
|
//! * Third axis `z` starts from the bottom of the volume and points
|
||||||
|
//! towards the top.
|
||||||
|
//!
|
||||||
|
//! # Waxholm Space
|
||||||
|
//!
|
||||||
|
//! ## Conversion to Waxholm Space
|
||||||
|
//!
|
||||||
|
//! The [Waxholm Space Atlas] of the Sprague Dawley Rat Brain (WHS) uses
|
||||||
|
//! the same axis order and orientation as the MeshView tool, there is
|
||||||
|
//! only a translation of the origin, and scaling have to be applied.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! ```txt
|
||||||
|
//! RGBA 1 0 0 1 # RGBA
|
||||||
|
//! 244,623,248 # WHS Origin
|
||||||
|
//! 246,653,440 # Bregma
|
||||||
|
//!
|
||||||
|
//! #Aar27s49 26 0
|
||||||
|
//! RGB 0.12941176470588237 0.403921568627451 0.1607843137254902
|
||||||
|
//! 221.40199877 413.34541500312037 172.79973508489095
|
||||||
|
//! 220.5800097805 412.82939421970866 173.56428074436994
|
||||||
|
//!
|
||||||
|
//! #Aar27s48 49 0
|
||||||
|
//! RGB 0.12941176470588237 0.403921568627451 0.1607843137254902
|
||||||
|
//! 237.35325687425 412.5720395183866 176.6713556605702
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Conversion to Waxholm
|
||||||
|
//!
|
||||||
|
//! Assuming the following extents of "WHS Rat 39 μm" in voxels:
|
||||||
|
//!
|
||||||
|
//! * Leftmost sagittal plane: `x = 0`
|
||||||
|
//! * Backmost coronal plane: `y = 0`
|
||||||
|
//! * Bottommost horizontal plane: `z = 0`
|
||||||
|
//! * Rightmost sagittal plane: `x = 511`
|
||||||
|
//! * Frontmost coronal plane: `y = 1023`
|
||||||
|
//! * Topmost horizontal plane: `z = 511`
|
||||||
|
//!
|
||||||
|
//! **NOTE**: Directions are deliberately matching the default
|
||||||
|
//! orientation of NIfTI data.
|
||||||
|
//!
|
||||||
|
//! 1. As per the `WHS Origin` directive, it is at 244, 623, 248 voxel
|
||||||
|
//! coordinates, which means each coordinate must be subtracted with
|
||||||
|
//! the corresponding value, then
|
||||||
|
//! 2. the coordinates must be converted to millimeters, a.k.a
|
||||||
|
//! multiplied by the atlas resolution. For the atlas of this example
|
||||||
|
//! it is 0.0390625 [mm], isotropic.
|
||||||
|
//!
|
||||||
|
//! This gives us the following conversion formula:
|
||||||
|
//!
|
||||||
|
//! ```txt
|
||||||
|
//! ⎡ 0.0390625 0 0 0 ⎤
|
||||||
|
//! [ xw yw zw 1 ] = [ xq yq zq 1 ] * ⎢ 0 0.0390625 0 0 ⎥
|
||||||
|
//! ⎢ 0 0 0.0390625 0 ⎥
|
||||||
|
//! ⎣ -9.53125 -24.3359375 -9.6875 1 ⎦
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Where:
|
||||||
|
//! * `[xw, yw, zw 1]` are WHS coordinates (RAS directions, expressed
|
||||||
|
//! in millimeters).
|
||||||
|
//! * `[xq, yq, zq 1]` are MeshView coordinates for the **WHS Rat 39 μm**
|
||||||
|
//! package (RAS directions, expressed in 39.0625 μm voxels).
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! [MeshView]: http://www.nesys.uio.no/MeshView/meshview.html?atlas=WHS_SD_rat_atlas_v2
|
||||||
|
//! [University of Oslo]: https://www.med.uio.no/imb/english/research/groups/neural-systems/index.html
|
||||||
|
//! [Waxholm Space Atlas]: https://www.nitrc.org/projects/whs-sd-atlas
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
@@ -102,8 +212,18 @@ fn convert(string: &str) -> Result<Vec<SpatialObject>, Error> {
|
|||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read a XYZ file and convert it to the internal format for indexing.
|
||||||
|
///
|
||||||
|
/// This only converts the data point definitions, a reference space
|
||||||
|
/// needs to be provided as well to be able to build an index.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `name`:
|
||||||
|
/// Base name of the file,
|
||||||
|
/// * `.xyz` will be automatically appended for the source file, while
|
||||||
|
/// * `.bin` will be appended for the output file.
|
||||||
pub fn from(name: &str) -> Result<(), Error> {
|
pub fn from(name: &str) -> Result<(), Error> {
|
||||||
// Convert Reference Space definitions
|
|
||||||
let fn_in = format!("{}.xyz", name);
|
let fn_in = format!("{}.xyz", name);
|
||||||
let fn_out = format!("{}.bin", name);
|
let fn_out = format!("{}.bin", name);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user