1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

//! **Theon** abstracts Euclidean spaces and geometric queries with support for
//! popular linear algebra and spatial crates in the Rust ecosystem.

// TODO: Require the geometry-nalgebra feature for doc tests.
//       See https://github.com/rust-lang/rust/issues/43781

#![doc(
html_favicon_url = "https://raw.githubusercontent.com/olson-sean-k/theon/master/doc/theon-favicon.ico"
)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/olson-sean-k/theon/master/doc/theon.svg?sanitize=true"
)]

pub mod integration;
pub mod lapack;
pub mod ops;
pub mod query;
pub mod space;

use decorum::R64;
use num::{self, Num, NumCast, One, Zero};

use crate::space::EuclideanSpace;

pub mod prelude {
//! Re-exports commonly used types and traits.

pub use crate::query::Intersection as _;
}

pub type Position<T> = <T as AsPosition>::Position;

/// Positional data.
///
/// This trait exposes positional data for geometric types.
///
/// # Examples
///
/// Exposing positional data for a vertex:
///
/// rust
/// # extern crate nalgebra;
/// # extern crate theon;
/// #
/// use nalgebra::{Point3, Vector3};
/// use theon::AsPosition;
///
/// pub struct Vertex {
///     position: Point3<f64>,
///     normal: Vector3<f64>,
/// }
///
/// impl AsPosition for Vertex {
///     type Position = Point3<f64>;
///
///     fn as_position(&self) -> &Self::Position {
///         &self.position
///     }
///
///     fn as_position_mut(&mut self) -> &mut Self::Position {
///         &mut self.position
///     }
/// }
/// 
pub trait AsPosition {
type Position: EuclideanSpace;

fn as_position(&self) -> &Self::Position;

fn as_position_mut(&mut self) -> &mut Self::Position;

fn transform<F>(&mut self, mut f: F)
where
F: FnMut(&Self::Position) -> Self::Position,
{
*self.as_position_mut() = f(self.as_position());
}

fn map_position<F>(mut self, f: F) -> Self
where
Self: Sized,
F: FnMut(&Self::Position) -> Self::Position,
{
self.transform(f);
self
}
}

impl<S> AsPosition for S
where
S: EuclideanSpace,
{
type Position = Self;

fn as_position(&self) -> &Self::Position {
self
}

fn as_position_mut(&mut self) -> &mut Self::Position {
self
}
}

/// Linearly interpolates between two values.
pub fn lerp<T>(a: T, b: T, f: R64) -> T
where
T: Num + NumCast,
{
let f = num::clamp(f, Zero::zero(), One::one());
let af = <R64 as NumCast>::from(a).unwrap() * (R64::one() - f);
let bf = <R64 as NumCast>::from(b).unwrap() * f;
<T as NumCast>::from(af + bf).unwrap()
}