Skip to content

feat(V2 Tier 4): 2D primitives and extrusion ops#15

Merged
particlesector merged 5 commits into
mainfrom
feat/2d-extrude
Apr 24, 2026
Merged

feat(V2 Tier 4): 2D primitives and extrusion ops#15
particlesector merged 5 commits into
mainfrom
feat/2d-extrude

Conversation

@particlesector
Copy link
Copy Markdown
Owner

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

chrislindseygames and others added 5 commits April 24, 2026 14:50
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>
@particlesector particlesector merged commit c631d9b into main Apr 24, 2026
4 checks passed
@particlesector particlesector deleted the feat/2d-extrude branch April 24, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants