Skip to content

Commit 88215d3

Browse files
Update documentation.
1 parent 3df51f0 commit 88215d3

3 files changed

Lines changed: 213 additions & 39 deletions

File tree

CONTRIBUTING.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Contributing to Canonical Sketch
2+
3+
Thank you for your interest in contributing to Canonical Sketch! This document provides guidelines and information for contributors.
4+
5+
## Ways to Contribute
6+
7+
- **Add CAD adapters**: Implement adapters for other CAD systems (Onshape, CATIA, etc.)
8+
- **Improve existing adapters**: Enhance FreeCAD, Fusion 360, SolidWorks, or Inventor adapters
9+
- **Improve test coverage**: Add tests for edge cases and new functionality
10+
- **Report bugs**: Open an issue with a clear description and reproduction steps
11+
- **Suggest features**: Propose new geometry types, constraints, or capabilities
12+
- **Improve documentation**: Fix typos, clarify explanations, or add examples
13+
14+
## Development Setup
15+
16+
1. Clone the repository:
17+
```bash
18+
git clone https://github.com/codereclaimers/canonical_sketch.git
19+
cd canonical_sketch
20+
```
21+
22+
2. Install in development mode with dev dependencies:
23+
```bash
24+
pip install -e ".[dev]"
25+
```
26+
27+
3. Run the tests:
28+
```bash
29+
pytest tests/
30+
```
31+
32+
## Code Style
33+
34+
This project uses automated tools to maintain consistent code style:
35+
36+
- **Black** for code formatting (line length: 100)
37+
- **Ruff** for linting
38+
- **Mypy** for type checking
39+
40+
Before submitting a pull request, please run:
41+
42+
```bash
43+
black .
44+
ruff check .
45+
mypy sketch_canonical
46+
```
47+
48+
## Adding a New CAD Adapter
49+
50+
All adapters are implemented in Python. To add support for a new CAD system:
51+
52+
1. Create a new package: `sketch_adapter_<cadname>/`
53+
2. Implement the `SketchBackendAdapter` abstract base class from `sketch_adapter_common`
54+
3. Add tests in `tests/test_<cadname>_adapter.py` or within the adapter package
55+
4. Update the README to mention the new adapter
56+
57+
See `sketch_adapter_freecad/` for a reference implementation. For Windows COM-based CAD systems (like SolidWorks or Inventor), see `sketch_adapter_solidworks/` for patterns using `pywin32`.
58+
59+
## Pull Request Guidelines
60+
61+
- Keep changes focused and atomic
62+
- Add tests for new functionality
63+
- Update documentation as needed
64+
- Ensure all tests pass before submitting
65+
66+
## Questions?
67+
68+
Open an issue on GitHub if you have questions or need help getting started.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ if SOLIDWORKS_AVAILABLE:
135135
- Dimensional constraints use geometry recreation to avoid blocking dialogs
136136

137137
**Supported Features:**
138-
- All primitive types: Line, Arc, Circle, Point, Spline
138+
- All primitive types: Line, Arc, Circle, Point, Spline, Ellipse, EllipticalArc
139139
- All geometric constraints: Coincident, Tangent, Parallel, Perpendicular, Horizontal, Vertical, Equal, Concentric, Collinear, Midpoint, Fixed, Symmetric
140140
- All dimensional constraints: Length, Radius, Diameter, Angle, Distance, DistanceX, DistanceY
141141
- Construction geometry
@@ -169,7 +169,7 @@ if INVENTOR_AVAILABLE:
169169
- Sketches are created on the XY plane by default
170170

171171
**Supported Features:**
172-
- All primitive types: Line, Arc, Circle, Point, Spline
172+
- All primitive types: Line, Arc, Circle, Point, Spline, Ellipse, EllipticalArc
173173
- All geometric constraints: Coincident, Tangent, Parallel, Perpendicular, Horizontal, Vertical, Equal, Concentric, Collinear, Midpoint, Fixed, Symmetric
174174
- All dimensional constraints: Length, Radius, Diameter, Angle, Distance, DistanceX, DistanceY
175175
- Construction geometry

