Files
create/docs/INTEGRATION_PLAN.md
forbes 6c45f0619f Add integration plan for ztools and Silo workbenches
- Define 4-layer architecture (FreeCAD Core, Python API, Create Extensions, Workbenches)
- Plan src/Mod/Create/ module for C++ features (Create::FlipPocket, DatumHelpers)
- Document 6 implementation phases with priorities
- Use Create:: namespace prefix for all Kindred Create features
- Silo server distributed separately
- ztools/Silo versions pinned via git submodules
2026-01-27 09:36:25 -06:00

18 KiB

Kindred Create Integration Plan

This document outlines the strategy for integrating ztools and Silo workbenches as built-in addons in Kindred Create while maintaining clear boundaries with FreeCAD core.

Goals

  1. Native feel - ztools and Silo should feel like first-class citizens, not bolted-on addons
  2. Clean boundaries - Clear separation between FreeCAD core, Kindred extensions, and addon code
  3. Minimal core modifications - Preserve FreeCAD's container models (Part, Body, Assembly)
  4. Maintainability - Easy to pull upstream FreeCAD changes without merge conflicts
  5. Extensibility - Architecture that supports future Kindred-specific features

Current State

Repository Structure

kindred-create/
├── src/Mod/              # FreeCAD core modules (PartDesign, Sketcher, Assembly, etc.)
├── mods/                 # Kindred addons (git submodules)
│   ├── ztools/           # Part design extensions, theme
│   └── silo/             # Parts database integration
└── resources/            # Branding, default preferences

Integration Points Today

  • ztools: Pure Python addon wrapping FreeCAD commands with enhanced UX
  • Silo: Pure Python addon with REST API integration
  • Theme: Preference pack + runtime stylesheet application

Architecture Layers

┌─────────────────────────────────────────────────────────────────┐
│                     Kindred Create Application                   │
├─────────────────────────────────────────────────────────────────┤
│  Layer 4: Kindred Workbenches (mods/)                           │
│  ┌─────────────────────┐  ┌─────────────────────┐               │
│  │      ztools         │  │       Silo          │               │
│  │  - Datum Creator    │  │  - Open/Save/Commit │               │
│  │  - Enhanced Pocket  │  │  - Part numbering   │               │
│  │  - Assembly Patterns│  │  - Revision control │               │
│  │  - Spreadsheet fmt  │  │  - BOM management   │               │
│  └─────────────────────┘  └─────────────────────┘               │
├─────────────────────────────────────────────────────────────────┤
│  Layer 3: Kindred Core Extensions (src/Mod/Kindred/)            │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │  - KindredFeatures: Flip-side pocket, custom geometry ops   ││
│  │  - KindredGui: Shared UI components, selection helpers      ││
│  │  - Theme integration hooks                                  ││
│  └─────────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────────┤
│  Layer 2: FreeCAD Python API                                    │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │  FreeCAD, FreeCADGui, Part, PartDesign, Sketcher, Assembly  ││
│  └─────────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────────┤
│  Layer 1: FreeCAD Core (C++)                                    │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │  App::Document, Part::Feature, PartDesign::Body, etc.       ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

Boundary Definitions

Layer 1: FreeCAD Core (DO NOT MODIFY)

Location: src/Mod/PartDesign/App/, src/Mod/Part/App/, etc.

These are FreeCAD's fundamental data structures and should remain untouched:

  • PartDesign::Body - Feature container
  • PartDesign::Pocket, PartDesign::Pad - Additive/subtractive features
  • Part::Feature - Base geometric feature
  • App::Document - Document container
  • Sketcher::SketchObject - 2D constraint system

Rationale: Modifying these creates merge conflicts with upstream FreeCAD and risks breaking compatibility with existing FCStd files.

Layer 2: FreeCAD Python API (USE AS-IS)

Access via: import FreeCAD, import FreeCADGui, import Part, etc.

The Python API provides everything needed for feature creation:

  • Create objects: body.newObject("PartDesign::Pocket", "Pocket")
  • Set properties: pocket.Length = 10.0
  • Register commands: FreeCADGui.addCommand("Name", CommandClass())
  • Access geometry: shape.Faces, shape.Edges, shape.Vertexes

Layer 3: Kindred Core Extensions (NEW - MINIMAL)

Location: src/Mod/Kindred/ (to be created)

A thin C++ module providing capabilities that cannot be achieved in pure Python:

Component Purpose Justification
CreateFeatures Custom PartDesign-like features Python feature objects have performance limitations for complex boolean operations
CreateGui Shared UI utilities Common selection helpers, task panel base classes
ThemeHooks Theme application entry points Ensure theme applies before any workbench loads

Namespace: All Kindred Create features use the Create:: prefix (e.g., Create::FlipPocket).

Design principle: Only add C++ code when Python cannot achieve the requirement. Document why each component exists.

Layer 4: Kindred Workbenches (ADDON PATTERN)

Location: mods/ztools/, mods/silo/

Pure Python workbenches following FreeCAD's addon pattern:

  • Self-contained with InitGui.py, Init.py, package.xml
  • Register commands via FreeCADGui.addCommand()
  • Define toolbars/menus via Workbench.appendToolbar()
  • Can be developed/tested independently

Detailed Integration Plan

Phase 1: Addon Auto-Loading

Goal: ztools and Silo load automatically without user intervention.

Implementation:

  1. Create addon manifest (src/Mod/Kindred/addons.json):
{
  "builtin_addons": [
    {
      "name": "ztools",
      "path": "mods/ztools/ztools",
      "autoload": true,
      "workbench": "ZToolsWorkbench"
    },
    {
      "name": "silo", 
      "path": "mods/silo/pkg/freecad",
      "autoload": true,
      "workbench": "SiloWorkbench"
    }
  ]
}
  1. Modify addon path discovery (src/Mod/Kindred/Init.py):
# Add mods/ directory to FreeCAD's module search path
import FreeCAD
import os

mods_dir = os.path.join(FreeCAD.getHomePath(), "mods")
if os.path.isdir(mods_dir):
    for addon in os.listdir(mods_dir):
        addon_path = os.path.join(mods_dir, addon)
        if os.path.isdir(addon_path) and addon_path not in sys.path:
            sys.path.insert(0, addon_path)
  1. Set default workbench in preferences:
<!-- resources/preferences/KindredCreate/KindredCreate.cfg -->
<FCText Name="StartUpModule">ZToolsWorkbench</FCText>

Files to create/modify:

  • Create: src/Mod/Kindred/Init.py
  • Create: src/Mod/Kindred/InitGui.py
  • Create: src/Mod/Kindred/CMakeLists.txt
  • Modify: src/Mod/CMakeLists.txt (add Kindred subdirectory)
  • Modify: resources/preferences/KindredCreate/KindredCreate.cfg

Phase 2: Enhanced Pocket as Separate Feature

Goal: "Flip Side to Cut" becomes a proper feature, not a command wrapper.

Current state (in ztools):

# ztools/commands/pocket_commands.py
class ZTools_EnhancedPocket:
    def Activated(self):
        # Creates standard Pocket, then applies boolean Common
        # Workaround using existing features

Proposed architecture:

src/Mod/Create/
├── App/
│   ├── CreateFeatures.cpp       # Feature implementations
│   ├── FeatureFlipPocket.cpp    # Flip-side pocket feature
│   └── FeatureFlipPocket.h
├── Gui/
│   ├── Command.cpp              # Command registrations
│   ├── TaskFlipPocket.cpp       # Task panel
│   └── ViewProviderFlipPocket.cpp
└── CMakeLists.txt

Feature design (Create::FlipPocket):

// Inherits from PartDesign::ProfileBased (same base as Pocket)
class FeatureFlipPocket : public PartDesign::ProfileBased {
public:
    // Properties (same as Pocket, plus flip flag)
    App::PropertyLength Length;
    App::PropertyEnumeration Type;  // Dimension, ThroughAll, ToFirst, UpToFace
    App::PropertyBool Symmetric;
    App::PropertyBool FlipSide;     // NEW: Cut outside instead of inside
    
    // Implementation uses Boolean Common instead of Cut when FlipSide=true
    App::DocumentObjectExecReturn* execute();
};

