Skip to content

Commit 66ee258

Browse files
pierremtbjtrangithub-actions[bot]adamchalmers
authored
Allow point-and-click Offset Plane to work from sweep faces (#7882)
* WIP: Offset Plane point-and-click for sweep faces Edit flows not working yet Will eventually close #7555 * Typo * Cont fixing of tests * Rm px coordinate from test * Clean up faces and unit tests for default planes * Add offset plane on offset plane unit test * Add offset plane on face unit tests * Add face offset tests * WIP: Add PlaneOfFace client-side artifact * Fix rust errors * Working unit tests and edit flows * Remove log, thanks bot * Allow face selection after command starts * Update snapshots * Move artifact creation logic to big match on commands * fmt * Update Mermaid snapshot in plane_of test * Update snapshots --------- Co-authored-by: Jonathan Tran <[email protected]> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Adam Chalmers <[email protected]>
1 parent b2c526f commit 66ee258

File tree

13 files changed

+602
-278
lines changed

13 files changed

+602
-278
lines changed

e2e/playwright/feature-tree-pane.spec.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -394,26 +394,23 @@ test.describe('Feature Tree pane', () => {
394394
await cmdBar.expectState({
395395
commandName: 'Offset plane',
396396
stage: 'arguments',
397-
currentArgKey: 'distance',
397+
currentArgKey: 'offset',
398398
currentArgValue: initialInput,
399399
headerArguments: {
400-
Plane: '1 plane',
401-
Distance: initialInput,
400+
Offset: initialInput,
402401
},
403-
highlightedHeaderArg: 'distance',
402+
highlightedHeaderArg: 'offset',
404403
})
405404
})
406405

407-
await test.step('Edit the distance argument and submit', async () => {
406+
await test.step('Edit the offset argument and submit', async () => {
408407
await expect(cmdBar.currentArgumentInput).toBeVisible()
409408
await cmdBar.currentArgumentInput.locator('.cm-content').fill(newInput)
410409
await cmdBar.progressCmdBar()
411410
await cmdBar.expectState({
412411
stage: 'review',
413412
headerArguments: {
414-
Plane: '1 plane',
415-
// We show the calculated value in the argument summary
416-
Distance: '15',
413+
Offset: '15',
417414
},
418415
commandName: 'Offset plane',
419416
})

e2e/playwright/point-click.spec.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -912,18 +912,10 @@ openSketch = startSketchOn(XY)
912912
toolbar,
913913
cmdBar,
914914
}) => {
915-
// One dumb hardcoded screen pixel value
916-
const testPoint = { x: 700, y: 200 }
917-
// TODO: replace the testPoint selection with a feature tree click once that's supported #7544
918-
const [clickOnXzPlane] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
919915
const expectedOutput = `plane001 = offsetPlane(XZ, offset = 5)`
920-
921916
await homePage.goToModelingScene()
922917
await scene.settled(cmdBar)
923918

924-
await test.step(`Look for the blue of the XZ plane`, async () => {
925-
//await scene.expectPixelColor([50, 51, 96], testPoint, 15) // FIXME
926-
})
927919
await test.step(`Go through the command bar flow`, async () => {
928920
await toolbar.offsetPlaneButton.click()
929921
await expect
@@ -933,30 +925,30 @@ openSketch = startSketchOn(XY)
933925
stage: 'arguments',
934926
currentArgKey: 'plane',
935927
currentArgValue: '',
936-
headerArguments: { Plane: '', Distance: '' },
928+
headerArguments: { Plane: '', Offset: '' },
937929
highlightedHeaderArg: 'plane',
938930
commandName: 'Offset plane',
939931
})
940-
await clickOnXzPlane()
932+
const xz = await toolbar.getFeatureTreeOperation('Front plane', 0)
933+
await xz.click()
941934
await cmdBar.expectState({
942935
stage: 'arguments',
943-
currentArgKey: 'distance',
936+
currentArgKey: 'offset',
944937
currentArgValue: '5',
945-
headerArguments: { Plane: '1 plane', Distance: '' },
946-
highlightedHeaderArg: 'distance',
938+
headerArguments: { Plane: '1 plane', Offset: '' },
939+
highlightedHeaderArg: 'offset',
947940
commandName: 'Offset plane',
948941
})
949942
await cmdBar.progressCmdBar()
950943
})
951944

952-
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
945+
await test.step(`Confirm code is added to the editor`, async () => {
953946
await editor.expectEditor.toContain(expectedOutput)
954947
await editor.expectState({
955948
diagnostics: [],
956949
activeLines: [expectedOutput],
957950
highlightedCode: '',
958951
})
959-
await scene.expectPixelColor([74, 74, 74], testPoint, 15)
960952
})
961953

962954
await test.step('Delete offset plane via feature tree selection', async () => {
@@ -967,7 +959,6 @@ openSketch = startSketchOn(XY)
967959
)
968960
await operationButton.click({ button: 'left' })
969961
await page.keyboard.press('Delete')
970-
//await scene.expectPixelColor([50, 51, 96], testPoint, 15) // FIXME
971962
})
972963
})
973964