SPECIFICATION.md

Lines changed: 143 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ This document defines a CAD-agnostic representation for 2D sketch geometry and c
1212

1313
### 1.1 Project structure
1414
```
15-
sketch-canonical/ # Core schema, validation, serialization (Python)
16-
sketch-adapter-freecad/ # FreeCAD adapter (Python, open source)
17-
sketch-adapter-solidworks/ # SolidWorks adapter (C#, commercial)
18-
sketch-adapter-inventor/ # Inventor adapter (C#, commercial)
19-
sketch-adapter-fusion360/ # Fusion 360 adapter (Python, commercial)
15+
sketch_canonical/ # Core schema, validation, serialization (Python)
16+
sketch_adapter_freecad/ # FreeCAD adapter (Python, open source)
17+
sketch_adapter_solidworks/ # SolidWorks adapter (Python, Windows only via COM)
18+
sketch_adapter_inventor/ # Inventor adapter (Python, Windows only via COM)
19+
sketch_adapter_fusion/ # Fusion 360 adapter (Python, runs inside Fusion)
2020
```
2121

2222
Each adapter project has:
@@ -97,6 +97,8 @@ class ElementPrefix:
9797
CIRCLE = "C"
9898
POINT = "P"
9999
SPLINE = "S"
100+
ELLIPSE = "E"
101+
ELLIPTICAL_ARC = "EA"
100102
```
101103

102104
---
@@ -371,6 +373,81 @@ class Spline(SketchPrimitive):
371373
return [PointType.START, PointType.END, PointType.CONTROL]
372374
```
373375

376+
### 3.8 Ellipse
377+
378+
```python
379+
@dataclass
380+
class Ellipse(SketchPrimitive):
381+
"""
382+
Full ellipse defined by center, radii, and rotation.
383+
384+
Valid point types: CENTER only
385+
"""
386+
center: Point2D
387+
major_radius: float # Semi-major axis length
388+
minor_radius: float # Semi-minor axis length
389+
rotation: float = 0.0 # Rotation angle in radians (CCW from X-axis)
390+
391+
def get_point(self, point_type: PointType) -> Point2D:
392+
match point_type:
393+
case PointType.CENTER: return self.center
394+
case _: raise ValueError(f"Invalid point type {point_type} for Ellipse")
395+
396+
def get_valid_point_types(self) -> list[PointType]:
397+
return [PointType.CENTER]
398+
399+
def point_at_parameter(self, t: float) -> Point2D:
400+
"""Get point on ellipse at parameter t (radians)."""
401+
import math
402+
cos_r, sin_r = math.cos(self.rotation), math.sin(self.rotation)
403+
x_local = self.major_radius * math.cos(t)
404+
y_local = self.minor_radius * math.sin(t)
405+
return Point2D(
406+
self.center.x + x_local * cos_r - y_local * sin_r,
407+
self.center.y + x_local * sin_r + y_local * cos_r
408+
)
409+
```
410+
411+
### 3.9 EllipticalArc
412+
413+
```python
414+
@dataclass
415+
class EllipticalArc(SketchPrimitive):
416+
"""
417+
Arc of an ellipse defined by center, radii, rotation, and angular range.
418+
419+
Valid point types: START, END, CENTER
420+
"""
421+
center: Point2D
422+
major_radius: float
423+
minor_radius: float
424+
rotation: float = 0.0 # Rotation angle in radians
425+
start_param: float = 0.0 # Start angle in radians (on unrotated ellipse)
426+
end_param: float = 0.0 # End angle in radians
427+
ccw: bool = True # Counter-clockwise from start to end
428+
429+
def get_point(self, point_type: PointType) -> Point2D:
430+
match point_type:
431+
case PointType.START: return self.point_at_parameter(self.start_param)
432+
case PointType.END: return self.point_at_parameter(self.end_param)
433+
case PointType.CENTER: return self.center
434+
case _: raise ValueError(f"Invalid point type {point_type} for EllipticalArc")
435+
436+
def get_valid_point_types(self) -> list[PointType]:
437+
return [PointType.START, PointType.END, PointType.CENTER]
438+
439+
def point_at_parameter(self, t: float) -> Point2D:
440+
"""Get point on ellipse at parameter t (radians)."""
441+
import math
442+
cos_r, sin_r = math.cos(self.rotation), math.sin(self.rotation)
443+
x_local = self.major_radius * math.cos(t)
444+
y_local = self.minor_radius * math.sin(t)
445+
return Point2D(
446+
self.center.x + x_local * cos_r - y_local * sin_r,
447+
self.center.y + x_local * sin_r + y_local * cos_r
448+
)
449+
```
450+
374451
---
375452

