Introduce Label for search within id
This allows to define a volume using an indexed object.
This commit is contained in:
@@ -19,6 +19,7 @@ bag_expression
|
||||
// Spatial Operators
|
||||
| inside
|
||||
| outside
|
||||
//| shape
|
||||
;
|
||||
|
||||
/**********************************************************************/
|
||||
@@ -113,6 +114,11 @@ inside
|
||||
: 'inside' '(' shapes ')'
|
||||
;
|
||||
|
||||
/* Returns the set of positions inside the shape, (face included) */
|
||||
shape
|
||||
: 'shape' '(' shapes ')'
|
||||
;
|
||||
|
||||
/**********************************************************************/
|
||||
/* SHAPES */
|
||||
/**********************************************************************/
|
||||
|
||||
@@ -18,7 +18,7 @@ projection_operators
|
||||
*
|
||||
* If it is provided, it MUST resolve to a NUMBER. */
|
||||
nifti_operator
|
||||
: 'nifti' '(' ( STRING ',' )? ( selector ',' )? bag_expression ')'
|
||||
: 'nifti' '(' ( selector ',' )? bag_expression ( ',' STRING )? ')'
|
||||
;
|
||||
|
||||
json_operator
|
||||
|
||||
@@ -80,33 +80,68 @@ fn distinct<'c>(
|
||||
}
|
||||
}
|
||||
}
|
||||
fn filter_helper<'c>(
|
||||
predicate: &Predicate,
|
||||
bag: &Bag,
|
||||
core_id: &str,
|
||||
parameters: &CoreQueryParameters<'c>,
|
||||
) -> mercator_db::ResultSet<'c> {
|
||||
match bag.execute(core_id, parameters) {
|
||||
e @ Err(_) => e,
|
||||
Ok(results) => Ok(results
|
||||
.into_iter()
|
||||
.filter_map(|(space, positions)| {
|
||||
let filtered = positions
|
||||
.into_iter()
|
||||
.filter(|(position, properties)| predicate.eval((space, position, properties)))
|
||||
.collect::<Vec<_>>();
|
||||
if filtered.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some((space, filtered))
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()),
|
||||
}
|
||||
}
|
||||
|
||||
fn filter<'c>(
|
||||
core_id: &str,
|
||||
parameters: &CoreQueryParameters<'c>,
|
||||
predicate: &Option<Predicate>,
|
||||
bag: &Bag,
|
||||
bag: &Option<Box<Bag>>,
|
||||
) -> mercator_db::ResultSet<'c> {
|
||||
match predicate {
|
||||
None => bag.execute(core_id, parameters),
|
||||
Some(predicate) => match bag.execute(core_id, parameters) {
|
||||
e @ Err(_) => e,
|
||||
Ok(results) => Ok(results
|
||||
.into_iter()
|
||||
.filter_map(|(space, positions)| {
|
||||
let filtered = positions
|
||||
.into_iter()
|
||||
.filter(|(position, properties)| {
|
||||
predicate.eval((space, position, properties))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if filtered.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some((space, filtered))
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()),
|
||||
None => {
|
||||
if let Some(bag) = bag {
|
||||
bag.execute(core_id, parameters)
|
||||
} else {
|
||||
Err("Filter without predicate nor data set.".to_string())
|
||||
}
|
||||
}
|
||||
Some(predicate) => match bag {
|
||||
None => {
|
||||
let (low, high) = space::Space::universe().bounding_box();
|
||||
let low: Vec<_> = low.into();
|
||||
let high: Vec<_> = high.into();
|
||||
let shape = Shape::HyperRectangle(
|
||||
space::Space::universe().name().clone(),
|
||||
vec![
|
||||
LiteralPosition(
|
||||
low.into_iter()
|
||||
.map(LiteralNumber::Float)
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
LiteralPosition(
|
||||
high.into_iter()
|
||||
.map(LiteralNumber::Float)
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
],
|
||||
);
|
||||
filter_helper(predicate, &Bag::Inside(shape), core_id, parameters)
|
||||
}
|
||||
Some(bag) => filter_helper(predicate, bag.as_ref(), core_id, parameters),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -248,6 +283,10 @@ fn inside<'c>(
|
||||
//FIXME: RADIUS IS A LENGTH, HOW TO ENCODE IT INTO THE SPACE?
|
||||
Ok((space_id, space::Shape::HyperSphere(position, radius)))
|
||||
}
|
||||
Shape::Label(_, id) => {
|
||||
// Not a real shape, so short circuit and return.
|
||||
return core.get_by_label(parameters, id);
|
||||
}
|
||||
Shape::Nifti(_space_id) => Err("Inside-Nifti: not yet implemented".to_string()),
|
||||
};
|
||||
|
||||
@@ -310,6 +349,7 @@ fn outside<'c>(
|
||||
Ok(inside) => complement_helper(core, parameters, space_id, inside),
|
||||
}
|
||||
}
|
||||
Shape::Label(_, _) => Err("Label: not yet implemented".to_string()),
|
||||
Shape::Nifti(_space_id) => Err("Outside-nifti: not yet implemented".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ fn main() {
|
||||
}
|
||||
|
||||
if let Ok(r) = execute {
|
||||
//let r = mercator_db::json::model::to_spatial_objects(&db, r);
|
||||
//let r = mercator_db::json::model::to_spatial_objects(r);
|
||||
info!("Execution: \n{:#?}", r);
|
||||
info!("NB results: {:?}", r.len());
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use mercator_db::space;
|
||||
use mercator_db::DataBase;
|
||||
|
||||
use super::expressions::Predictor;
|
||||
@@ -17,7 +18,10 @@ impl Predictor for Bag {
|
||||
match self {
|
||||
Bag::ViewPort(bag) => bag.predict(db),
|
||||
Bag::Distinct(bag) => bag.predict(db),
|
||||
Bag::Filter(_, bag) => bag.predict(db),
|
||||
Bag::Filter(_, bag) => match bag {
|
||||
None => Ok(db.space(space::Space::universe().name())?.volume()),
|
||||
Some(b) => b.predict(db),
|
||||
},
|
||||
Bag::Complement(bag) => Ok(db.space(bag.space())?.volume() - bag.predict(db)?),
|
||||
Bag::Intersection(lh, rh) => {
|
||||
let l = lh.predict(db)?;
|
||||
|
||||
@@ -153,6 +153,8 @@ Bags: symbols::Bag = {
|
||||
// Spatial Operators
|
||||
Inside,
|
||||
Outside,
|
||||
// returns the positions or volume of the shape, instead of the data points in or outside it.
|
||||
//Shape,
|
||||
};
|
||||
|
||||
//*********************************************************************/
|
||||
@@ -187,9 +189,13 @@ Union: symbols::Bag = {
|
||||
Filter: symbols::Bag = {
|
||||
// "filter" "(" <p:Predicates> "," <b:Bags> ")" =>
|
||||
"filter" "(" <b:Bags> ")" =>
|
||||
symbols::Bag::Filter(None, Box::new(b)),
|
||||
symbols::Bag::Filter(None, Some(Box::new(b))),
|
||||
"filter" "(" <p:Predicates> <b:("," <Bags> )?> ")" =>
|
||||
symbols::get_filter(p, b)
|
||||
match b {
|
||||
None => symbols::Bag::Filter(Some(p), None),
|
||||
Some(b) => symbols::Bag::Filter(Some(p), Some(Box::new(b))),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Predicates: symbols::Predicate = {
|
||||
@@ -272,6 +278,12 @@ Inside: symbols::Bag = {
|
||||
symbols::Bag::Inside(<>)
|
||||
};
|
||||
|
||||
//FIXME: ADD A SHAPE VARIANT WHICH JUST RETURNS ALL THE POSITIONS OF THAT SHAPE
|
||||
//Shape: symbols::Bag = {
|
||||
// <Shapes> =>
|
||||
// symbols::Bag::Shape(<>)
|
||||
//}
|
||||
|
||||
//*********************************************************************/
|
||||
// SHAPES */
|
||||
//*********************************************************************/
|
||||
@@ -282,6 +294,7 @@ Shapes: symbols::Shape = {
|
||||
Point,
|
||||
HyperRectangle,
|
||||
HyperSphere,
|
||||
Label,
|
||||
Nifti
|
||||
};
|
||||
|
||||
@@ -333,6 +346,21 @@ Point: symbols::Shape = {
|
||||
}
|
||||
};
|
||||
|
||||
// Filter by Label, a.k.a use an ID to define a volume, and use that volume to
|
||||
// select data points.
|
||||
Label: symbols::Shape = {
|
||||
"label" "{"
|
||||
<id:String>
|
||||
<rs:( "," <String> )?>
|
||||
"}" => {
|
||||
let space_id = match rs {
|
||||
Some(id) => id,
|
||||
None => Space::universe().name().clone(),
|
||||
};
|
||||
symbols::Shape::Label(space_id, id)
|
||||
}
|
||||
};
|
||||
|
||||
// Define a shape as the non-zero values in a NIfTI object, defined by
|
||||
// nifti{
|
||||
// spaceId: string,
|
||||
|
||||
@@ -61,7 +61,7 @@ pub enum Bag {
|
||||
ViewPort(Box<Bag>),
|
||||
// Bags
|
||||
Distinct(Box<Bag>),
|
||||
Filter(Option<Predicate>, Box<Bag>),
|
||||
Filter(Option<Predicate>, Option<Box<Bag>>),
|
||||
Complement(Box<Bag>),
|
||||
Intersection(Box<Bag>, Box<Bag>),
|
||||
Union(Box<Bag>, Box<Bag>),
|
||||
@@ -77,7 +77,10 @@ impl Bag {
|
||||
match self {
|
||||
Bag::ViewPort(bag) => bag.space(),
|
||||
Bag::Distinct(bag) => bag.space(),
|
||||
Bag::Filter(_, bag) => bag.space(),
|
||||
Bag::Filter(_, bag) => match bag {
|
||||
None => space::Space::universe().name(),
|
||||
Some(b) => b.space(),
|
||||
},
|
||||
Bag::Complement(bag) => bag.space(),
|
||||
Bag::Intersection(lh, _) => {
|
||||
// We are assuming lh and rh are in the same space.
|
||||
@@ -124,6 +127,7 @@ pub enum Shape {
|
||||
Point(String, LiteralPosition),
|
||||
HyperRectangle(String, Vec<LiteralPosition>),
|
||||
HyperSphere(String, LiteralPosition, LiteralNumber),
|
||||
Label(String, String),
|
||||
Nifti(String),
|
||||
}
|
||||
|
||||
@@ -133,6 +137,7 @@ impl Shape {
|
||||
Shape::Point(space, _) => space,
|
||||
Shape::HyperRectangle(space, _) => space,
|
||||
Shape::HyperSphere(space, _, _) => space,
|
||||
Shape::Label(space, _) => space,
|
||||
Shape::Nifti(space) => space,
|
||||
}
|
||||
}
|
||||
@@ -201,9 +206,17 @@ impl Shape {
|
||||
|
||||
a * radius.powi(i as i32)
|
||||
}
|
||||
Shape::Nifti(_) => unimplemented!(),
|
||||
Shape::Label(_, _) => {
|
||||
// FIXME: Needs to find a way to figure out the approximate volume of this specific ID, or return MAX or MIN..
|
||||
std::f64::EPSILON
|
||||
}
|
||||
Shape::Nifti(_) => unimplemented!("Nifti"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rasterize<'e>(&self) -> mercator_db::ResultSet<'e> {
|
||||
unimplemented!("rasterize")
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
@@ -426,37 +439,7 @@ impl LiteralSelector {
|
||||
}
|
||||
|
||||
println!("LiteralSelector.str(): {:?}", self);
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
// The logic was getting a bit too complex to be embedded directly into the
|
||||
// grammar definition.
|
||||
pub fn get_filter(p: Predicate, b: Option<Bag>) -> Bag {
|
||||
match b {
|
||||
Some(b) => Bag::Filter(Some(p), Box::new(b)),
|
||||
None => {
|
||||
let (low, high) = space::Space::universe().bounding_box();
|
||||
let low: Vec<_> = low.into();
|
||||
let high: Vec<_> = high.into();
|
||||
let bb = Shape::HyperRectangle(
|
||||
space::Space::universe().name().clone(),
|
||||
vec![
|
||||
LiteralPosition(
|
||||
low.into_iter()
|
||||
.map(LiteralNumber::Float)
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
LiteralPosition(
|
||||
high.into_iter()
|
||||
.map(LiteralNumber::Float)
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Bag::Filter(Some(p), Box::new(Bag::Inside(bb)))
|
||||
}
|
||||
unimplemented!("Unknown Field");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,10 @@ impl Validator for Bag {
|
||||
match self {
|
||||
Bag::ViewPort(bag) => bag.validate(),
|
||||
Bag::Distinct(bag) => bag.validate(),
|
||||
Bag::Filter(_, bag) => bag.validate(),
|
||||
Bag::Filter(_, bag) => match bag {
|
||||
None => Ok(LiteralPosition(vec![]).get_type()),
|
||||
Some(b) => b.validate(),
|
||||
},
|
||||
Bag::Complement(bag) => bag.validate(),
|
||||
Bag::Intersection(lh, rh) => compare_bag_types(lh, rh),
|
||||
Bag::Union(lh, rh) => compare_bag_types(lh, rh),
|
||||
@@ -149,6 +152,10 @@ impl Validator for Shape {
|
||||
}
|
||||
}
|
||||
Shape::HyperSphere(_, pos, _) => pos.validate(),
|
||||
Shape::Label(_, _) => {
|
||||
// FIXME: Quick Hack, we need to fix this and return the effective type of the object Id.
|
||||
Ok(LiteralPosition(vec![]).get_type())
|
||||
}
|
||||
Shape::Nifti(_) => Err("not yet implemented".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user