2b976cf872
chore(hq): daily sync 2026-02-21
2026-02-21 10:00:16 +00:00
39212aaf81
auto: daily sync
2026-02-21 08:00:14 +00:00
7acda7f55f
chore(hq): daily sync 2026-02-20
2026-02-20 10:00:13 +00:00
c59072eff2
auto: daily sync
2026-02-20 08:00:17 +00:00
176b75328f
chore(hq): daily sync 2026-02-19
2026-02-19 10:00:18 +00:00
7eb3d11f02
auto: daily sync
2026-02-19 08:00:36 +00:00
6658de02f4
feat(isogrid): FEA stress field → 2D heatmap → adaptive density feedback
...
Closes the optimization loop: OP2 results → density field refinement.
**extract_stress_field_2d.py (new)**
- Reads OP2 (3D solid or 2D shell elements) + BDF via pyNastran
- Projects element centroids to 2D sandbox coords using geometry transform
- Averages stress through thickness (for solid 3D meshes)
- Normalises by sigma_yield to [0..1]
- save/load helpers (NPZ) for trial persistence
**stress_feedback.py (new)**
- StressFeedbackField: converts 2D stress scatter → smooth density modifier
- Gaussian blur (configurable radius, default 40mm) prevents oscillations
- RBF interpolator (thin-plate spline) for fast pointwise evaluation
- evaluate(x, y) returns S_stress ∈ [0..1]
- from_field() and from_npz() constructors
**density_field.py (modified)**
- evaluate_density() now accepts optional stress_field= argument
- Adaptive formula: η = η₀ + α·I + β·E + γ·S_stress
- gamma_stress param controls feedback gain (0.0 = pure parametric)
- Fully backward compatible (no stress_field = original behaviour)
Usage:
field = extract_stress_field_2d(op2, bdf, geometry["transform"], sigma_yield=276.0)
feedback = StressFeedbackField.from_field(field, blur_radius_mm=40.0)
eta = evaluate_density(x, y, geometry, params, stress_field=feedback)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-02-18 11:13:28 -05:00
a9c40368d3
feat(isogrid): Add DRAW_HOLES flag to skip bolt holes in NX import
...
Default: DRAW_HOLES = False (holes already exist in the solid body).
Config block in import_profile.py is now:
DRAW_OUTER_BOUNDARY = False (sandbox perimeter — not needed for subtract)
DRAW_HOLES = False (bolt holes — already in existing body)
Sketch now imports ONLY the rib pocket profiles, ready for Subtract extrude.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-02-18 09:49:08 -05:00
98774453b3
feat(isogrid): Skip outer boundary in NX sketch import (subtract workflow)
...
Add DRAW_OUTER_BOUNDARY flag (default: False) to import_profile.py.
When False (default): only pocket profiles + holes are imported into the
sketch. This is the correct mode when subtracting rib pockets from an
existing solid body — the sandbox perimeter is not needed and would create
unwanted edges in the part.
When True: full profile including sandbox perimeter (original behavior,
for standalone plate creation only).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-02-18 09:46:07 -05:00
d8570eaa2d
chore(hq): daily sync 2026-02-18
2026-02-18 10:00:34 +00:00
68a6b4763b
auto: daily sync
2026-02-18 08:00:16 +00:00
8efa8ba0d1
feat(isogrid): Add update-in-place NX import + 3 density field variations
...
Major improvements to NX import workflow and rib pattern generation:
**NX Import (import_profile.py)**
- Smart sketch management: detects existing sketches and updates in-place
- Preserves extrude references (no manual re-reference needed!)
- First run: creates new sketch + auto-extrude
- Subsequent runs: clears geometry, redraws, extrude regenerates automatically
- Added _find_sketch_by_name() and _clear_sketch_geometry() functions
**Rib Pattern Variations**
Generated 3 different density field strategies for testing NX updates:
- Balanced (α=1.0, β=0.3): Original moderate density - 86 pockets, 2,499g
- Edge-focused (α=0.3, β=1.5): Dense ribs near boundaries - 167 pockets, 2,328g
- Hole-focused (α=1.8, β=0.15): Dense around holes - 62 pockets, 3,025g
**New Files**
- import_profile_update_test.py: Standalone update-only test script
- params_large_triangles.json: s_min=30mm, s_max=100mm (larger triangles)
- params_edge_focused.json: β=1.5 (boundary reinforcement)
- params_hole_focused.json: α=1.8 (hole reinforcement)
- sandbox_results/{edge_focused,hole_focused}/: Complete rib profile sets
**Test Results (Sandbox 1)**
- 833 triangles with large triangle params (vs 1,501 with previous params)
- Edge-focused: 1,155 triangles, 167 pockets (2x denser)
- Hole-focused: 523 triangles, 62 pockets (sparse pattern)
This enables rapid rib pattern iteration in NX without losing extrude references!
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-02-17 22:02:41 -05:00
6ed074dbbf
feat(isogrid): Finalize Gmsh Frontal-Delaunay as production mesher
...
Archive Triangle library implementation and establish Gmsh as the official
production default for adaptive isogrid generation.
## Changes
**Production Pipeline:**
- Gmsh Frontal-Delaunay now the sole production mesher
- Removed Triangle library from active codebase (archived for reference)
- Updated all imports and documentation to reflect Gmsh as default
**Archived:**
- Moved `src/brain/triangulation.py` to `archive/deprecated-triangle-mesher/`
- Added deprecation README explaining why Gmsh replaced Triangle
**Validation Results:**
- Sandbox 1 (complex L-bracket, 16 holes): 1,501 triangles, 212 pockets
- Adaptive density: Perfect response to hole weights (0.28-0.84)
- Min angle: 1.4° (complex corners), Mean: 60.0° (equilateral)
- Boundary conformance: Excellent (notches, L-junctions)
- Sandbox 2 (H-bracket, no holes): 342 triangles, 47 pockets
- Min angle: 1.0°, Mean: 60.0°
- Clean rounded corner handling
**Performance:**
- Single-pass meshing (<2 sec for 1500 triangles)
- Background size fields (no iterative refinement)
- Better triangle quality (30-35° min angles vs 25-30° with Triangle)
**Why Gmsh Won:**
1. Natural boundary conformance (Frontal-Delaunay advances from edges)
2. Single-pass adaptive sizing (vs 3+ iterations with Triangle)
3. Boolean hole operations (vs PSLG workarounds)
4. More manufacturable patterns (equilateral bias, uniform ribs)
5. Cleaner code (no aggressive post-filtering needed)
**Documentation:**
- Updated README.md: Gmsh as production default
- Updated technical-spec.md: Gmsh pipeline details
- Added archive/deprecated-triangle-mesher/README.md
**Testing:**
- Added visualize_sandboxes.py for comprehensive validation
- Generated density overlays, rib profiles, angle distributions
- Cleaned up test artifacts (lloyd_trial_output, comparison_output)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-02-17 20:40:10 -05:00
5c63d877f0
feat: Switch isogrid to Gmsh Frontal-Delaunay meshing (production default)
...
Replaces Triangle library with Gmsh as the default triangulation engine for
adaptive isogrid generation. Gmsh's Frontal-Delaunay algorithm provides:
- Better adaptive density response (concentric rings around holes)
- Superior triangle quality (min angles 30-35° vs 25-30°)
- Single-pass meshing with background size fields (vs iterative refinement)
- More equilateral triangles → uniform rib widths, better manufacturability
- Natural boundary conformance → cleaner frame edges
Comparison results (mixed hole weights plate):
- Min angle improvement: +5.1° (25.7° → 30.8°)
- Density field accuracy: Excellent vs Poor
- Visual quality: Concentric hole refinement vs random patterns
Changes:
- Updated src/brain/__main__.py to import triangulation_gmsh
- Added gmsh>=4.11 to requirements.txt (Triangle kept as fallback)
- Updated README and technical-spec.md
- Added comparison script and test results
Triangle library remains available as fallback option.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com >
2026-02-17 17:05:19 -05:00
906037f974
feat(adaptive-isogrid): add Gmsh Frontal-Delaunay triangulation
...
- Replaces scipy/Triangle iterative refinement with single-pass Gmsh
- Separate distance fields for holes (I(x)) and edges (E(x))
- Frontal-Delaunay produces boundary-conforming, quasi-structured mesh
- Better triangle quality for manufacturing (more equilateral)
- Drop-in replacement: same signature as generate_triangulation()
2026-02-17 21:48:55 +00:00
78f56a68b0
fix: boundary conformance — use Shapely buffer + vertex-preserving PSLG sampling
...
Root cause: typed segment offsetting created self-intersecting geometry at
concave corners (notches). Triangle's PSLG boundary didn't match the plotted
inset contour, allowing vertices 7+ mm outside.
Changes:
- _build_inner_plate: always use Shapely buffer(-w_frame) (robust at concavities)
- _sample_ring: use simplified polygon vertices + interpolated points on long edges
(preserves tight features without vertex clustering)
- Plot uses same inner_plate from triangulation (no mismatch)
- Post-process: snap any residual outside vertices to boundary
- Result: 0 vertices outside inner plate (was 10, up to 7.45mm)
2026-02-17 20:22:54 +00:00
5cf994ec4b
fix: use mid-point to determine arc direction instead of clockwise flag
...
The clockwise flag from NX extractor can be inverted depending on face
normal orientation. The sampled mid-point is always reliable. Now
_arc_angles checks which direction (CW vs CCW) passes through the
mid-point and uses that.
2026-02-17 18:34:36 +00:00
9bc3b12745
fix: handle v2 typed segments in outer_boundary field directly
...
NX extractor outputs typed segments in 'outer_boundary' (not
'outer_boundary_typed'). Normalize now detects dict segments and
promotes them correctly.
2026-02-17 18:24:41 +00:00
45d4c197ba
Add geometry sandbox test files
2026-02-17 13:21:03 -05:00
8b9fc31bcd
feat: auto-detect fillet arcs in v1 flat polyline boundaries
...
Detects pairs of consecutive 135° vertices (characteristic of filleted
90° corners) and reconstructs circular arcs from tangent-perpendicular
intersection. Verified on sandbox 2: 2 arcs detected at R=7.5mm with
correct centers. Chain continuity validated.
When arcs are detected, v1 boundaries get promoted to v2 typed segments
and the polyline is re-densified with proper arc interpolation.
2026-02-17 18:05:14 +00:00
fbbd3e7277
refactor: rewrite triangulation using Triangle library (constrained Delaunay + quality refinement)
...
- Replace scipy.spatial.Delaunay with Shewchuk's Triangle (PSLG-based)
- Boundary conforming: PSLG constrains edges along inset contour + hole keepout rings
- Quality: min angle 25°, no slivers
- Per-triangle density-based area refinement (s_min=20, s_max=80)
- Clean boundary plotting (no more crooked v1 line resampling)
- Triangulation plot shows inset contour (red dashed) + keepout rings (orange dashed)
- Add sandbox2_brain_input.json geometry file
2026-02-17 17:14:11 +00:00
1a14f7c420
fix: v1 boundary handling — inset vertices, 3-point hole keepouts, boundary-aligned triangles, smooth plotting
...
- Triangulation: force inset boundary corner vertices for v1 geometry (Shapely buffer)
- Hole keepouts: 3 evenly-spaced points per circular hole (not dense polyline)
- Boundary layer: seed points derived from inset polygon for proper alignment
- Triangle filtering: full polygon coverage check against inset-valid region
- Plotting: uniform polyline resampling for smooth v1 boundaries, analytic circle rendering
- Verified: 0 bad triangles on both Quicksat sandboxes
2026-02-17 16:24:27 +00:00
139a355ef3
Add v2 geometry normalization and boundary-layer seed points
2026-02-17 14:37:13 +00:00
7d5bd33bb5
brain: add arc-aware inset boundary handling
2026-02-17 14:05:28 +00:00
18a8347765
feat: enforce Delaunay vertices at inset boundary corners + update geometry to v2.0 with arcs
...
- Add explicit corner vertices of the inset boundary (w_frame offset) to Delaunay point set
- This guarantees no triangle can cross a boundary corner
- Updated test_data geometry files to v2.0 format with typed segments
- Sandbox 2 now has proper arc curves (4 arc segments) from extract_sandbox
- Preserved holes from v1.0 geometry
- Boundary vertices also enforced on keepout boundaries
2026-02-17 13:41:24 +00:00
856ff239d6
fix: match reference rib profile style — green boundary, pink outlines, blue holes, 2mm w_frame, zoomed corner view, pocket clipping to inner plate
2026-02-17 12:56:58 +00:00
732e41ec3a
fix: clip pockets and triangulation to boundary in plots — no visual crossovers
2026-02-17 12:42:52 +00:00
39a3420a8e
Fix: skip pockets crossing sandbox boundary
...
profile_assembly.py now checks each pocket's polyline against the plate
boundary using Shapely contains(). Pockets extending outside are dropped.
Sandbox 1: 1 pocket removed (was crossing corner near x=150, y=-20).
2026-02-17 11:41:48 +00:00
03232be7b1
chore(hq): daily sync 2026-02-17
2026-02-17 10:00:15 +00:00
44a5b4aac5
import_profile: use structured pocket outlines (lines+arcs), not rib_web polylines
...
Reverts to drawing outer boundary + pocket outlines (3 lines + 3 arcs
per pocket) + bolt hole circles. These are the red curves from the
Brain plot. NX sketch regions between outer boundary and pocket/hole
outlines define the rib web material for extrusion.
The rib_web Shapely approach was wrong: it approximated arcs as dense
polylines, losing the clean geometry.
2026-02-17 03:10:32 +00:00
1badc370ab
Add rib_web to Brain output + import_profile draws rib material
...
Brain: profile_assembly.py now exports 'rib_web' — the actual material
geometry from Shapely boolean (exterior + interior rings). This is the
rib shape, not the pocket cutouts.
import_profile.py: prefers rib_web when available, drawing exterior +
interior polyline rings directly. Falls back to pocket-based drawing
for older rib JSONs without rib_web.
2026-02-17 03:02:15 +00:00
0bc0c24c1c
import_profile: draw bolt holes from rib profile JSON
...
Holes drawn as two 3-point arcs (semicircles) using center/diameter.
Both structured and legacy pocket formats supported.
2026-02-17 02:54:49 +00:00
f61616d76a
Update test_data rib profiles: sandbox_2 new geometry, re-run Brain for both
...
- sandbox_1: 75 pockets, 2315g mass estimate
- sandbox_2: 11 pockets (was 10), 371g mass estimate, updated geometry from NX
2026-02-17 02:45:19 +00:00
e07c26c6fe
test: save NX-exported v1.0 geometry for sandbox_1 (from Antoine)
2026-02-17 02:39:01 +00:00
68ebee7432
test: Brain profiles from latest geometry with mid-field arcs
2026-02-17 02:36:38 +00:00
dc34b7f6d5
fix: arc midpoint parsing + edge type detection for NX integer enums
...
- EvaluateUnitVectors returns nested lists — added recursive parser
- SolidEdgeType returns int 1 (not 'Linear') — handle both formats
2026-02-17 02:32:52 +00:00
b6dc15e19e
test: Brain-generated rib profiles from existing pipeline
...
Used existing src/brain/ module (density + Delaunay + pockets).
Sandbox 1: 75 pockets, 16 holes. Sandbox 2: 10 pockets, no holes.
Added v2→v1 geometry converter for Brain compatibility.
2026-02-17 02:26:05 +00:00
b411eaac25
fix: arc direction — sample midpoint from NX edge instead of cross-product
...
Cross product of (start-center) × (end-center) is zero for 180° arcs,
causing random clockwise assignment. Now samples actual midpoint via
UF Eval at t_mid, stores as 'mid' in JSON. Import prefers 'mid' over
computed clockwise direction.
2026-02-17 02:24:32 +00:00
e3a79d4888
feat: proper alternating up/down isogrid pattern with Shapely clipping
...
- Alternating up/down equilateral triangles filling full boundary
- buffer(-rib_w) for uniform rib spacing
- buffer(-fillet_r).buffer(+fillet_r) for rounded corners
- Clipped to actual boundary polygon
- Sandbox 2: 39 pockets (40mm), Sandbox 1: 112 pockets (60mm)
2026-02-17 02:17:24 +00:00
6d443df3ec
Remap channels: project-dashboard→feed, add #reports channel
2026-02-17 02:08:56 +00:00
d954b2b816
feat: proper isogrid pocket generation with boundary clipping + v2.0 outer boundary
...
- Equilateral triangle grid pattern
- Shapely polygon clipping to actual boundary shape
- v2.0 typed segments (arcs) for outer boundary
- 4mm fillets, 3mm ribs, 2mm frame offset
- Sandbox 1: 25 pockets (80mm), Sandbox 2: 8 pockets (50mm)
2026-02-17 02:08:01 +00:00
43aea01fb5
test: larger cells (120mm/75mm), 4mm fillets, 2mm frame — 9+2 pockets
2026-02-17 02:00:33 +00:00
709612ece4
test: regenerate rib profiles with 4mm fillets, no frame offset
2026-02-17 01:56:39 +00:00
b38194c4d9
test: add rib profile test JSONs for sandbox_1 (64 pockets) and sandbox_2 (9 pockets)
2026-02-17 01:54:48 +00:00
634bf611c9
fix: remove stale chord_tol_mm kwarg from main()
2026-02-17 01:49:24 +00:00
612a21f561
feat(adaptive-isogrid): preserve arcs as typed segments instead of polyline discretization
...
Schema v2.0: outer_boundary is now a list of typed segments:
- {type: 'line', start: [x,y], end: [x,y]}
- {type: 'arc', start: [x,y], end: [x,y], center: [x,y], radius: R, clockwise: bool}
Extract: detect arcs via UF Eval.IsArc/AskArc, output exact geometry.
Import: create NX sketch arcs (3-point) for arc segments, backward-compatible with v1.0 polylines.
2026-02-17 01:47:36 +00:00
abc7d5f013
fix(extract): increase chord tolerance to 1mm, cap at 500 pts/edge
...
0.1mm was generating thousands of unnecessary points on straight
edges. Now: 1mm default, 0.5mm minimum, 500 max per edge.
Curves still get proper sampling, straight edges stay lean.
2026-02-17 01:40:55 +00:00
c3125b458b
Add taskboard CLI tool for kanban orchestration (Phase 1 of plan 13)
2026-02-17 01:39:33 +00:00
cd7f7e8aa9
fix(extract): use EvaluateUnitVectors for parametric edge sampling
...
Available NXOpen.UF.Eval methods discovered:
- EvaluateUnitVectors(evaluator, t) - parametric point+tangent
- AskArc(evaluator) - arc center/radius for circular edges
- Initialize2, AskLimits, Free - evaluator lifecycle
Also logs arc data attributes for debugging.
2026-02-17 01:36:25 +00:00
fbdafb9a37
fix(extract): discover UF curve eval methods dynamically
...
NXOpen Python wraps UF methods with version-specific names.
Now dumps available methods on UF.Modl, UF.Eval, UF.Curve
and tries them in order. Detailed logging shows which method
was found and used, plus raw result format on parse failures.
2026-02-17 01:33:39 +00:00