376453
## 4. Constraints
@@ -1097,15 +1174,25 @@ Both approaches produce equivalent results. Use Approach 1 for clarity.
10971174

10981175
| Constraint | Status | Method |
10991176
|------------|--------|--------|
1100-
| FIXED | ✓ Implemented | `swConstraintType_e.swConstraintType_FIXED` |
1101-
| HORIZONTAL | ✓ Implemented | `swConstraintType_e.swConstraintType_HORIZONTAL` |
1102-
| VERTICAL | ✓ Implemented | `swConstraintType_e.swConstraintType_VERTICAL` |
1103-
| COINCIDENT | Use Alternative | `sgMERGEPOINTS` for path connections |
1104-
| TANGENT | ⚠ Not Implemented | Would need implementation |
1105-
| PERPENDICULAR | ⚠ Not Implemented | Would need implementation |
1106-
| PARALLEL | ⚠ Not Implemented | Would need implementation |
1107-
| EQUAL | ⚠ Not Implemented | Would need implementation |
1108-
| CONCENTRIC | ⚠ Not Implemented | Would need implementation |
1177+
| FIXED | ✓ Implemented | `sgFIXED` |
1178+
| HORIZONTAL | ✓ Implemented | `sgHORIZONTAL2D` |
1179+
| VERTICAL | ✓ Implemented | `sgVERTICAL2D` |
1180+
| COINCIDENT | ✓ Implemented | `sgCOINCIDENT` or `sgMERGEPOINTS` |
1181+
| TANGENT | ✓ Implemented | `sgTANGENT` |
1182+
| PERPENDICULAR | ✓ Implemented | `sgPERPENDICULAR` |
1183+
| PARALLEL | ✓ Implemented | `sgPARALLEL` |
1184+
| EQUAL | ✓ Implemented | `sgSAMELENGTH` |
1185+
| CONCENTRIC | ✓ Implemented | `sgCONCENTRIC` |
1186+
| COLLINEAR | ✓ Implemented | `sgCOLINEAR` |
1187+
| MIDPOINT | ✓ Implemented | `sgATMIDDLE` |
1188+
| SYMMETRIC | ✓ Implemented | `sgSYMMETRIC` |
1189+
| LENGTH | ✓ Implemented | Dimensional constraint |
1190+
| RADIUS | ✓ Implemented | Dimensional constraint |
1191+
| DIAMETER | ✓ Implemented | Dimensional constraint |
1192+
| ANGLE | ✓ Implemented | Dimensional constraint |
1193+
| DISTANCE | ✓ Implemented | Dimensional constraint |
1194+
| DISTANCE_X | ✓ Implemented | Dimensional constraint |
1195+
| DISTANCE_Y | ✓ Implemented | Dimensional constraint |
11091196

