From 949a9ffc7d5ef99e44ae834e1fa31ca83563c26f Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Fri, 6 Mar 2026 22:50:27 -0500 Subject: [PATCH] chore: remove rotating calipers design plan Co-Authored-By: Claude Opus 4.6 --- .../2026-03-06-rotating-calipers-design.md | 88 ------------------- 1 file changed, 88 deletions(-) delete mode 100644 docs/plans/2026-03-06-rotating-calipers-design.md diff --git a/docs/plans/2026-03-06-rotating-calipers-design.md b/docs/plans/2026-03-06-rotating-calipers-design.md deleted file mode 100644 index eb959cb..0000000 --- a/docs/plans/2026-03-06-rotating-calipers-design.md +++ /dev/null @@ -1,88 +0,0 @@ -# Rotating Calipers for Optimal Rotation - -## Problem - -The current `FindBestRotation` is brute-force: it samples rotations at fixed `stepAngle` intervals and returns the angle with the smallest axis-aligned bounding box area. This is O(n * s) where s = number of step samples, and it can miss the true optimum between samples. - -## Solution - -Replace it with the **rotating calipers algorithm**, which finds the exact minimum bounding rectangle of a convex polygon in O(n log n) time (dominated by hull computation). The algorithm exploits the fact that the minimum-area bounding rectangle of a convex polygon must have one side flush with a hull edge. - -## New Files - -### 1. `OpenNest.Core/Geometry/ConvexHull.cs` - -- Static class in `namespace OpenNest.Geometry` -- `Compute(IList points)` returns a `Polygon` (convex hull) -- Algorithm: Andrew's monotone chain -- O(n log n), numerically stable -- Returns vertices in counter-clockwise order (consistent with existing `Polygon` conventions) - -### 2. `OpenNest.Core/Geometry/RotatingCalipers.cs` - -- Static class in `namespace OpenNest.Geometry` -- Primary method: `MinimumBoundingRectangle(Polygon convexHull)` returns `BoundingRectangleResult` -- Overloads: - - `MinimumBoundingRectangle(Polygon hull, double startAngle, double endAngle)` -- filters candidates to constraint range, evaluates range boundaries as fallback - - `MinimumBoundingRectangle(IList points)` -- convenience overload that computes hull internally -- Optimization target: minimum area by default; result contains both dimensions so callers can choose minimum width - -### 3. `BoundingRectangleResult` (in `RotatingCalipers.cs`) - -```csharp -public class BoundingRectangleResult -{ - public double Angle { get; } // Optimal rotation in radians - public double Width { get; } // Rectangle width at optimal angle - public double Height { get; } // Rectangle height at optimal angle - public double Area { get; } // Width * Height -} -``` - -## Modified Files - -### 4. `OpenNest.Core/Geometry/Entity.cs` - -- Change `FindBestRotation` extension method signature: - - Old: `double FindBestRotation(this List entities, double stepAngle, ...)` - - New: `BoundingRectangleResult FindBestRotation(this List entities, double startAngle = 0, double endAngle = Angle.TwoPI)` -- `stepAngle` parameter removed (no longer needed -- exact solution) -- Implementation: extract vertices from entities, call `RotatingCalipers.MinimumBoundingRectangle()` - -### 5. `OpenNest.Core/Geometry/Polygon.cs` - -- Update `FindBestRotation` wrapper methods to match new signature and return `BoundingRectangleResult` - -### 6. `OpenNest.Core/Geometry/Shape.cs` - -- Update `FindBestRotation` wrapper methods to match new signature and return `BoundingRectangleResult` - -### 7. All callers of `FindBestRotation` - -- Update to use `BoundingRectangleResult` instead of `double` -- Access `.Angle` for the rotation value where only the angle was used before - -## Algorithm Detail - -### Rotating Calipers for Minimum Bounding Rectangle - -1. Compute convex hull (Andrew's monotone chain) -2. For each edge of the hull, compute the angle it makes with the x-axis -3. Project all hull vertices onto the edge direction and its perpendicular -4. Compute the bounding rectangle from the min/max projections -5. Track the rectangle with minimum area (and separately, minimum width) -6. When constrained by `startAngle`/`endAngle`: filter candidate angles to range, also evaluate the range boundaries, return best valid result - -### Rotation Constraint Handling - -The algorithm naturally produces a set of candidate angles (one per hull edge). For constrained rotation: - -1. Compute all candidate angles and their bounding rectangles -2. Filter to candidates within `[startAngle, endAngle]` -3. Also evaluate the bounding rectangle at `startAngle` and `endAngle` (range boundaries) -4. Return the best result from the filtered set - -## What This Does NOT Change - -- The nesting engine's packing algorithms (still uses axis-aligned rectangles for bin packing) -- The `NestItem`, `Part`, or `Program` rotation mechanics -- The `Box`/`BoundingBox` classes (remain axis-aligned)