use std::cmp::Ordering;
use mercator_db::space;
use mercator_db::Properties;
pub use super::types::*;
#[derive(Clone, Debug)]
pub enum Projection {
Nifti(String, LiteralSelector, Bag),
JSON(String, JsonValue, Bag),
}
impl Projection {
pub fn space(&self) -> &String {
match self {
Projection::Nifti(space, _, _) => &space,
Projection::JSON(space, _, _) => &space,
}
}
}
#[derive(Clone, Debug)]
pub enum JsonValue {
String(String),
JsonNumber(LiteralNumber),
Bool(bool),
Null,
Object(Vec<(String, JsonValue)>),
Array(Vec<JsonValue>),
Selector(LiteralSelector),
Aggregation(Aggregation),
}
#[derive(Clone, Debug)]
pub enum Aggregation {
Count(bool, LiteralSelector),
Sum(LiteralSelector),
Min(LiteralSelector),
Max(LiteralSelector),
}
#[derive(Clone, Debug)]
struct Transform {
reference: String,
offset: Vec<LiteralNumber>,
rotation: Vec<Vec<LiteralNumber>>,
}
#[derive(Clone, Debug)]
pub enum Bag {
ViewPort(Box<Bag>),
Distinct(Box<Bag>),
Filter(Option<Predicate>, Option<Box<Bag>>),
Complement(Box<Bag>),
Intersection(Box<Bag>, Box<Bag>),
Union(Box<Bag>, Box<Bag>),
Bag(Vec<Bag>),
Inside(Shape),
Outside(Shape),
}
impl Bag {
pub fn space(&self) -> &String {
match self {
Bag::ViewPort(bag) => bag.space(),
Bag::Distinct(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, _) => {
lh.space()
}
Bag::Union(lh, _) => {
lh.space()
}
Bag::Bag(_) => {
space::Space::universe().name()
}
Bag::Inside(shape) => shape.space(),
Bag::Outside(shape) => shape.space(),
}
}
}
#[derive(Clone, Debug)]
pub enum Predicate {
Less(Position, LiteralPosition),
Greater(Position, LiteralPosition),
Equal(Position, LiteralPosition),
Not(Box<Predicate>),
And(Box<Predicate>, Box<Predicate>),
Or(Box<Predicate>, Box<Predicate>),
}
#[derive(Clone, Debug)]
pub enum Shape {
Point(String, LiteralPosition),
HyperRectangle(String, Vec<LiteralPosition>),
HyperSphere(String, LiteralPosition, LiteralNumber),
Label(String, String),
Nifti(String),
}
impl Shape {
pub fn space(&self) -> &String {
match self {
Shape::Point(space, _) => space,
Shape::HyperRectangle(space, _) => space,
Shape::HyperSphere(space, _, _) => space,
Shape::Label(space, _) => space,
Shape::Nifti(space) => space,
}
}
pub fn volume(&self) -> f64 {
match self {
Shape::Point(_, _) => std::f64::EPSILON,
Shape::HyperRectangle(_space, pos) => {
assert_eq!(pos.len(), 2);
let mut volume = 1.0;
let LiteralPosition(low) = &pos[0];
let LiteralPosition(high) = &pos[pos.len() - 1];
for i in 0..low.len() {
let l = match low[i] {
LiteralNumber::Int(x) => x as f64,
LiteralNumber::Float(x) => x,
};
let h = match high[i] {
LiteralNumber::Int(x) => x as f64,
LiteralNumber::Float(x) => x,
};
let length = if h > l { h - l } else { l - h };
volume *= length;
}
volume
}
Shape::HyperSphere(_space, pos, radius) => {
let LiteralPosition(position) = pos;
let k = position.len();
let radius = match *radius {
LiteralNumber::Int(x) => x as f64,
LiteralNumber::Float(x) => x,
};
let pi = std::f64::consts::PI;
let factor = 2.0 * pi;
let mut a = 2.0;
let mut i = if (k % 2) == 0 {
a = pi;
2
} else {
1
};
while i < k {
i += 2;
a *= factor;
a /= i as f64;
}
a * radius.powi(i as i32)
}
Shape::Label(_, _) => {
std::f64::EPSILON
}
Shape::Nifti(_) => unimplemented!("Nifti"),
}
}
pub fn rasterize<'e>(&self) -> mercator_db::ResultSet<'e> {
unimplemented!("rasterize")
}
}
#[derive(Clone, Debug)]
pub enum Position {
StrCmp(LiteralSelector, String),
Selector(LiteralSelector),
Literal(LiteralPosition),
}
impl Position {
pub fn value<'e>(
&self,
object: (&'e String, &'e space::Position, &'e Properties),
) -> LiteralPosition {
match self {
Position::Literal(literal) => literal.clone(),
Position::Selector(selector) => selector.position(object),
Position::StrCmp(selector, literal) => {
let x = match (selector.str(object)).cmp(literal) {
Ordering::Equal => 0,
Ordering::Greater => 1,
Ordering::Less => -1,
};
LiteralPosition(vec![LiteralNumber::Int(x)])
}
}
}
}
#[derive(Clone, Debug)]
pub struct Field(pub String, pub Option<usize>);
#[derive(Clone, Debug)]
pub enum LiteralNumber {
Int(i64),
Float(f64),
}
impl From<&LiteralNumber> for Vec<f64> {
fn from(l: &LiteralNumber) -> Self {
let r = match l {
LiteralNumber::Int(x) => (*x) as f64,
LiteralNumber::Float(x) => *x,
};
vec![r]
}
}
impl PartialEq for LiteralNumber {
fn eq(&self, other: &LiteralNumber) -> bool {
match self {
LiteralNumber::Int(l) => match other {
LiteralNumber::Int(r) => l == r,
LiteralNumber::Float(_) => false,
},
LiteralNumber::Float(l) => match other {
LiteralNumber::Int(r) => l == &(*r as f64),
LiteralNumber::Float(r) => l == r,
},
}
}
}
#[derive(Clone, Debug)]
pub struct LiteralPosition(pub Vec<LiteralNumber>);
impl LiteralPosition {
pub fn get_type(&self) -> LiteralTypes {
let Self(v) = self;
let mut t = Vec::new();
for n in v {
t.push(match n {
LiteralNumber::Int(_) => LiteralTypes::Int,
LiteralNumber::Float(_) => LiteralTypes::Float,
});
}
LiteralTypes::Vector(t)
}
pub fn length(&self) -> f64 {
let LiteralPosition(v) = self;
let mut a = 0.0;
for x in v {
let x = match x {
LiteralNumber::Int(x) => (*x) as f64,
LiteralNumber::Float(x) => *x,
};
a += x * x;
}
a
}
pub fn dimensions(&self) -> usize {
self.0.len()
}
}
impl From<&LiteralNumber> for f64 {
fn from(l: &LiteralNumber) -> Self {
match l {
LiteralNumber::Int(x) => (*x) as f64,
LiteralNumber::Float(x) => *x,
}
}
}
impl From<&LiteralPosition> for Vec<f64> {
fn from(l: &LiteralPosition) -> Self {
let LiteralPosition(v) = l;
let mut r = Vec::with_capacity(v.len());
for x in v {
let x = match x {
LiteralNumber::Int(x) => (*x) as f64,
LiteralNumber::Float(x) => *x,
};
r.push(x);
}
r
}
}
impl From<&Vec<f64>> for LiteralPosition {
fn from(v: &Vec<f64>) -> Self {
let mut lv = Vec::with_capacity(v.len());
for value in v {
lv.push(LiteralNumber::Float(*value));
}
LiteralPosition(lv)
}
}
impl From<&space::Position> for LiteralPosition {
fn from(position: &space::Position) -> Self {
let lv: Vec<f64> = position.into();
(&lv).into()
}
}
impl PartialOrd for LiteralPosition {
fn partial_cmp(&self, other: &LiteralPosition) -> Option<Ordering> {
let LiteralPosition(lh) = self;
let LiteralPosition(rh) = other;
if lh.len() != rh.len() {
None
} else {
let l = self.length();
let r = other.length();
l.partial_cmp(&r)
}
}
}
impl PartialEq for LiteralPosition {
fn eq(&self, other: &LiteralPosition) -> bool {
let LiteralPosition(lh) = self;
let LiteralPosition(rh) = other;
if lh.len() == rh.len() {
for i in 0..lh.len() {
if lh[i] != rh[i] {
return false;
}
}
true
} else {
false
}
}
}
#[derive(Clone, Debug)]
pub struct LiteralSelector(pub Vec<Field>);
impl LiteralSelector {
pub fn get_type(&self) -> LiteralTypes {
LiteralTypes::Int
}
pub fn position<'e>(
&self,
object: (&'e String, &'e space::Position, &'e Properties),
) -> LiteralPosition {
println!("LiteralSelector.position(): {:?}", self);
object.1.into()
}
pub fn str<'e>(&self, object: (&'e String, &'e space::Position, &'e Properties)) -> &'e str {
let LiteralSelector(v) = self;
let last = v.last();
if let Some(Field(name, _)) = last {
if name == "id" {
return object.2.id();
} else if name == "type" {
return object.2.type_name();
} else if name == "reference_space" {
return object.0;
}
}
println!("LiteralSelector.str(): {:?}", self);
unimplemented!("Unknown Field");
}
}
pub fn get_type() -> LiteralTypes {
LiteralTypes::Vector(vec![
LiteralTypes::Float,
LiteralTypes::Float,
LiteralTypes::Float,
])
}