brep_kernel/brep/
transform_topology.rs1use crate::topology::BrepSolid;
2use crate::{NurbsCurve, NurbsSurface, Vec3, Vec4};
3
4#[derive(Clone, Copy, Debug)]
5pub struct AffineTransform {
6 pub elements: [f64; 16],
7}
8
9impl AffineTransform {
10 pub fn new(elements: [f64; 16]) -> Result<Self, String> {
11 if elements.iter().any(|value| !value.is_finite()) {
12 return Err("AffineTransform: matrix must be finite".into());
13 }
14 if elements[12].abs() > 1e-12
15 || elements[13].abs() > 1e-12
16 || elements[14].abs() > 1e-12
17 || (elements[15] - 1.0).abs() > 1e-12
18 {
19 return Err("AffineTransform: projective matrices are unsupported".into());
20 }
21 if (Self { elements }).determinant3().abs() <= 1e-14 {
22 return Err("AffineTransform: singular matrix".into());
23 }
24 Ok(Self { elements })
25 }
26
27 pub(crate) fn rigid_inverse(&self) -> Result<Self, String> {
29 let m = &self.elements;
30 let r = [[m[0], m[1], m[2]], [m[4], m[5], m[6]], [m[8], m[9], m[10]]];
31 let t = [m[3], m[7], m[11]];
32 let mut out = [0.0f64; 16];
33 for row in 0..3 {
34 for col in 0..3 {
35 out[row * 4 + col] = r[col][row]; }
37 out[row * 4 + 3] = -(0..3).map(|k| r[k][row] * t[k]).sum::<f64>();
38 }
39 out[15] = 1.0;
40 AffineTransform::new(out)
41 }
42
43 pub fn determinant3(self) -> f64 {
44 let m = self.elements;
45 m[0] * (m[5] * m[10] - m[6] * m[9]) - m[1] * (m[4] * m[10] - m[6] * m[8])
46 + m[2] * (m[4] * m[9] - m[5] * m[8])
47 }
48
49 pub fn point(self, point: Vec3) -> Vec3 {
50 let m = self.elements;
51 Vec3::new(
52 m[0] * point.x + m[1] * point.y + m[2] * point.z + m[3],
53 m[4] * point.x + m[5] * point.y + m[6] * point.z + m[7],
54 m[8] * point.x + m[9] * point.y + m[10] * point.z + m[11],
55 )
56 }
57
58 fn homogeneous(self, point: Vec4) -> Result<Vec4, String> {
59 Ok(Vec4::from_point(self.point(point.point()?), point.w))
60 }
61}
62
63pub(crate) fn transform_curve(
64 curve: &NurbsCurve,
65 transform: AffineTransform,
66) -> Result<NurbsCurve, String> {
67 NurbsCurve::new(
68 curve.degree,
69 curve.knots.clone(),
70 curve
71 .control_points
72 .iter()
73 .map(|point| transform.homogeneous(*point))
74 .collect::<Result<_, _>>()?,
75 )
76}
77
78pub(crate) fn transform_surface(
79 surface: &NurbsSurface,
80 transform: AffineTransform,
81) -> Result<NurbsSurface, String> {
82 NurbsSurface::new(
83 surface.degree_u,
84 surface.degree_v,
85 surface.knots_u.clone(),
86 surface.knots_v.clone(),
87 surface
88 .control_points
89 .iter()
90 .map(|row| {
91 row.iter()
92 .map(|point| transform.homogeneous(*point))
93 .collect::<Result<Vec<_>, _>>()
94 })
95 .collect::<Result<_, _>>()?,
96 )
97}
98
99pub fn transform_brep(
102 solid: &BrepSolid,
103 transform: AffineTransform,
104 reverse_orientation: bool,
105) -> Result<BrepSolid, String> {
106 let determinant = transform.determinant3();
107 if determinant < 0.0 && !reverse_orientation {
108 return Err("transformSolid: reflection requires orientation reversal".into());
109 }
110 if determinant > 0.0 && reverse_orientation {
111 return Err("transformSolid: orientation reversal requires a reflection".into());
112 }
113 let mut result = solid.clone();
114 for vertex in &mut result.vertices {
115 vertex.point = transform.point(vertex.point);
116 }
117 for edge in &mut result.edges {
118 edge.curve = transform_curve(&edge.curve, transform)?;
119 }
120 for shell in &mut result.shells {
121 for face in &mut shell.faces {
122 face.surface = transform_surface(&face.surface, transform)?;
123 if reverse_orientation {
124 face.same_sense = !face.same_sense;
125 for loop_record in &mut face.loops {
126 loop_record.coedges.reverse();
127 for coedge in &mut loop_record.coedges {
128 coedge.forward = !coedge.forward;
129 coedge.pcurve = coedge.pcurve.reversed()?;
130 }
131 }
132 }
133 }
134 }
135 let issues = result.validate();
136 if issues.is_empty() {
137 Ok(result)
138 } else {
139 Err(format!("transformed BREP is invalid: {issues:?}"))
140 }
141}
142
143pub fn mirror_brep(
151 solid: &BrepSolid,
152 plane_point: Vec3,
153 plane_normal: Vec3,
154) -> Result<BrepSolid, String> {
155 let n = plane_normal.normalized()?;
156 let (nx, ny, nz) = (n.x, n.y, n.z);
157 let d = plane_point.dot(n);
158 let (tx, ty, tz) = (2.0 * d * nx, 2.0 * d * ny, 2.0 * d * nz);
159 let matrix = [
160 1.0 - 2.0 * nx * nx,
161 -2.0 * nx * ny,
162 -2.0 * nx * nz,
163 tx,
164 -2.0 * ny * nx,
165 1.0 - 2.0 * ny * ny,
166 -2.0 * ny * nz,
167 ty,
168 -2.0 * nz * nx,
169 -2.0 * nz * ny,
170 1.0 - 2.0 * nz * nz,
171 tz,
172 0.0,
173 0.0,
174 0.0,
175 1.0,
176 ];
177 let transform = AffineTransform::new(matrix)?;
178 transform_brep(solid, transform, true)
179}
180
181