11101197
```csharp
11111198
public bool AddConstraint(SketchConstraint constraint)
@@ -1470,14 +1557,25 @@ public SketchPoint GetArcEndPoint(SketchArc arc, bool ccw)
14701557

14711558
| Constraint | Status | Method |
14721559
|------------|--------|--------|
1473-
| FIXED (Ground) | ✓ Verified | `AddGround(entity)` |
1474-
| HORIZONTAL | ✓ Verified | `AddHorizontal(entity)` |
1475-
| VERTICAL | ✓ Verified | `AddVertical(entity)` |
1476-
| COINCIDENT | ✓ Verified | `AddCoincident(e1, e2)` — wrap in try-catch |
1477-
| TANGENT | ⚠ Unverified | Likely `AddTangent(e1, e2)` |
1478-
| PERPENDICULAR | ⚠ Unverified | Likely `AddPerpendicular(e1, e2)` |
1479-
| PARALLEL | ⚠ Unverified | Likely `AddParallel(e1, e2)` |
1480-
| EQUAL | ⚠ Unverified | Likely `AddEqual(e1, e2)` |
1560+
| FIXED (Ground) | ✓ Implemented | `AddGround(entity)` |
1561+
| HORIZONTAL | ✓ Implemented | `AddHorizontal(entity)` |
1562+
| VERTICAL | ✓ Implemented | `AddVertical(entity)` |
1563+
| COINCIDENT | ✓ Implemented | `AddCoincident(e1, e2)` — wrap in try-catch |
1564+
| TANGENT | ✓ Implemented | `AddTangent(e1, e2)` |
1565+
| PERPENDICULAR | ✓ Implemented | `AddPerpendicular(e1, e2)` |
1566+
| PARALLEL | ✓ Implemented | `AddParallel(e1, e2)` |
1567+
| EQUAL | ✓ Implemented | `AddEqual(e1, e2)` |
1568+
| CONCENTRIC | ✓ Implemented | `AddConcentric(e1, e2)` |
1569+
| COLLINEAR | ✓ Implemented | `AddCollinear(e1, e2)` |
1570+
| MIDPOINT | ✓ Implemented | `AddMidpoint(point, line)` |
1571+
| SYMMETRIC | ✓ Implemented | `AddSymmetry(e1, e2, axis)` |
1572+
| LENGTH | ✓ Implemented | Dimensional constraint |
1573+
| RADIUS | ✓ Implemented | `AddRadial(entity, placement)` |
1574+
| DIAMETER | ✓ Implemented | `AddDiameter(entity, placement)` |
1575+
| ANGLE | ✓ Implemented | `AddTwoLineAngle(e1, e2, placement)` |
1576+
| DISTANCE | ✓ Implemented | `AddTwoPointDistance(p1, p2, placement)` |
1577+
| DISTANCE_X | ✓ Implemented | Horizontal dimension |
1578+
| DISTANCE_Y | ✓ Implemented | Vertical dimension |
14811579

14821580
```csharp
14831581
public bool AddConstraint(SketchConstraint constraint)
@@ -1979,19 +2077,27 @@ def export_sketch(self) -> SketchDocument:
19792077

