All checks were successful
Build and Test / build (pull_request) Successful in 32m17s
Copy QuickNav and ZTools source trees into reference/ for developer reference during the UI/UX rework. These are plain directories (not submodules) and are not included in the build. - reference/quicknav/ — QuickNav addon source - reference/ztools/ — ZTools addon source Part of the UI/UX rework preparation. See #346.
592 lines
16 KiB
Markdown
592 lines
16 KiB
Markdown
# FreeCAD 1.0.2 PartDesign Workbench Command Reference
|
|
|
|
## Overview
|
|
|
|
The PartDesign Workbench uses a **feature-based parametric methodology** where a component is represented by a Body container. Features are cumulative—each builds on the result of preceding features. Most features are based on parametric sketches and are either additive (adding material) or subtractive (removing material).
|
|
|
|
FreeCAD 1.0 introduced significant improvements including **Topological Naming Problem (TNP) mitigation**, making parametric models more stable when earlier features are modified.
|
|
|
|
---
|
|
|
|
## Structure & Containers
|
|
|
|
### Body
|
|
The fundamental container for PartDesign features. Defines a local coordinate system and contains all features that define a single solid component.
|
|
|
|
```python
|
|
body = doc.addObject('PartDesign::Body', 'Body')
|
|
```
|
|
|
|
**Properties:**
|
|
- `Tip` — The feature representing the current state of the body
|
|
- `BaseFeature` — Optional external solid to build upon
|
|
- `Origin` — Contains reference planes (XY, XZ, YZ) and axes (X, Y, Z)
|
|
|
|
### Part Container
|
|
Groups multiple Bodies for organization. Not a PartDesign-specific object but commonly used.
|
|
|
|
```python
|
|
part = doc.addObject('App::Part', 'Part')
|
|
```
|
|
|
|
---
|
|
|
|
## Sketch Tools
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| **Create Sketch** | Creates a new sketch on a selected face or datum plane |
|
|
| **Attach Sketch** | Attaches a sketch to geometry from the active body |
|
|
| **Edit Sketch** | Opens selected sketch for editing |
|
|
| **Validate Sketch** | Verifies tolerance of points and adjusts them |
|
|
| **Check Geometry** | Checks geometry for errors |
|
|
|
|
```python
|
|
# Create sketch attached to XY plane
|
|
sketch = body.newObject('Sketcher::SketchObject', 'Sketch')
|
|
sketch.AttachmentSupport = [(body.getObject('Origin').getObject('XY_Plane'), '')]
|
|
sketch.MapMode = 'FlatFace'
|
|
```
|
|
|
|
---
|
|
|
|
## Reference Geometry (Datums)
|
|
|
|
### Datum Plane
|
|
Creates a reference plane for sketch attachment or as a mirror/pattern reference.
|
|
|
|
```python
|
|
plane = body.newObject('PartDesign::Plane', 'DatumPlane')
|
|
plane.AttachmentSupport = [(face_reference, '')]
|
|
plane.MapMode = 'FlatFace'
|
|
plane.Offset = App.Vector(0, 0, 10) # Offset along normal
|
|
```
|
|
|
|
### Datum Line
|
|
Creates a reference axis for revolutions, grooves, or patterns.
|
|
|
|
```python
|
|
line = body.newObject('PartDesign::Line', 'DatumLine')
|
|
line.AttachmentSupport = [(edge_reference, '')]
|
|
line.MapMode = 'ObjectXY'
|
|
```
|
|
|
|
### Datum Point
|
|
Creates a reference point for geometry attachment.
|
|
|
|
```python
|
|
point = body.newObject('PartDesign::Point', 'DatumPoint')
|
|
point.AttachmentSupport = [(vertex_reference, '')]
|
|
```
|
|
|
|
### Local Coordinate System
|
|
Creates a local coordinate system (LCS) attached to datum geometry.
|
|
|
|
```python
|
|
lcs = body.newObject('PartDesign::CoordinateSystem', 'LocalCS')
|
|
```
|
|
|
|
### Shape Binder
|
|
References geometry from a single parent object.
|
|
|
|
```python
|
|
binder = body.newObject('PartDesign::ShapeBinder', 'ShapeBinder')
|
|
binder.Support = [(external_object, ['Face1'])]
|
|
```
|
|
|
|
### SubShapeBinder
|
|
References geometry from one or more parent objects (more flexible than ShapeBinder).
|
|
|
|
```python
|
|
subbinder = body.newObject('PartDesign::SubShapeBinder', 'SubShapeBinder')
|
|
subbinder.Support = [(obj1, ['Face1']), (obj2, ['Edge2'])]
|
|
```
|
|
|
|
### Clone
|
|
Creates a clone of a selected body.
|
|
|
|
```python
|
|
clone = doc.addObject('PartDesign::FeatureBase', 'Clone')
|
|
clone.BaseFeature = source_body
|
|
```
|
|
|
|
---
|
|
|
|
## Additive Features (Add Material)
|
|
|
|
### Pad
|
|
Extrudes a sketch profile to create a solid.
|
|
|
|
```python
|
|
pad = body.newObject('PartDesign::Pad', 'Pad')
|
|
pad.Profile = sketch
|
|
pad.Length = 20.0
|
|
pad.Type = 0 # 0=Dimension, 1=UpToLast, 2=UpToFirst, 3=UpToFace, 4=TwoLengths, 5=UpToShape
|
|
pad.Reversed = False
|
|
pad.Midplane = False
|
|
pad.Symmetric = False
|
|
pad.Length2 = 10.0 # For TwoLengths type
|
|
pad.UseCustomVector = False
|
|
pad.Direction = App.Vector(0, 0, 1)
|
|
pad.TaperAngle = 0.0 # Draft angle (new in 1.0)
|
|
pad.TaperAngle2 = 0.0
|
|
```
|
|
|
|
**Type Options:**
|
|
| Value | Mode | Description |
|
|
|-------|------|-------------|
|
|
| 0 | Dimension | Fixed length |
|
|
| 1 | UpToLast | Extends to last face in direction |
|
|
| 2 | UpToFirst | Extends to first face encountered |
|
|
| 3 | UpToFace | Extends to selected face |
|
|
| 4 | TwoLengths | Extends in both directions |
|
|
| 5 | UpToShape | Extends to selected shape (new in 1.0) |
|
|
|
|
### Revolution
|
|
Creates a solid by revolving a sketch around an axis.
|
|
|
|
```python
|
|
revolution = body.newObject('PartDesign::Revolution', 'Revolution')
|
|
revolution.Profile = sketch
|
|
revolution.Axis = (body.getObject('Origin').getObject('Z_Axis'), [''])
|
|
revolution.Angle = 360.0
|
|
revolution.Midplane = False
|
|
revolution.Reversed = False
|
|
```
|
|
|
|
### Additive Loft
|
|
Creates a solid by transitioning between two or more sketch profiles.
|
|
|
|
```python
|
|
loft = body.newObject('PartDesign::AdditiveLoft', 'AdditiveLoft')
|
|
loft.Profile = sketch1
|
|
loft.Sections = [sketch2, sketch3]
|
|
loft.Ruled = False
|
|
loft.Closed = False
|
|
```
|
|
|
|
### Additive Pipe (Sweep)
|
|
Creates a solid by sweeping a profile along a path.
|
|
|
|
```python
|
|
pipe = body.newObject('PartDesign::AdditivePipe', 'AdditivePipe')
|
|
pipe.Profile = profile_sketch
|
|
pipe.Spine = path_sketch # or (object, ['Edge1', 'Edge2'])
|
|
pipe.Transition = 0 # 0=Transformed, 1=RightCorner, 2=RoundCorner
|
|
pipe.Mode = 0 # 0=Standard, 1=Fixed, 2=Frenet, 3=Auxiliary
|
|
pipe.Auxiliary = None # Auxiliary spine for Mode=3
|
|
```
|
|
|
|
### Additive Helix
|
|
Creates a solid by sweeping a sketch along a helix.
|
|
|
|
```python
|
|
helix = body.newObject('PartDesign::AdditiveHelix', 'AdditiveHelix')
|
|
helix.Profile = sketch
|
|
helix.Axis = (body.getObject('Origin').getObject('Z_Axis'), [''])
|
|
helix.Pitch = 5.0
|
|
helix.Height = 30.0
|
|
helix.Turns = 6.0
|
|
helix.Mode = 0 # 0=pitch-height, 1=pitch-turns, 2=height-turns
|
|
helix.LeftHanded = False
|
|
helix.Reversed = False
|
|
helix.Angle = 0.0 # Taper angle
|
|
helix.Growth = 0.0 # Radius growth per turn
|
|
```
|
|
|
|
### Additive Primitives
|
|
Direct primitive creation without sketches.
|
|
|
|
```python
|
|
# Box
|
|
box = body.newObject('PartDesign::AdditiveBox', 'Box')
|
|
box.Length = 10.0
|
|
box.Width = 10.0
|
|
box.Height = 10.0
|
|
|
|
# Cylinder
|
|
cyl = body.newObject('PartDesign::AdditiveCylinder', 'Cylinder')
|
|
cyl.Radius = 5.0
|
|
cyl.Height = 20.0
|
|
cyl.Angle = 360.0
|
|
|
|
# Sphere
|
|
sphere = body.newObject('PartDesign::AdditiveSphere', 'Sphere')
|
|
sphere.Radius = 10.0
|
|
sphere.Angle1 = -90.0
|
|
sphere.Angle2 = 90.0
|
|
sphere.Angle3 = 360.0
|
|
|
|
# Cone
|
|
cone = body.newObject('PartDesign::AdditiveCone', 'Cone')
|
|
cone.Radius1 = 10.0
|
|
cone.Radius2 = 5.0
|
|
cone.Height = 15.0
|
|
cone.Angle = 360.0
|
|
|
|
# Ellipsoid
|
|
ellipsoid = body.newObject('PartDesign::AdditiveEllipsoid', 'Ellipsoid')
|
|
ellipsoid.Radius1 = 10.0
|
|
ellipsoid.Radius2 = 5.0
|
|
ellipsoid.Radius3 = 8.0
|
|
|
|
# Torus
|
|
torus = body.newObject('PartDesign::AdditiveTorus', 'Torus')
|
|
torus.Radius1 = 20.0
|
|
torus.Radius2 = 5.0
|
|
|
|
# Prism
|
|
prism = body.newObject('PartDesign::AdditivePrism', 'Prism')
|
|
prism.Polygon = 6
|
|
prism.Circumradius = 10.0
|
|
prism.Height = 20.0
|
|
|
|
# Wedge
|
|
wedge = body.newObject('PartDesign::AdditiveWedge', 'Wedge')
|
|
wedge.Xmin = 0.0
|
|
wedge.Xmax = 10.0
|
|
wedge.Ymin = 0.0
|
|
wedge.Ymax = 10.0
|
|
wedge.Zmin = 0.0
|
|
wedge.Zmax = 10.0
|
|
wedge.X2min = 2.0
|
|
wedge.X2max = 8.0
|
|
wedge.Z2min = 2.0
|
|
wedge.Z2max = 8.0
|
|
```
|
|
|
|
---
|
|
|
|
## Subtractive Features (Remove Material)
|
|
|
|
### Pocket
|
|
Cuts material by extruding a sketch inward.
|
|
|
|
```python
|
|
pocket = body.newObject('PartDesign::Pocket', 'Pocket')
|
|
pocket.Profile = sketch
|
|
pocket.Length = 15.0
|
|
pocket.Type = 0 # Same options as Pad, plus 1=ThroughAll
|
|
pocket.Reversed = False
|
|
pocket.Midplane = False
|
|
pocket.Symmetric = False
|
|
pocket.TaperAngle = 0.0
|
|
```
|
|
|
|
### Hole
|
|
Creates parametric holes with threading options.
|
|
|
|
```python
|
|
hole = body.newObject('PartDesign::Hole', 'Hole')
|
|
hole.Profile = sketch # Sketch with center points
|
|
hole.Diameter = 6.0
|
|
hole.Depth = 15.0
|
|
hole.DepthType = 0 # 0=Dimension, 1=ThroughAll
|
|
hole.Threaded = True
|
|
hole.ThreadType = 0 # 0=None, 1=ISOMetricCoarse, 2=ISOMetricFine, 3=UNC, 4=UNF, 5=NPT, etc.
|
|
hole.ThreadSize = 'M6'
|
|
hole.ThreadFit = 0 # 0=Standard, 1=Close
|
|
hole.ThreadDirection = 0 # 0=Right, 1=Left
|
|
hole.HoleCutType = 0 # 0=None, 1=Counterbore, 2=Countersink
|
|
hole.HoleCutDiameter = 10.0
|
|
hole.HoleCutDepth = 3.0
|
|
hole.HoleCutCountersinkAngle = 90.0
|
|
hole.DrillPoint = 0 # 0=Flat, 1=Angled
|
|
hole.DrillPointAngle = 118.0
|
|
hole.DrillForDepth = False
|
|
```
|
|
|
|
**Thread Types:**
|
|
- ISO Metric Coarse/Fine
|
|
- UNC/UNF (Unified National)
|
|
- NPT/NPTF (National Pipe Thread)
|
|
- BSW/BSF (British Standard)
|
|
- UTS (Unified Thread Standard)
|
|
|
|
### Groove
|
|
Creates a cut by revolving a sketch around an axis (subtractive revolution).
|
|
|
|
```python
|
|
groove = body.newObject('PartDesign::Groove', 'Groove')
|
|
groove.Profile = sketch
|
|
groove.Axis = (body.getObject('Origin').getObject('Z_Axis'), [''])
|
|
groove.Angle = 360.0
|
|
groove.Midplane = False
|
|
groove.Reversed = False
|
|
```
|
|
|
|
### Subtractive Loft
|
|
Cuts by transitioning between profiles.
|
|
|
|
```python
|
|
subloft = body.newObject('PartDesign::SubtractiveLoft', 'SubtractiveLoft')
|
|
subloft.Profile = sketch1
|
|
subloft.Sections = [sketch2]
|
|
```
|
|
|
|
### Subtractive Pipe
|
|
Cuts by sweeping a profile along a path.
|
|
|
|
```python
|
|
subpipe = body.newObject('PartDesign::SubtractivePipe', 'SubtractivePipe')
|
|
subpipe.Profile = profile_sketch
|
|
subpipe.Spine = path_sketch
|
|
```
|
|
|
|
### Subtractive Helix
|
|
Cuts by sweeping along a helix (e.g., for threads).
|
|
|
|
```python
|
|
subhelix = body.newObject('PartDesign::SubtractiveHelix', 'SubtractiveHelix')
|
|
subhelix.Profile = thread_profile_sketch
|
|
subhelix.Axis = (body.getObject('Origin').getObject('Z_Axis'), [''])
|
|
subhelix.Pitch = 1.0
|
|
subhelix.Height = 10.0
|
|
```
|
|
|
|
### Subtractive Primitives
|
|
Same primitives as additive, but subtract material:
|
|
- `PartDesign::SubtractiveBox`
|
|
- `PartDesign::SubtractiveCylinder`
|
|
- `PartDesign::SubtractiveSphere`
|
|
- `PartDesign::SubtractiveCone`
|
|
- `PartDesign::SubtractiveEllipsoid`
|
|
- `PartDesign::SubtractiveTorus`
|
|
- `PartDesign::SubtractivePrism`
|
|
- `PartDesign::SubtractiveWedge`
|
|
|
|
---
|
|
|
|
## Transformation Features (Patterns)
|
|
|
|
### Mirrored
|
|
Creates a mirror copy of features across a plane.
|
|
|
|
```python
|
|
mirrored = body.newObject('PartDesign::Mirrored', 'Mirrored')
|
|
mirrored.Originals = [pad, pocket]
|
|
mirrored.MirrorPlane = (body.getObject('Origin').getObject('XZ_Plane'), [''])
|
|
```
|
|
|
|
### Linear Pattern
|
|
Creates copies in a linear arrangement.
|
|
|
|
```python
|
|
linear = body.newObject('PartDesign::LinearPattern', 'LinearPattern')
|
|
linear.Originals = [pocket]
|
|
linear.Direction = (body.getObject('Origin').getObject('X_Axis'), [''])
|
|
linear.Length = 100.0
|
|
linear.Occurrences = 5
|
|
linear.Mode = 0 # 0=OverallLength, 1=Offset
|
|
```
|
|
|
|
### Polar Pattern
|
|
Creates copies in a circular arrangement.
|
|
|
|
```python
|
|
polar = body.newObject('PartDesign::PolarPattern', 'PolarPattern')
|
|
polar.Originals = [pocket]
|
|
polar.Axis = (body.getObject('Origin').getObject('Z_Axis'), [''])
|
|
polar.Angle = 360.0
|
|
polar.Occurrences = 6
|
|
polar.Mode = 0 # 0=OverallAngle, 1=Offset
|
|
```
|
|
|
|
### MultiTransform
|
|
Combines multiple transformations (mirrored, linear, polar, scaled).
|
|
|
|
```python
|
|
multi = body.newObject('PartDesign::MultiTransform', 'MultiTransform')
|
|
multi.Originals = [pocket]
|
|
|
|
# Add transformations (created within MultiTransform)
|
|
# Typically done via GUI or by setting Transformations property
|
|
multi.Transformations = [mirrored_transform, linear_transform]
|
|
```
|
|
|
|
### Scaled
|
|
Scales features (only available within MultiTransform).
|
|
|
|
```python
|
|
# Only accessible as part of MultiTransform
|
|
scaled = body.newObject('PartDesign::Scaled', 'Scaled')
|
|
scaled.Factor = 0.5
|
|
scaled.Occurrences = 3
|
|
```
|
|
|
|
---
|
|
|
|
## Dress-Up Features (Edge/Face Treatment)
|
|
|
|
### Fillet
|
|
Rounds edges with a specified radius.
|
|
|
|
```python
|
|
fillet = body.newObject('PartDesign::Fillet', 'Fillet')
|
|
fillet.Base = (pad, ['Edge1', 'Edge5', 'Edge9'])
|
|
fillet.Radius = 2.0
|
|
```
|
|
|
|
### Chamfer
|
|
Bevels edges.
|
|
|
|
```python
|
|
chamfer = body.newObject('PartDesign::Chamfer', 'Chamfer')
|
|
chamfer.Base = (pad, ['Edge2', 'Edge6'])
|
|
chamfer.ChamferType = 'Equal Distance' # or 'Two Distances' or 'Distance and Angle'
|
|
chamfer.Size = 1.5
|
|
chamfer.Size2 = 2.0 # For asymmetric
|
|
chamfer.Angle = 45.0 # For 'Distance and Angle'
|
|
```
|
|
|
|
### Draft
|
|
Applies angular draft to faces (for mold release).
|
|
|
|
```python
|
|
draft = body.newObject('PartDesign::Draft', 'Draft')
|
|
draft.Base = (pad, ['Face2', 'Face4'])
|
|
draft.Angle = 3.0 # Degrees
|
|
draft.NeutralPlane = (body.getObject('Origin').getObject('XY_Plane'), [''])
|
|
draft.PullDirection = App.Vector(0, 0, 1)
|
|
draft.Reversed = False
|
|
```
|
|
|
|
### Thickness
|
|
Creates a shell by hollowing out a solid, keeping selected faces open.
|
|
|
|
```python
|
|
thickness = body.newObject('PartDesign::Thickness', 'Thickness')
|
|
thickness.Base = (pad, ['Face6']) # Faces to remove (open)
|
|
thickness.Value = 2.0 # Wall thickness
|
|
thickness.Mode = 0 # 0=Skin, 1=Pipe, 2=RectoVerso
|
|
thickness.Join = 0 # 0=Arc, 1=Intersection
|
|
thickness.Reversed = False
|
|
```
|
|
|
|
---
|
|
|
|
## Boolean Operations
|
|
|
|
### Boolean
|
|
Imports bodies and applies boolean operations.
|
|
|
|
```python
|
|
boolean = body.newObject('PartDesign::Boolean', 'Boolean')
|
|
boolean.Type = 0 # 0=Fuse, 1=Cut, 2=Common (intersection)
|
|
boolean.Bodies = [other_body1, other_body2]
|
|
```
|
|
|
|
---
|
|
|
|
## Context Menu Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| **Set Tip** | Sets selected feature as the body's current state (tip) |
|
|
| **Move object to other body** | Transfers feature to a different body |
|
|
| **Move object after other object** | Reorders features in the tree |
|
|
| **Appearance** | Sets color and transparency |
|
|
| **Color per face** | Assigns different colors to individual faces |
|
|
|
|
```python
|
|
# Set tip programmatically
|
|
body.Tip = pocket
|
|
|
|
# Move feature order
|
|
doc.moveObject(feature, body, after_feature)
|
|
```
|
|
|
|
---
|
|
|
|
## Additional Tools
|
|
|
|
### Sprocket
|
|
Creates a sprocket profile for chain drives.
|
|
|
|
```python
|
|
# Available via Gui.runCommand('PartDesign_Sprocket')
|
|
```
|
|
|
|
### Involute Gear
|
|
Creates an involute gear profile.
|
|
|
|
```python
|
|
# Available via Gui.runCommand('PartDesign_InvoluteGear')
|
|
```
|
|
|
|
---
|
|
|
|
## Common Properties (All Features)
|
|
|
|
| Property | Type | Description |
|
|
|----------|------|-------------|
|
|
| `Label` | String | User-visible name |
|
|
| `Placement` | Placement | Position and orientation |
|
|
| `BaseFeature` | Link | Feature this builds upon |
|
|
| `Shape` | Shape | Resulting geometry |
|
|
|
|
---
|
|
|
|
## Expression Binding
|
|
|
|
All dimensional properties can be driven by expressions:
|
|
|
|
```python
|
|
pad.setExpression('Length', 'Spreadsheet.plate_height')
|
|
fillet.setExpression('Radius', 'Spreadsheet.fillet_r * 0.5')
|
|
hole.setExpression('Diameter', '<<Parameters>>.hole_dia')
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
1. **Always work within a Body** — PartDesign features require a body container
|
|
2. **Use fully constrained sketches** — Prevents unexpected behavior when parameters change
|
|
3. **Leverage datum geometry** — Creates stable references that survive TNP issues
|
|
4. **Name constraints** — Enables expression-based parametric design
|
|
5. **Use spreadsheets** — Centralizes parameters for easy modification
|
|
6. **Set meaningful Labels** — Internal Names are auto-generated; Labels are user-friendly
|
|
7. **Check isSolid()** — Before subtractive operations, verify the body has solid geometry
|
|
|
|
```python
|
|
if not body.isSolid():
|
|
raise ValueError("Body must contain solid geometry for subtractive features")
|
|
```
|
|
|
|
---
|
|
|
|
## FreeCAD 1.0 Changes
|
|
|
|
| Change | Description |
|
|
|--------|-------------|
|
|
| **TNP Mitigation** | Topological naming more stable |
|
|
| **UpToShape** | New Pad/Pocket type extending to arbitrary shapes |
|
|
| **Draft Angle** | Taper angles on Pad/Pocket |
|
|
| **Improved Hole** | More thread types, better UI |
|
|
| **Assembly Integration** | Native assembly workbench |
|
|
| **Arch → BIM** | Workbench rename |
|
|
| **Path → CAM** | Workbench rename |
|
|
|
|
---
|
|
|
|
## Python Module Access
|
|
|
|
```python
|
|
import FreeCAD as App
|
|
import FreeCADGui as Gui
|
|
import Part
|
|
import Sketcher
|
|
import PartDesign
|
|
import PartDesignGui
|
|
|
|
# Access feature classes
|
|
print(dir(PartDesign))
|
|
# ['Additive', 'AdditiveBox', 'AdditiveCone', 'AdditiveCylinder', ...]
|
|
```
|
|
|
|
---
|
|
|
|
*Document version: FreeCAD 1.0.2 / January 2026*
|
|
*Reference: FreeCAD Wiki, GitHub FreeCAD-documentation, FreeCAD Forum*
|