Skip to content

Commit e4de79e

Browse files
authored
Artifact graph recognizes inner faces (#7805)
Consider a 2D sketch with a hole. Such a sketch has both outer edges and inner edges. When this sketch is extruded, the resulting solid will have both outer faces and inner faces. In #7753 I fixed a bug where sketches weren't tracking their inner edges, and solids weren't tracking their inner faces. But this only affected the KCL runtime. I forgot to update the artifact graph to handle these faces. This PR ensures the artifact graph still builds even if a solid has inner faces. For example, this solid couldn't have an artifact graph before: <img width="1632" height="1376" alt="inner face" src="https://github.com/user-attachments/assets/7af80f76-4e29-4be9-8bc9-45f911590269" />
1 parent e4482f4 commit e4de79e

22 files changed

+2721
-12
lines changed

rust/kcl-lib/src/execution/artifact.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ pub struct Path {
128128
/// this can be used as input for another composite solid.
129129
#[serde(default, skip_serializing_if = "Option::is_none")]
130130
pub composite_solid_id: Option<ArtifactId>,
131+
/// The hole, if any, from a subtract2d() call.
132+
#[serde(default, skip_serializing_if = "Option::is_none")]
133+
pub inner_path_id: Option<ArtifactId>,
134+
/// The `Path` that this is a hole of, if any. The inverse link of
135+
/// `inner_path_id`.
136+
#[serde(default, skip_serializing_if = "Option::is_none")]
137+
pub outer_path_id: Option<ArtifactId>,
131138
}
132139

133140
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
@@ -443,6 +450,8 @@ impl Path {
443450
merge_ids(&mut self.seg_ids, new.seg_ids);
444451
merge_opt_id(&mut self.solid2d_id, new.solid2d_id);
445452
merge_opt_id(&mut self.composite_solid_id, new.composite_solid_id);
453+
merge_opt_id(&mut self.inner_path_id, new.inner_path_id);
454+
merge_opt_id(&mut self.outer_path_id, new.outer_path_id);
446455

447456
None
448457
}
@@ -805,6 +814,8 @@ fn artifacts_to_update(
805814
solid2d_id: None,
806815
code_ref,
807816
composite_solid_id: None,
817+
inner_path_id: None,
818+
outer_path_id: None,
808819
}));
809820
let plane = artifacts.get(&ArtifactId::new(*current_plane_id));
810821
if let Some(Artifact::Plane(plane)) = plane {
@@ -924,6 +935,8 @@ fn artifacts_to_update(
924935
solid2d_id: None,
925936
code_ref: code_ref.clone(),
926937
composite_solid_id: None,
938+
inner_path_id: None,
939+
outer_path_id: None,
927940
}
928941
};
929942

