Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

write AST-mod for adding fillet, piped to extrude variable expression #2607

Closed
Tracked by #2606
Irev-Dev opened this issue Jun 5, 2024 · 10 comments · Fixed by #2718
Closed
Tracked by #2606

write AST-mod for adding fillet, piped to extrude variable expression #2607

Irev-Dev opened this issue Jun 5, 2024 · 10 comments · Fixed by #2718
Assignees
Labels
ast Issues / features relevant to ast and parser.

Comments

@Irev-Dev
Copy link
Collaborator

Irev-Dev commented Jun 5, 2024

See video in #2606 for context but essentially write an ast-mod that takes

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %)
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %)
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)

And transforms it to

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %, 'seg01')
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %)
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
  |> fillet({
    radius: 5,
    tags: ["seg01"],
  }, %)
@Irev-Dev Irev-Dev mentioned this issue Jun 5, 2024
52 tasks
@Irev-Dev Irev-Dev changed the title wright AST-mod for adding fillet, piped to extrude variable expression write AST-mod for adding fillet, piped to extrude variable expression Jun 5, 2024
@max-mrgrsk max-mrgrsk self-assigned this Jun 6, 2024
@max-mrgrsk max-mrgrsk added the ast Issues / features relevant to ast and parser. label Jun 6, 2024
@max-mrgrsk
Copy link
Collaborator

max-mrgrsk commented Jun 9, 2024

@Irev-Dev, thank you for the sketch on face tip; it helped a lot to understand the situation. Please see my findings and ideas and check if I am missing anything.

We need to create a UI button for filleting, which involves selecting an edge, tagging it, and modifying the AST to include the fillet operation within the Extrude.

Data Flow

  1. User Interaction: User interacts with the application (e.g., selects an edge).
  2. Event Capture: Stream.tsx handles mouse events and captures the edge selection.
  3. Event Processing:
    • sendSelectEventToEngine creates a selection event.
  4. State Management:
    • Modeling Machine State: modelingMachine.ts stores selections (edges/faces) in selectionRanges.
    • Context Provision: ModelingMachineProvider.tsx provides context and state management for the modeling machine, enabling components to access the current state and send events.
  5. AST Modification:
    • Function Invocation: The state machine calls functions in modifyAst.ts -> addFillet.ts, addFillet.test.ts to modify the AST based on the selections stored in the context.
    • Guards: Guards in modelingMachine.ts ensure certain conditions are met before transitions or actions occur.

Main Components

  1. src/components/Stream.tsx - Capture user interactions and trigger events.
  2. src/machines/modelingMachine.ts - Manage the application's state, store selections, and trigger actions.
  3. src/components/ModelingMachineProvider.tsx - Provide context and state management for the modeling machine.
  4. src/lang/modifyAst.ts - Define functions to modify the AST based on selections and the fillet operation.
  5. src/Toolbar.tsx - Provide UI for selecting tools and triggering operations like fillet.
  6. src/handlers/EdgeSelectHandler.ts - Handle logic specific to edge selection and processing.

Steps

  1. Create Fillet Button: Add a Fillet button in src/Toolbar.tsx.
<ActionButton
  onClick={() => send({ type: 'Enter fillet', data: { forceNewFillet: true } })} 
>
  1. Manage Fillet State: Update modelingMachine.ts to manage Fillet mode state.
on: { 'Enter fillet': 'filletMode', }, 
states: { filletMode: { /* State Logic */ }, }
  1. Edge Selection Handling: Ensure edge selection logic in src/components/Stream.tsx captures edges.
sendSelectEventToEngine(e, videoRef.current, streamDimensions)
  1. Trigger Fillet Operation: Use modelingSend to send the selection event to the state machine.
modelingSend({ type: 'Process Fillet', data: edgeSelection })
  1. AST Modification: Write AST transformation logic for Fillet in src/lang/modifyAst.ts.
function applyFilletToEdge(ast, edge) { /* Logic */ }

//////////////////

