mesh_geometry/utils/
jacobian.rs1use crate::{Float, Point2};
2
3#[derive(Debug, Clone, Copy, PartialEq)]
6pub struct Jacobian2x2<T: Float> {
7 pub m11: T,
9 pub m12: T,
11 pub m21: T,
13 pub m22: T,
15}
16
17impl<T: Float> Jacobian2x2<T> {
18 pub fn for_quad(
20 xi: T,
21 eta: T,
22 a: Point2<T>,
23 b: Point2<T>,
24 c: Point2<T>,
25 d: Point2<T>,
26 ) -> Self {
27 let one = T::one();
29 let d_n1_dxi = -one + eta; let d_n1_deta = -one + xi; let d_n2_dxi = one - eta; let d_n2_deta = -one - xi; let d_n3_dxi = one + eta; let d_n3_deta = one + xi; let d_n4_dxi = -one - eta; let d_n4_deta = one - xi; let m11 = d_n1_dxi * a.x + d_n2_dxi * b.x + d_n3_dxi * c.x + d_n4_dxi * d.x;
35 let m12 = d_n1_deta * a.x + d_n2_deta * b.x + d_n3_deta * c.x + d_n4_deta * d.x;
36 let m21 = d_n1_dxi * a.y + d_n2_dxi * b.y + d_n3_dxi * c.y + d_n4_dxi * d.y;
37 let m22 = d_n1_deta * a.y + d_n2_deta * b.y + d_n3_deta * c.y + d_n4_deta * d.y;
38 Jacobian2x2 { m11, m12, m21, m22 }
39 }
40
41 pub fn det(self) -> T {
43 self.m11 * self.m22 - self.m12 * self.m21
44 }
45
46 pub fn inverse(self) -> Option<Jacobian2x2<T>> {
48 let d = self.det();
49 if d.abs() < T::epsilon() { return None; }
50 let inv = T::one() / d;
51 Some(Jacobian2x2 {
52 m11: self.m22 * inv,
53 m12: -self.m12 * inv,
54 m21: -self.m21 * inv,
55 m22: self.m11 * inv,
56 })
57 }
58}
59
60pub fn invert_quad_mapping<T: Float>(
62 mut xi: T,
63 mut eta: T,
64 p: Point2<T>,
65 a: Point2<T>,
66 b: Point2<T>,
67 c: Point2<T>,
68 d: Point2<T>,
69 tol: T,
70 max_iters: usize,
71) -> Option<(T, T)> {
72 for _ in 0..max_iters {
73 let n1 = (T::one()-xi)*(T::one()-eta)/T::from(4.0).unwrap();
75 let n2 = (T::one()+xi)*(T::one()-eta)/T::from(4.0).unwrap();
76 let n3 = (T::one()+xi)*(T::one()+eta)/T::from(4.0).unwrap();
77 let n4 = (T::one()-xi)*(T::one()+eta)/T::from(4.0).unwrap();
78 let x = a.x*n1 + b.x*n2 + c.x*n3 + d.x*n4;
80 let y = a.y*n1 + b.y*n2 + c.y*n3 + d.y*n4;
81 let rx = x - p.x;
83 let ry = y - p.y;
84 if rx.abs() < tol && ry.abs() < tol {
85 return Some((xi, eta));
86 }
87 let j = Jacobian2x2::for_quad(xi, eta, a, b, c, d);
89 let inv_j = match j.inverse() {
90 Some(inv) => inv,
91 None => return None,
92 };
93 let dxi = inv_j.m11 * rx + inv_j.m12 * ry;
95 let deta = inv_j.m21 * rx + inv_j.m22 * ry;
96 xi = xi - dxi;
97 eta = eta - deta;
98 }
99 None
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::Point2;
106 use num_traits::Zero;
107
108 #[test]
109 fn jacobian_quad_det_nonzero() {
110 let a = Point2::new(0.0,0.0);
111 let b = Point2::new(2.0,0.0);
112 let c = Point2::new(2.0,1.0);
113 let d = Point2::new(0.0,1.0);
114 let j = Jacobian2x2::for_quad(0.0_f64, 0.0, a,b,c,d );
115 assert!(!j.det().is_zero());
116 }
117
118 #[test]
119 fn invert_quad_identity() {
120 let a=Point2::new(0.0,0.0);
122 let b=Point2::new(1.0,0.0);
123 let c=Point2::new(1.0,1.0);
124 let d=Point2::new(0.0,1.0);
125 let p = Point2::new(0.3, 0.7);
126 let got = invert_quad_mapping(0.0_f64, 0.0, p, a,b,c,d, 1e-6, 50 );
127 assert!(got.is_some());
128 let (xi,eta)=got.unwrap();
129 assert!((xi - (-0.4)).abs() < 1e-3);
130 assert!((eta - 0.4).abs() < 1e-3);
131 }
132}