19802078
| Canonical | FreeCAD | SolidWorks | Inventor | Fusion 360 |
19812079
|-----------|---------|------------|----------|------------|
1982-
| COINCIDENT | Coincident ✓ | sgMERGEPOINTS| AddCoincident ✓ | addCoincident ✓ |
1983-
| TANGENT | Tangent ✓ | ⚠ Not impl | AddTangent | addTangent ✓ |
1984-
| PERPENDICULAR | Perpendicular ✓ | ⚠ Not impl | AddPerpendicular | addPerpendicular ✓ |
1985-
| PARALLEL | Parallel ✓ | ⚠ Not impl | AddParallel | addParallel ✓ |
2080+
| COINCIDENT | Coincident ✓ | sgCOINCIDENT| AddCoincident ✓ | addCoincident ✓ |
2081+
| TANGENT | Tangent ✓ | sgTANGENT ✓ | AddTangent | addTangent ✓ |
2082+
| PERPENDICULAR | Perpendicular ✓ | sgPERPENDICULAR ✓ | AddPerpendicular | addPerpendicular ✓ |
2083+
| PARALLEL | Parallel ✓ | sgPARALLEL ✓ | AddParallel | addParallel ✓ |
19862084
| HORIZONTAL | Horizontal ✓ | sgHORIZONTAL2D ✓ | AddHorizontal ✓ | addHorizontal ✓ |
19872085
| VERTICAL | Vertical ✓ | sgVERTICAL2D ✓ | AddVertical ✓ | addVertical ✓ |
1988-
| EQUAL | Equal ✓ | ⚠ Not impl | AddEqual ⚠ | addEqual ✓ |
1989-
| CONCENTRIC | Concentric ✓ | ⚠ Not impl | AddConcentric ⚠ | addConcentric ✓ |
1990-
| FIXED | Fixed ✓ | sgFIXED ✓ | AddGround ✓ | addFix ⚠ |
1991-
| RADIUS | Radius ✓ | Radial dim | AddRadial ⚠ | addRadialDimension ✓ |
1992-
| DISTANCE | Distance ✓ | Linear dim | AddTwoPointDistance ⚠ | addDistanceDimension ✓ |
1993-
1994-
Legend: ✓ = Verified, ⚠ = Unverified/Not Implemented
2086+
| EQUAL | Equal ✓ | sgSAMELENGTH ✓ | AddEqual ✓ | addEqual ✓ |
2087+
| CONCENTRIC | Concentric ✓ | sgCONCENTRIC ✓ | AddConcentric ✓ | addConcentric ✓ |
2088+
| COLLINEAR | Collinear ✓ | sgCOLINEAR ✓ | AddCollinear ✓ | addCollinear ✓ |
2089+
| FIXED | Fixed ✓ | sgFIXED ✓ | AddGround ✓ | addFix ✓ |
2090+
| SYMMETRIC | Symmetric ✓ | sgSYMMETRIC ✓ | AddSymmetry ✓ | addSymmetry ✓ |
2091+
| MIDPOINT | Midpoint ✓ | sgATMIDDLE ✓ | AddMidpoint ✓ | addMidpoint ✓ |
2092+
| LENGTH | Length ✓ | Dimension ✓ | Dimension ✓ | addSketchLineDimension ✓ |
2093+
| RADIUS | Radius ✓ | Dimension ✓ | AddRadial ✓ | addRadialDimension ✓ |
2094+
| DIAMETER | Diameter ✓ | Dimension ✓ | AddDiameter ✓ | addDiameterDimension ✓ |
2095+
| ANGLE | Angle ✓ | Dimension ✓ | AddTwoLineAngle ✓ | addAngularDimension ✓ |
2096+
| DISTANCE | Distance ✓ | Dimension ✓ | AddTwoPointDistance ✓ | addDistanceDimension ✓ |
2097+
| DISTANCE_X | DistanceX ✓ | Dimension ✓ | Dimension ✓ | addDistanceDimension ✓ |
2098+
| DISTANCE_Y | DistanceY ✓ | Dimension ✓ | Dimension ✓ | addDistanceDimension ✓ |
2099+
2100+
Legend: ✓ = Implemented
19952101

19962102
### 11.4 Special Handling Requirements
19972103

@@ -2188,16 +2294,16 @@ def constraint_to_dict(c: SketchConstraint) -> dict:
21882294
## 14. Future Extensions
21892295

21902296
### 14.1 Additional Primitives
2191-
- **Ellipse**: center, major_axis, minor_axis, rotation
21922297
- **Conic sections**: Generic conic representation
21932298
- **Text**: For annotations (typically not constrained)
21942299

2300+
Note: Ellipse and EllipticalArc are now fully implemented (see Section 3).
2301+
21952302
### 14.2 Additional Constraints
2196-
- **SYMMETRIC**: Two elements symmetric about a line
2197-
- **MIDPOINT_CONSTRAINT**: Point constrained to midpoint of line
2198-
- **COLINEAR**: Multiple lines on same infinite line
21992303
- **PATTERN**: Linear or circular patterns of elements
22002304

2305+
Note: SYMMETRIC, MIDPOINT_CONSTRAINT, and COLLINEAR are now fully implemented (see Section 4).
2306+
22012307
### 14.3 3D Sketch Support
22022308
- Extend `Point2D``Point3D`
22032309
- Add work plane references

0 commit comments

Comments
 (0)