@@ -1030,14 +1043,20 @@ fn artifacts_to_update(
10301043
continue;
10311044
};
10321045
last_path = Some(path);
1033-
let path_sweep_id = path.sweep_id.ok_or_else(|| {
1034-
KclError::new_internal(KclErrorDetails::new(
1046+
let Some(path_sweep_id) = path.sweep_id else {
1047+
// If the path doesn't have a sweep ID, check if it's a
1048+
// hole.
1049+
if path.outer_path_id.is_some() {
1050+
// This is a hole.
1051+
continue;
1052+
}
1053+
return Err(KclError::new_internal(KclErrorDetails::new(
10351054
format!(
1036-
"Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}"
1055+
"Expected a sweep ID on the path when processing Solid3dGetExtrusionFaceInfo command, but we have none:\n{id:#?}\n{path:#?}"
10371056
),
10381057
vec![range],
1039-
))
1040-
})?;
1058+
)));
1059+
};
10411060
let extra_artifact = exec_artifacts.values().find(|a| {
10421061
if let Artifact::StartSketchOnFace(s) = a {
10431062
s.face_id == face_id
@@ -1084,14 +1103,20 @@ fn artifacts_to_update(
10841103
let Some(face_id) = face.face_id.map(ArtifactId::new) else {
10851104
continue;
10861105
};
1087-
let path_sweep_id = path.sweep_id.ok_or_else(|| {
1088-
KclError::new_internal(KclErrorDetails::new(
1106+
let Some(path_sweep_id) = path.sweep_id else {
1107+
// If the path doesn't have a sweep ID, check if it's a
1108+
// hole.
1109+
if path.outer_path_id.is_some() {
1110+
// This is a hole.
1111+
continue;
1112+
}
1113+
return Err(KclError::new_internal(KclErrorDetails::new(
10891114
format!(
1090-
"Expected a sweep ID on the path when processing last path's Solid3dGetExtrusionFaceInfo command, but we have none: {id:?}, {path:?}"
1115+
"Expected a sweep ID on the path when processing last path's Solid3dGetExtrusionFaceInfo command, but we have none:\n{id:#?}\n{path:#?}"
10911116
),
10921117
vec![range],
1093-
))
1094-
})?;
1118+
)));
1119+
};
10951120
let extra_artifact = exec_artifacts.values().find(|a| {
10961121
if let Artifact::StartSketchOnFace(s) = a {
10971122
s.face_id == face_id
@@ -1267,6 +1292,24 @@ fn artifacts_to_update(
12671292
// the helix here, but it's not useful right now.
12681293
return Ok(return_arr);
12691294
}
1295+
ModelingCmd::Solid2dAddHole(solid2d_add_hole) => {
1296+
let mut return_arr = Vec::new();
1297+
// Add the hole to the outer.
1298+
let outer_path = artifacts.get(&ArtifactId::new(solid2d_add_hole.object_id));
1299+
if let Some(Artifact::Path(path)) = outer_path {
1300+
let mut new_path = path.clone();
1301+
new_path.inner_path_id = Some(ArtifactId::new(solid2d_add_hole.hole_id));
1302+
return_arr.push(Artifact::Path(new_path));
1303+
}
1304+
// Add the outer to the hole.
1305+
let inner_solid2d = artifacts.get(&ArtifactId::new(solid2d_add_hole.hole_id));
1306+
if let Some(Artifact::Path(path)) = inner_solid2d {
1307+
let mut new_path = path.clone();
1308+
new_path.outer_path_id = Some(ArtifactId::new(solid2d_add_hole.object_id));
1309+
return_arr.push(Artifact::Path(new_path));
1310+
}
1311+
return Ok(return_arr);
1312+
}
12701313
ModelingCmd::BooleanIntersection(_) | ModelingCmd::BooleanSubtract(_) | ModelingCmd::BooleanUnion(_) => {
12711314
let (sub_type, solid_ids, tool_ids) = match cmd {
12721315
ModelingCmd::BooleanIntersection(intersection) => {

rust/kcl-lib/src/execution/artifact/mermaid_tests.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,16 @@ impl Artifact {
7373
ids
7474
}
7575
Artifact::Plane(_) => Vec::new(),
76-
Artifact::Path(a) => vec![a.plane_id],
76+
Artifact::Path(a) => {
77+
let mut ids = vec![a.plane_id];
78+
if let Some(inner_path_id) = a.inner_path_id {
79+
ids.push(inner_path_id);
80+
}
81+
if let Some(outer_path_id) = a.outer_path_id {
82+
ids.push(outer_path_id);
83+
}
84+
ids
85+
}
7786
Artifact::Segment(a) => vec![a.path_id],
7887
Artifact::Solid2d(a) => vec![a.path_id],
7988
Artifact::StartSketchOnFace(a) => vec![a.face_id],
@@ -103,7 +112,8 @@ impl Artifact {
103112
}
104113
Artifact::Plane(a) => a.path_ids.clone(),
105114
Artifact::Path(a) => {
106-
// Note: Don't include these since they're parents: plane_id.
115+
// Note: Don't include these since they're parents: plane_id,
116+
// inner_path_id, outer_path_id.
107117
let mut ids = a.seg_ids.clone();
108118
if let Some(sweep_id) = a.sweep_id {
109119
ids.push(sweep_id);

rust/kcl-lib/src/simulation_tests.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3817,3 +3817,24 @@ mod elliptic_curve_inches_regression {
38173817
super::execute(TEST_NAME, true).await
38183818
}
38193819
}
3820+
mod tag_inner_face {
3821+
const TEST_NAME: &str = "tag_inner_face";
3822+
3823+
/// Test parsing KCL.
3824+
#[test]
3825+
fn parse() {
3826+
super::parse(TEST_NAME)
3827+
}
3828+
3829+
/// Test that parsing and unparsing KCL produces the original KCL input.
3830+
#[tokio::test(flavor = "multi_thread")]
3831+
async fn unparse() {
3832+
super::unparse(TEST_NAME).await
3833+
}
3834+
3835+
/// Test that KCL is executed correctly.
3836+
#[tokio::test(flavor = "multi_thread")]
3837+
async fn kcl_test_execute() {
3838+
super::execute(TEST_NAME, true).await
3839+
}
3840+
}

rust/kcl-lib/tests/fillet-and-shell/artifact_graph_flowchart.snap.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ flowchart LR
239239
31 --- 36
240240
33 --- 34
241241
33 --- 35
242+
36 --- 33
242243
33 ---- 39
243244
34 --- 40
244245
34 x--> 41
@@ -259,6 +260,7 @@ flowchart LR
259260
45 --- 50
260261
47 --- 48
261262
47 --- 49
263+
50 --- 47
262264
47 ---- 53
263265
48 --- 54
264266
48 x--> 55
@@ -279,6 +281,7 @@ flowchart LR
279281
59 --- 64
280282
61 --- 62
281283
61 --- 63
284+
64 --- 61
282285
61 ---- 67
283286
62 --- 68
284287
62 x--> 69
@@ -299,6 +302,7 @@ flowchart LR
299302
73 --- 78
300303
75 --- 76
301304
75 --- 77
305+
78 --- 75
302306
75 ---- 81
303307
76 --- 82
304308
76 x--> 83

rust/kcl-lib/tests/flush_batch_on_end/artifact_graph_flowchart.snap.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ flowchart LR
3030
1 --- 5
3131
2 --- 3
3232
2 --- 4
33+
5 --- 2
3334
2 ---- 8
3435
3 --- 9
3536
3 x--> 10

rust/kcl-lib/tests/i_shape/artifact_graph_flowchart.snap.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ flowchart LR
211211
2 --- 26
212212
2 --- 27
213213
2 --- 28
214+
30 --- 2
214215
2 ---- 41
215216
3 --- 42
216217
3 x--> 66

rust/kcl-lib/tests/import_async/artifact_graph_flowchart.snap.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ flowchart LR
9898
2 --- 7
9999
2 --- 8
100100
2 --- 9
101+
2 <--x 11
102+
2 <--x 19
103+
27 --- 2
101104
10 --- 11
102105
10 <--x 45
103106
11 --- 12

rust/kcl-lib/tests/involute_circular_units/artifact_graph_flowchart.snap.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ flowchart LR
6868
2 --- 8
6969
2 --- 9
7070
2 --- 10
71+
11 --- 2
7172
2 ---- 14
7273
3 --- 15
7374
3 x--> 21

rust/kcl-lib/tests/multi_target_csg/artifact_graph_flowchart.snap.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ flowchart LR
201201
2 --- 10
202202
2 --- 11
203203
2 --- 12
204+
13 --- 2
204205
2 ---- 16
205206
3 --- 24
206207
3 x--> 25

rust/kcl-lib/tests/sketch_on_face_union/artifact_graph_flowchart.snap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ flowchart LR
193193
2 --- 6
194194
2 --- 7
195195
2 --- 8
196+
2 <--x 9
197+
15 --- 2
196198
2 ---- 21
197199
2 --- 82
198200
3 --- 26

0 commit comments

Comments
 (0)