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
|
// Spatial Operators
|
||||||
| inside
|
| inside
|
||||||
| outside
|
| outside
|
||||||
|
//| shape
|
||||||
;
|
;
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
@@ -113,6 +114,11 @@ inside
|
|||||||
: 'inside' '(' shapes ')'
|
: 'inside' '(' shapes ')'
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* Returns the set of positions inside the shape, (face included) */
|
||||||
|
shape
|
||||||
|
: 'shape' '(' shapes ')'
|
||||||
|
;
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/* SHAPES */
|
/* SHAPES */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ projection_operators
|
|||||||
*
|
*
|
||||||
* If it is provided, it MUST resolve to a NUMBER. */
|
* If it is provided, it MUST resolve to a NUMBER. */
|
||||||
nifti_operator
|
nifti_operator
|
||||||
: 'nifti' '(' ( STRING ',' )? ( selector ',' )? bag_expression ')'
|
: 'nifti' '(' ( selector ',' )? bag_expression ( ',' STRING )? ')'
|
||||||
;
|
;
|
||||||
|
|
||||||
json_operator
|
json_operator
|
||||||
|
|||||||
@@ -80,25 +80,20 @@ fn distinct<'c>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn filter_helper<'c>(
|
||||||
fn filter<'c>(
|
predicate: &Predicate,
|
||||||
|
bag: &Bag,
|
||||||
core_id: &str,
|
core_id: &str,
|
||||||
parameters: &CoreQueryParameters<'c>,
|
parameters: &CoreQueryParameters<'c>,
|
||||||
predicate: &Option<Predicate>,
|
|
||||||
bag: &Bag,
|
|
||||||
) -> mercator_db::ResultSet<'c> {
|
) -> mercator_db::ResultSet<'c> {
|
||||||
match predicate {
|
match bag.execute(core_id, parameters) {
|
||||||
None => bag.execute(core_id, parameters),
|
|
||||||
Some(predicate) => match bag.execute(core_id, parameters) {
|
|
||||||
e @ Err(_) => e,
|
e @ Err(_) => e,
|
||||||
Ok(results) => Ok(results
|
Ok(results) => Ok(results
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(space, positions)| {
|
.filter_map(|(space, positions)| {
|
||||||
let filtered = positions
|
let filtered = positions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|(position, properties)| {
|
.filter(|(position, properties)| predicate.eval((space, position, properties)))
|
||||||
predicate.eval((space, position, properties))
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if filtered.is_empty() {
|
if filtered.is_empty() {
|
||||||
None
|
None
|
||||||
@@ -107,6 +102,46 @@ fn filter<'c>(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()),
|
.collect::<Vec<_>>()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter<'c>(
|
||||||
|
core_id: &str,
|
||||||
|
parameters: &CoreQueryParameters<'c>,
|
||||||
|
predicate: &Option<Predicate>,
|
||||||
|
bag: &Option<Box<Bag>>,
|
||||||
|
) -> mercator_db::ResultSet<'c> {
|
||||||
|
match predicate {
|
||||||
|
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?
|
//FIXME: RADIUS IS A LENGTH, HOW TO ENCODE IT INTO THE SPACE?
|
||||||
Ok((space_id, space::Shape::HyperSphere(position, radius)))
|
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()),
|
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),
|
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()),
|
Shape::Nifti(_space_id) => Err("Outside-nifti: not yet implemented".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(r) = execute {
|
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!("Execution: \n{:#?}", r);
|
||||||
info!("NB results: {:?}", r.len());
|
info!("NB results: {:?}", r.len());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use mercator_db::space;
|
||||||
use mercator_db::DataBase;
|
use mercator_db::DataBase;
|
||||||
|
|
||||||
use super::expressions::Predictor;
|
use super::expressions::Predictor;
|
||||||
@@ -17,7 +18,10 @@ impl Predictor for Bag {
|
|||||||
match self {
|
match self {
|
||||||
Bag::ViewPort(bag) => bag.predict(db),
|
Bag::ViewPort(bag) => bag.predict(db),
|
||||||
Bag::Distinct(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::Complement(bag) => Ok(db.space(bag.space())?.volume() - bag.predict(db)?),
|
||||||
Bag::Intersection(lh, rh) => {
|
Bag::Intersection(lh, rh) => {
|
||||||
let l = lh.predict(db)?;
|
let l = lh.predict(db)?;
|
||||||
|
|||||||
@@ -153,6 +153,8 @@ Bags: symbols::Bag = {
|
|||||||
// Spatial Operators
|
// Spatial Operators
|
||||||
Inside,
|
Inside,
|
||||||
Outside,
|
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: symbols::Bag = {
|
||||||
// "filter" "(" <p:Predicates> "," <b:Bags> ")" =>
|
// "filter" "(" <p:Predicates> "," <b:Bags> ")" =>
|
||||||
"filter" "(" <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> )?> ")" =>
|
"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 = {
|
Predicates: symbols::Predicate = {
|
||||||
@@ -272,6 +278,12 @@ Inside: symbols::Bag = {
|
|||||||
symbols::Bag::Inside(<>)
|
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 */
|
// SHAPES */
|
||||||
//*********************************************************************/
|
//*********************************************************************/
|
||||||
@@ -282,6 +294,7 @@ Shapes: symbols::Shape = {
|
|||||||
Point,
|
Point,
|
||||||
HyperRectangle,
|
HyperRectangle,
|
||||||
HyperSphere,
|
HyperSphere,
|
||||||
|
Label,
|
||||||
Nifti
|
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
|
// Define a shape as the non-zero values in a NIfTI object, defined by
|
||||||
// nifti{
|
// nifti{
|
||||||
// spaceId: string,
|
// spaceId: string,
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ pub enum Bag {
|
|||||||
ViewPort(Box<Bag>),
|
ViewPort(Box<Bag>),
|
||||||
// Bags
|
// Bags
|
||||||
Distinct(Box<Bag>),
|
Distinct(Box<Bag>),
|
||||||
Filter(Option<Predicate>, Box<Bag>),
|
Filter(Option<Predicate>, Option<Box<Bag>>),
|
||||||
Complement(Box<Bag>),
|
Complement(Box<Bag>),
|
||||||
Intersection(Box<Bag>, Box<Bag>),
|
Intersection(Box<Bag>, Box<Bag>),
|
||||||
Union(Box<Bag>, Box<Bag>),
|
Union(Box<Bag>, Box<Bag>),
|
||||||
@@ -77,7 +77,10 @@ impl Bag {
|
|||||||
match self {
|
match self {
|
||||||
Bag::ViewPort(bag) => bag.space(),
|
Bag::ViewPort(bag) => bag.space(),
|
||||||
Bag::Distinct(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::Complement(bag) => bag.space(),
|
||||||
Bag::Intersection(lh, _) => {
|
Bag::Intersection(lh, _) => {
|
||||||
// We are assuming lh and rh are in the same space.
|
// We are assuming lh and rh are in the same space.
|
||||||
@@ -124,6 +127,7 @@ pub enum Shape {
|
|||||||
Point(String, LiteralPosition),
|
Point(String, LiteralPosition),
|
||||||
HyperRectangle(String, Vec<LiteralPosition>),
|
HyperRectangle(String, Vec<LiteralPosition>),
|
||||||
HyperSphere(String, LiteralPosition, LiteralNumber),
|
HyperSphere(String, LiteralPosition, LiteralNumber),
|
||||||
|
Label(String, String),
|
||||||
Nifti(String),
|
Nifti(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +137,7 @@ impl Shape {
|
|||||||
Shape::Point(space, _) => space,
|
Shape::Point(space, _) => space,
|
||||||
Shape::HyperRectangle(space, _) => space,
|
Shape::HyperRectangle(space, _) => space,
|
||||||
Shape::HyperSphere(space, _, _) => space,
|
Shape::HyperSphere(space, _, _) => space,
|
||||||
|
Shape::Label(space, _) => space,
|
||||||
Shape::Nifti(space) => space,
|
Shape::Nifti(space) => space,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,8 +206,16 @@ impl Shape {
|
|||||||
|
|
||||||
a * radius.powi(i as i32)
|
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);
|
println!("LiteralSelector.str(): {:?}", self);
|
||||||
unimplemented!();
|
unimplemented!("Unknown Field");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,10 @@ impl Validator for Bag {
|
|||||||
match self {
|
match self {
|
||||||
Bag::ViewPort(bag) => bag.validate(),
|
Bag::ViewPort(bag) => bag.validate(),
|
||||||
Bag::Distinct(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::Complement(bag) => bag.validate(),
|
||||||
Bag::Intersection(lh, rh) => compare_bag_types(lh, rh),
|
Bag::Intersection(lh, rh) => compare_bag_types(lh, rh),
|
||||||
Bag::Union(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::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()),
|
Shape::Nifti(_) => Err("not yet implemented".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user