feat(V2 Tier 4): 2D primitives and extrusion ops#15
Merged
Conversation
Adds square(), circle(), polygon(), linear_extrude(), and rotate_extrude(). 2-D primitives are parsed as PrimitiveNode (Square2D/Circle2D/Polygon2D) and compiled to CsgLeaf in the CSG IR. polygon() stores resolved contour points and optional path indices directly on the leaf. Extrusions are a new AST/IR node (ExtrusionNode / CsgExtrusion). MeshEvaluator converts 2-D children to manifold::CrossSection via getChildCrossSection(), which handles nested 2-D booleans and 2-D transforms (translate/rotate in XY applied as mat2x3). The resulting CrossSection is extruded with Manifold::Extrude() (height, twist, scale, center) or Manifold::Revolve() (angle, $fn). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
'scale' is a keyword (TokenKind::Scale) so 'scale=0.3' inside linear_extrude or any primitive param list was not being parsed as a named parameter. Fix both parseParamList and parseExtrusionParams to accept any token followed by '=' as a named parameter, matching OpenSCAD's behaviour where keywords are not reserved in param position. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
OpenSCAD documents that twist follows the left-hand rule (positive twist is clockwise when viewed from above). Manifold::Extrude uses the standard right-hand rule (positive = counter-clockwise). Negate the twist value so the two renderers agree. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Scale-only extrusions (e.g. frustums) work correctly with nDivisions=0 since Manifold linearly interpolates vertex positions from bottom to top. Intermediate divisions are only needed for twist to smoothly interpolate the rotation, so restrict the division count to the twist != 0 case. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…semantics Nested same-winding contours (e.g. outer CCW square + inner CCW square) create holes in OpenSCAD because the inner region has an even crossing count. Manifold defaulted to FillRule::Positive (nonzero), making both contours fill solid. Switching to FillRule::EvenOdd reproduces the frame/ring shape OpenSCAD produces for polygon() with paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(lang): add 2-D primitives and extrusion ops (Tier 4) — core implementation
fix(parser): accept keyword tokens as named params in param lists — fixes scale=0.3
fix(extrude): negate twist to match OpenSCAD left-hand rule
fix(extrude): only use nDivisions for twist, not plain scale taper
fix(polygon): use EvenOdd fill rule to match OpenSCAD's polygon path semantics — fixes scene 9 frame/ring