1use crate::curve::{curve_to_plane_parameters, parameter_line};
2use crate::topology::{
3 BrepSolid, CoedgeRecord, EdgeRecord, FaceRecord, LoopRecord, ShellRecord, VertexRecord,
4};
5use crate::{
6 make_cone_surface, make_line, make_plane, make_sphere_surface_framed, make_torus_surface,
7 Vec3,
8};
9
10fn validated(solid: BrepSolid, label: &str) -> Result<BrepSolid, String> {
11 let issues = solid.validate();
12 if issues.is_empty() {
13 Ok(solid)
14 } else {
15 Err(format!(
16 "Rust {label} builder produced invalid topology: {issues:?}"
17 ))
18 }
19}
20
21pub fn make_sphere_brep(center: Vec3, radius: f64, polar_axis: Vec3) -> Result<BrepSolid, String> {
22 make_sphere_brep_framed(center, radius, polar_axis, None)
23}
24
25pub fn make_sphere_brep_framed(
32 center: Vec3,
33 radius: f64,
34 polar_axis: Vec3,
35 seam_direction: Option<Vec3>,
36) -> Result<BrepSolid, String> {
37 let surface = make_sphere_surface_framed(center, radius, polar_axis, seam_direction)?;
38 let south = surface.evaluate(0.0, 0.0)?;
39 let north = surface.evaluate(0.0, 1.0)?;
40 let seam = surface.iso_curve_u(0.0)?;
41 validated(
42 BrepSolid {
43 id: 120,
44 vertices: vec![
45 VertexRecord {
46 id: 1,
47 point: south,
48 },
49 VertexRecord {
50 id: 2,
51 point: north,
52 },
53 ],
54 edges: vec![
55 EdgeRecord {
56 id: 10,
57 curve: seam,
58 t0: 0.0,
59 t1: 1.0,
60 start_vertex_id: 1,
61 end_vertex_id: 2,
62 degenerate: false,
63 name: None,
64 },
65 EdgeRecord {
66 id: 11,
67 curve: make_line(south, south)?,
68 t0: 0.0,
69 t1: 1.0,
70 start_vertex_id: 1,
71 end_vertex_id: 1,
72 degenerate: true,
73 name: None,
74 },
75 EdgeRecord {
76 id: 12,
77 curve: make_line(north, north)?,
78 t0: 0.0,
79 t1: 1.0,
80 start_vertex_id: 2,
81 end_vertex_id: 2,
82 degenerate: true,
83 name: None,
84 },
85 ],
86 shells: vec![ShellRecord {
87 id: 119,
88 faces: vec![FaceRecord {
89 id: 118,
90 surface,
91 same_sense: true,
92 loops: vec![LoopRecord {
93 id: 117,
94 coedges: vec![
95 CoedgeRecord {
96 id: 101,
97 edge_id: 11,
98 forward: true,
99 pcurve: parameter_line(0.0, 0.0, 1.0, 0.0)?,
100 },
101 CoedgeRecord {
102 id: 102,
103 edge_id: 10,
104 forward: true,
105 pcurve: parameter_line(1.0, 0.0, 1.0, 1.0)?,
106 },
107 CoedgeRecord {
108 id: 103,
109 edge_id: 12,
110 forward: true,
111 pcurve: parameter_line(1.0, 1.0, 0.0, 1.0)?,
112 },
113 CoedgeRecord {
114 id: 104,
115 edge_id: 10,
116 forward: false,
117 pcurve: parameter_line(0.0, 1.0, 0.0, 0.0)?,
118 },
119 ],
120 }],
121 name: None,
122 }],
123 }],
124 genus: 0,
125 },
126 "sphere",
127 )
128}
129
130pub fn make_torus_brep(
131 center: Vec3,
132 axis_direction: Vec3,
133 major_radius: f64,
134 minor_radius: f64,
135) -> Result<BrepSolid, String> {
136 let surface = make_torus_surface(center, axis_direction, major_radius, minor_radius)?;
137 let corner = surface.evaluate(0.0, 0.0)?;
138 let major_curve = surface.iso_curve_v(0.0)?;
139 let tube_curve = surface.iso_curve_u(0.0)?;
140 validated(
141 BrepSolid {
142 id: 130,
143 vertices: vec![VertexRecord {
144 id: 1,
145 point: corner,
146 }],
147 edges: vec![
148 EdgeRecord {
149 id: 10,
150 curve: major_curve,
151 t0: 0.0,
152 t1: 1.0,
153 start_vertex_id: 1,
154 end_vertex_id: 1,
155 degenerate: false,
156 name: None,
157 },
158 EdgeRecord {
159 id: 11,
160 curve: tube_curve,
161 t0: 0.0,
162 t1: 1.0,
163 start_vertex_id: 1,
164 end_vertex_id: 1,
165 degenerate: false,
166 name: None,
167 },
168 ],
169 shells: vec![ShellRecord {
170 id: 129,
171 faces: vec![FaceRecord {
172 id: 128,
173 surface,
174 same_sense: true,
175 loops: vec![LoopRecord {
176 id: 127,
177 coedges: vec![
178 CoedgeRecord {
179 id: 101,
180 edge_id: 10,
181 forward: true,
182 pcurve: parameter_line(0.0, 0.0, 1.0, 0.0)?,
183 },
184 CoedgeRecord {
185 id: 102,
186 edge_id: 11,
187 forward: true,
188 pcurve: parameter_line(1.0, 0.0, 1.0, 1.0)?,
189 },
190 CoedgeRecord {
191 id: 103,
192 edge_id: 10,
193 forward: false,
194 pcurve: parameter_line(1.0, 1.0, 0.0, 1.0)?,
195 },
196 CoedgeRecord {
197 id: 104,
198 edge_id: 11,
199 forward: false,
200 pcurve: parameter_line(0.0, 1.0, 0.0, 0.0)?,
201 },
202 ],
203 }],
204 name: None,
205 }],
206 }],
207 genus: 1,
208 },
209 "torus",
210 )
211}
212
213pub fn make_cone_brep(
214 base: Vec3,
215 axis_direction: Vec3,
216 radius_bottom: f64,
217 radius_top: f64,
218 height: f64,
219) -> Result<BrepSolid, String> {
220 if radius_bottom <= 0.0 || radius_top < 0.0 || height <= 0.0 {
221 return Err("makeConeSolid: invalid radius or height".into());
222 }
223 let axis = axis_direction.normalized()?;
224 let side = make_cone_surface(base, axis, radius_bottom, radius_top, height)?;
225 let bottom_point = side.evaluate(0.0, 0.0)?;
226 let bottom_circle = side.iso_curve_v(0.0)?;
227 let seam = side.iso_curve_u(0.0)?;
228 let x_axis = axis.perpendicular()?;
229 let y_axis = axis.cross(x_axis).normalized()?;
230 let bottom_origin = base
231 .add(x_axis.scale(-radius_bottom))
232 .add(y_axis.scale(-radius_bottom));
233 let bottom_plane = make_plane(
234 bottom_origin,
235 x_axis,
236 y_axis,
237 2.0 * radius_bottom,
238 2.0 * radius_bottom,
239 )?;
240 let bottom_pcurve =
241 curve_to_plane_parameters(&bottom_circle, bottom_origin, x_axis, y_axis)?.reversed()?;
242 let bottom_face = FaceRecord {
243 id: 108,
244 surface: bottom_plane,
245 same_sense: false,
246 loops: vec![LoopRecord {
247 id: 107,
248 coedges: vec![CoedgeRecord {
249 id: 106,
250 edge_id: 10,
251 forward: false,
252 pcurve: bottom_pcurve,
253 }],
254 }],
255 name: None,
256 };
257
258 if radius_top <= 1e-7 {
259 let apex = side.evaluate(0.0, 1.0)?;
260 return validated(
261 BrepSolid {
262 id: 140,
263 vertices: vec![
264 VertexRecord {
265 id: 1,
266 point: bottom_point,
267 },
268 VertexRecord { id: 2, point: apex },
269 ],
270 edges: vec![
271 EdgeRecord {
272 id: 10,
273 curve: bottom_circle,
274 t0: 0.0,
275 t1: 1.0,
276 start_vertex_id: 1,
277 end_vertex_id: 1,
278 degenerate: false,
279 name: None,
280 },
281 EdgeRecord {
282 id: 11,
283 curve: seam,
284 t0: 0.0,
285 t1: 1.0,
286 start_vertex_id: 1,
287 end_vertex_id: 2,
288 degenerate: false,
289 name: None,
290 },
291 EdgeRecord {
292 id: 12,
293 curve: make_line(apex, apex)?,
294 t0: 0.0,
295 t1: 1.0,
296 start_vertex_id: 2,
297 end_vertex_id: 2,
298 degenerate: true,
299 name: None,
300 },
301 ],
302 shells: vec![ShellRecord {
303 id: 139,
304 faces: vec![
305 FaceRecord {
306 id: 105,
307 surface: side,
308 same_sense: true,
309 loops: vec![LoopRecord {
310 id: 100,
311 coedges: vec![
312 CoedgeRecord {
313 id: 101,
314 edge_id: 10,
315 forward: true,
316 pcurve: parameter_line(0.0, 0.0, 1.0, 0.0)?,
317 },
318 CoedgeRecord {
319 id: 102,
320 edge_id: 11,
321 forward: true,
322 pcurve: parameter_line(1.0, 0.0, 1.0, 1.0)?,
323 },
324 CoedgeRecord {
325 id: 103,
326 edge_id: 12,
327 forward: true,
328 pcurve: parameter_line(1.0, 1.0, 0.0, 1.0)?,
329 },
330 CoedgeRecord {
331 id: 104,
332 edge_id: 11,
333 forward: false,
334 pcurve: parameter_line(0.0, 1.0, 0.0, 0.0)?,
335 },
336 ],
337 }],
338 name: None,
339 },
340 bottom_face,
341 ],
342 }],
343 genus: 0,
344 },
345 "cone",
346 );
347 }
348
349 let top_point = side.evaluate(0.0, 1.0)?;
350 let top_circle = side.iso_curve_v(1.0)?;
351 let top_origin = base
352 .add(axis.scale(height))
353 .add(x_axis.scale(-radius_top))
354 .add(y_axis.scale(-radius_top));
355 let top_plane = make_plane(
356 top_origin,
357 x_axis,
358 y_axis,
359 2.0 * radius_top,
360 2.0 * radius_top,
361 )?;
362 let top_pcurve = curve_to_plane_parameters(&top_circle, top_origin, x_axis, y_axis)?;
363 validated(
364 BrepSolid {
365 id: 150,
366 vertices: vec![
367 VertexRecord {
368 id: 1,
369 point: bottom_point,
370 },
371 VertexRecord {
372 id: 2,
373 point: top_point,
374 },
375 ],
376 edges: vec![
377 EdgeRecord {
378 id: 10,
379 curve: bottom_circle,
380 t0: 0.0,
381 t1: 1.0,
382 start_vertex_id: 1,
383 end_vertex_id: 1,
384 degenerate: false,
385 name: None,
386 },
387 EdgeRecord {
388 id: 11,
389 curve: top_circle,
390 t0: 0.0,
391 t1: 1.0,
392 start_vertex_id: 2,
393 end_vertex_id: 2,
394 degenerate: false,
395 name: None,
396 },
397 EdgeRecord {
398 id: 12,
399 curve: seam,
400 t0: 0.0,
401 t1: 1.0,
402 start_vertex_id: 1,
403 end_vertex_id: 2,
404 degenerate: false,
405 name: None,
406 },
407 ],
408 shells: vec![ShellRecord {
409 id: 149,
410 faces: vec![
411 FaceRecord {
412 id: 105,
413 surface: side,
414 same_sense: true,
415 loops: vec![LoopRecord {
416 id: 100,
417 coedges: vec![
418 CoedgeRecord {
419 id: 101,
420 edge_id: 10,
421 forward: true,
422 pcurve: parameter_line(0.0, 0.0, 1.0, 0.0)?,
423 },
424 CoedgeRecord {
425 id: 102,
426 edge_id: 12,
427 forward: true,
428 pcurve: parameter_line(1.0, 0.0, 1.0, 1.0)?,
429 },
430 CoedgeRecord {
431 id: 103,
432 edge_id: 11,
433 forward: false,
434 pcurve: parameter_line(1.0, 1.0, 0.0, 1.0)?,
435 },
436 CoedgeRecord {
437 id: 104,
438 edge_id: 12,
439 forward: false,
440 pcurve: parameter_line(0.0, 1.0, 0.0, 0.0)?,
441 },
442 ],
443 }],
444 name: None,
445 },
446 bottom_face,
447 FaceRecord {
448 id: 111,
449 surface: top_plane,
450 same_sense: true,
451 loops: vec![LoopRecord {
452 id: 110,
453 coedges: vec![CoedgeRecord {
454 id: 109,
455 edge_id: 11,
456 forward: true,
457 pcurve: top_pcurve,
458 }],
459 }],
460 name: None,
461 },
462 ],
463 }],
464 genus: 0,
465 },
466 "cone frustum",
467 )
468}
469
470