Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
50 most recent check-ins
|
2026-08-26
| ||
| 08:34 |
polygon(): spline modifier, parametric curve trim, docs
- Spline sub-lists accept trailing modifier: [[x,y], r] for fillet/chamfer - Chamfer2._trim_edge(): parametric trim via BRep_Tool.Curve for any edge type - GCPnts_AbscissaPoint: 4-arg constructor (3-arg returned arc length as parameter for non-linear curves, only worked by accident for lines) - docs/polygon_extended.md: new syntax, OpenSCAD compatibility table leaf check-in: 854218e519 user: johnfound tags: master, trunk | |
|
2026-08-25
| ||
| 14:10 | polygon(): extended point formats - chamfer, fillet, spline sub-lists check-in: 658e603502 user: johnfound tags: master, trunk | |
|
2026-08-23
| ||
| 22:01 |
Sync Linux env scripts with Windows: build FreeType/HarfBuzz/RapidJSON from source
- Add setup_freetype.sh, setup_harfbuzz.sh, setup_rapidjson.sh mirroring the Windows .bat scripts; libraries float on default branches (no version pins). - FreeType/HarfBuzz install into bcad.venv/lib/{freetype,harfbuzz} so consumers reach them via relocatable $ORIGIN-relative RPATHs (same pattern as OCCT); libharfbuzz carries its own RUNPATH to our FreeType - transitive deps do not see consumer RUNPATH and would otherwise silently pick up the system library. - setup_harfbuzz.sh points CMAKE_PREFIX_PATH/PKG_CONFIG_PATH at our FreeType. - setup_occt.sh: USE_RAPIDJSON=ON + INSTALL_RAPIDJSON=ON against cpp/rapidjson headers (pythonocc SWIG glTF module includes them unconditionally). - setup_text_shaper.sh: explicit HARFBUZZ_*/FREETYPE_* cmake vars override the pkg-config fallback; INSTALL_RPATH extended with freetype/harfbuzz lib dirs. - setup_imgui.sh: add IMGUI_BUNDLE_BUILD_DEMOS=OFF and IMGUI_BUNDLE_INSTALL_CPP=OFF; apply patches via git apply instead of patch(1) (stricter, matches .bat). - Unpin Windows FreeType VER-2-13-3 / HarfBuzz 10.2.0, track floating default branches instead; FT_DISABLE_ZLIB/PNG/BZIP2=ON on both platforms; fix no-op update in setup_rapidjson.bat (reset --hard HEAD never moved the clone). - pip version caps: nanobind below 3.x and swig below 4.5 on both platforms. imgui_bundle bindings break against the nanobind 3.x ndarray_export API; pythonocc-core 7.9.3 only accepts SWIG 4.2.1..4.4.1. Drop after upstream fixes. - docs/build.md: ft/hb/rapidjson are built from source, no system packages. check-in: f586182777 user: johnfound tags: master, trunk | |
| 12:00 |
Merge imgui_bundle upstream (407065b7, TextEdit bc5bb95) into patches
Upstream adopted: SetText scrolling reset via resetScrolling() (#78), hover crash fix on empty lines, ImGui::Shortcut-based navigation, caret rendering rework, squiggles API. No duplication of our features found; both scroll fixes coexist (upstream resets on SetText, ours keeps cursor visibility requests alive during typesetter updates). Adaptations of our patches: - Rejected hunks re-integrated into new contexts: previousCursorLine reset in setText (now after clearSquiggles), updateState guard additionally checks ensureVisiblePos.line, scrollToLine no longer clears a pending ensureVisiblePos request (verified against new handlePossibleScrolling ordering), deleteText sync follows new deletesHappened bookkeeping - Ctrl+Q calltip fallback switched to ImGui::Shortcut idiom (isShortcut local removed upstream) - Esc dismissal: calltipState.active added to the outer guard introduced upstream (inner branch was unreachable otherwise) - renderGutterBackground declaration moved after renamed renderCursorCarets - Removed stale whitespace artifact at the updateState section header All three patches now apply cleanly with patch -p1 (no offsets/fuzz/rejects). check-in: fd4da86764 user: johnfound tags: master, trunk | |
|
2026-08-13
| ||
| 14:59 |
projection(cut=false): keep hole winding in full-circle merge; sphere silhouette respects UV bounds; insert exact projected vertices into polylines
- simplify_loop merged two CW semicircle arcs of a circular hole into a full circle with the canonical CCW winding: _arc_pieces normalized directed fit angles through _angular_pieces and lost the sign of traversal, and _union_angular_pieces collapsed full coverage to the positive sweep. The hole became a filled disk (2 faces, area 160.26 instead of 120.99) for cone_vert. Circle and ellipse pieces are now directed intervals (sign of span is the traversal direction); _pieces_connected and _merge_pieces handle them with the 2*pi seam, and _dir_union_pieces unwraps the next arc to continue the chain, preserving CW for holes and CCW for outer boundaries. - Sphere silhouette: only emit the equator arc lying within the face UV bounds; a partial sphere (rounded corner octant) no longer emits a phantom full circle that extended the merged coverage and created false junction vertices. - insert_projected_vertices: split polylines at the exact projected positions of vertices that are true edge endpoints lying on the same support curve; the merge resampling previously lost the exact line/circle junction points of offset() rounded corners and the contour did not close within the assemble_loops tolerance. - Tests: test_projection_outline gains p5d (offset(1.2) cube, area 152.52) and p5 (cone_vert, one face with circular hole, area 120.99) now passes. check-in: 04915204be user: johnfound tags: master, trunk | |
| 05:11 |
classify_arc: do not replace circle with ellipse on marginal fit gain; add edge_kinds() builtin
projection(cut=false) offset(1) cube(10) exported corner arcs as ellipses instead of exact circles: the Fitzgibbon ellipse fit overfits the noisy line/circle junction endpoints and wins over the Kasa circle fit on a marginal residual edge (1.53e-4 vs 1.90e-4, ratio 0.79). A true flat ellipse improves the circle residual by 6-8x (ratio 0.12-0.17). Now the circle gives way to an ellipse only when the ellipse residual is at most half of the circle residual. Adds edge_kinds(shape) builtin returning the sorted curve types of all edges (line/circle/ellipse/...) for tests. Regression test 5c asserts the four offset-cube corners are circles (area 140+pi=143.14); arg-validation coverage in tests/builtin_args/inspection.scad. check-in: 97dee3486e user: johnfound tags: master, trunk | |
| 04:43 |
Fix projection(cut=false) silently dropping outline edges; snap junction vertices before MakeWire
Flat ellipse outline arcs (cut_false.scad h=15.1/14.9) meet line arcs with ~1e-4 vertex gaps, far above MakeWire's 1e-7 coincidence threshold, so BRepBuilderAPI_MakeWire silently discarded edges and the resulting face was garbage (-15.5 area instead of ~118.7) with no warning. Before assembly, snap each adjacent pair of part vertices to their midpoint via BRep_Builder.UpdateVertex (tolerance = gap + 1e-6). Conic edges stay exact, polyline fallback unchanged. Adds regression test 5b (cut_false h=15.1, area 118.67). check-in: cf95a2f4f3 user: johnfound tags: master, trunk | |
|
2026-08-12
| ||
| 16:17 | Updated build script. check-in: 4979ba5502 user: johnfound tags: master, trunk | |
| 04:55 | projection(cut=false): generic silhouette — Adaptor3d_Surface_D1 out-args, half-cell grid, contour tracing check-in: 70d92f525e user: johnfound tags: master, trunk | |
|
2026-08-11
| ||
| 19:48 |
projection(cut=false): merge conic arcs on shared supports; deterministic winding of full circle/ellipse holes
simplify_loop and merge_polylines now merge arcs on shared hyperbola/parabola supports (interval overlap, axis normalized). The axis-angle key clamps near-axis directions to 0 degrees so one direction cannot split into keys 0 and 180. Full-circle/ellipse loops keep their winding: angular pieces carry the sign of the span (CW full coverage -> (0,-2pi)), rebuild accepts negative ranges, and the endpoint-flip heuristic is skipped for closed arcs (it compared p[0]/p[-1] distances at float-noise level and randomly filled round holes, e.g. cut_false.scad). check-in: 5bb46244ba user: johnfound tags: master, trunk | |
| 17:10 |
projection(cut=false): merge collinear arcs across loop wrap
The assembled outline loop is a closed cycle, but simplify_loop ran a linear pass and only merged consecutive collinear arcs. The loop start depends on OCCT edge traversal order, which differs between X and Y rotations: a straight boundary run split by interior silhouette crossings could land across the loop's start/end junction and stay split (cone base line came out as 12.5+7.5 for rotate([0,90,0]) but a single 20 for rotate([90,0,0])). Now the first and last result arcs are merged too when they share a support line and touch. check-in: 7444a6d0a5 user: johnfound tags: master, trunk | |
| 16:25 |
projection(cut=false): mixed exact/polyline contour wires
_loop_wire now builds exact BRep edges for arcs that fit line/circle/ ellipse and polylines only for unclassifiable ones (e.g. hyperbolas), instead of falling back to a full polygon when a single arc fails. Fix _edge_signed_area shoelace sum (closing chord zeroed open straight-edge contributions). rebuild_line returns exactly 2 points. classify_arcs uses the geometric midpoint for 2-point arcs so the +/-eps normal test is not sampled at an endpoint. check-in: 69c5aff979 user: johnfound tags: master, trunk | |
| 13:49 | Fix projection(cut=false) outline for non-circle silhouette tangencies check-in: b1bb70d3a4 user: johnfound tags: master, trunk | |
| 11:13 |
Fix projection(cut=false) outline for non-circle silhouette tangencies
Two fixes in bcad/binterpreter/projection_outline.py: 1. Seam edges of periodic surfaces (cylinder/cone lateral faces from OCCT primitives) touch only one face and are a parametrization artifact, not a contour feature. Their projection is an interior line that splits the boundary at collinear vertices and breaks the loop into an open contour. solid_candidate_curves now takes true edges only from break lines (edges adjacent to >= 2 faces), resolving the known issue of rotated cylinders around Y. Regression: tests 3a/3b (axis-Y cylinder, seam independent of prior Z-rotation). 2. Tangency points of a silhouette line with the projection of a closed junction loop (e.g. cone + transverse tunnel) are extrema of the loop's projection. The uniform 48-point sampling placed no vertex at the touch point (max sampling error ~0.75), so the two candidates shared no vertex within the 1e-3 assembly tolerance and assemble_loops failed to close. New curve_projection_extrema() generalizes circle_extremal_params to any curve (sign-scan + parabolic vertex fit, incl. the seam extremum of closed loops, accuracy ~1e-6) and feeds the params into sample_3d_curve() extra. _resample now always resamples to exactly n points so closed junction loops with varying point counts compare correctly. Fixes cut_false.scad rotY90 (was invalid face with area 0.0). check-in: b52ed24b98 user: johnfound tags: master, trunk | |
| 05:43 |
Integrate projection(cut=false) into bcad as orthographic outline port
Port test_code/projection_outline.py to bcad/binterpreter/projection_outline.py and wire it into SCLProjection.projection (cut=False branch): per wrapper child, outline_faces() is computed in try/except, failures warn and yield an empty compound. Adds tests/test_projection_outline.scad (areas from test_code/run_outline.py) and updates the test_projection.scad header. Known issue: rotated cylinders around Y (rotate([0,45,0])) still produce a wrong outline area; investigation is ongoing. check-in: d9cafea959 user: johnfound tags: master, trunk | |
| 04:40 |
Add orthographic projection outline algorithm for solids (test harness)
projection_outline.py extracts the 2D silhouette outline of a BRep solid projected along Z: gathers candidate edges from the solid's pcurves, splits polylines at crossings (including shared-vertex contacts, which segment-intersection tests miss), classifies arcs as boundary via exact ray-casting inside-tester, fits lines/circles/ellipses, assembles closed loops and reports exact loop areas. Verified against analytic geometry for: cube (100), cube_hole (400 + -28.274 circle), cylx (200), cylz/sphere (78.540 circle), cone (150), cyl45 (196.957 with 2 line + 2 ellipse edges), cone_vert (140.625 + -19.635), cone3 (cone with 3 bores rotated edge-on: 137.365 + -19.635, rim curves kept as polylines since cone x cylinder intersections project to hyperbola arcs). run_outline.py drives the shapes; prototype_outline.py is an interactive ImGui viewer comparing the result against the input solid. check-in: 9dff008907 user: johnfound tags: master, trunk | |
|
2026-08-10
| ||
| 12:56 |
Implement 3D planar chamfer for offset(delta, chamfer=true)
Bevel all convex join edges of the miter (Intersection) 3D offset result via BRepFilletAPI_MakeChamfer with symmetric distance equal to |offset| — the exact 3D analogue of the 2D chord chamfer (bevel legs equal the offset distance). New helpers: _adjacent_faces, _face_normal_at_edge (outward normal via pcurve, honoring face orientation), _edge_is_convex (point P+eps(n1+n2) classified by BRepClass3d_SolidClassifier), _chamfer_offset_3d (unique edges via topexp.MapShapes since TopExp_Explorer duplicates edges per face in this pythonocc build; skips seam and tangent-continuous edges; falls back to the sharp miter result with a warning on any failure). _offset_3d gains a chamfer param and remaps face colors through the chamfer builder (_map_colors) with adjacency fill for the new bevel faces. SCLOffset.offset() passes chamfer and have_delta to the 3D path (chamfer stays ignored in r mode, OpenSCAD parity). Add true-3D cases to tests/offset_chamfer.scad: cube (2450.667), cylinder seam handling (1995.959), box+hole (1615.257) plus miter and rounded controls. check-in: aabd5850c9 user: johnfound tags: master, trunk | |
| 10:31 |
Implement offset(chamfer=true): beveled joins for delta mode
Replace the round-join arcs of the 2D offset (radius exactly |offset|) with their chords via _chamfer_offset_wire, giving OpenSCAD-style chamfered corners (identical to Clipper jtSquare for right angles). Concave corners have no join arc and stay sharp; non-join arcs and full-circle outlines are untouched. chamfer has no effect in r mode (OpenSCAD parity). _offset_3d now honors join_type in PerformByJoin (previously hardcoded GeomAbs_Arc), so 3D delta/chamfer produce sharp edges and 3D r keeps rounded ones. Remove the 'not yet supported' warning. Add tests/offset_chamfer.scad verifying areas (chamfer 188, miter 196, round 192.566, L-shape 116.5). check-in: 03266d7599 user: johnfound tags: master, trunk | |
| 07:04 |
Refactor list comprehension grammar: unify for/let/each into recursive comp_item scheme
Replace the monolithic productions (expr_array_for single-var, expr_array_multi_for, array_for_body/expr_array_tail/for_gen_rest) with a small recursive grammar: vector_element : comp_item; comp_item : expression | comprehension; comprehension : FOR (...) comp_item | FOR (cstyle) (...) comp_item | LET (...) comprehension | EACH expression. Comprehensions are now valid at any position inside a vector literal, not only at the start. expr_array_for gains a 'counters' list (multi-variable for is a Cartesian product like OpenSCAD, evaluated by the same recursion as _exec_for). cstyle for keeps inits/cond/incrs. scl.py eval: _exec_array_for recursion, _each_flatten, _is_list_comprehension for nested flattening; removed the expr_array_multi_for branch and per-form tail handlers. Tests extended in test_comprehension_midlist.scad (cstyle double generator, for...let...for, let...each). AGENTS.md updated. check-in: 026533c939 user: johnfound tags: master, trunk | |
|
2026-08-09
| ||
| 11:45 |
Fix mesh wings on clipped periodic BSpline faces in BRepMesh_EdgeDiscret
A SameParam edge is discretized from its 3D curve; a seam edge of a closed surface has no 3D curve, and BRepAdaptor_Curve(edge) then falls back to the first pcurve representation stored on the edge. After a boolean operation that edge can keep a dangling pcurve covering the whole periodic range [0, 2*pi] while the actual face pcurve is clipped to the face UV window. The mesher then generates UV points outside the window, expanding the wire polygon and NURBSRangeSplitter range, and classified nodes poke outside the surface (wings, zmax=+2.5 on bad_diff_scale.scad whose top is at z=0). CreateEdgeTessellator now uses the face-aware CurveTessellator constructor for SameParam edges without a 3D curve (seam edges) as well, resolving the pcurve on the given face. bad_diff_scale.scad cone face now meshes z [-4.99, 0.00] (was [+2.50]); cylinder/cone/sphere/fuse/cut/common unchanged. Regenerated cpp/occt-patches/BRepTools_GTrsfModification.cxx.patch, added cpp/occt-patches/BRepMesh_EdgeDiscret.cxx.patch, updated docs/cpp-patches.md. check-in: b88529b2dc user: johnfound tags: master, trunk | |
| 09:28 |
Fix GTrsfModification preservable check for sx smaller than sy
elemImage rejected only sx greater than sy as non-preservable; the sx smaller than sy case wrongly took the analytic circular-cone path and produced an invalid shell (negative semi-angle). Use Abs(sx - sy) so any asymmetric cross-section image takes the exact ruled B-spline path. The output matches the BRepBuilderAPI_NurbsConvert reference (volume, surface structure, bounding box). Regenerated cpp/occt-patches/BRepTools_GTrsfModification.cxx.patch. Rework tests/test_scale_cone_asymmetric.scad to assert volume instead of bbox: BRepBndLib over-estimates the bounding box of rational B-spline surfaces with this weight layout (the OCCT reference behaves identically), while volume is integration-based and exact. Test now passes (volume ~= pi/3*5*10*15 for the elliptical cone image). check-in: 1da0df910a user: johnfound tags: master, trunk | |
| 09:10 |
Fix GTrsfModification ruled-image seam (knot shift + U-periodic)
buildRuledImage produced a B-spline surface whose U-domain did not match the source face p2d u-window when the rail edge's 3D parameter aF differs from the pcurve start (e.g. rim circle of a cut cone, aF = pi/2 vs u = 0), making scale([1,1,0.5]) BRepCheck-invalid. Shift rail knots so the surface U-domain equals the source u-window, and call SetUPeriodic() when the surface is U-closed (full-turn rails) to match the NurbsConvert reference. Regenerated cpp/occt-patches/BRepTools_GTrsfModification.cxx.patch. Add failing regression test tests/test_scale_cone_asymmetric.scad documenting the elemImage asymmetric preservable check (sx - sy only catches sx greater than sy; the sx smaller than sy case wrongly takes the circular-cone path and produces an invalid shell). check-in: f269e09e37 user: johnfound tags: master, trunk | |
|
2026-08-08
| ||
| 12:54 |
docs: document third-party git repo / patch scheme
Rewrite cpp-patches.md as the full scheme for disposable git clones (OCCT, pythonocc-core, imgui_bundle) whose local modifications live only as patch files tracked in Fossil; add OCCT GTransform/GTrsfModification patches inventory. Fix stale imgui patch paths in build.md, macos-setup.md and the patch READMEs (old cpp/imgui/ no longer exists); add the scheme link to AGENTS.md. check-in: 6f665fc1db user: johnfound tags: master, trunk | |
| 12:46 |
occt-patches: exact affine transform in BRepBuilderAPI_GTransform
Add BRepTools_GTrsfModification and BRepBuilderAPI_GTransform patches keeping analytic parametrization under general affine maps (elementary surface images, line/circle preservation, pcurve re-parametrization including collapsed circle images on degenerate plane faces, edge->faces adjacency); update the Sewing patch (prefer simpler curve types when merging coincident edges). check-in: 38586db315 user: johnfound tags: master, trunk | |
|
2026-08-07
| ||
| 12:15 | projection(): cut=true via Section at z=0; cut=false warns not implemented and returns empty check-in: 9de95418d4 user: johnfound tags: master, trunk | |
|
2026-08-06
| ||
| 14:08 | export() should be transparent for the geometry - use SCLGroup instead of SCLPart3. check-in: 35f560a673 user: johnfound tags: master, trunk | |
| 13:55 | Export progress bar in GUI; unified error messages without empty-file fallback check-in: 766a340a5e user: johnfound tags: master, trunk | |
|
2026-08-05
| ||
| 21:23 | Per-face color STEP test: bcad-generated fixture, import and roundtrip face-count stability check-in: 87463f1e6d user: johnfound tags: master, trunk | |
| 21:23 | Resolve include/use/import/surface paths relative to the calling file, not cwd check-in: aa72586c7f user: johnfound tags: master, trunk | |
| 20:44 | Editor: remove Ctrl+E debug flash indicator check-in: 810eb4d0b3 user: johnfound tags: master, trunk | |
| 20:44 | Settings: configurable recent files limit (default 20) in Preferences|General check-in: 956e36bbde user: johnfound tags: master, trunk | |
| 20:31 | Editor: Ctrl+Tab/Ctrl+Shift+Tab cycles through editor tabs; disable native window switcher check-in: d205ee0bde user: johnfound tags: master, trunk | |
| 18:43 | Editor: Ctrl+E opens the include/use file under the caret check-in: e7817610e1 user: johnfound tags: master, trunk | |
| 14:11 |
Fix moiré/z-fighting on STEP import of SolidWorks-style per-face colored files
read_step emitted a compound AND every sub-shape of a compound label, so faces stored as FACE sub-shapes (OVER_RIDING_STYLED_ITEM) rendered twice coincident with the same faces inside the solids, causing z-fighting/moiré (SFM4100.step imported as 666-4474 parts instead of 5). Compound branch now emits each SOLID/SHELL sub-shape once with per-face colors resolved via TopTools_IndexedMapOfShape (O(n) IsSame matching), absorbs matching FACE sub-shapes into their parent solid, and only emits the compound itself when it has no solid/shell children (loose faces). Orphan colored faces keep their own display entry. Non-compound simple shapes are emitted once as before, then per-face sub-shape colors override. TransferColored gains a default_color parameter (fallback for uncolored faces) threaded from _write_face_colors via get_default_color(). Add tests/test_step_perface.scad regression test: SFM4100.step imports as 5 parts/3689 faces, Straight.STEP as 13 parts/4483 faces, roundtrip keeps the face count (no duplication). check-in: 1dc6ecc20d user: johnfound tags: master, trunk | |
| 08:25 |
Fix children() leaking the enclosing module's block
children() now resolves its owner lexically: the innermost module frame, or the _lexical_owner carried by an active children-exec frame. Previously it did a dynamic reverse search for $children_block, which crossed module boundaries and made a module called without children render the block of an ancestor module (test_chain.scad produced 7 cylinders instead of 3). Every module frame now always sets $children_block (None when called without a block) and $children (0 without a block), so no-block modules shadow outer blocks and children() renders nothing instead of leaking. Exec frames keep parent=call_scope for lexical variable visibility. Remove the delete/restore hack around $children_block and the misleading 'No children to render' warning. Add tests/test_chain_children.scad regression test (3 cylinders -> 9 faces). check-in: 9073d86682 user: johnfound tags: master, trunk | |
|
2026-08-04
| ||
| 20:41 |
Clean up noisy STEP export logging and remove dead debug code
Remove all Russian INFO progress messages from the STEP writer (writer setup, transfer, file write steps) and keep a single informative 'STEP export written: file path' line. Warnings and errors are now in English and errors are reported once by the caller instead of being double-logged with a full traceback inside the writer. Suppress OCCT's 'Statistics on Transfer' block via the documented Message_Messenger API (SetTraceLevel(Message_Alarm)) instead of the previous console noise, since bcad surfaces OCCT failures programmatically. This silences the output process-wide. Delete dead Russian debug utilities from scl_context.py (_shape_type_str, debug_shape_structure, print_algo_diagnostics) and the Message_Warning/Message_Alarm imports they were the only users of. check-in: e325863644 user: johnfound tags: master, trunk | |
| 20:19 |
Fix STEP import losing whole-shape base color when per-face colors exist
import_file discarded the shape's base color whenever per-face colors were present, so non-overridden faces fell back to the default PERU. The STEP colors are encoded as base STYLED_ITEM (whole shape, readable via GetColor on the shape label) plus OVER_RIDING_STYLED_ITEM per face. Now the base color is always applied to all faces first and per-face overrides are merged on top. Files without a base color keep the same default behavior since the base falls back to PERU. Fixes scl_examples/spheres_freecad.step showing the red sphere as default color instead of red. Verified round-trip re-import keeps both colors. check-in: f90f47da14 user: johnfound tags: master, trunk | |
| 20:02 |
Preserve per-face colors in STEP round-trip; compact STYLED_ITEM emission
Bake assembly location into geometry during STEP import (BRepBuilderAPI_Transform copy=True), so exported shapes have an identity top Location. A located shape made XCAFDoc_ShapeTool::AddShape create a reference label, silently dropping per-face SetColor calls. TransferColored now sets the most frequent color as the base shape style and emits OVER_RIDING_STYLED_ITEMs only for the remaining faces, shrinking the color section from ~31.5k to ~4.7k entities. sfm4100 round-trip drops from 7.91 MB to 6.92 MB with all colors preserved. check-in: 9fda7bf056 user: johnfound tags: master, trunk | |
| 11:57 | Less contrast for the intent marker lines. check-in: 792299accc user: johnfound tags: master, trunk | |
| 10:02 |
Editor calltip: trigger parameter hint only on '(' and ',' instead of any input
The calltip (function/module parameter hint) was re-triggered on every keystroke inside the argument list, which made it intrusive. Now it is shown only when a call's argument list opens with a left paren, when an argument separator comma is typed, via Ctrl+Q as a manual fallback, or right after autocomplete inserts a function/module with the cursor placed between the parens. Language separation: the cheap trigger gate is now a language property (Language::isCallTrigger set to paren and comma in OpenscadLanguage), while the precise analysis lives in the generic editor: - findEnclosingCallParen scans backwards respecting parens, square and curly brackets, and only accepts a paren that is preceded by a module/function name, so a comma inside a vector/block literal or a grouping paren does not fire. - tryActivateCalltip ignores parens inside strings/comments. - CalltipState gains argumentIndex (index of the argument being edited), exposed to Python as argument_index. - findEnclosingOpenParen keeps the per-frame dismissal behavior. Regenerated TextEditor.cpp/.h and pybind patches. check-in: 68a7f75ba7 user: johnfound tags: master, trunk | |
| 08:44 |
Restrict module/function parameter definitions to ID or ID = expr
Parameter lists of module and function definitions used the generic varargslist grammar, so an expression like s-10 (missing '=') parsed as expr_binop. get_args_list then dereferenced a['id']/a['val'] on it and raised UnhandledCaseError, which killed the OCCT worker process. Add a strict paramdefs/paramdef_list/paramdef grammar (ID | ID = expr), matching OpenSCAD, and use it in module_definition and function_definition. Call sites still use the permissive parameters rule. Invalid definitions now produce a syntax error at the correct line instead of crashing. Fixes scl_examples/crash_arg.scad. Adds tests/test_module_param_defs.scad regression test. check-in: 1ce3d1c039 user: johnfound tags: master, trunk | |
| 07:22 |
Remove warnings from 2D primitives; skip degenerate edges silently
Line3/Arc3/Spline3.to_edge and SCLProfile2 no longer emit warnings (they crashed with AttributeError since edge classes lacked warn()). Degenerate elements (zero-length segments, duplicate consecutive polygon points) are now silently skipped and simply not drawn, matching OpenSCAD behavior. add_profile_shape leaves the shape unset on failure instead of warning. Fixes scl_examples/big_polygon.scad (duplicate point [16,31]). Adds tests/test_polygon_duplicate_points.scad regression test. check-in: ba050db5a4 user: johnfound tags: master, trunk | |
| 05:23 | Allow trailing commas in vector literals check-in: 7a41ea0fde user: johnfound tags: master, trunk | |
|
2026-08-03
| ||
| 14:48 | Compile all C++ sources with -Os for Linux and Windows. check-in: ae330c92ca user: johnfound tags: master, trunk | |
|
2026-08-02
| ||
| 22:39 |
Boolean ops: empty results are first-class shapes, not failures
Empty results of boolean operations (difference/intersection/union) are now legitimate: a completed op (IsDone) returns its shape even when it is an empty compound, silently. A None result means a real OCCT failure and always comes with a warning ('boolean operation failed — result omitted'). - get_children() returns direct children only — shapeless/failed nodes no longer leak their grandchildren into parent operations - New SCLRoot(SCLPart3) container: no own shape, display() renders children; SCLPart3.display() renders only its own shape (no children fallback) - _cut_parts returns None (failure) vs empty list (legitimately all removed); _fuse_parts returns empty compound for no parts; universal_optimized_common_colored returns (None, None) only on failure - _unify_shape early-returns empty input (no spurious UnifySameDomain warning) - SCLShape.display/display_with_modifier skip empty compounds early - Regression test: tests/test_bool_empty.scad (6 cases) - Fixes 3 spurious 'boolean cut failed — showing individual children' warnings in Cluster_loft3.scad check-in: 23a1ec95ae user: johnfound tags: master, trunk | |
| 17:07 |
Set OCCT release flags to -Os and keep exceptions on
- Override CMAKE_C_FLAGS_RELEASE/CXX_FLAGS_RELEASE to "-Os -DNDEBUG". GCC 16.1.1 miscompiles BRepClass3d_SClassifier at -O3: the shared UBTree Select devirtualizes Reject/Accept to the Line selector, so the point Select calls Line::Accept on a point selector and reads uninitialized myLC -> intermittent SIGSEGV (e.g. is_valid() on sfm4100.step). -Os avoids the crash. - Set BUILD_RELEASE_DISABLE_EXCEPTIONS=OFF explicitly (OCCT default is ON) so exceptions remain enabled for pythonocc. - Drop BUILD_MODULE_DETools=ON (absent from the Windows script, not required for the build). check-in: 7db63b36ff user: johnfound tags: master, trunk | |
|
2026-08-01
| ||
| 21:24 |
Persist main and auxiliary window state across sessions
Add a generic AuxWindow base class (bcad/binterpreter/aux_window.py) for auxiliary windows whose open state is persisted. Subclasses declare a settings key, title and default size; imgui is imported lazily in render() so modules shared with the OCCT worker process stay GUI-free. AuxWindow provides is_open/show/close/toggle/restore plus an activate() that sets a per-window focus flag consumed via set_window_focus() right after begin() (the same safe pattern the editor uses for tab activation). Refactor ColorPickerDialog and the measurement results window to subclass AuxWindow: - Color Picker (key 'color_picker', 350x500) keeps its dialog body in draw_content(). - Measurement (key 'measurement', 400x300) moves into measure_tools.py together with _parse_markers(), keeping the one-way coupling: enabling measure mode opens (and activates) the window, disabling it does not close it, opening it does not enable the mode. Transition detection via _mode_was_on covers both the Tools menu and the toolbar Meas button. Persist state in a new settings [windows] section (main_maximized, color_picker, measurement), saved at exit in _save_window_state() and restored at startup in _restore_window_state(). Main window maximization is saved/restored via glfw; non-maximized position/size are left to the OS. Render aux windows before the Output/Console log views so that on the first frame the newly appearing log windows steal focus last, keeping Console/Output as the active dock tabs after restoring open windows. Remove the now-dead _measure_lines/_show_measure/_fmt_display code from main_window.py. check-in: a745a4a683 user: johnfound tags: master, trunk | |
| 17:53 |
Honor $fn/$fa/$fs/$fe in STL export, add export() module
STL mesh resolution now follows OpenSCAD semantics (approximated by OCCT): make_writer reads all four special vars: $fn > 0 -> ang = 2PI/max(fn,3), else ang = radians($fa); lin = min($fs, $fe). SCLSTLWriter.Write replaces pythonocc write_stl_file (theForce=false kept the preview tessellation) with breptools.Clean + forced BRepMesh_IncrementalMesh + StlAPI_Writer, so GUI exports are no longer pinned to preview density. hull() uses the same min($fs, $fe) rule. New bcad-specific export() module: export('file') { children } writes a subtree to step/stl/dxf during evaluation (transparent SCLPart3 container, % background children skipped, relative paths against the script dir). Registered in _builtin_modules (FUNC_EXPORT=37). Uses _module_scope so the block is compiled before writing. The file name is never modified by make_writer: with an explicit fmt the format is determined by the parameter (/dev/null, extension-less and custom names all work); without fmt it is detected from the extension. Removed the now-dead extensions attributes from the writer classes. Test tests/test_stl_resolution.scad covers all four variables via export/import/capture/num_faces (each mesh density in its own if(true) block due to 3-phase evaluation). Docs updated (docs/export_module.md, docs/scl.md, AGENTS.md). check-in: 10a6d9bd57 user: johnfound tags: master, trunk | |
| 13:31 |
editor: fix crash when deleting large multi-line selections
The auto-strip-trailing-whitespace patch accessed document[previousCursorLine] with a stale frame-to-frame line index. Deleting a large selection shrinks the document below that index in the same frame, causing an out-of-bounds std::vector access and a segfault (small 1-3 line selections stayed in bounds, which is why they never crashed). - guard the strip block with previousCursorLine less than document.size() - keep previousCursorLine in sync with edits in TextEditor::deleteText/insertText using the same line-shift arithmetic as cursors, so it keeps pointing at the same logical line instead of a shifted one - reset previousCursorLine = -1 in setText() for a new document - AGENTS.md: drop stale cpp/imgui/ references, point to cpp/imgui-patches/, and document the strip mechanism and the crash guard check-in: 4cec3745b1 user: johnfound tags: master, trunk | |
| 12:33 |
linear_extrude: make caps disjoint to fix twist=360 self-overlap
When the profile extends along the sweep axis further than height, the bottom and top caps overlap coplanarly (the pipe closes on itself like a torus), producing a self-intersecting shell. As a boolean tool this hard- crashed Cut.Build() with fuzzy tolerance (thread twist=360 segfaulted). _disjoint_caps() mutually cuts the caps (BRepAlgoAPI_Cut) in all branches (twist/scale/plain) before sewing; when caps don't overlap the Cut is a no-op. Adds tall-profile regression tests: tool validity and difference() against the twist=360 tool. check-in: 75d4435721 user: johnfound tags: master, trunk | |