Functionality Discussion
We start with something simple, but the logic must be valid for the following scenarios:

  1. Selection: The selection involves not only individual edges but also chained edges and faces.
  |> fillet({
    radius: 5,
    // edges
    tags: ["seg01”, "seg02”, "seg03"]
    // or chained edgestags: [“chain01”]
    // or facestags: [“face01”]
  1. Tags: There are more edges in the extruded volume than sketch segments, especially if the extrusion merges with a different volume. Tagging the fillets to the sketch segments can be tricky. We can use a naming convention, like seg01(E) for extruded ones, seg01(A) for edges along the extrusion, and seg01(1), seg01(2), etc., for those that will be shattered by different volumes. For example:
const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %, 'seg01')
  |> line([1.29, -115.74], %)
  // other segments 
  |> close(%)
const extrude001 = extrude(50, sketch001)
  |> fillet({
    radius: 5,
    tags: ["seg01(1)”, "seg01(2), “seg01(A), "seg01(E)”]
  }, %)
Screenshot 2024-06-09 at 22 38 13

Or we can skip all that and just make fresh tags for each fillet without referencing the sketch segments.

  1. Reference: Since fillets can be applied to several parts, it is worth writing a separate pipeline for it:
const fillet001 = fillet(10, [extrude001, extrude002]) 
    |> edge01 
    |> edge02

UPD: Besides, following common design practices and RSM, it is important to gather all fillet-related operations at the end of the code. I think it is a good practice to follow.

rsm

@Irev-Dev
Copy link
Collaborator Author

Nice digging around, I couldn't actually tell you if you found everything or not without digging through it again myself, but it sounds about right.

I had thought the steps involved will roughly be the three tasks in #1206, i.e. we could start with just the code mod, write unit test for them etc, Then we look into getting the most basic UI selections working. Then we look into fixing up some of the selections. I think I want to stick with tags, and we are able to use the tags to get to all edges from an extrusion, but we can talk about it because I didn't quiet follow what you were talking about with some of the alternatives.

We should talk about gathering the fillets at the end because maybe that will effect the code-mod we want to right.

@Irev-Dev
Copy link
Collaborator Author

For refernce we were talking about

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([-6.27, -7.26], %)
  |> line([35.14, 55.93], %, 'tag')
  |> line([54.94, -6.44], %)
  |> line([15.67, -52.79], %, 'tag2')
  |> close(%)

const myExtrude = extrude(10.14, sketch001)

const sketch002 = startSketchOn(myExtrude, 'END')
  |> startProfileAt([49.21, 20.48], %)
  |> line([0.14, 12.33], %)
  |> line([31.52, 0], %)
  |> line([-2.94, -16.54], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)

const extrude001 = extrude(5, sketch002)
const myBody = fillet({
  radius: 1,
  tags: [
    getNextAdjacentEdge("tag", myExtrude),
    getOppositeEdge("tag2", myExtrude)
  ]
}, extrude001)

@max-mrgrsk
Copy link
Collaborator

@Irev-Dev the mod and test are still in progress, but it would be great if you could check them out: 78fb73a

It works with 3 cases now:

  1. Simple Case
const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %)
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %)
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
  1. Edge Case with Existing Tag on Another Line. A new unique tag is generated when another segment is already tagged.
const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %)  // selected edge
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %, 'seg01') // tagged edge
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
  1. Edge Case Where the Selected Segment Already Has a Tag
const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %)
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %, 'seg03') // selected edge
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)

I will continue to work on edge cases.
Please let me know if there are any changes or improvements needed.

@max-mrgrsk
Copy link
Collaborator

Hi @Irev-Dev

Update: 5ff9239

I've started to cover the cases where the fillet already exists, like here:

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %,) // selection
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %, 'seg03') // existing tag
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
  |> fillet({ radius: 10, tags: ['seg03'] }, %) // existing fillet

Terraformed to:

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %, 'seg01') // new tag
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %, 'seg03')
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
  |> fillet({ radius: 10, tags: ['seg03'] }, %)
  |> fillet({ radius: 5, tags: ['seg01'] }, %) // new fillet

The next case to cover would be:

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %,)
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %, 'seg03') // select line with existing tag
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
  |> fillet({ radius: 10, tags: ['seg03'] }, %) // modify existing fillet

@max-mrgrsk
Copy link
Collaborator

Fillet the fillet

how to tag the edge of the fillet ?

Bildschirmfoto 2024-06-18 um 15 14 20

I think it would be good to follow the same logic as with the general shatter case, when extruded edge gets shattered after the boolean operation, like this:

Bildschirmfoto 2024-06-18 um 15 54 36

and treat the fillet like the last part of the shattered edge

in this case the code will look like this:

Bildschirmfoto 2024-06-18 um 15 40 07

for example:

// initail edge
getOppositeEdge('seg01', extrude001)

// shattered edge parts:
getOppositeEdgeStart('seg01', extrude001)
getOppositeEdge01('seg01', extrude001)
getOppositeEdge02('seg01', extrude001)
getOppositeEdge03('seg01', extrude001)
getOppositeEdge05('seg01', extrude001)
getOppositeEdgeEnd('seg01', extrude001)

@max-mrgrsk
Copy link
Collaborator

@Irev-Dev added new edge case, with existing fillet that has to be modified:

d1b5157

take this:

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %,)
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %, 'seg03') // select line with existing tag
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
  |> fillet({ radius: 10, tags: ['seg03'] }, %) // modify existing fillet

and transform to this:

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([2.16, 49.67], %)
  |> line([101.49, 139.93], %)
  |> line([60.04, -55.72], %)
  |> line([1.29, -115.74], %)
  |> line([-87.24, -47.08], %, 'seg03')
  |> tangentialArcTo([56.15, -94.58], %)
  |> tangentialArcTo([14.68, -104.52], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
  |> fillet({ radius: 5, tags: ['seg03'] }, %) // new radius

there are still a lot of other cases, that I've mentioned above
But I think it is a good time to hook up ast-mod with UI and user's selections..
@Irev-Dev what do you think?

@Irev-Dev
Copy link
Collaborator Author

Irev-Dev commented Jun 20, 2024

how to tag the edge of the fillet ?

Right!, another idea would be to keep the convention we have so far, of being able to tag faces and edges in the operation in which they are created, so that if you have |> fillet({ radius: 10, tags: ['seg03'] }, %, 'filletTag'), this face the arc surface and the two deges get the filleTag tag, Then we can use the tag by itself for the face/surface and getEdge getOppositeEdge for the two edges (using the same extrude direction for them).

But having said that, is there a real need to select this edge? I ask because when you have a straight edge going into a tangential arc, that then follows with another tangential segment, in most CAD can you fillet these separately? I thought they must be all filleted together? in which case using getOppositeEdge('seg01', extrude001) to fillet one segment will naturally also fillet the curved edge from the previous fillet? hopefully that made sense.

But I think it is a good time to hook up ast-mod with UI and user's selections

Absolutely!

I might make you branch so far into a PR again, I think it's the best way to leave comments in line.

@Irev-Dev Irev-Dev linked a pull request Jun 20, 2024 that will close this issue
@jessfraz jessfraz added this to the v1 Modeling App Launch milestone Jun 21, 2024
@max-mrgrsk
Copy link
Collaborator

max-mrgrsk commented Jun 23, 2024

But having said that, is there a real need to select this edge?

I think, yes, we need to be able to select it in order to cover these cases:

Screenshot 2024-06-23 at 18 46 20 add the fillet setting like:
  1. tangent propagation - off
  2. tangent propagation - on
  3. partition fillet - on
    etc..

keep the convention we have so far

In all these cases, one fillet operation created several new faces. Depending on the object, it could be hundreds of new faces. Some of them might be shattered with other booleans.

The question is how to select them for further operations. getEdge, getOppositeEdge, and a couple more might not be enough for all cases.

One idea I came up with is numbers, like getFace1, getFace2, getFace3 etc.. It is not quite obvious where the face might pop, but if you select them with mouse it is fine...

Other idea is to create a selection object that would just contain selected faces/edges without showing the tags.

@Irev-Dev
Copy link
Collaborator Author

add the fillet setting like:
tangent propagation - off
tangent propagation - on
partition fillet - on
etc..

Oh right that's helpful.

Face1, 2, 3 etc might be needed, but would be curious if we can avoid it, I think just using indexes like like that is more likely to be brittle to changes but we might have to do it, (I think we spoke previously about a boolean operation that splits a staged face into two, it's unavoidable I think at that stage, need to use indices.)

Maybe conceptualizing an edge as something two faces have in common.
image

const sketch001 = startSketchOn('XZ')
  |> startProfileAt([1.64, 2.24], %)
  |> line([0.52, 1.62], %, 'tag2')
  |> line([3.38, -0.12], %, 'tag1')
  |> line([0.22, -2.38], %)
  |> line([-4.04, -0.96], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(5, sketch001)
  |> fillet({
    radius: 1,
    tags: ["tag1"],
    tag: 'filletTag'
  }, %)
  // and then for filleting the edge highlighted in red
  // |> fillet({
  //   radius: 1,
  //   tags: [commonEdgeOfTwoFaces('tag2, filletTag')],
  // }, %)

Currently we don't allow adding tags to fillet calls, and commonEdgeOfTwoFaces is a hypothetical helper function (which would be named better).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ast Issues / features relevant to ast and parser.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants