Skip to content

Commit 68eb6e2

Browse files
author
Your Name
committed
refactor: restructure packages into domain-specific modules
microfinity: - microfinity.core.constants -> microfinity.spec.constants - microfinity.core.base -> microfinity.parts.base - microfinity.core.helpers -> microfinity.cq.helpers - microfinity.core.export -> microfinity.cq.export - microfinity.core.spec -> microfinity.spec.loader meshcutter: - meshcutter.core.* -> meshcutter.{pipeline,cutter,detection,mesh}.* - meshcutter.core.constants -> meshcutter.constants - meshcutter.core.replace_base -> meshcutter.pipeline.replace_base - meshcutter.core.detection -> meshcutter.detection.footprint - meshcutter.core.boolean -> meshcutter.mesh.boolean Also: - Delete legacy microfinity/scripts/ CLI entry points - Move tests into package directories - Consolidate shared CadQuery utilities in microfinity.cq
1 parent 62f970b commit 68eb6e2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+432
-1756
lines changed

CLAUDE.md

Lines changed: 87 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,65 @@ This file provides context for Claude when working on this project.
99
1. **microfinity/** - CadQuery-based generator for boxes, baseplates, and spacers
1010
2. **meshcutter/** - Mesh-based tool to convert 1U Gridfinity boxes to micro-divided feet
1111

12+
## Package Structure
13+
14+
### microfinity/
15+
```
16+
microfinity/
17+
├── __init__.py # Package exports and version
18+
├── py.typed # PEP 561 marker
19+
├── cli/ # CLI commands
20+
│ ├── main.py # Unified CLI entry point
21+
│ └── debug.py # Debug subcommands
22+
├── spec/ # Gridfinity specifications
23+
│ ├── loader.py # YAML spec loading
24+
│ └── constants.py # Derived constants
25+
├── cq/ # CadQuery utilities (shared)
26+
│ ├── compat.py # ZLEN_FIX version detection
27+
│ ├── extrude.py # extrude_profile()
28+
│ ├── helpers.py # Geometry helpers
29+
│ └── export.py # STEP/STL/SVG export
30+
├── parts/ # Gridfinity objects
31+
│ ├── base.py # GridfinityObject base class
32+
│ ├── box.py # GridfinityBox
33+
│ ├── baseplate.py # GridfinityBaseplate
34+
│ ├── baseplate_layout.py
35+
│ └── drawer.py # GridfinityDrawerSpacer
36+
├── calibration/ # Calibration prints
37+
│ └── test_prints.py
38+
└── tests/ # Package tests
39+
```
40+
41+
### meshcutter/
42+
```
43+
meshcutter/
44+
├── __init__.py # Package exports
45+
├── py.typed # PEP 561 marker
46+
├── constants.py # Re-exports + meshcutter-specific
47+
├── cli/ # CLI commands
48+
│ └── meshcut.py
49+
├── pipeline/ # Main conversion pipelines
50+
│ └── replace_base.py
51+
├── cutter/ # Cutter geometry generation
52+
│ ├── base.py # generate_cutter()
53+
│ ├── cq.py # CadQuery cutter generation
54+
│ ├── foot.py # Micro-foot generation
55+
│ └── grid.py # Grid/offset calculations
56+
├── detection/ # Mesh analysis
57+
│ ├── footprint.py # Bottom frame detection
58+
│ └── validation.py # Geometry validation
59+
├── mesh/ # Mesh operations
60+
│ ├── convert.py # Trimesh/Manifold conversions
61+
│ ├── boolean.py # Boolean operations
62+
│ ├── geometry.py # 2D geometry helpers
63+
│ ├── grid.py # Grid mask generation
64+
│ └── profile.py # Profile constants
65+
├── io/ # File I/O
66+
│ ├── loader.py
67+
│ └── exporter.py
68+
└── tests/ # Package tests
69+
```
70+
1271
## Key Architecture Decisions
1372

1473
### Meshcutter: Replace-Base Approach
@@ -21,11 +80,10 @@ The meshcutter uses a **replace-base pipeline** (not boolean subtraction) to con
2180

2281
This produces geometry **identical** to natively-generated micro boxes (<1mm³ difference).
2382

24-
**Important**: The legacy boolean subtraction approach has been deprecated and removed.
25-
2683
### Gridfinity Constants
2784

28-
All Gridfinity constants should come from `meshcutter/core/constants.py`, which re-exports from `microfinity.core.constants`.
85+
All Gridfinity constants should come from `microfinity.spec.constants`, which loads from YAML specs.
86+
Meshcutter re-exports these via `meshcutter.constants`.
2987

3088
Key values:
3189
- `GRU = 42.0` - 1U pitch (mm)
@@ -34,52 +92,41 @@ Key values:
3492
- `GR_BASE_CLR = 0.25` - Clearance above foot
3593
- `Z_SPLIT_HEIGHT = 5.0` - Where we cut between top and base
3694

37-
## Important Files
95+
### Shared CadQuery Utilities
3896

39-
### Core Modules
40-
- `meshcutter/core/replace_base.py` - Main replace-base pipeline
41-
- `meshcutter/core/constants.py` - Centralized constants
42-
- `meshcutter/core/mesh_utils.py` - Mesh conversion utilities
43-
- `meshcutter/core/cq_utils.py` - CadQuery utilities
44-
- `meshcutter/core/grid_utils.py` - Grid/offset calculations
97+
All CadQuery utilities live in `microfinity.cq/`:
98+
- `ZLEN_FIX` detection - single source of truth
99+
- `extrude_profile()` - shared by both packages
100+
- Export utilities (STEP/STL/SVG)
45101

46-
### CLI
47-
- `meshcutter/cli/meshcut.py` - Command-line interface
102+
Meshcutter imports from `microfinity.cq` instead of duplicating.
103+
104+
## Testing
48105

49-
### Tests
50-
- `tests/test_meshcutter/test_golden.py` - Golden comparison tests
51-
- `tests/test_meshcutter/golden_utils.py` - Test utilities
106+
### Running Tests
107+
```bash
108+
# All tests
109+
pytest -v
52110

53-
## Refactoring Tracking
111+
# Microfinity tests only
112+
pytest microfinity/tests/ -v
54113

55-
**IMPORTANT**: When completing refactoring tasks, update `REFACTOR_TODO.md` to mark items as complete.
114+
# Meshcutter tests only
115+
pytest meshcutter/tests/ -v
56116

57-
The refactoring TODO file tracks:
58-
- DRY elimination (utility modules)
59-
- Module updates
60-
- Test creation
61-
- CI setup
117+
# Shared/integration tests
118+
pytest tests/ -v
62119

63-
## Testing
120+
# Skip slow golden tests
121+
pytest -v -m "not golden"
122+
```
64123

65124
### Golden Tests
66125
Golden tests compare meshcutter output against microfinity-generated references:
67126
- Reference meshes are generated on-demand (not stored)
68127
- Acceptance threshold: <1mm³ total geometric difference
69128
- Test configurations: 1x1x1, 2x3x2, 1x1x3, 3x3x1
70129

71-
### Running Tests
72-
```bash
73-
# All meshcutter tests
74-
pytest tests/test_meshcutter/ -v
75-
76-
# Just golden tests
77-
pytest tests/test_meshcutter/test_golden.py -v
78-
79-
# Quick unit tests (skip slow golden tests)
80-
pytest tests/test_meshcutter/ -v -m "not golden"
81-
```
82-
83130
## Code Style
84131

85132
- **Line length**: 120 characters (configured in pyproject.toml)
@@ -90,16 +137,16 @@ pytest tests/test_meshcutter/ -v -m "not golden"
90137
## Common Tasks
91138

92139
### Adding a New Micro-Division Size
93-
1. Update `meshcutter/core/grid_utils.py` if offset calculations change
94-
2. Add test configuration to `tests/test_meshcutter/test_golden.py`
140+
1. Update `meshcutter/cutter/grid.py` if offset calculations change
141+
2. Add test configuration to `meshcutter/tests/test_golden.py`
95142
3. Update `docs/TODO_FUTURE_DIVISIONS.md`
96143

97144
### Updating Constants
98-
1. Check if constant exists in `microfinity.core.constants`
99-
2. If yes, re-export in `meshcutter/core/constants.py`
145+
1. Check if constant exists in `microfinity.spec.constants`
146+
2. If yes, re-export in `meshcutter/constants.py`
100147
3. If no, add to meshcutter-specific section
101148

102149
### Debugging Mesh Issues
103-
1. Use `mesh_utils.get_mesh_diagnostics()` for mesh info
150+
1. Use `meshcutter.mesh.convert.get_mesh_diagnostics()` for mesh info
104151
2. Export intermediate meshes with `mesh.export('/tmp/debug.stl')`
105152
3. View in external tool (MeshLab, Blender)

lefthook.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ pre-commit:
88
lint-fix:
99
glob: "*.py"
1010
run: black {staged_files} && git add {staged_files}
11+
flake8:
12+
glob: "*.py"
13+
fail_text: "Lint warnings found (non-blocking)"
14+
run: flake8 {staged_files} --max-line-length=120 --extend-ignore=E203,W503,F401,F403,F405,E402,F821,W293,W605,F841 || true
1115

1216
commit-msg:
1317
commands:

meshcutter/__init__.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
#! /usr/bin/env python3
2-
#
3-
# meshcutter - Gridfinity mesh profile cutter
4-
#
5-
# Cut gridfinity micro-division profiles into existing STL/3MF models
6-
# using mesh boolean operations.
7-
#
8-
# Part of the microfinity package - shares version with microfinity.
9-
#
2+
"""
3+
meshcutter - Gridfinity mesh profile cutter.
4+
5+
Cut gridfinity micro-division profiles into existing STL/3MF models
6+
using mesh boolean operations.
7+
8+
Part of the microfinity package - shares version with microfinity.
9+
"""
1010

1111
from microfinity import __version__
1212

13-
from meshcutter.core.detection import detect_bottom_frame, extract_footprint
14-
from meshcutter.core.grid import generate_grid_mask, compute_grid_positions
15-
from meshcutter.core.cutter import generate_cutter
16-
from meshcutter.core.boolean import boolean_difference, repair_mesh
13+
from meshcutter.detection import detect_bottom_frame, extract_footprint
14+
from meshcutter.mesh import generate_grid_mask, compute_grid_positions, boolean_difference, repair_mesh
15+
from meshcutter.cutter import generate_cutter
1716
from meshcutter.io.loader import load_mesh
1817
from meshcutter.io.exporter import export_stl
1918

meshcutter/cli/meshcut.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@
1818
from pathlib import Path
1919

2020
from meshcutter import __version__
21-
from meshcutter.core.constants import (
21+
from meshcutter.constants import (
2222
GR_BASE_HEIGHT,
2323
COPLANAR_EPSILON,
2424
MIN_COMPONENT_FACES,
2525
MIN_SLIVER_SIZE,
2626
MIN_SLIVER_VOLUME,
2727
GRU,
2828
)
29-
from meshcutter.core.detection import detect_aligned_frame
30-
from meshcutter.core.foot_cutter import generate_microgrid_cutter, convert_to_micro_feet
31-
from meshcutter.core.boolean import (
29+
from meshcutter.detection.footprint import detect_aligned_frame
30+
from meshcutter.cutter.foot import generate_microgrid_cutter, convert_to_micro_feet
31+
from meshcutter.mesh.boolean import (
3232
boolean_difference,
3333
validate_boolean_inputs,
3434
check_manifold3d_available,
@@ -508,7 +508,7 @@ def run_meshcut(args: argparse.Namespace) -> None:
508508
print(f" Footprint: {width:.1f} x {height:.1f} mm")
509509

510510
# Infer cell count
511-
from meshcutter.core.foot_cutter import detect_cell_centers
511+
from meshcutter.cutter.foot import detect_cell_centers
512512

513513
centers = detect_cell_centers(footprint, GRU)
514514
cells_x = int(round((width + 0.5) / GRU))
@@ -573,7 +573,7 @@ def run_meshcut(args: argparse.Namespace) -> None:
573573

574574
# Validate cutter geometry (detect internal faces / stacked sheets)
575575
if not args.no_validate:
576-
from meshcutter.core.validation import validate_cutter_geometry, CutterValidationError
576+
from meshcutter.detection.validation import validate_cutter_geometry, CutterValidationError
577577

578578
if args.verbose:
579579
print("Validating cutter geometry...", end=" ", flush=True)
Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
#! /usr/bin/env python3
2-
#
3-
# meshcutter.core.constants - Centralized Gridfinity constants
4-
#
5-
# Re-exports constants from microfinity.core.constants for consistency,
6-
# plus meshcutter-specific constants for the replace-base pipeline.
2+
"""
3+
meshcutter.constants - Centralized Gridfinity constants.
4+
5+
Re-exports constants from microfinity.spec.constants for consistency,
6+
plus meshcutter-specific constants for the replace-base pipeline.
7+
"""
78

89
from __future__ import annotations
910

1011
# Re-export Gridfinity constants from microfinity
11-
from microfinity.core.constants import (
12+
from microfinity.spec.constants import (
1213
GRU, # 42.0 - 1U pitch (mm)
1314
GR_TOL, # 0.5 - Clearance between feet (mm)
1415
GR_RAD, # 4.0 - Nominal exterior fillet radius (mm)
@@ -25,20 +26,18 @@
2526
# -----------------------------------------------------------------------------
2627

2728
# Z_SPLIT_HEIGHT is the plane where we cut between top (kept) and base (replaced)
28-
# z_split = z_min + GR_BASE_HEIGHT + GR_BASE_CLR = z_min + 5.0mm
2929
Z_SPLIT_HEIGHT: float = GR_BASE_HEIGHT + GR_BASE_CLR # 4.75 + 0.25 = 5.0mm
3030

3131
# SLEEVE_HEIGHT - how far the new base extends ABOVE z_split for overlap
32-
# This is critical: overlap ensures robust union (no coplanar faces)
3332
SLEEVE_HEIGHT: float = 0.5 # mm
3433

3534
# COPLANAR_EPSILON - offset to avoid coplanar geometry issues in booleans
3635
COPLANAR_EPSILON: float = 0.02 # mm
3736

3837
# Mesh cleanup thresholds
3938
MIN_COMPONENT_FACES: int = 100 # Minimum faces to keep a component
40-
MIN_SLIVER_SIZE: float = 0.001 # 1 µm - any dimension smaller is suspicious
41-
MIN_SLIVER_VOLUME: float = 1e-12 # mm³ - volumes below this are effectively zero
39+
MIN_SLIVER_SIZE: float = 0.001 # 1 micron
40+
MIN_SLIVER_VOLUME: float = 1e-12 # mm^3
4241

4342
# Golden test acceptance threshold
44-
MAX_VOLUME_DIFF_MM3: float = 1.0 # Maximum acceptable difference in mm³
43+
MAX_VOLUME_DIFF_MM3: float = 1.0 # mm^3

meshcutter/core/__init__.py

Lines changed: 0 additions & 25 deletions
This file was deleted.

meshcutter/cutter/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#! /usr/bin/env python3
2+
"""
3+
meshcutter.cutter - Cutter geometry generation.
4+
5+
Provides functions for generating micro-foot cutters using CadQuery.
6+
"""
7+
8+
from meshcutter.cutter.base import generate_cutter
9+
from meshcutter.cutter.grid import micro_foot_offsets_single_cell, micro_foot_offsets_grid, detect_cell_centers
10+
11+
__all__ = [
12+
"generate_cutter",
13+
"micro_foot_offsets_single_cell",
14+
"micro_foot_offsets_grid",
15+
"detect_cell_centers",
16+
]
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#! /usr/bin/env python3
22
#
3-
# meshcutter.core.cutter - 2D to 3D extrusion for cutter mesh generation
3+
# meshcutter.cutter - 2D to 3D extrusion for cutter mesh generation
44
#
55

66
from __future__ import annotations
@@ -12,8 +12,8 @@
1212
from shapely.geometry import Polygon, MultiPolygon
1313
from shapely.ops import unary_union
1414

15-
from meshcutter.core.detection import BottomFrame
16-
from meshcutter.core.profile import CutterProfile, get_profile, PROFILE_RECTANGULAR
15+
from meshcutter.detection.footprint import BottomFrame
16+
from meshcutter.mesh.profile import CutterProfile, get_profile, PROFILE_RECTANGULAR
1717

1818

1919
# Penetration below the bottom plane to avoid coplanar boolean degeneracy.

0 commit comments

Comments
 (0)