Skip to main content

brep_kernel/brep/
topology.rs

1use crate::{
2    make_cylinder_surface, make_line, make_plane, KernelTolerances, NurbsCurve, NurbsSurface, Vec2,
3    Vec3, Vec4,
4};
5use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, Deserialize, Serialize)]
9pub struct VertexRecord {
10    pub id: u64,
11    pub point: Vec3,
12}
13
14#[derive(Clone, Debug, Deserialize, Serialize)]
15pub struct EdgeRecord {
16    pub id: u64,
17    pub curve: NurbsCurve,
18    pub t0: f64,
19    pub t1: f64,
20    pub start_vertex_id: u64,
21    pub end_vertex_id: u64,
22    #[serde(default)]
23    pub degenerate: bool,
24    /// Persistent name carried through splits, welds, and booleans so the
25    /// application never has to re-derive edge identity geometrically.
26    #[serde(default, skip_serializing_if = "Option::is_none")]
27    pub name: Option<String>,
28}
29
30#[derive(Clone, Debug, Deserialize, Serialize)]
31pub struct CoedgeRecord {
32    pub id: u64,
33    pub edge_id: u64,
34    pub forward: bool,
35    pub pcurve: NurbsCurve,
36}
37
38#[derive(Clone, Debug, Deserialize, Serialize)]
39pub struct LoopRecord {
40    pub id: u64,
41    pub coedges: Vec<CoedgeRecord>,
42}
43
44#[derive(Clone, Debug, Deserialize, Serialize)]
45pub struct FaceRecord {
46    pub id: u64,
47    pub surface: NurbsSurface,
48    pub same_sense: bool,
49    pub loops: Vec<LoopRecord>,
50    /// Persistent name propagated through booleans (split fragments get
51    /// deterministic `_1`, `_2` suffixes; merges keep the first name).
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub name: Option<String>,
54}
55
56#[derive(Clone, Debug, Deserialize, Serialize)]
57pub struct ShellRecord {
58    pub id: u64,
59    pub faces: Vec<FaceRecord>,
60}
61
62#[derive(Clone, Debug, Deserialize, Serialize)]
63pub struct BrepSolid {
64    pub id: u64,
65    pub vertices: Vec<VertexRecord>,
66    pub edges: Vec<EdgeRecord>,
67    pub shells: Vec<ShellRecord>,
68    #[serde(default)]
69    pub genus: i64,
70}
71
72#[derive(Clone, Debug, Deserialize, Serialize)]
73pub struct ValidationIssue {
74    pub severity: &'static str,
75    pub message: String,
76}
77
78impl ValidationIssue {
79    fn error(message: impl Into<String>) -> Self {
80        Self {
81            severity: "error",
82            message: message.into(),
83        }
84    }
85
86    fn warning(message: impl Into<String>) -> Self {
87        Self {
88            severity: "warning",
89            message: message.into(),
90        }
91    }
92}
93
94#[derive(Clone, Debug, Serialize)]
95pub struct ValidationReport {
96    pub issues: Vec<ValidationIssue>,
97    pub wire_warnings: Vec<ValidationIssue>,
98    pub max_pcurve_error: f64,
99}
100
101// `topology` is declared with `#[path = "brep/topology.rs"] mod topology;` in
102// src/lib.rs, so its children need explicit `#[path]` attributes pointing into
103// src/brep/topology/. The core record types stay declared here in the module
104// root (the whole crate imports them via `crate::topology::…`); only impl blocks
105// and free functions move into the children, which stay private. The pre-split
106// public surface is re-exported below at unchanged paths.
107#[path = "topology/seam.rs"]
108mod seam;
109#[path = "topology/validate.rs"]
110mod validate;
111#[path = "topology/primitives.rs"]
112mod primitives;
113#[cfg(test)]
114#[path = "topology/tests.rs"]
115mod tests;
116
117pub use seam::{
118    analyze_doubly_periodic_seam_band, loop_seam_offsets, seam_band_uv_polygon,
119};
120pub(crate) use seam::doubly_periodic_has_only_collapsed_loops;
121pub(crate) use validate::adaptive_coedge_error;
122pub use primitives::{make_box_brep, make_cylinder_brep, make_pyramid_brep};