use std::sync::Arc;
use num_bigint::BigInt;
use num_traits::One;
use num_traits::Zero;
use crate::symbolic::core::Expr;
use crate::symbolic::elementary::cos;
use crate::symbolic::elementary::sin;
use crate::symbolic::elementary::tan;
use crate::symbolic::simplify_dag::simplify;
use crate::symbolic::vector::Vector;
#[must_use]
pub fn translation_2d(
tx: Expr,
ty: Expr,
) -> Expr {
Expr::Matrix(vec![
vec![
Expr::BigInt(BigInt::one()),
Expr::BigInt(BigInt::zero()),
tx,
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
ty,
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn translation_3d(
tx: Expr,
ty: Expr,
tz: Expr,
) -> Expr {
Expr::Matrix(vec![
vec![
Expr::BigInt(BigInt::one()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
tx,
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
Expr::BigInt(BigInt::zero()),
ty,
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
tz,
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn rotation_2d(angle: Expr) -> Expr {
let c = cos(angle.clone());
let s = sin(angle);
Expr::Matrix(vec![
vec![
c.clone(),
Expr::Neg(Arc::new(s.clone())),
Expr::BigInt(BigInt::zero()),
],
vec![s, c, Expr::BigInt(BigInt::zero())],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn rotation_3d_x(angle: Expr) -> Expr {
let c = cos(angle.clone());
let s = sin(angle);
Expr::Matrix(vec![
vec![
Expr::BigInt(BigInt::one()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
c.clone(),
Expr::Neg(Arc::new(s.clone())),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
s,
c,
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn rotation_3d_y(angle: Expr) -> Expr {
let c = cos(angle.clone());
let s = sin(angle);
Expr::Matrix(vec![
vec![
c.clone(),
Expr::BigInt(BigInt::zero()),
s.clone(),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::Neg(Arc::new(s)),
Expr::BigInt(BigInt::zero()),
c,
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn rotation_3d_z(angle: Expr) -> Expr {
let c = cos(angle.clone());
let s = sin(angle);
Expr::Matrix(vec![
vec![
c.clone(),
Expr::Neg(Arc::new(s.clone())),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
s,
c,
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn scaling_2d(
sx: Expr,
sy: Expr,
) -> Expr {
Expr::Matrix(vec![
vec![
sx,
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
sy,
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn scaling_3d(
sx: Expr,
sy: Expr,
sz: Expr,
) -> Expr {
Expr::Matrix(vec![
vec![
sx,
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
sy,
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
sz,
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn perspective_projection(
fovy: Expr,
aspect: &Expr,
near: Expr,
far: Expr,
) -> Expr {
let f = tan(Expr::new_div(fovy, Expr::BigInt(BigInt::from(2))));
let range_inv = Expr::new_div(
Expr::BigInt(BigInt::one()),
Expr::new_sub(near.clone(), far.clone()),
);
Expr::Matrix(vec![
vec![
Expr::Div(
Arc::new(Expr::BigInt(BigInt::one())),
Arc::new(Expr::Mul(Arc::new(f.clone()), Arc::new(aspect.clone()))),
),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::Div(Arc::new(Expr::BigInt(BigInt::one())), Arc::new(f)),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::Mul(
Arc::new(Expr::Add(Arc::new(near.clone()), Arc::new(far.clone()))),
Arc::new(range_inv),
),
Expr::Mul(
Arc::new(Expr::Mul(
Arc::new(Expr::BigInt(BigInt::from(2))),
Arc::new(near),
)),
Arc::new(far),
),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::from(-1)),
Expr::BigInt(BigInt::zero()),
],
])
}
#[must_use]
pub fn orthographic_projection(
left: Expr,
right: Expr,
bottom: Expr,
top: Expr,
near: Expr,
far: Expr,
) -> Expr {
let r_l = Expr::new_div(
Expr::BigInt(BigInt::one()),
Expr::new_sub(right.clone(), left.clone()),
);
let t_b = Expr::new_div(
Expr::BigInt(BigInt::one()),
Expr::new_sub(top.clone(), bottom.clone()),
);
let f_n = Expr::new_div(
Expr::BigInt(BigInt::one()),
Expr::new_sub(far.clone(), near.clone()),
);
Expr::Matrix(vec![
vec![
Expr::Mul(
Arc::new(Expr::BigInt(BigInt::from(2))),
Arc::new(r_l.clone()),
),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::Neg(Arc::new(Expr::Mul(
Arc::new(Expr::Add(Arc::new(right), Arc::new(left))),
Arc::new(r_l),
))),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::Mul(
Arc::new(Expr::BigInt(BigInt::from(2))),
Arc::new(t_b.clone()),
),
Expr::BigInt(BigInt::zero()),
Expr::Neg(Arc::new(Expr::Mul(
Arc::new(Expr::Add(Arc::new(top), Arc::new(bottom))),
Arc::new(t_b),
))),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::Neg(Arc::new(Expr::Mul(
Arc::new(Expr::BigInt(BigInt::from(2))),
Arc::new(f_n.clone()),
))),
Expr::Neg(Arc::new(Expr::Mul(
Arc::new(Expr::Add(Arc::new(far), Arc::new(near))),
Arc::new(f_n),
))),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn look_at(
eye: &Vector,
center: &Vector,
up: &Vector,
) -> Expr {
let f = (center.clone() - eye.clone()).normalize();
let s = f.cross(up).normalize();
let u = s.cross(&f);
Expr::Matrix(vec![
vec![
s.x.clone(),
s.y.clone(),
s.z.clone(),
Expr::Neg(Arc::new(s.dot(eye))),
],
vec![
u.x.clone(),
u.y.clone(),
u.z.clone(),
Expr::Neg(Arc::new(u.dot(eye))),
],
vec![
Expr::Neg(Arc::new(f.x.clone())),
Expr::Neg(Arc::new(f.y.clone())),
Expr::Neg(Arc::new(f.z.clone())),
f.dot(eye),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BezierCurve {
pub control_points: Vec<Vector>,
pub degree: usize,
}
impl BezierCurve {
#[allow(clippy::cast_possible_wrap)]
#[must_use]
pub fn evaluate(
&self,
t: &Expr,
) -> Vector {
let n = self.degree as i64;
let mut result = Vector::new(
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
);
for (i, pt) in self.control_points.iter().enumerate() {
let i_bigint = BigInt::from(i);
let n_bigint = BigInt::from(n);
let bernstein = Expr::new_mul(
Expr::Binomial(
Arc::new(Expr::BigInt(n_bigint.clone())),
Arc::new(Expr::BigInt(i_bigint.clone())),
),
Expr::new_pow(t.clone(), Expr::BigInt(i_bigint.clone())),
);
let bernstein = Expr::new_mul(
bernstein,
Expr::new_pow(
Expr::new_sub(Expr::BigInt(BigInt::one()), t.clone()),
Expr::BigInt(n_bigint - i_bigint),
),
);
result = result + pt.scalar_mul(&bernstein);
}
result
}
#[must_use]
pub fn derivative(
&self,
t: &Expr,
) -> Vector {
if self.degree == 0 || self.control_points.len() < 2 {
return Vector::new(
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
);
}
let n = Expr::BigInt(BigInt::from(self.degree as i64));
let derivative_points: Vec<Vector> = (0..self.control_points.len() - 1)
.map(|i| {
let diff = self.control_points[i + 1].clone() - self.control_points[i].clone();
diff.scalar_mul(&n)
})
.collect();
let derivative_curve = Self {
control_points: derivative_points,
degree: self.degree - 1,
};
derivative_curve.evaluate(t)
}
#[must_use]
pub fn split(
&self,
t: &Expr,
) -> (Self, Self) {
let n = self.control_points.len();
let mut pyramid: Vec<Vec<Vector>> = vec![self.control_points.clone()];
for level in 1..n {
let prev = &pyramid[level - 1];
let mut current = Vec::with_capacity(n - level);
for i in 0..(n - level) {
let one_minus_t = simplify(&Expr::new_sub(Expr::BigInt(BigInt::one()), t.clone()));
let left = prev[i].scalar_mul(&one_minus_t);
let right = prev[i + 1].scalar_mul(t);
current.push(left + right);
}
pyramid.push(current);
}
let left_points: Vec<Vector> = (0..n).map(|i| pyramid[i][0].clone()).collect();
let right_points: Vec<Vector> = (0..n).map(|i| pyramid[n - 1 - i][i].clone()).collect();
(
Self {
control_points: left_points,
degree: self.degree,
},
Self {
control_points: right_points,
degree: self.degree,
},
)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BSplineCurve {
pub control_points: Vec<Vector>,
pub knots: Vec<Expr>,
pub degree: usize,
}
impl BSplineCurve {
#[must_use]
pub fn evaluate(
&self,
t: &Expr,
) -> Vector {
let p = self.degree;
let k = self.knots.len() - 1 - p - 1;
let mut d: Vec<Vector> = self.control_points[..=k + p].to_vec();
for r in 1..=p {
for j in (r..=k + p).rev() {
let t_j = &self.knots[j];
let t_j_p1 = &self.knots[j + p + 1 - r];
let alpha = simplify(&Expr::new_div(
Expr::new_sub(t.clone(), t_j.clone()),
Expr::new_sub(t_j_p1.clone(), t_j.clone()),
));
d[j] = d[j - 1].scalar_mul(&simplify(&Expr::new_sub(
Expr::BigInt(BigInt::one()),
alpha.clone(),
))) + d[j].scalar_mul(&alpha);
}
}
d[k + p].clone()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Polygon {
pub indices: Vec<usize>,
}
impl Polygon {
#[must_use]
pub const fn new(indices: Vec<usize>) -> Self {
Self { indices }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PolygonMesh {
pub vertices: Vec<Vector>,
pub polygons: Vec<Polygon>,
}
impl PolygonMesh {
#[must_use]
pub const fn new(
vertices: Vec<Vector>,
polygons: Vec<Polygon>,
) -> Self {
Self { vertices, polygons }
}
pub fn apply_transformation(
&self,
transformation: &Expr,
) -> Result<Self, String> {
if let Expr::Matrix(matrix) = transformation {
let transformed_vertices = self
.vertices
.iter()
.map(|vertex| {
let homogeneous_vertex = Expr::Vector(vec![
vertex.x.clone(),
vertex.y.clone(),
vertex.z.clone(),
Expr::BigInt(BigInt::one()),
]);
let transformed_homogeneous = simplify(&Expr::new_matrix_vec_mul(
Expr::Matrix(matrix.clone()),
homogeneous_vertex,
));
if let Expr::Vector(vec) = transformed_homogeneous {
let w = vec
.get(3)
.cloned()
.unwrap_or_else(|| Expr::BigInt(BigInt::one()));
let x = simplify(&Expr::new_div(vec[0].clone(), w.clone()));
let y = simplify(&Expr::new_div(vec[1].clone(), w.clone()));
let z = simplify(&Expr::new_div(vec[2].clone(), w));
Vector::new(x, y, z)
} else {
vertex.clone()
}
})
.collect();
Ok(Self {
vertices: transformed_vertices,
polygons: self.polygons.clone(),
})
} else {
Err("Transformation must \
be an Expr::Matrix"
.to_string())
}
}
#[must_use]
pub fn compute_normals(&self) -> Vec<Vector> {
self.polygons
.iter()
.filter_map(|poly| {
if poly.indices.len() >= 3 {
let v0 = &self.vertices[poly.indices[0]];
let v1 = &self.vertices[poly.indices[1]];
let v2 = &self.vertices[poly.indices[2]];
let edge1 = v1.clone() - v0.clone();
let edge2 = v2.clone() - v0.clone();
Some(edge1.cross(&edge2).normalize())
} else {
None
}
})
.collect()
}
#[must_use]
pub fn triangulate(&self) -> Self {
let triangles: Vec<Polygon> = self
.polygons
.iter()
.flat_map(|poly| {
if poly.indices.len() <= 3 {
vec![poly.clone()]
} else {
(1..poly.indices.len() - 1)
.map(|i| {
Polygon::new(vec![
poly.indices[0],
poly.indices[i],
poly.indices[i + 1],
])
})
.collect()
}
})
.collect();
Self {
vertices: self.vertices.clone(),
polygons: triangles,
}
}
}
#[must_use]
pub fn shear_2d(
shx: Expr,
shy: Expr,
) -> Expr {
Expr::Matrix(vec![
vec![
Expr::BigInt(BigInt::one()),
shx,
Expr::BigInt(BigInt::zero()),
],
vec![
shy,
Expr::BigInt(BigInt::one()),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn reflection_2d(angle: Expr) -> Expr {
let two_angle = Expr::new_mul(Expr::Constant(2.0), angle);
let c = cos(two_angle.clone());
let s = sin(two_angle);
Expr::Matrix(vec![
vec![c.clone(), s.clone(), Expr::BigInt(BigInt::zero())],
vec![s, Expr::Neg(Arc::new(c)), Expr::BigInt(BigInt::zero())],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn reflection_3d(
nx: Expr,
ny: Expr,
nz: Expr,
) -> Expr {
let two = Expr::Constant(2.0);
Expr::Matrix(vec![
vec![
simplify(&Expr::new_sub(
Expr::BigInt(BigInt::one()),
Expr::new_mul(two.clone(), Expr::new_mul(nx.clone(), nx.clone())),
)),
simplify(&Expr::new_neg(Expr::new_mul(
two.clone(),
Expr::new_mul(nx.clone(), ny.clone()),
))),
simplify(&Expr::new_neg(Expr::new_mul(
two.clone(),
Expr::new_mul(nx.clone(), nz.clone()),
))),
Expr::BigInt(BigInt::zero()),
],
vec![
simplify(&Expr::new_neg(Expr::new_mul(
two.clone(),
Expr::new_mul(ny.clone(), nx.clone()),
))),
simplify(&Expr::new_sub(
Expr::BigInt(BigInt::one()),
Expr::new_mul(two.clone(), Expr::new_mul(ny.clone(), ny.clone())),
)),
simplify(&Expr::new_neg(Expr::new_mul(
two.clone(),
Expr::new_mul(ny.clone(), nz.clone()),
))),
Expr::BigInt(BigInt::zero()),
],
vec![
simplify(&Expr::new_neg(Expr::new_mul(
two.clone(),
Expr::new_mul(nz.clone(), nx),
))),
simplify(&Expr::new_neg(Expr::new_mul(
two.clone(),
Expr::new_mul(nz.clone(), ny),
))),
simplify(&Expr::new_sub(
Expr::BigInt(BigInt::one()),
Expr::new_mul(two, Expr::new_mul(nz.clone(), nz)),
)),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}
#[must_use]
pub fn rotation_axis_angle(
axis: &Vector,
angle: Expr,
) -> Expr {
let c = cos(angle.clone());
let s = sin(angle);
let one_minus_c = simplify(&Expr::new_sub(Expr::BigInt(BigInt::one()), c.clone()));
let ux = axis.x.clone();
let uy = axis.y.clone();
let uz = axis.z.clone();
Expr::Matrix(vec![
vec![
simplify(&Expr::new_add(
c.clone(),
Expr::new_mul(Expr::new_mul(ux.clone(), ux.clone()), one_minus_c.clone()),
)),
simplify(&Expr::new_sub(
Expr::new_mul(Expr::new_mul(ux.clone(), uy.clone()), one_minus_c.clone()),
Expr::new_mul(uz.clone(), s.clone()),
)),
simplify(&Expr::new_add(
Expr::new_mul(Expr::new_mul(ux.clone(), uz.clone()), one_minus_c.clone()),
Expr::new_mul(uy.clone(), s.clone()),
)),
Expr::BigInt(BigInt::zero()),
],
vec![
simplify(&Expr::new_add(
Expr::new_mul(Expr::new_mul(uy.clone(), ux.clone()), one_minus_c.clone()),
Expr::new_mul(uz.clone(), s.clone()),
)),
simplify(&Expr::new_add(
c.clone(),
Expr::new_mul(Expr::new_mul(uy.clone(), uy.clone()), one_minus_c.clone()),
)),
simplify(&Expr::new_sub(
Expr::new_mul(Expr::new_mul(uy.clone(), uz.clone()), one_minus_c.clone()),
Expr::new_mul(ux.clone(), s.clone()),
)),
Expr::BigInt(BigInt::zero()),
],
vec![
simplify(&Expr::new_sub(
Expr::new_mul(Expr::new_mul(uz.clone(), ux.clone()), one_minus_c.clone()),
Expr::new_mul(uy.clone(), s.clone()),
)),
simplify(&Expr::new_add(
Expr::new_mul(Expr::new_mul(uz.clone(), uy), one_minus_c.clone()),
Expr::new_mul(ux, s),
)),
simplify(&Expr::new_add(
c,
Expr::new_mul(Expr::new_mul(uz.clone(), uz), one_minus_c),
)),
Expr::BigInt(BigInt::zero()),
],
vec![
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::zero()),
Expr::BigInt(BigInt::one()),
],
])
}