Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c104a22407 | |||
| bd257cf2dd | |||
| 17d9cbc86f | |||
| ba02162d97 |
29
Cargo.toml
29
Cargo.toml
@@ -30,23 +30,26 @@ required-features = ["bin"]
|
|||||||
[features]
|
[features]
|
||||||
bin = ["measure_time", "pretty_env_logger"]
|
bin = ["measure_time", "pretty_env_logger"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ironsea_index = "^0.1"
|
ironsea_index = "0.1"
|
||||||
ironsea_index_sfc_dbc = "^0.1"
|
ironsea_index_sfc_dbc = "0.1"
|
||||||
ironsea_index_hashmap = "^0.1"
|
ironsea_index_hashmap = "0.1"
|
||||||
|
|
||||||
arrayref = "^0.3" # For Positions Objects
|
arrayref = "0.3" # For Positions Objects
|
||||||
lazy_static = "^1.3"
|
lazy_static = "1.5"
|
||||||
memmap = "^0.7"
|
memmap = "0.7"
|
||||||
|
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "^1.0"
|
serde_json = "1.0"
|
||||||
bincode = "^1.1"
|
bincode = "1.3"
|
||||||
|
|
||||||
# Logging macros API
|
# Logging macros API
|
||||||
#log = { version = "^0.4", features = ["max_level_trace", "release_max_level_info"] }
|
#log = { version = "0.4", features = ["max_level_trace", "release_max_level_info"] }
|
||||||
log = { version = "^0.4", features = ["max_level_trace", "release_max_level_trace"] }
|
log = { version = "0.4", features = ["max_level_trace", "release_max_level_trace"] }
|
||||||
|
|
||||||
# Used for main.rs as integration test
|
# Used for main.rs as integration test
|
||||||
pretty_env_logger = { version = "^0.3", optional = true } # Logger implementation
|
pretty_env_logger = { version = "0.5", optional = true } # Logger implementation
|
||||||
measure_time = { version = "^0.6", optional = true } # To mesure parsing time, only required by binary
|
measure_time = { version = "0.8", optional = true } # To mesure parsing time, only required by binary
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use super::space::Space;
|
|||||||
use super::space_db::SpaceDB;
|
use super::space_db::SpaceDB;
|
||||||
use super::space_index::SpaceSetObject;
|
use super::space_index::SpaceSetObject;
|
||||||
use super::DataBase;
|
use super::DataBase;
|
||||||
|
use super::IterObjects;
|
||||||
|
use super::IterPositions;
|
||||||
use super::ResultSet;
|
use super::ResultSet;
|
||||||
|
|
||||||
/// Query Parameters.
|
/// Query Parameters.
|
||||||
@@ -174,11 +176,7 @@ impl Core {
|
|||||||
|
|
||||||
// We cannot return less that the total number of individual Ids stored
|
// We cannot return less that the total number of individual Ids stored
|
||||||
// in the index for a full-volume query.
|
// in the index for a full-volume query.
|
||||||
let max_elements = if let Some(elem) = max_elements {
|
let max_elements = max_elements.map(|elem| elem.max(properties.len()));
|
||||||
Some(elem.max(properties.len()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
for space in spaces {
|
for space in spaces {
|
||||||
// Filter the points of this space, and encode them before creating the index.
|
// Filter the points of this space, and encode them before creating the index.
|
||||||
@@ -194,7 +192,7 @@ impl Core {
|
|||||||
object.set_position(space.encode(&position)?);
|
object.set_position(space.encode(&position)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
space_dbs.push(SpaceDB::new(&space, filtered, scales.clone(), max_elements))
|
space_dbs.push(SpaceDB::new(space, filtered, scales.clone(), max_elements))
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Core {
|
Ok(Core {
|
||||||
@@ -220,31 +218,37 @@ impl Core {
|
|||||||
&self.properties
|
&self.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_positions(
|
fn decode_positions<'b>(
|
||||||
list: &mut [(Position, &Properties)],
|
list: IterObjects<'b>,
|
||||||
space: &Space,
|
space: &'b Space,
|
||||||
db: &DataBase,
|
db: &'b DataBase,
|
||||||
output_space: &Option<&str>,
|
output_space: &Option<&str>,
|
||||||
) -> Result<(), String> {
|
) -> Result<IterObjects<'b>, String> {
|
||||||
if let Some(unified_id) = *output_space {
|
let b: IterObjects = if let Some(unified_id) = *output_space {
|
||||||
let unified = db.space(unified_id)?;
|
let unified = db.space(unified_id)?;
|
||||||
|
|
||||||
// Rebase the point to the requested output space before decoding.
|
// Rebase the point to the requested output space before decoding.
|
||||||
for (position, _) in list {
|
Box::new(list.filter_map(move |(position, properties)| {
|
||||||
*position = unified
|
match Space::change_base(&position, space, unified) {
|
||||||
.decode(&Space::change_base(&position, space, unified)?)?
|
Err(_) => None,
|
||||||
.into();
|
Ok(rebased) => match unified.decode(&rebased) {
|
||||||
}
|
Err(_) => None,
|
||||||
|
Ok(decoded) => Some((decoded.into(), properties)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
// Decode the positions into f64 values, which are defined in their
|
// Decode the positions into f64 values, which are defined in their
|
||||||
// respective reference space.
|
// respective reference space.
|
||||||
for (position, _) in list {
|
Box::new(list.filter_map(
|
||||||
// Simply decode
|
move |(position, properties)| match space.decode(&position) {
|
||||||
*position = space.decode(&position)?.into();
|
Err(_) => None,
|
||||||
}
|
Ok(decoded) => Some((decoded.into(), properties)),
|
||||||
}
|
},
|
||||||
|
))
|
||||||
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve everything located at specific positions.
|
/// Retrieve everything located at specific positions.
|
||||||
@@ -262,46 +266,57 @@ impl Core {
|
|||||||
/// reference space.
|
/// reference space.
|
||||||
///
|
///
|
||||||
/// [shape]: space/enum.Shape.html
|
/// [shape]: space/enum.Shape.html
|
||||||
pub fn get_by_positions(
|
pub fn get_by_positions<'d>(
|
||||||
&self,
|
&'d self,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &'d CoreQueryParameters,
|
||||||
positions: &[Position],
|
positions: Vec<Position>,
|
||||||
space_id: &str,
|
space_id: &'d str,
|
||||||
) -> ResultSet {
|
) -> ResultSet<'d> {
|
||||||
let CoreQueryParameters {
|
let CoreQueryParameters {
|
||||||
db, output_space, ..
|
db, output_space, ..
|
||||||
} = parameters;
|
} = parameters;
|
||||||
|
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
let count = positions.len();
|
|
||||||
let from = db.space(space_id)?;
|
let from = db.space(space_id)?;
|
||||||
|
|
||||||
// Filter positions based on the view port, if present
|
|
||||||
let filtered = match parameters.view_port(from) {
|
|
||||||
None => positions.iter().map(|p| p).collect::<Vec<_>>(),
|
|
||||||
Some(view_port) => positions
|
|
||||||
.iter()
|
|
||||||
.filter(|&p| view_port.contains(p))
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
};
|
|
||||||
|
|
||||||
for s in &self.space_db {
|
for s in &self.space_db {
|
||||||
let to = db.space(s.name())?;
|
let to = db.space(s.name())?;
|
||||||
let mut p = Vec::with_capacity(count);
|
|
||||||
|
|
||||||
for position in filtered.as_slice() {
|
// Filter positions based on the view port, if present
|
||||||
let position: Vec<f64> = Space::change_base(position, from, to)?.into();
|
// FIXME: remove clone() on positions?
|
||||||
p.push(to.encode(&position)?);
|
let filtered: IterPositions = match parameters.view_port(from) {
|
||||||
}
|
None => Box::new(positions.clone().into_iter()),
|
||||||
|
Some(view_port) => Box::new(
|
||||||
|
positions
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.filter(move |p| view_port.contains(p)),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
let mut r = s
|
// Rebase the positions into the current space
|
||||||
.get_by_positions(&p, parameters)?
|
let p = filtered.filter_map(move |position| {
|
||||||
.into_iter()
|
match Space::change_base(&position, from, to) {
|
||||||
.map(|(position, fields)| (position, &self.properties[fields.value()]))
|
Err(_) => None,
|
||||||
.collect::<Vec<_>>();
|
Ok(position) => {
|
||||||
Self::decode_positions(r.as_mut_slice(), to, db, output_space)?;
|
let position: Vec<f64> = position.into();
|
||||||
|
match to.encode(&position) {
|
||||||
|
Err(_) => None,
|
||||||
|
Ok(position) => Some(position),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
results.push((s.name(), r));
|
// Select the data based on the rebased viewport filter.
|
||||||
|
let r = s
|
||||||
|
.get_by_positions(p, parameters)?
|
||||||
|
.map(move |(position, fields)| (position, &self.properties[fields.value()]));
|
||||||
|
|
||||||
|
results.push((
|
||||||
|
s.name(),
|
||||||
|
Self::decode_positions(Box::new(r), to, db, output_space)?,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(results)
|
Ok(results)
|
||||||
@@ -322,12 +337,12 @@ impl Core {
|
|||||||
/// reference space.
|
/// reference space.
|
||||||
///
|
///
|
||||||
/// [shape]: space/enum.Shape.html
|
/// [shape]: space/enum.Shape.html
|
||||||
pub fn get_by_shape(
|
pub fn get_by_shape<'d>(
|
||||||
&self,
|
&'d self,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &'d CoreQueryParameters,
|
||||||
shape: &Shape,
|
shape: Shape,
|
||||||
space_id: &str,
|
space_id: &'d str,
|
||||||
) -> ResultSet {
|
) -> ResultSet<'d> {
|
||||||
let CoreQueryParameters {
|
let CoreQueryParameters {
|
||||||
db, output_space, ..
|
db, output_space, ..
|
||||||
} = parameters;
|
} = parameters;
|
||||||
@@ -343,14 +358,14 @@ impl Core {
|
|||||||
// let current_shape = shape.encode(current_space)?;
|
// let current_shape = shape.encode(current_space)?;
|
||||||
// println!("current shape Encoded: {:?}", current_shape);
|
// println!("current shape Encoded: {:?}", current_shape);
|
||||||
|
|
||||||
let mut r = s
|
let r = s
|
||||||
.get_by_shape(¤t_shape, parameters)?
|
.get_by_shape(current_shape, parameters)?
|
||||||
.into_iter()
|
.map(move |(position, fields)| (position, &self.properties[fields.value()]));
|
||||||
.map(|(position, fields)| (position, &self.properties[fields.value()]))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
Self::decode_positions(r.as_mut_slice(), current_space, db, output_space)?;
|
|
||||||
|
|
||||||
results.push((s.name(), r));
|
results.push((
|
||||||
|
s.name(),
|
||||||
|
Self::decode_positions(Box::new(r), current_space, db, output_space)?,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(results)
|
Ok(results)
|
||||||
@@ -366,11 +381,11 @@ impl Core {
|
|||||||
/// * `id`:
|
/// * `id`:
|
||||||
/// Identifier for which to retrieve is positions.
|
/// Identifier for which to retrieve is positions.
|
||||||
///
|
///
|
||||||
pub fn get_by_id<S>(
|
pub fn get_by_id<'s, S>(
|
||||||
&self,
|
&'s self,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &'s CoreQueryParameters,
|
||||||
id: S,
|
id: S,
|
||||||
) -> Result<Vec<(&String, Vec<Position>)>, String>
|
) -> Result<Vec<(&String, IterPositions<'s>)>, String>
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
@@ -391,26 +406,32 @@ impl Core {
|
|||||||
for s in &self.space_db {
|
for s in &self.space_db {
|
||||||
let current_space = db.space(s.name())?;
|
let current_space = db.space(s.name())?;
|
||||||
|
|
||||||
let mut positions = s.get_by_id(offset, parameters)?;
|
let positions_by_id = s.get_by_id(offset, parameters)?;
|
||||||
|
|
||||||
//Self::decode_positions(r.as_mut_slice(), current_space, db, output_space)?;
|
//Self::decode_positions(r.as_mut_slice(), current_space, db, output_space)?;
|
||||||
if let Some(unified_id) = *output_space {
|
let positions: IterPositions = if let Some(unified_id) = *output_space {
|
||||||
let unified = db.space(unified_id)?;
|
let unified = db.space(unified_id)?;
|
||||||
|
|
||||||
// Rebase the point to the requested output space before decoding.
|
// Rebase the point to the requested output space before decoding.
|
||||||
for position in &mut positions {
|
Box::new(positions_by_id.filter_map(move |position| {
|
||||||
*position = unified
|
match Space::change_base(&position, current_space, unified) {
|
||||||
.decode(&Space::change_base(position, current_space, unified)?)?
|
Err(_) => None,
|
||||||
.into();
|
Ok(rebased) => match unified.decode(&rebased) {
|
||||||
}
|
Err(_) => None,
|
||||||
|
Ok(decoded) => Some(decoded.into()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
// Decode the positions into f64 values, which are defined in their
|
// Decode the positions into f64 values, which are defined in their
|
||||||
// respective reference space.
|
// respective reference space.
|
||||||
for position in &mut positions {
|
Box::new(positions_by_id.filter_map(move |position| {
|
||||||
// Simply decode
|
match current_space.decode(&position) {
|
||||||
*position = current_space.decode(position)?.into();
|
Err(_) => None,
|
||||||
}
|
Ok(decoded) => Some(decoded.into()),
|
||||||
}
|
}
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
results.push((s.name(), positions));
|
results.push((s.name(), positions));
|
||||||
}
|
}
|
||||||
@@ -430,7 +451,11 @@ impl Core {
|
|||||||
/// * `id`:
|
/// * `id`:
|
||||||
/// Identifier to use to define the search volume.
|
/// 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<'d, S>(
|
||||||
|
&'d self,
|
||||||
|
parameters: &'d CoreQueryParameters,
|
||||||
|
id: S,
|
||||||
|
) -> ResultSet<'d>
|
||||||
where
|
where
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
@@ -454,7 +479,7 @@ impl Core {
|
|||||||
let search_volume = self
|
let search_volume = self
|
||||||
.space_db
|
.space_db
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|s| {
|
.filter_map(move |s| {
|
||||||
match db.space(s.name()) {
|
match db.space(s.name()) {
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
Ok(from) => match s.get_by_id(offset, parameters) {
|
Ok(from) => match s.get_by_id(offset, parameters) {
|
||||||
@@ -475,42 +500,40 @@ impl Core {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flat_map(|v| v);
|
.flatten();
|
||||||
|
|
||||||
let search_volume = if let Some(view) = view_port {
|
|
||||||
search_volume
|
|
||||||
.filter(|p| view.contains(p))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
} else {
|
|
||||||
search_volume.collect::<Vec<_>>()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Select based on the volume, and filter out the label position themselves.
|
// Select based on the volume, and filter out the label position themselves.
|
||||||
for s in &self.space_db {
|
for s in &self.space_db {
|
||||||
let to = db.space(s.name())?;
|
let to = db.space(s.name())?;
|
||||||
let mut p = vec![];
|
|
||||||
|
let search_volume: IterPositions = if let Some(view) = view_port.clone() {
|
||||||
|
Box::new(search_volume.clone().filter(move |p| view.contains(p)))
|
||||||
|
} else {
|
||||||
|
Box::new(search_volume.clone())
|
||||||
|
};
|
||||||
|
|
||||||
// Convert the search Volume into the target space.
|
// Convert the search Volume into the target space.
|
||||||
for position in &search_volume {
|
let p = search_volume.filter_map(move |position| {
|
||||||
let position = Space::change_base(position, Space::universe(), to)?;
|
match Space::change_base(&position, Space::universe(), to) {
|
||||||
p.push(position);
|
Err(_) => None,
|
||||||
}
|
Ok(position) => Some(position),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let mut r = s
|
let r = s
|
||||||
.get_by_positions(&p, parameters)?
|
.get_by_positions(p, parameters)?
|
||||||
.into_iter()
|
.filter_map(move |(position, fields)| {
|
||||||
.filter_map(|(position, fields)| {
|
|
||||||
if fields.value() == offset {
|
if fields.value() == offset {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some((position, &self.properties[fields.value()]))
|
Some((position, &self.properties[fields.value()]))
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
Self::decode_positions(r.as_mut_slice(), to, db, output_space)?;
|
results.push((
|
||||||
|
s.name(),
|
||||||
results.push((s.name(), r));
|
Self::decode_positions(Box::new(r), to, db, output_space)?,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,20 @@ pub use db_core::Properties;
|
|||||||
use space::Position;
|
use space::Position;
|
||||||
use space::Space;
|
use space::Space;
|
||||||
|
|
||||||
|
/// TODO doc
|
||||||
|
pub type IterPositions<'i> = Box<dyn Iterator<Item = Position> + 'i>;
|
||||||
|
/// TODO doc
|
||||||
|
pub type IterObjects<'i> = Box<dyn Iterator<Item = (Position, &'i Properties)> + 'i>;
|
||||||
|
/// TODO doc
|
||||||
|
pub type IterObjectsBySpaces<'i> = Vec<(&'i String, IterObjects<'i>)>;
|
||||||
|
|
||||||
/// Selected tuples matching a query.
|
/// Selected tuples matching a query.
|
||||||
///
|
///
|
||||||
/// This is either:
|
/// This is either:
|
||||||
/// * `Err` with a reason stored as a `String`
|
/// * `Err` with a reason stored as a `String`
|
||||||
/// * `Ok`, with a vector of tuples defined as:
|
/// * `Ok`, with a vector of tuples defined as:
|
||||||
/// `(Space Name, [(Position, Properties)])`
|
/// `(Space Name, [(Position, Properties)])`
|
||||||
pub type ResultSet<'r> = Result<Vec<(&'r String, Vec<(Position, &'r Properties)>)>, String>;
|
pub type ResultSet<'r> = Result<IterObjectsBySpaces<'r>, String>;
|
||||||
|
|
||||||
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>;
|
||||||
@@ -109,7 +116,7 @@ impl DataBase {
|
|||||||
list.len()
|
list.len()
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(&list[0])
|
Ok(list[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +135,10 @@ impl DataBase {
|
|||||||
if name == space::Space::universe().name() {
|
if name == space::Space::universe().name() {
|
||||||
Ok(space::Space::universe())
|
Ok(space::Space::universe())
|
||||||
} else {
|
} else {
|
||||||
let r = self.reference_spaces.find(&name.to_string());
|
let r = self
|
||||||
|
.reference_spaces
|
||||||
|
.find(&name.to_string())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
Self::check_exactly_one(&r, "spaces", name)
|
Self::check_exactly_one(&r, "spaces", name)
|
||||||
}
|
}
|
||||||
@@ -146,7 +156,7 @@ impl DataBase {
|
|||||||
/// * `name`:
|
/// * `name`:
|
||||||
/// The name of the dataset (core) to search for.
|
/// 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()).collect::<Vec<_>>();
|
||||||
|
|
||||||
Self::check_exactly_one(&r, "cores", name)
|
Self::check_exactly_one(&r, "cores", name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,10 +206,10 @@ impl From<u64> for Coordinate {
|
|||||||
// Slight syntax hack, as exclusive ranges are not yet available.
|
// Slight syntax hack, as exclusive ranges are not yet available.
|
||||||
// cf: https://github.com/rust-lang/rust/issues/37854
|
// cf: https://github.com/rust-lang/rust/issues/37854
|
||||||
match v {
|
match v {
|
||||||
_ if v <= u64::from(std::u8::MAX) => Coordinate::CoordinateU8(v as u8),
|
_ if v <= u64::from(u8::MAX) => Coordinate::CoordinateU8(v as u8),
|
||||||
_ if v <= u64::from(std::u16::MAX) => Coordinate::CoordinateU16(v as u16),
|
_ if v <= u64::from(u16::MAX) => Coordinate::CoordinateU16(v as u16),
|
||||||
_ if v <= u64::from(std::u32::MAX) => Coordinate::CoordinateU32(v as u32),
|
_ if v <= u64::from(u32::MAX) => Coordinate::CoordinateU32(v as u32),
|
||||||
_ => Coordinate::CoordinateU64(v as u64),
|
_ => Coordinate::CoordinateU64(v),
|
||||||
/*_ => {
|
/*_ => {
|
||||||
panic!("Out of range {} > {}", v, std::u64::MAX);
|
panic!("Out of range {} > {}", v, std::u64::MAX);
|
||||||
} */
|
} */
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ impl CoordinateSystem {
|
|||||||
match self {
|
match self {
|
||||||
CoordinateSystem::Universe { .. } => {
|
CoordinateSystem::Universe { .. } => {
|
||||||
for _ in 0..self.dimensions() {
|
for _ in 0..self.dimensions() {
|
||||||
low.push(std::f64::MIN);
|
low.push(f64::MIN);
|
||||||
high.push(std::f64::MAX);
|
high.push(f64::MAX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CoordinateSystem::AffineSystem { axes, .. } => {
|
CoordinateSystem::AffineSystem { axes, .. } => {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use serde::Serialize;
|
|||||||
use super::coordinate::Coordinate;
|
use super::coordinate::Coordinate;
|
||||||
|
|
||||||
/// Store a position as efficiently as possible in terms of space.
|
/// 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, PartialEq, Serialize)]
|
||||||
pub enum Position {
|
pub enum Position {
|
||||||
/// 1 dimension positions.
|
/// 1 dimension positions.
|
||||||
Position1(Coordinate),
|
Position1(Coordinate),
|
||||||
@@ -60,7 +60,8 @@ impl Position {
|
|||||||
/// Compute `||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.
|
||||||
coordinates.f64().abs()
|
coordinates.f64().abs()
|
||||||
} else {
|
} else {
|
||||||
let point: Vec<&Coordinate> = self.into();
|
let point: Vec<&Coordinate> = self.into();
|
||||||
@@ -127,6 +128,12 @@ impl Display for Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Ord for Position {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.partial_cmp(other).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd for Position {
|
impl PartialOrd for Position {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
// Let's restrict for now to same-length vectors.
|
// Let's restrict for now to same-length vectors.
|
||||||
@@ -143,7 +150,7 @@ impl PartialOrd for Position {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ordering = ordering.drain().filter_map(|v| v).collect::<Vec<_>>();
|
let ordering = ordering.drain().flatten().collect::<Vec<_>>();
|
||||||
match ordering.len() {
|
match ordering.len() {
|
||||||
3 => None,
|
3 => None,
|
||||||
2 => {
|
2 => {
|
||||||
@@ -356,14 +363,14 @@ impl<'s> From<&'s Position> for Vec<&'s Coordinate> {
|
|||||||
fn from(position: &'s Position) -> Self {
|
fn from(position: &'s Position) -> Self {
|
||||||
match position {
|
match position {
|
||||||
Position::Position1(coordinate) => vec![coordinate],
|
Position::Position1(coordinate) => vec![coordinate],
|
||||||
Position::Position2(coordinates) => coordinates.iter().map(|c| c).collect(),
|
Position::Position2(coordinates) => coordinates.iter().collect(),
|
||||||
Position::Position3(coordinates) => coordinates.iter().map(|c| c).collect(),
|
Position::Position3(coordinates) => coordinates.iter().collect(),
|
||||||
Position::Position4(coordinates) => coordinates.iter().map(|c| c).collect(),
|
Position::Position4(coordinates) => coordinates.iter().collect(),
|
||||||
Position::Position5(coordinates) => coordinates.iter().map(|c| c).collect(),
|
Position::Position5(coordinates) => coordinates.iter().collect(),
|
||||||
Position::Position6(coordinates) => coordinates.iter().map(|c| c).collect(),
|
Position::Position6(coordinates) => coordinates.iter().collect(),
|
||||||
Position::Position7(coordinates) => coordinates.iter().map(|c| c).collect(),
|
Position::Position7(coordinates) => coordinates.iter().collect(),
|
||||||
Position::Position8(coordinates) => coordinates.iter().map(|c| c).collect(),
|
Position::Position8(coordinates) => coordinates.iter().collect(),
|
||||||
Position::PositionN(coordinates) => coordinates.iter().map(|c| c).collect(),
|
Position::PositionN(coordinates) => coordinates.iter().collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl Shape {
|
|||||||
//FIXME: Is the length properly dealt with? How do we process this for space conversions?
|
//FIXME: Is the length properly dealt with? How do we process this for space conversions?
|
||||||
let mut r = Vec::with_capacity(center.dimensions());
|
let mut r = Vec::with_capacity(center.dimensions());
|
||||||
for _ in 0..center.dimensions() {
|
for _ in 0..center.dimensions() {
|
||||||
r.push(radius.clone());
|
r.push(*radius);
|
||||||
}
|
}
|
||||||
let r = r.into();
|
let r = r.into();
|
||||||
let r = from.absolute_position(&r)?;
|
let r = from.absolute_position(&r)?;
|
||||||
@@ -276,7 +276,7 @@ impl Shape {
|
|||||||
/// Compute the volume.
|
/// 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(_) => f64::EPSILON, // Smallest non-zero volume possible
|
||||||
Shape::BoundingBox(low, high) => {
|
Shape::BoundingBox(low, high) => {
|
||||||
let mut volume = 1.0;
|
let mut volume = 1.0;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ use super::space_index::SpaceIndex;
|
|||||||
use super::space_index::SpaceSetIndex;
|
use super::space_index::SpaceSetIndex;
|
||||||
use super::space_index::SpaceSetObject;
|
use super::space_index::SpaceSetObject;
|
||||||
use super::CoreQueryParameters;
|
use super::CoreQueryParameters;
|
||||||
|
use super::IterPositions;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct SpaceDB {
|
pub struct SpaceDB {
|
||||||
@@ -59,8 +61,7 @@ impl SpaceDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply fixed scales
|
// Apply fixed scales
|
||||||
let mut count = 0;
|
for (count, power) in powers.iter().enumerate() {
|
||||||
for power in &powers {
|
|
||||||
space_objects = space_objects
|
space_objects = space_objects
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mut o| {
|
.map(|mut o| {
|
||||||
@@ -79,8 +80,7 @@ impl SpaceDB {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Make sure we do not shift more position than available
|
// Make sure we do not shift more position than available
|
||||||
let shift = if count >= 31 { 31 } else { count };
|
let shift: u32 = if count >= 31 { 31 } else { count.try_into().unwrap() };
|
||||||
count += 1;
|
|
||||||
indices.push((
|
indices.push((
|
||||||
SpaceSetIndex::new(space_objects.iter(), DIMENSIONS, CELL_BITS),
|
SpaceSetIndex::new(space_objects.iter(), DIMENSIONS, CELL_BITS),
|
||||||
vec![power.0, power.0, power.0],
|
vec![power.0, power.0, power.0],
|
||||||
@@ -279,11 +279,11 @@ impl SpaceDB {
|
|||||||
|
|
||||||
// Search by Id, a.k.a values
|
// Search by Id, a.k.a values
|
||||||
// The results are in encoded space coordinates.
|
// The results are in encoded space coordinates.
|
||||||
pub fn get_by_id(
|
pub fn get_by_id<'s>(
|
||||||
&self,
|
&'s self,
|
||||||
id: usize,
|
id: usize,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &CoreQueryParameters,
|
||||||
) -> Result<Vec<Position>, String> {
|
) -> Result<IterPositions<'s>, String> {
|
||||||
// Is that ID referenced in the current space?
|
// Is that ID referenced in the current space?
|
||||||
let index = self.resolution(parameters);
|
let index = self.resolution(parameters);
|
||||||
|
|
||||||
@@ -292,15 +292,20 @@ impl SpaceDB {
|
|||||||
let view_port = parameters.view_port(space);
|
let view_port = parameters.view_port(space);
|
||||||
|
|
||||||
// Select the objects
|
// Select the objects
|
||||||
let objects = self.resolutions[index].find_by_value(&SpaceFields::new(self.name(), id));
|
// FIXME: How to return an iterator instead of instantiating all
|
||||||
|
// the points here? Needed because of &SpaceFields.
|
||||||
|
let objects = self.resolutions[index]
|
||||||
|
.find_by_value(&SpaceFields::new(self.name(), id))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let results = if let Some(view_port) = view_port {
|
let results: IterPositions<'s> = if let Some(view_port) = view_port {
|
||||||
objects
|
Box::new(
|
||||||
.into_iter()
|
objects
|
||||||
.filter(|position| view_port.contains(position))
|
.into_iter()
|
||||||
.collect::<Vec<_>>()
|
.filter(move |position| view_port.contains(position)),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
objects
|
Box::new(objects.into_iter())
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(results)
|
Ok(results)
|
||||||
@@ -308,11 +313,11 @@ impl SpaceDB {
|
|||||||
|
|
||||||
// Search by positions defining a volume.
|
// Search by positions defining a volume.
|
||||||
// The position is expressed in encoded space coordinates, and results are in encoded space coordinates.
|
// The position is expressed in encoded space coordinates, and results are in encoded space coordinates.
|
||||||
pub fn get_by_positions(
|
pub fn get_by_positions<'s>(
|
||||||
&self,
|
&'s self,
|
||||||
positions: &[Position],
|
positions: impl Iterator<Item = Position> + 's,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &CoreQueryParameters,
|
||||||
) -> Result<Vec<(Position, &SpaceFields)>, String> {
|
) -> Result<Box<dyn Iterator<Item = (Position, &SpaceFields)> + 's>, String> {
|
||||||
let index = self.resolution(parameters);
|
let index = self.resolution(parameters);
|
||||||
|
|
||||||
// FIXME: Should I do it here, or add the assumption this is a clean list?
|
// FIXME: Should I do it here, or add the assumption this is a clean list?
|
||||||
@@ -321,17 +326,13 @@ impl SpaceDB {
|
|||||||
//let view_port = parameters.view_port(space);
|
//let view_port = parameters.view_port(space);
|
||||||
|
|
||||||
// Select the objects
|
// Select the objects
|
||||||
let results = positions
|
let results = positions.flat_map(move |position| {
|
||||||
.iter()
|
self.resolutions[index]
|
||||||
.flat_map(|position| {
|
.find(&position)
|
||||||
self.resolutions[index]
|
.map(move |fields| (position.clone(), fields))
|
||||||
.find(position)
|
});
|
||||||
.into_iter()
|
|
||||||
.map(move |fields| (position.clone(), fields))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(results)
|
Ok(Box::new(results))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search by Shape defining a volume:
|
// Search by Shape defining a volume:
|
||||||
@@ -340,11 +341,11 @@ impl SpaceDB {
|
|||||||
// * Point (Specific position)
|
// * Point (Specific position)
|
||||||
|
|
||||||
// The Shape is expressed in encoded space coordinates, and results are in encoded space coordinates.
|
// The Shape is expressed in encoded space coordinates, and results are in encoded space coordinates.
|
||||||
pub fn get_by_shape(
|
pub fn get_by_shape<'s>(
|
||||||
&self,
|
&'s self,
|
||||||
shape: &Shape,
|
shape: Shape,
|
||||||
parameters: &CoreQueryParameters,
|
parameters: &CoreQueryParameters,
|
||||||
) -> Result<Vec<(Position, &SpaceFields)>, String> {
|
) -> Result<Box<dyn Iterator<Item = (Position, &SpaceFields)> + 's>, String> {
|
||||||
let index = self.resolution(parameters);
|
let index = self.resolution(parameters);
|
||||||
|
|
||||||
// Convert the view port to the encoded space coordinates
|
// Convert the view port to the encoded space coordinates
|
||||||
@@ -352,7 +353,7 @@ impl SpaceDB {
|
|||||||
let view_port = parameters.view_port(space);
|
let view_port = parameters.view_port(space);
|
||||||
|
|
||||||
// Select the objects
|
// Select the objects
|
||||||
let results = self.resolutions[index].find_by_shape(&shape, &view_port)?;
|
let results = self.resolutions[index].find_by_shape(shape, &view_port)?;
|
||||||
|
|
||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use serde::Serialize;
|
|||||||
use super::space::Coordinate;
|
use super::space::Coordinate;
|
||||||
use super::space::Position;
|
use super::space::Position;
|
||||||
use super::space::Shape;
|
use super::space::Shape;
|
||||||
|
use super::IterPositions;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash)]
|
#[derive(Clone, Debug, Hash)]
|
||||||
pub struct SpaceSetObject {
|
pub struct SpaceSetObject {
|
||||||
@@ -125,59 +126,63 @@ impl SpaceIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inputs and Results are expressed in encoded space coordinates.
|
// Inputs and Results are expressed in encoded space coordinates.
|
||||||
pub fn find(&self, key: &Position) -> Vec<&SpaceFields> {
|
pub fn find<'s>(&'s self, key: &Position) -> Box<dyn Iterator<Item = &SpaceFields> + 's> {
|
||||||
self.index.find(key)
|
self.index.find(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inputs and Results are expressed in encoded space coordinates.
|
// Inputs and Results are expressed in encoded space coordinates.
|
||||||
fn find_range(&self, start: &Position, end: &Position) -> Vec<(Position, &SpaceFields)> {
|
fn find_range<'s>(
|
||||||
|
&'s self,
|
||||||
|
start: &Position,
|
||||||
|
end: &Position,
|
||||||
|
) -> Box<dyn Iterator<Item = (Position, &SpaceFields)> + 's> {
|
||||||
self.index.find_range(start, end)
|
self.index.find_range(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inputs and Results are expressed in encoded space coordinates.
|
// Inputs and Results are expressed in encoded space coordinates.
|
||||||
pub fn find_by_value(&self, id: &SpaceFields) -> Vec<Position> {
|
pub fn find_by_value<'s>(&'s self, id: &'s SpaceFields) -> IterPositions<'s> {
|
||||||
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<'s>(
|
||||||
&self,
|
&'s self,
|
||||||
shape: &Shape,
|
shape: Shape,
|
||||||
view_port: &Option<Shape>,
|
view_port: &Option<Shape>,
|
||||||
) -> Result<Vec<(Position, &SpaceFields)>, String> {
|
) -> Result<Box<dyn Iterator<Item = (Position, &SpaceFields)> + 's>, String> {
|
||||||
match shape {
|
match shape {
|
||||||
Shape::Point(position) => {
|
Shape::Point(position) => {
|
||||||
if let Some(mbb) = view_port {
|
if let Some(mbb) = view_port {
|
||||||
if !mbb.contains(position) {
|
if !mbb.contains(&position) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"View port '{:?}' does not contain '{:?}'",
|
"View port '{:?}' does not contain '{:?}'",
|
||||||
mbb, position
|
mbb, position
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(self
|
Ok(Box::new(
|
||||||
.find(position)
|
self.find(&position)
|
||||||
.into_iter()
|
.map(move |fields| (position.clone(), fields)),
|
||||||
.map(|fields| (position.clone(), fields))
|
))
|
||||||
.collect())
|
|
||||||
}
|
}
|
||||||
Shape::BoundingBox(bl, bh) => {
|
Shape::BoundingBox(bl, bh) => {
|
||||||
if let Some(mbb) = view_port {
|
if let Some(mbb) = view_port {
|
||||||
match mbb {
|
match mbb {
|
||||||
Shape::BoundingBox(vl, vh) => {
|
Shape::BoundingBox(vl, vh) => {
|
||||||
// Compute the intersection of the two boxes.
|
// Compute the intersection of the two boxes.
|
||||||
let lower = bl.max(vl);
|
let lower = (&bl).max(vl);
|
||||||
let higher = bh.min(vh);
|
let higher = (&bh).min(vh);
|
||||||
if higher < lower {
|
if higher < lower {
|
||||||
Err(format!(
|
Err(format!(
|
||||||
"View port '{:?}' does not intersect '{:?}'",
|
"View port '{:?}' does not intersect '{:?}'",
|
||||||
mbb, shape
|
mbb,
|
||||||
|
Shape::BoundingBox(bl.clone(), bh.clone())
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
trace!(
|
trace!(
|
||||||
"mbb {:?} shape {:?} lower {:?} higher {:?}",
|
"mbb {:?} shape {:?} lower {:?} higher {:?}",
|
||||||
mbb,
|
mbb,
|
||||||
shape,
|
Shape::BoundingBox(bl.clone(), bh.clone()),
|
||||||
lower,
|
lower,
|
||||||
higher
|
higher
|
||||||
);
|
);
|
||||||
@@ -187,11 +192,11 @@ impl SpaceIndex {
|
|||||||
_ => Err(format!("Invalid view port shape '{:?}'", mbb)),
|
_ => Err(format!("Invalid view port shape '{:?}'", mbb)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(self.find_range(bl, bh))
|
Ok(self.find_range(&bl, &bh))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Shape::HyperSphere(center, radius) => {
|
Shape::HyperSphere(center, radius) => {
|
||||||
let (bl, bh) = &shape.get_mbb();
|
let (bl, bh) = Shape::HyperSphere(center.clone(), radius).get_mbb();
|
||||||
let lower;
|
let lower;
|
||||||
let higher;
|
let higher;
|
||||||
|
|
||||||
@@ -199,26 +204,24 @@ impl SpaceIndex {
|
|||||||
match mbb {
|
match mbb {
|
||||||
Shape::BoundingBox(vl, vh) => {
|
Shape::BoundingBox(vl, vh) => {
|
||||||
// Compute the intersection of the two boxes.
|
// Compute the intersection of the two boxes.
|
||||||
lower = bl.max(vl);
|
lower = (&bl).max(vl);
|
||||||
higher = bh.min(vh);
|
higher = (&bh).min(vh);
|
||||||
}
|
}
|
||||||
_ => return Err(format!("Invalid view port shape '{:?}'", mbb)),
|
_ => return Err(format!("Invalid view port shape '{:?}'", mbb)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lower = bl;
|
lower = &bl;
|
||||||
higher = bh;
|
higher = &bh;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out results using using a range query over the MBB,
|
// Filter out results using using a range query over the MBB,
|
||||||
// then add the condition of the radius as we are working within
|
// then add the condition of the radius as we are working within
|
||||||
// a sphere.
|
// a sphere.
|
||||||
let results = self
|
let results = self
|
||||||
.find_range(&lower, &higher)
|
.find_range(lower, higher)
|
||||||
.into_iter()
|
.filter(move |(position, _)| (position - ¢er).norm() <= radius.f64());
|
||||||
.filter(|(position, _)| (position - center).norm() <= radius.f64())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(results)
|
Ok(Box::new(results))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,9 +68,8 @@ pub mod v1 {
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::database;
|
use super::database;
|
||||||
use database::space;
|
use super::space;
|
||||||
|
|
||||||
use super::Point;
|
use super::Point;
|
||||||
use super::Properties;
|
use super::Properties;
|
||||||
|
|
||||||
@@ -87,7 +86,8 @@ pub mod v1 {
|
|||||||
/// Define a Shape, within a specific reference space.
|
/// 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`.
|
/// 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,
|
||||||
|
|
||||||
@@ -99,8 +99,8 @@ pub mod v1 {
|
|||||||
pub vertices: Vec<Point>,
|
pub vertices: Vec<Point>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a list of properties grouped by space id, then positions to a
|
/// Convert a list of properties grouped by space id, then positions
|
||||||
/// list of Spatial Objects for the rest API v1.
|
/// to a list of Spatial Objects for the rest API v1.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
///
|
///
|
||||||
@@ -109,13 +109,14 @@ pub mod v1 {
|
|||||||
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> {
|
||||||
// Filter per Properties, in order to regroup by it, then build a single SpatialObject per Properties.
|
// Filter per Properties, in order to regroup by it, then build
|
||||||
|
// a single SpatialObject per Properties.
|
||||||
let mut hashmap = HashMap::new();
|
let mut hashmap = HashMap::new();
|
||||||
for (space, v) in list {
|
for (space, v) in list {
|
||||||
for (position, properties) in v {
|
for (position, properties) in v {
|
||||||
hashmap
|
hashmap
|
||||||
.entry(properties)
|
.entry(properties)
|
||||||
.or_insert_with(|| vec![])
|
.or_insert_with(Vec::new)
|
||||||
.push((space, position));
|
.push((space, position));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,9 +151,8 @@ pub mod v2 {
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::database;
|
use super::database;
|
||||||
use database::space;
|
use super::space;
|
||||||
|
|
||||||
use super::Point;
|
use super::Point;
|
||||||
use super::Properties;
|
use super::Properties;
|
||||||
|
|
||||||
@@ -208,46 +208,88 @@ pub mod v2 {
|
|||||||
HyperSpheres(Vec<(Point, f64)>),
|
HyperSpheres(Vec<(Point, f64)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a list of properties grouped by space id, then positions to a
|
/// Convert a list of space id grouped by properties, then positions
|
||||||
/// list of Spatial Objects for the rest API v2.
|
/// to a list of Spatial Objects for the rest API v2.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `list`:
|
||||||
|
/// A list of (`&Properties`, [ ( **Space Id**, [ *Spatial position* ] ) ]) tuples.
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
// Type alias cannot be used as Traits, so we can't use the alias to add the lifetime specifications.
|
||||||
|
pub fn from_spaces_by_properties<'o>(
|
||||||
|
objects: Box<
|
||||||
|
(dyn Iterator<
|
||||||
|
Item=(
|
||||||
|
&'o database::Properties,
|
||||||
|
Vec<(&'o String, Box<dyn Iterator<Item=space::Position> + 'o>)>,
|
||||||
|
),
|
||||||
|
> + 'o),
|
||||||
|
>,
|
||||||
|
) -> impl Iterator<Item=SpatialObject> + 'o {
|
||||||
|
objects.map(|(property, positions_by_spaces)| {
|
||||||
|
let volumes = positions_by_spaces
|
||||||
|
.into_iter()
|
||||||
|
.map(|(space, positions)| {
|
||||||
|
// We are not using vec![] as we now beforehand we
|
||||||
|
// will have only one element in the vector, so we
|
||||||
|
// optimise for space by allocating it as such.
|
||||||
|
let shapes = vec![
|
||||||
|
Shape::Points(positions.map(|position|
|
||||||
|
position.into()).collect::<Vec<_>>())
|
||||||
|
];
|
||||||
|
|
||||||
|
Volume {
|
||||||
|
space: space.clone(),
|
||||||
|
shapes,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
SpatialObject {
|
||||||
|
properties: (&property).into(),
|
||||||
|
volumes,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a list of properties grouped by space id, then positions
|
||||||
|
/// to a list of Spatial Objects for the rest API v2.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
///
|
///
|
||||||
/// * `list`:
|
/// * `list`:
|
||||||
/// A list of (**Space Id**, [ ( *Spatial position*, `&Properties` ) ]) tuples.
|
/// A list of (**Space Id**, [ ( *Spatial position*, `&Properties` ) ]) tuples.
|
||||||
pub fn to_spatial_objects(
|
pub fn from_properties_by_spaces(
|
||||||
list: Vec<(&String, Vec<(space::Position, &database::Properties)>)>,
|
objects: database::IterObjectsBySpaces<'_>,
|
||||||
) -> Vec<SpatialObject> {
|
) -> impl Iterator<Item=SpatialObject> + '_ {
|
||||||
// Filter per Properties, in order to regroup by it, then build a single SpatialObject per Properties.
|
// Filter per Properties, in order to regroup by it, then build
|
||||||
|
// a single SpatialObject per Properties.
|
||||||
let mut hashmap = HashMap::new();
|
let mut hashmap = HashMap::new();
|
||||||
for (space, v) in list {
|
for (space, v) in objects {
|
||||||
for (position, properties) in v {
|
for (position, properties) in v {
|
||||||
hashmap
|
hashmap
|
||||||
.entry(properties)
|
.entry(properties)
|
||||||
.or_insert_with(HashMap::new)
|
.or_insert_with(HashMap::new)
|
||||||
.entry(space)
|
.entry(space)
|
||||||
.or_insert_with(|| vec![])
|
.or_insert_with(Vec::new)
|
||||||
.push(position.into());
|
.push(position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut results = vec![];
|
let results = Box::new(hashmap.into_iter().map(|(property, hm)| {
|
||||||
for (properties, v) in hashmap.iter_mut() {
|
let positions = hm
|
||||||
let volumes = v
|
.into_iter()
|
||||||
.drain()
|
.map(|(space, positions)| {
|
||||||
.map(|(space, positions)| Volume {
|
let positions: database::IterPositions = Box::new(positions.into_iter());
|
||||||
space: space.clone(),
|
(space, positions)
|
||||||
shapes: vec![Shape::Points(positions)],
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
results.push(SpatialObject {
|
(property, positions)
|
||||||
properties: properties.into(),
|
}));
|
||||||
volumes,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
results
|
from_spaces_by_properties(results)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,6 +452,9 @@ pub fn build_index(
|
|||||||
}
|
}
|
||||||
|
|
||||||
properties.append(&mut properties_hm.drain().map(|(_, v)| v).collect::<Vec<_>>());
|
properties.append(&mut properties_hm.drain().map(|(_, v)| v).collect::<Vec<_>>());
|
||||||
|
|
||||||
|
// We we use sort_by_key, we get borrow checker errors.
|
||||||
|
#[allow(clippy::unnecessary_sort_by)]
|
||||||
properties.sort_unstable_by(|a, b| a.id().cmp(b.id()));
|
properties.sort_unstable_by(|a, b| a.id().cmp(b.id()));
|
||||||
|
|
||||||
space_set_objects.iter_mut().for_each(|object| {
|
space_set_objects.iter_mut().for_each(|object| {
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ fn convert(string: &str) -> Result<Vec<SpatialObject>, Error> {
|
|||||||
let (x, y, z) = (x * 0.039_062_5, y * 0.039_062_5, z * 0.039_062_5);
|
let (x, y, z) = (x * 0.039_062_5, y * 0.039_062_5, z * 0.039_062_5);
|
||||||
|
|
||||||
oids.entry(oid)
|
oids.entry(oid)
|
||||||
.or_insert_with(|| vec![])
|
.or_insert_with(Vec::new)
|
||||||
.push(vec![x, y, z]);
|
.push(vec![x, y, z]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user