Separation of concerns:

  • FreeCAD Core (PartDesign::Pocket): Standard inside-cut behavior, unchanged
  • Create Extension (Create::FlipPocket): Outside-cut using boolean common
  • ztools Workbench: Provides UI command that creates Create::FlipPocket

Files to create:

  • src/Mod/Create/App/FeatureFlipPocket.cpp
  • src/Mod/Create/App/FeatureFlipPocket.h
  • src/Mod/Create/Gui/TaskFlipPocket.cpp
  • src/Mod/Create/Gui/ViewProviderFlipPocket.cpp

ztools update:

# mods/ztools/ztools/commands/pocket_commands.py
class ZTools_EnhancedPocket:
    def Activated(self):
        # Now creates Create::FlipPocket instead of workaround
        body = FreeCADGui.ActiveDocument.ActiveView.getActiveObject("pdbody")
        pocket = body.newObject("Create::FlipPocket", "FlipPocket")
        pocket.Profile = sketch
        # Show task panel...

Phase 3: Datum System Integration

Goal: ztools datum creation uses stable, efficient C++ geometry calculations.

Current state: Pure Python geometry calculations in ztools/datums/core.py.

Issue: Python geometry operations can be slow and less precise for complex cases.

Proposed solution: Create C++ helper functions, expose via Python.

// src/Mod/Create/App/DatumHelpers.cpp
namespace Create {
    // Calculate midplane between two parallel faces
    gp_Pln computeMidplane(const TopoDS_Face& face1, const TopoDS_Face& face2);
    
    // Calculate plane through three points
    gp_Pln computePlaneFrom3Points(gp_Pnt p1, gp_Pnt p2, gp_Pnt p3);
    
    // Calculate axis at cylinder center
    gp_Ax1 computeCylinderAxis(const TopoDS_Face& cylinderFace);
    
    // ... other datum calculations ...
}

Python binding:

# In ztools after Create module is available
from Create import DatumHelpers

plane = DatumHelpers.computeMidplane(face1, face2)

Separation of concerns:

  • FreeCAD Core (PartDesign::DatumPlane): Data structure, unchanged
  • Create Extension (DatumHelpers): Geometry calculation utilities
  • ztools Workbench: UI, selection handling, property storage

Phase 4: Theme System Refinement

Goal: Theme applies consistently at startup, no workbench dependency.

Current state: Theme applied when ztools workbench activates.

Issue: If user opens FreeCAD and doesn't activate ztools, theme isn't applied.

Proposed solution:

  1. Move theme to Create module (src/Mod/Create/InitGui.py):
# This runs at GUI startup, before any workbench
def applyKindredTheme():
    from PySide import QtWidgets
    qss_path = os.path.join(FreeCAD.getResourceDir(), 
                            "preferences", "KindredCreate", "KindredCreate.qss")
    with open(qss_path) as f:
        QtWidgets.QApplication.instance().setStyleSheet(f.read())
    
    # Apply spreadsheet colors
    applySpreadsheetColors()

# Run at import time
applyKindredTheme()
  1. Remove theme code from ztools: ztools focuses on commands, not theming.

  2. Ensure load order: Create module loads before other workbenches via src/Mod/CMakeLists.txt ordering.

Phase 5: Silo Deep Integration

Goal: Silo commands available globally, not just in Silo workbench.

Current state: Must switch to Silo workbench to access commands.

Proposed solution:

  1. Global menu registration (src/Mod/Create/InitGui.py):
def setupSiloMenu():
    # Add Silo menu to menu bar regardless of active workbench
    import silo_commands
    
    mw = FreeCADGui.getMainWindow()
    menuBar = mw.menuBar()
    
    siloMenu = QtWidgets.QMenu("Silo", mw)
    menuBar.addMenu(siloMenu)
    
    for cmd in ["Silo_Open", "Silo_Save", "Silo_Commit", "Silo_Pull", "Silo_Push"]:
        action = FreeCADGui.Command.get(cmd).getAction()
        siloMenu.addAction(action[0])
  1. Keyboard shortcuts (global):
# Ctrl+Shift+O: Silo Open
# Ctrl+Shift+S: Silo Save  
# Ctrl+Shift+C: Silo Commit
  1. Status bar integration: Show current Silo item info in status bar.

Phase 6: Build System Integration

Goal: mods/ submodules installed correctly during build.

Implementation (src/Mod/Create/CMakeLists.txt):

# Install ztools workbench
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/ztools/ztools
        DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/ztools)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/ztools/CatppuccinMocha
        DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/ztools)
install(FILES ${CMAKE_SOURCE_DIR}/mods/ztools/package.xml
        DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/ztools)

# Install Silo workbench
install(DIRECTORY ${CMAKE_SOURCE_DIR}/mods/silo/pkg/freecad/
        DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/Silo)

File Organization Summary

New files to create

src/Mod/Create/                     # NEW: Kindred Create core extensions
├── CMakeLists.txt
├── Init.py                         # Addon path setup
├── InitGui.py                      # Theme application, global menus
├── App/
│   ├── CMakeLists.txt
│   ├── CreateModule.cpp            # Module registration
│   ├── FeatureFlipPocket.cpp/h     # Flip-side pocket feature
│   └── DatumHelpers.cpp/h          # Datum geometry utilities
└── Gui/
    ├── CMakeLists.txt
    ├── CreateGuiModule.cpp
    ├── Command.cpp                 # Create-specific commands
    ├── TaskFlipPocket.cpp/h
    └── ViewProviderFlipPocket.cpp/h

Files to modify

File Change
src/Mod/CMakeLists.txt Add add_subdirectory(Create)
resources/preferences/KindredCreate/KindredCreate.cfg Set default workbench
mods/ztools/ztools/commands/pocket_commands.py Use Create::FlipPocket
mods/ztools/ztools/datums/core.py Use Create.DatumHelpers when available

Files to remove/deprecate from ztools

File Reason
ztools/resources/theme.py Moved to Create module
Theme application in InitGui.py Handled globally

Implementation Priority

Priority Phase Effort Impact
1 Phase 1: Addon Auto-Loading Low High - Seamless user experience
2 Phase 4: Theme System Low High - Consistent appearance
3 Phase 5: Silo Global Menu Medium High - Always-available database access
4 Phase 2: Enhanced Pocket High Medium - Proper feature architecture
5 Phase 3: Datum Helpers Medium Medium - Performance improvement
6 Phase 6: Build System Low High - Clean distribution

Testing Strategy

Unit Tests

  • Create feature creation and execution
  • Datum helper calculations
  • Theme application verification

Integration Tests

  • Addon auto-loading on fresh install
  • Feature creation via ztools commands
  • Silo operations with mock server
  • Theme persistence across sessions

Compatibility Tests

  • Open existing FCStd files (no regressions)
  • Export to STEP/IGES (geometry unchanged)
  • Upstream FreeCAD file compatibility

Migration Notes

For existing ztools/silo users

  • No changes required - workbenches continue to function
  • Enhanced features available automatically when Create module present
  • Theme applies globally instead of per-workbench

For developers

  • ztools can check for Create module availability:
try:
    import Create
    HAS_CREATE = True
except ImportError:
    HAS_CREATE = False

# Use C++ implementation if available, fall back to Python
if HAS_CREATE:
    plane = Create.DatumHelpers.computeMidplane(f1, f2)
else:
    plane = compute_midplane_python(f1, f2)

Design Decisions

  1. Naming convention: Kindred Create features use the Create:: prefix (e.g., Create::FlipPocket, Create::DatumHelpers) to clearly identify them as Kindred Create extensions separate from FreeCAD core.

  2. Upstream contribution: Kindred Create is a standalone product and does not plan to contribute features upstream to FreeCAD. This allows for divergent design decisions optimized for Kindred Create's target use cases.

  3. Silo server distribution: Silo server is distributed separately from Kindred Create. Users download and deploy the Silo server independently. Setup instructions are documented in mods/silo/README.md.

  4. Version synchronization: ztools and Silo versions are determined by pinned git submodule commits. Updates are deliberate and tested before each Kindred Create release. To update:

    cd mods/ztools && git pull origin main && cd ../..
    git add mods/ztools && git commit -m "Update ztools to <version>"