-191 Bytes
Loading

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use fnv::FnvHashMap;
22
use indexmap::IndexMap;
33
use kittycad_modeling_cmds::{
4-
self as kcmc, EnableSketchMode, ModelingCmd,
4+
self as kcmc, EnableSketchMode, FaceIsPlanar, ModelingCmd,
55
ok_response::OkModelingCmdResponse,
66
shared::ExtrusionFaceCapType,
77
websocket::{BatchResponse, OkWebSocketResponseData, WebSocketResponse},
@@ -185,6 +185,15 @@ pub struct Solid2d {
185185
pub path_id: ArtifactId,
186186
}
187187

188+
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
189+
#[ts(export_to = "Artifact.ts")]
190+
#[serde(rename_all = "camelCase")]
191+
pub struct PlaneOfFace {
192+
pub id: ArtifactId,
193+
pub face_id: ArtifactId,
194+
pub code_ref: CodeRef,
195+
}
196+
188197
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
189198
#[ts(export_to = "Artifact.ts")]
190199
#[serde(rename_all = "camelCase")]
@@ -325,6 +334,7 @@ pub enum Artifact {
325334
Path(Path),
326335
Segment(Segment),
327336
Solid2d(Solid2d),
337+
PlaneOfFace(PlaneOfFace),
328338
StartSketchOnFace(StartSketchOnFace),
329339
StartSketchOnPlane(StartSketchOnPlane),
330340
Sweep(Sweep),
@@ -346,6 +356,7 @@ impl Artifact {
346356
Artifact::Solid2d(a) => a.id,
347357
Artifact::StartSketchOnFace(a) => a.id,
348358
Artifact::StartSketchOnPlane(a) => a.id,
359+
Artifact::PlaneOfFace(a) => a.id,
349360
Artifact::Sweep(a) => a.id,
350361
Artifact::Wall(a) => a.id,
351362
Artifact::Cap(a) => a.id,
@@ -367,6 +378,7 @@ impl Artifact {
367378
Artifact::Solid2d(_) => None,
368379
Artifact::StartSketchOnFace(a) => Some(&a.code_ref),
369380
Artifact::StartSketchOnPlane(a) => Some(&a.code_ref),
381+
Artifact::PlaneOfFace(a) => Some(&a.code_ref),
370382
Artifact::Sweep(a) => Some(&a.code_ref),
371383
Artifact::Wall(_) => None,
372384
Artifact::Cap(_) => None,
@@ -387,6 +399,7 @@ impl Artifact {
387399
| Artifact::Segment(_)
388400
| Artifact::Solid2d(_)
389401
| Artifact::StartSketchOnFace(_)
402+
| Artifact::PlaneOfFace(_)
390403
| Artifact::StartSketchOnPlane(_)
391404
| Artifact::Sweep(_) => None,
392405
Artifact::Wall(a) => Some(&a.face_code_ref),
@@ -406,6 +419,7 @@ impl Artifact {
406419
Artifact::Solid2d(_) => Some(new),
407420
Artifact::StartSketchOnFace { .. } => Some(new),
408421
Artifact::StartSketchOnPlane { .. } => Some(new),
422+
Artifact::PlaneOfFace { .. } => Some(new),
409423
Artifact::Sweep(a) => a.merge(new),
410424
Artifact::Wall(a) => a.merge(new),
411425
Artifact::Cap(a) => a.merge(new),
@@ -760,6 +774,13 @@ fn artifacts_to_update(
760774
code_ref,
761775
})]);
762776
}
777+
ModelingCmd::FaceIsPlanar(FaceIsPlanar { object_id, .. }) => {
778+
return Ok(vec![Artifact::PlaneOfFace(PlaneOfFace {
779+
id,
780+
face_id: object_id.into(),
781+
code_ref,
782+
})]);
783+
}
763784
ModelingCmd::EnableSketchMode(EnableSketchMode { entity_id, .. }) => {
764785
let existing_plane = artifacts.get(&ArtifactId::new(*entity_id));
765786
match existing_plane {

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ impl Artifact {
8787
Artifact::Solid2d(a) => vec![a.path_id],
8888
Artifact::StartSketchOnFace(a) => vec![a.face_id],
8989
Artifact::StartSketchOnPlane(a) => vec![a.plane_id],
90+
Artifact::PlaneOfFace(a) => vec![a.face_id],
9091
Artifact::Sweep(a) => vec![a.path_id],
9192
Artifact::Wall(a) => vec![a.seg_id, a.sweep_id],
9293
Artifact::Cap(a) => vec![a.sweep_id],
@@ -151,6 +152,10 @@ impl Artifact {
151152
// Note: Don't include these since they're parents: plane_id.
152153
Vec::new()
153154
}
155+
Artifact::PlaneOfFace { .. } => {
156+
// Note: Don't include these since they're parents: face_id.
157+
Vec::new()
158+
}
154159
Artifact::Sweep(a) => {
155160
// Note: Don't include these since they're parents: path_id.
156161
let mut ids = Vec::new();
@@ -262,6 +267,7 @@ impl ArtifactGraph {
262267
}
263268
Artifact::StartSketchOnFace { .. }
264269
| Artifact::StartSketchOnPlane { .. }
270+
| Artifact::PlaneOfFace { .. }
265271
| Artifact::Sweep(_)
266272
| Artifact::Wall(_)
267273
| Artifact::Cap(_)
@@ -381,6 +387,14 @@ impl ArtifactGraph {
381387
)?;
382388
node_path_display(output, prefix, None, code_ref)?;
383389
}
390+
Artifact::PlaneOfFace(PlaneOfFace { code_ref, .. }) => {
391+
writeln!(
392+
output,
393+
"{prefix}{id}[\"PlaneOfFace<br>{:?}\"]",
394+
code_ref_display(code_ref)
395+
)?;
396+
node_path_display(output, prefix, None, code_ref)?;
397+
}
384398
Artifact::Sweep(sweep) => {
385399
writeln!(
386400
output,

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ flowchart LR
1313
%% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 1 }]
1414
7[Solid2d]
1515
end
16-
subgraph path21 [Path]
17-
21["Path<br>[311, 361, 0]"]
18-
%% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }]
19-
22["Segment<br>[311, 361, 0]"]
16+
subgraph path22 [Path]
17+
22["Path<br>[311, 361, 0]"]
2018
%% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }]
2119
23["Segment<br>[311, 361, 0]"]
2220
%% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }]
@@ -26,7 +24,9 @@ flowchart LR
2624
%% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }]
2725
26["Segment<br>[311, 361, 0]"]
2826
%% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }]
29-
27[Solid2d]
27+
27["Segment<br>[311, 361, 0]"]
28+
%% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 1 }]
29+
28[Solid2d]
3030
end
3131
1["Plane<br>[41, 58, 0]"]
3232
%% [ProgramBodyItem { index: 0 }, VariableDeclarationDeclaration, VariableDeclarationInit, PipeBodyItem { index: 0 }]
@@ -48,9 +48,11 @@ flowchart LR
4848
17["SweepEdge Adjacent"]
4949
18["SweepEdge Opposite"]
5050
19["SweepEdge Adjacent"]
51-
20["Plane<br>[277, 304, 0]"]
51+
20["PlaneOfFace<br>[184, 208, 0]"]
52+
%% [ProgramBodyItem { index: 1 }, VariableDeclarationDeclaration, VariableDeclarationInit]
53+
21["Plane<br>[277, 304, 0]"]
5254
%% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 0 }, CallKwUnlabeledArg]
53-
28["StartSketchOnPlane<br>[263, 305, 0]"]
55+
29["StartSketchOnPlane<br>[263, 305, 0]"]
5456
%% [ProgramBodyItem { index: 2 }, ExpressionStatementExpr, PipeBodyItem { index: 0 }]
5557
1 --- 2
5658
2 --- 3
@@ -94,12 +96,13 @@ flowchart LR
9496
14 <--x 13
9597
16 <--x 13
9698
18 <--x 13
97-
20 --- 21
98-
20 <--x 28
99+
13 <--x 20
99100
21 --- 22
100-
21 --- 23
101-
21 --- 24
102-
21 --- 25
103-
21 --- 26
104-
21 --- 27
101+
21 <--x 29
102+
22 --- 23
103+
22 --- 24
104+
22 --- 25
105+
22 --- 26
106+
22 --- 27
107+
22 --- 28
105108
```

src/components/CommandBar/CommandBarSelectionInput.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@ function CommandBarSelectionInput({
5353
useEffect(() => {
5454
if (arg.selectionTypes.includes('plane') && !canSubmitSelection) {
5555
toSync(() => {
56-
return Promise.all([
57-
kclManager.showPlanes(),
58-
kclManager.setSelectionFilter(['plane', 'object']),
59-
])
56+
return kclManager.showPlanes()
6057
}, reportRejection)()
6158
}
6259

src/lang/modifyAst.ts

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { BodyItem } from '@rust/kcl-lib/bindings/BodyItem'
2-
import type { Name } from '@rust/kcl-lib/bindings/Name'
32
import type { Node } from '@rust/kcl-lib/bindings/Node'
43
import type { NonCodeMeta } from '@rust/kcl-lib/bindings/NonCodeMeta'
54

@@ -27,11 +26,7 @@ import {
2726
isNodeSafeToReplace,
2827
isNodeSafeToReplacePath,
2928
} from '@src/lang/queryAst'
30-
import {
31-
ARG_INDEX_FIELD,
32-
LABELED_ARG_FIELD,
33-
UNLABELED_ARG,
34-
} from '@src/lang/queryAstConstants'
29+
import { ARG_INDEX_FIELD, LABELED_ARG_FIELD } from '@src/lang/queryAstConstants'
3530
import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
3631
import {
3732
addTagForSketchOnFace,
@@ -422,56 +417,6 @@ export function sketchOnExtrudedFace(
422417
}
423418
}
424419

425-
/**
426-
* Append an offset plane to the AST
427-
*/
428-
export function addOffsetPlane({
429-
node,
430-
plane,
431-
insertIndex,
432-
offset,
433-
planeName,
434-
}: {
435-
node: Node<Program>
436-
plane: Node<Literal> | Node<Name> // Can be DefaultPlaneStr or string for offsetPlanes
437-
insertIndex?: number
438-
offset: Expr
439-
planeName?: string
440-
}): { modifiedAst: Node<Program>; pathToNode: PathToNode } {
441-
const modifiedAst = structuredClone(node)
442-
const newPlaneName =
443-
planeName ?? findUniqueName(node, KCL_DEFAULT_CONSTANT_PREFIXES.PLANE)
444-
445-
const newPlane = createVariableDeclaration(
446-
newPlaneName,
447-
createCallExpressionStdLibKw('offsetPlane', plane, [
448-
createLabeledArg('offset', offset),
449-
])
450-
)
451-
452-
const insertAt =
453-
insertIndex !== undefined
454-
? insertIndex
455-
: modifiedAst.body.length
456-
? modifiedAst.body.length
457-
: 0
458-
459-
modifiedAst.body.length
460-
? modifiedAst.body.splice(insertAt, 0, newPlane)
461-
: modifiedAst.body.push(newPlane)
462-
const pathToNode: PathToNode = [
463-
['body', ''],
464-
[insertAt, 'index'],
465-
['declaration', 'VariableDeclaration'],
466-
['init', 'VariableDeclarator'],
467-
['unlabeled', UNLABELED_ARG],
468-
]
469-
return {
470-
modifiedAst,
471-
pathToNode,
472-
}
473-
}
474-
475420
/**
476421
* Add an import call to load a part
477422
*/

0 commit comments

Comments
 (0)