Commit Graph

45618 Commits

Author SHA1 Message Date
418e947cbd Merge pull request 'fix(solver): world-anchored reference normal prevents planar axial drift' (#336) from fix/planar-halfspace-drag-flip into main
All checks were successful
Build and Test / build (push) Successful in 29m17s
Sync Silo Server Docs / sync (push) Successful in 34s
Reviewed-on: #336
2026-02-26 17:10:39 +00:00
4c9ff957e3 Merge branch 'main' into fix/planar-halfspace-drag-flip
All checks were successful
Build and Test / build (pull_request) Successful in 28m48s
2026-02-26 17:10:27 +00:00
9aaf244179 fix(solver): update solver submodule — world-anchored planar reference normal
All checks were successful
Build and Test / build (pull_request) Successful in 29m11s
Updates solver to include the fix for PlanarConstraint axial drift
when combined with CylindricalConstraint. The distance residual now
uses a world-frame reference normal (Const nodes) instead of the
body-attached normal that rotates with the body.
2026-02-26 11:07:06 -06:00
69ccdbf742 Merge pull request 'fix(assembly): use instance suffixes for duplicate part labels' (#335) from fix/assembly-part-number-suffix into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #335
2026-02-26 16:34:34 +00:00
4acd09171e Merge pull request 'fix(theme): prevent panel element headings from being clipped' (#334) from fix/theme-panel-heading-clipping into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #334
2026-02-26 16:34:17 +00:00
7f909f166f Merge pull request 'fix(ci): add target_commitish to release payload to fix HTTP 500' (#333) from fix/ci-release-target-commitish into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #333
2026-02-26 16:34:04 +00:00
f69e0efec7 Merge pull request 'docs: add CLAUDE.md for developer context' (#332) from docs/claude-md into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #332
2026-02-26 16:33:36 +00:00
forbes
559a240799 fix(assembly): update solver submodule — fix planar half-space drag flip
Some checks failed
Build and Test / build (pull_request) Has been cancelled
Updates mods/solver to include fix for the planar half-space correction
that caused 'flipped orientation' rejections when dragging a body
connected by a Cylindrical joint + distance=0 Planar constraint.

The solver's PlanarConstraint half-space tracker was reflecting the body
through the plane when the face normal dot product crossed zero during
legitimate rotation about the cylindrical axis. Now returns a tracking-
only HalfSpace (no correction) for on-plane constraints, matching the
pattern used by Cylindrical/Revolute/Concentric trackers.

See: kindred/solver#38
2026-02-26 09:04:14 -06:00
7c85b2ad93 fix(assembly): use instance suffixes for duplicate part labels
All checks were successful
Build and Test / build (pull_request) Successful in 29m11s
When parts with structured part numbers (e.g., P03-0001) are inserted
into an assembly multiple times, UniqueNameManager::decomposeName()
treats the trailing digits as an auto-generated suffix and increments
them (P03-0002, P03-0003), corrupting the part number.

Add a makeInstanceLabel() helper in AssemblyLink.cpp that appends -N
instance suffixes instead (P03-0001-1, P03-0001-2). All instances get
a suffix starting at -1 so the original part number is never modified.

Applied at all three Label.setValue() sites in
synchronizeComponents() (AssemblyLink, link group, and regular link
creation paths).

Also add a UniqueNameManager test documenting the trailing-digit
decomposition behavior for structured part numbers.

Closes #327
2026-02-26 09:00:13 -06:00
311d911cfa fix(theme): prevent panel element headings from being clipped
All checks were successful
Build and Test / build (pull_request) Successful in 29m23s
Three QSS issues caused headings to render with only the top ~60%
visible:

- QGroupBox: margin-top 12px was insufficient for the title rendered
  in subcontrol-origin: margin. Increased to 16px and added 2px
  vertical padding to the title.
- QDockWidget::title: min-height 18px conflicted with padding 8px 6px,
  constraining the content area. Removed min-height to let Qt auto-size
  from padding + font metrics.
- QSint--ActionGroup QToolButton: min-height 18px forced a height that
  was then clipped by the C++ setFixedHeight(headerSize) calculation.
  Set min-height to 0px so the C++ layout controls sizing.

Closes #325
2026-02-26 08:48:01 -06:00
4ef8e64a7c fix(ci): add target_commitish to release payload to fix HTTP 500
All checks were successful
Build and Test / build (pull_request) Successful in 29m30s
The publish-release job was missing the target_commitish field in the
Gitea release creation API payload. Without it, Gitea cannot resolve
the tag to a git object and returns HTTP 500 with 'object does not
exist'.

Add COMMIT_SHA (from github.sha) to the job env and pass it as
target_commitish in the JSON payload.

Closes #326
2026-02-26 08:45:58 -06:00
d94e8c8294 docs: add CLAUDE.md for developer context
All checks were successful
Build and Test / build (pull_request) Successful in 29m9s
2026-02-26 08:40:34 -06:00
3550d916bd Merge pull request 'docs(solver): update drag protocol docs to reflect implemented caching' (#330) from docs/solver-drag-cache into main
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 40s
Build and Test / build (push) Successful in 29m53s
Reviewed-on: #330
2026-02-26 14:25:17 +00:00
6e15b25134 docs(solver): update drag protocol docs to reflect implemented caching
All checks were successful
Build and Test / build (pull_request) Successful in 30m27s
The interactive drag section described the original naive implementation
(re-solve from scratch each step) and called the caching layer a
'planned future optimization'. In reality _DragCache is fully
implemented: pre_drag() builds the system, Jacobian, and compiled
evaluator once, and drag_step() reuses them.

Update code snippets, add _DragCache field table, and document the
single_equation_pass exclusion from the drag path.
2026-02-25 13:23:41 -06:00
82f2422285 Merge pull request 'fix(solver): skip single_equation_pass during drag to prevent stale constraints' (#329) from fix/planar-drag-prepass into main
Some checks failed
Build and Test / build (push) Has been cancelled
Sync Silo Server Docs / sync (push) Successful in 40s
Reviewed-on: #329
2026-02-25 19:03:16 +00:00
314955c3ef fix(solver): update solver submodule — skip prepass during drag
Some checks failed
Build and Test / build (pull_request) Has been cancelled
Updates solver submodule to include fix for planar distance=0
constraints not holding during drag operations.
2026-02-25 12:58:03 -06:00
c7a7436e7b Merge pull request 'chore: update solver submodule' (#328) from chore/update-solver-submodule into main
All checks were successful
Sync Silo Server Docs / sync (push) Successful in 38s
Build and Test / build (push) Successful in 30m20s
Reviewed-on: #328
2026-02-25 02:49:57 +00:00
forbes
40dd8e09d7 chore: update solver submodule
All checks were successful
Build and Test / build (pull_request) Successful in 29m42s
Picks up fix/drag-orientation-stability (kindred/solver#36):
- Half-space tracking for all compound constraints with branch ambiguity
- Quaternion continuity enforcement during interactive drag
2026-02-24 20:49:27 -06:00
1fd52ccf1c Merge pull request 'feat: add QuickNav addon — Phase 1 core infrastructure (#320)' (#324) from feat/quicknav-phase1 into main
All checks were successful
Deploy Docs / build-and-deploy (push) Successful in 46s
Build and Test / build (push) Successful in 29m41s
Reviewed-on: #324
2026-02-24 18:37:19 +00:00
e73c5fc750 feat: add QuickNav addon — Phase 1 core infrastructure (#320)
All checks were successful
Build and Test / build (pull_request) Successful in 29m58s
Add quicknav submodule and create-side integration for keyboard-driven
command navigation.

Submodule: mods/quicknav (https://git.kindred-systems.com/kindred/quicknav)

Create-side changes:
- CMakeLists.txt: add quicknav install rules
- test_kindred_pure.py: add 16 workbench_map validation tests
- docs/src/quicknav/SPEC.md: QuickNav specification

QuickNav provides numbered-key access to workbenches (Ctrl+1-5),
command groupings (Shift+1-9), and individual commands (1-9), with
a navigation bar toolbar and input-widget safety guards.
2026-02-23 14:12:02 -06:00
f652d6ccf8 Merge pull request 'fix(assembly): handle non-standard datum element types in Distance joint classification' (#319) from fix/datum-plane-classification-all-hierarchies into main
Some checks failed
Build and Test / build (push) Has been cancelled
Sync Silo Server Docs / sync (push) Successful in 37s
Reviewed-on: #319
2026-02-23 03:20:04 +00:00
forbes
14ee8c673f fix(assembly): classify datum planes from all class hierarchies in Distance joints
Some checks failed
Build and Test / build (pull_request) Has been cancelled
The datum plane detection in getDistanceType() only checked for
App::Plane (origin planes). This missed two other class hierarchies:

  - PartDesign::Plane (inherits Part::Datum, NOT App::Plane)
  - Part::Plane primitive referenced bare (no Face element)

Both produce empty element types (sub-name ends with ".") but failed
the isDerivedFrom<App::Plane>() check, falling through to
DistanceType::Other and the Planar fallback. This caused incorrect
constraint geometry, leading to conflicting/unsatisfiable constraints
and solver failures.

Add shape-based isDatumPlane/Line/Point helpers that cover all three
hierarchies by inspecting the actual OCCT geometry rather than relying
on class identity alone. Extend getDistanceType() to use these helpers
for all datum-vs-datum and datum-vs-element combinations.

Adds TestDatumClassification.py with tests for PartDesign::Plane,
Part::Plane (bare ref), and cross-hierarchy datum combinations.
2026-02-22 21:18:34 -06:00
a6a5db11f8 Merge pull request 'fix(assembly): classify datum planes from all class hierarchies in Distance joints' (#318) from fix/datum-plane-classification-all-hierarchies into main
All checks were successful
Build and Test / build (push) Successful in 31m20s
Reviewed-on: #318
2026-02-23 00:56:20 +00:00
forbes
962b521f5c fix(assembly): classify datum planes from all class hierarchies in Distance joints
All checks were successful
Build and Test / build (pull_request) Successful in 30m13s
The datum plane detection in getDistanceType() only checked for
App::Plane (origin planes). This missed two other class hierarchies:

  - PartDesign::Plane (inherits Part::Datum, NOT App::Plane)
  - Part::Plane primitive referenced bare (no Face element)

Both produce empty element types (sub-name ends with ".") but failed
the isDerivedFrom<App::Plane>() check, falling through to
DistanceType::Other and the Planar fallback. This caused incorrect
constraint geometry, leading to conflicting/unsatisfiable constraints
and solver failures.

Add shape-based isDatumPlane/Line/Point helpers that cover all three
hierarchies by inspecting the actual OCCT geometry rather than relying
on class identity alone. Extend getDistanceType() to use these helpers
for all datum-vs-datum and datum-vs-element combinations.

Adds TestDatumClassification.py with tests for PartDesign::Plane,
Part::Plane (bare ref), and cross-hierarchy datum combinations.
2026-02-22 18:55:39 -06:00
5c9212247a Merge pull request 'fix(assembly): add datum plane logging + fix cross-product singularity' (#317) from fix/distance-datum-plane-classification into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #317
2026-02-22 22:05:48 +00:00
forbes
cf0cd3db7e fix(assembly): classify datum plane references in Distance joints
Some checks failed
Build and Test / build (pull_request) Has been cancelled
When a Distance joint references a datum plane (XY_Plane, XZ_Plane,
YZ_Plane), getDistanceType() failed to recognize it because datum
plane sub-names yield an empty element type. This caused the fallback
to DistanceType::Other → BaseJointKind::Planar, which adds spurious
parallel-normal residuals that overconstrain the system.

For example, three vertex-to-datum-plane Distance joints produced
10 residuals (3×Planar) with 6 mutually contradictory orientation
constraints, causing the solver to find garbage least-squares
solutions.

Add early detection of App::Plane datum objects before the main
geometry classification chain. Datum planes are now correctly mapped:
- Vertex + DatumPlane → PointPlane → PointInPlane (1 residual)
- Edge + DatumPlane → LinePlane → LineInPlane
- Face/DatumPlane + DatumPlane → PlanePlane → Planar
2026-02-22 15:52:22 -06:00
50dc8c8ea1 Merge pull request 'fix(assembly): classify datum plane references in Distance joints' (#316) from fix/distance-datum-plane-classification into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #316
2026-02-22 20:21:07 +00:00
forbes
b4835e1b05 fix(assembly): classify datum plane references in Distance joints
Some checks failed
Build and Test / build (pull_request) Has been cancelled
When a Distance joint references a datum plane (XY_Plane, XZ_Plane,
YZ_Plane), getDistanceType() failed to recognize it because datum
plane sub-names yield an empty element type. This caused the fallback
to DistanceType::Other → BaseJointKind::Planar, which adds spurious
parallel-normal residuals that overconstrain the system.

For example, three vertex-to-datum-plane Distance joints produced
10 residuals (3×Planar) with 6 mutually contradictory orientation
constraints, causing the solver to find garbage least-squares
solutions.

Add early detection of App::Plane datum objects before the main
geometry classification chain. Datum planes are now correctly mapped:
- Vertex + DatumPlane → PointPlane → PointInPlane (1 residual)
- Edge + DatumPlane → LinePlane → LineInPlane
- Face/DatumPlane + DatumPlane → PlanePlane → Planar
2026-02-22 14:19:11 -06:00
cf2fc82eac Merge pull request 'fix(assembly): classify datum plane references in Distance joints' (#315) from fix/distance-datum-plane-classification into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #315
2026-02-22 18:25:32 +00:00
forbes
e5b07449d7 fix(assembly): classify datum plane references in Distance joints
Some checks failed
Build and Test / build (pull_request) Has been cancelled
When a Distance joint references a datum plane (XY_Plane, XZ_Plane,
YZ_Plane), getDistanceType() failed to recognize it because datum
plane sub-names yield an empty element type. This caused the fallback
to DistanceType::Other → BaseJointKind::Planar, which adds spurious
parallel-normal residuals that overconstrain the system.

For example, three vertex-to-datum-plane Distance joints produced
10 residuals (3×Planar) with 6 mutually contradictory orientation
constraints, causing the solver to find garbage least-squares
solutions.

Add early detection of App::Plane datum objects before the main
geometry classification chain. Datum planes are now correctly mapped:
- Vertex + DatumPlane → PointPlane → PointInPlane (1 residual)
- Edge + DatumPlane → LinePlane → LineInPlane
- Face/DatumPlane + DatumPlane → PlanePlane → Planar
2026-02-22 12:24:44 -06:00
58d98c6d92 Merge pull request 'fix(assembly): classify datum plane references in Distance joints' (#314) from fix/distance-datum-plane-classification into main
All checks were successful
Build and Test / build (push) Successful in 41m35s
Sync Silo Server Docs / sync (push) Successful in 34s
Reviewed-on: #314
2026-02-22 04:04:41 +00:00
forbes
a10b9d9a9f fix(assembly): classify datum plane references in Distance joints
All checks were successful
Build and Test / build (pull_request) Successful in 41m13s
When a Distance joint references a datum plane (XY_Plane, XZ_Plane,
YZ_Plane), getDistanceType() failed to recognize it because datum
plane sub-names yield an empty element type. This caused the fallback
to DistanceType::Other → BaseJointKind::Planar, which adds spurious
parallel-normal residuals that overconstrain the system.

For example, three vertex-to-datum-plane Distance joints produced
10 residuals (3×Planar) with 6 mutually contradictory orientation
constraints, causing the solver to find garbage least-squares
solutions.

Add early detection of App::Plane datum objects before the main
geometry classification chain. Datum planes are now correctly mapped:
- Vertex + DatumPlane → PointPlane → PointInPlane (1 residual)
- Edge + DatumPlane → LinePlane → LineInPlane
- Face/DatumPlane + DatumPlane → PlanePlane → Planar
2026-02-21 22:04:18 -06:00
forbes
d0e6d91642 chore: update solver submodule (drag step caching)
Some checks failed
Build and Test / build (push) Has been cancelled
2026-02-21 12:23:42 -06:00
forbes
05428f8a1c chore: bump version to 0.1.5
Some checks failed
Deploy Docs / build-and-deploy (push) Successful in 40s
Build and Test / build (push) Has been cancelled
2026-02-21 12:05:09 -06:00
forbes
14f314e137 chore: update solver submodule (distance=0 fix)
Some checks failed
Build and Test / build (push) Has been cancelled
2026-02-21 11:46:52 -06:00
forbes
30c35af3be chore: update solver submodule (compiled Jacobian evaluation)
Some checks are pending
Build and Test / build (push) Has started running
2026-02-21 11:42:48 -06:00
441cf9e826 Merge pull request 'feat(assembly): add diagnostic logging to solver and assembly' (#313) from feat/solver-diagnostic-logging into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #313
2026-02-21 16:11:34 +00:00
forbes
c682c5d153 feat(assembly): add diagnostic logging to solver and assembly
Some checks failed
Build and Test / build (pull_request) Has been cancelled
C++ (AssemblyObject):
- getOrCreateSolver: log which solver backend was loaded
- solve: log assembly name, grounded/joint counts, context size,
  result status with DOF and placement count, per-constraint
  diagnostics on failure
- preDrag/doDragStep/postDrag: log drag part count, per-step
  validation failures, and summary (total steps / rejected count)
- buildSolveContext: log grounded/free part counts, constraint count,
  limits count, and bundle_fixed flag

Python (kindred_solver submodule):
- solver.py: log solve entry/exit with timing, system build stats,
  decomposition decisions, Newton/BFGS fallback events, drag lifecycle
- decompose.py: log cluster stats and per-cluster convergence
- Init.py: FreeCAD log handler routing Python logging to Console
2026-02-21 10:08:51 -06:00
f65a4a5e2b Merge pull request 'fix(assembly): update flip-detection baseline during drag steps' (#312) from fix/assembly-drag-flip-detection into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #312
2026-02-21 15:59:55 +00:00
forbes
5d55f091d0 fix(assembly): update flip-detection baseline during drag steps
Some checks failed
Build and Test / build (pull_request) Has been cancelled
During drag operations, validateNewPlacements() compared each solver
result against the pre-drag positions saved once in preDrag().  As the
user dragged further, the cumulative rotation from that fixed baseline
easily exceeded the 91-degree threshold, causing valid intermediate
results to be rejected with 'flipped orientation' warnings and making
parts appear to explode.

Fix: call savePlacementsForUndo() after each accepted drag step so
that the flip check compares against the last accepted state rather
than the original pre-drag origin.
2026-02-21 09:59:04 -06:00
a445275fd2 Merge pull request 'fix(kc_format): eliminate duplicate silo/manifest.json in .kc files' (#311) from fix/kc-duplicate-manifest into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #311
2026-02-21 15:50:58 +00:00
forbes
88efa2a6ae fix(kc_format): eliminate duplicate silo/manifest.json entries in .kc files
Some checks failed
Build and Test / build (pull_request) Has been cancelled
Two code paths were appending silo/manifest.json to the ZIP without
removing the previous entry, causing Python's zipfile module to warn
about duplicate names:

1. slotFinishSaveDocument() re-injected the cached manifest from
   entries, then the modified_at update branch wrote a second copy.

2. update_manifest_fields() opened the ZIP in append mode and wrote
   an updated manifest without removing the old one.

Fix slotFinishSaveDocument() by preparing the final manifest (with
updated modified_at) in the entries dict before writing, so only one
copy is written to the ZIP.

Fix update_manifest_fields() by rewriting the ZIP atomically via a
temp file, deduplicating any pre-existing duplicate entries in the
process.
2026-02-21 09:49:36 -06:00
62f077a267 Merge pull request 'fix(assembly): prevent segfault when all joints are removed' (#310) from fix/assembly-empty-joints-segfault into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #310
2026-02-21 15:47:59 +00:00
forbes
b6b0ebb4dc fix(assembly): prevent segfault when all joints are removed
Some checks failed
Build and Test / build (pull_request) Has been cancelled
updateSolveStatus() calls solve() when lastResult_.placements is empty,
but solve() calls updateSolveStatus() at the end. When an assembly has
zero constraints (all joints removed), the solver returns zero
placements, causing infinite recursion until stack overflow (segfault).

Add a static re-entrancy guard so the recursive solve() call is skipped
if updateSolveStatus() is already on the call stack.
2026-02-21 09:47:15 -06:00
a6d0427639 Merge pull request 'fix(gui): resolve PartDesign toolbars and breadcrumb when editing body inside assembly' (#309) from fix/partdesign-context-in-assembly into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #309
2026-02-21 15:44:49 +00:00
forbes
5883ac8a0d fix(gui): resolve PartDesign toolbars and breadcrumb when editing body inside assembly
Some checks failed
Build and Test / build (pull_request) Has been cancelled
When double-clicking a PartDesign Body inside an Assembly, the editing
context resolver failed to show PartDesign toolbars or a proper
breadcrumb. Three root causes:

1. Priority preemption: assembly.edit (priority 90) always matched
   because the Assembly VP remained in edit mode, blocking all
   PartDesign contexts (priorities 30-40).

2. Wrong active-object key: PartDesign matchers only queried the
   "part" active object, but ViewProviderBody::toggleActiveBody()
   sets "part" to the containing App::Part (which is the Assembly
   itself). The Body is set under "pdbody", which was never queried.

3. Missing refresh trigger: ActiveObjectList::setObject() fires
   Document::signalActivatedViewProvider, but EditingContextResolver
   had no connection to it, so setActiveObject("pdbody", body) never
   triggered a context re-resolve.

Changes:
- Forward signalActivatedViewProvider from Gui::Document to
  Gui::Application (same pattern as signalInEdit/signalResetEdit)
- Connect EditingContextResolver to the new application-level signal
- Add getActivePdBodyObject() helper querying the "pdbody" key
- Add partdesign.in_assembly context (priority 95) that matches when
  a Body is active pdbody while an Assembly is in edit
- Update partdesign.body and partdesign.feature matchers to check
  pdbody before falling back to the part key
- Add Assembly > Body breadcrumb with Blue > Mauve coloring
- Update label resolution to prefer pdbody name
2026-02-21 09:43:51 -06:00
f9b13710f3 Merge pull request 'fix(solver): add networkx to runtime dependencies' (#308) from fix/solver-networkx-dep into main
Some checks failed
Build and Test / build (push) Has been cancelled
Reviewed-on: #308
2026-02-21 15:29:30 +00:00
forbes
39e78ee0a2 fix(solver): add networkx to runtime dependencies
All checks were successful
Build and Test / build (pull_request) Successful in 30m3s
The kindred-solver addon imports networkx in its decompose module.
Without it, KindredSolver fails to import and solver registration
silently fails, leaving only the ondsel backend available.
2026-02-21 09:24:30 -06:00
0f8fa0be86 Merge pull request 'feat(assembly): fixed reference planes (Top/Front/Right) + solver docs' (#307) from feat/assembly-origin-planes into main
Some checks failed
Deploy Docs / build-and-deploy (push) Successful in 51s
Build and Test / build (push) Has been cancelled
Reviewed-on: #307
2026-02-21 15:09:55 +00:00
forbes
acc255972d feat(assembly): fixed reference planes + solver docs
Some checks failed
Build and Test / build (pull_request) Failing after 7m52s
Assembly Origin Planes:
- AssemblyObject::setupObject() relabels origin planes to
  Top (XY), Front (XZ), Right (YZ) on assembly creation
- CommandCreateAssembly.py makes origin planes visible by default
- AssemblyUtils.cpp getObjFromRef() resolves LocalCoordinateSystem
  to child datum elements for joint references to origin planes
- TestAssemblyOriginPlanes.py: 9 integration tests covering
  structure, labels, grounding, reference resolution, solver,
  and save/load round-trip

Solver Documentation:
- docs/src/solver/: 7 new pages covering architecture overview,
  expression DAG, constraints, solving algorithms, diagnostics,
  assembly integration, and writing custom solvers
- docs/src/SUMMARY.md: added Kindred Solver section
2026-02-21 09:09:16 -06:00