605 lines
22 KiB
Markdown
Executable File
605 lines
22 KiB
Markdown
Executable File
# Joints
|
||
|
||
**Joints** enable `Solid` and `Compound` objects to be arranged relative to each other in an intuitive manner – with the same degree of motion that is found with the equivalent physical joints.
|
||
|
||
Joints always work in pairs – a Joint can only be connected to another Joint as follows:
|
||
|
||
| Joint Type | Connects to | Example |
|
||
| :--- | :--- | :--- |
|
||
| **BallJoint** | `RigidJoint` | Gimbal |
|
||
| **CylindricalJoint** | `RigidJoint` | Screw |
|
||
| **LinearJoint** | `RigidJoint`, `RevoluteJoint` | Slider or Pin Slot |
|
||
| **RevoluteJoint** | `RigidJoint` | Hinge |
|
||
| **RigidJoint** | `RigidJoint` | Fixed |
|
||
|
||
Objects may have many joints bound to them, each with an identifying label. All Joint objects have a `symbol` property that can be displayed to help visualize their position and orientation (the [ocp-vscode](https://github.com/bernhard-42/vscode-ocp-cad-viewer) viewer has built-in support for displaying joints).
|
||
|
||
> **Note:**
|
||
> If joints are created within the scope of a `BuildPart` builder, the `to_part` parameter need not be specified. The builder will, on exit, automatically transfer the joints created in its scope to the part created.
|
||
|
||
The following sections provide more detail on the available joints and describe how they are used.
|
||
|
||
---
|
||
|
||
## Rigid Joint
|
||
|
||
A **rigid joint** positions two components relative to each other with no freedom of movement. When a `RigidJoint` is instantiated, it is assigned a label, a part to bind to (`to_part`), and a `joint_location` which defines both the position and orientation of the joint (see *Location*) – as follows:
|
||
|
||
```python
|
||
RigidJoint(label="outlet", to_part=pipe, joint_location=path.location_at(1))
|
||
```
|
||
|
||
Once a joint is bound to a part this way, the `connect_to()` method can be used to reposition another part relative to `self` (which stays fixed) – as follows:
|
||
|
||
```python
|
||
pipe.joints["outlet"].connect_to(flange_outlet.joints["pipe"])
|
||
```
|
||
|
||
> **Note:**
|
||
> Within a part, all of the joint labels must be unique.
|
||
|
||
The `connect_to()` method only does a **one-time re-position** of a part and does not bind them in any way; however, putting them into an `Assembly` will maintain their relative locations, as will combining parts with boolean operations or within a `BuildPart` context.
|
||
|
||
### Example: Connecting Flanges to a Pipe
|
||
|
||
Consider the following code where flanges are attached to the ends of a curved pipe:
|
||
|
||
```python
|
||
import copy
|
||
from build123d import *
|
||
from bd_warehouse.flange import WeldNeckFlange
|
||
from bd_warehouse.pipe import PipeSection
|
||
from ocp_vscode import *
|
||
|
||
flange_inlet = WeldNeckFlange(nps="10", flange_class=300)
|
||
flange_outlet = copy.copy(flange_inlet)
|
||
|
||
with BuildPart() as pipe_builder:
|
||
# Create the pipe
|
||
with BuildLine():
|
||
path = TangentArc((0, 0, 0), (2 * FT, 0, 1 * FT), tangent=(1, 0, 0))
|
||
with BuildSketch(Plane(origin=path @ 0, z_dir=path % 0)):
|
||
PipeSection("10", material="stainless", identifier="40S")
|
||
sweep()
|
||
|
||
# Add the joints
|
||
RigidJoint(label="inlet", joint_location=-path.location_at(0))
|
||
RigidJoint(label="outlet", joint_location=path.location_at(1))
|
||
|
||
# Place the flanges at the ends of the pipe
|
||
pipe_builder.part.joints["inlet"].connect_to(flange_inlet.joints["pipe"])
|
||
pipe_builder.part.joints["outlet"].connect_to(flange_outlet.joints["pipe"])
|
||
|
||
show(pipe_builder, flange_inlet, flange_outlet, render_joints=True)
|
||
```
|
||
|
||
**Key Observations:**
|
||
* The locations of the joints are determined by the `location_at()` method.
|
||
* The `-` (negate) operator is used to reverse the direction of the location without changing its position.
|
||
* The `WeldNeckFlange` class predefines two joints (one at the pipe end and one at the face end), which are visualized when `render_joints=True` is set in the viewer.
|
||
|
||
---
|
||
|
||
## API Reference
|
||
|
||
### `class RigidJoint`
|
||
|
||
```python
|
||
class RigidJoint(label: str, to_part: Solid | Compound | None = None, joint_location: Location | None = None)
|
||
```
|
||
A rigid joint fixes two components to one another.
|
||
|
||
**Parameters:**
|
||
* `label` (str): Joint label.
|
||
* `to_part` (Union[Solid, Compound], optional): Object to attach joint to.
|
||
* `joint_location` (Location): Global location of joint.
|
||
|
||
**Variables:**
|
||
* `relative_location` (Location): Joint location relative to bound object.
|
||
|
||
#### Methods
|
||
|
||
**`connect_to`**
|
||
```python
|
||
connect_to(other: BallJoint, *, angles: Rotation | tuple[float, float, float] | None = None, **kwargs)
|
||
connect_to(other: CylindricalJoint, *, position: float | None = None, angle: float | None = None)
|
||
connect_to(other: LinearJoint, *, position: float | None = None)
|
||
connect_to(other: RevoluteJoint, *, angle: float | None = None)
|
||
connect_to(other: RigidJoint)
|
||
```
|
||
Connect the `RigidJoint` to another `Joint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (Joint): Joint to connect to.
|
||
* `angle` (float, optional): Angle in degrees. Defaults to range min.
|
||
* `angles` (RotationLike, optional): Angles about axes in degrees. Defaults to range minimums.
|
||
* `position` (float, optional): Linear position. Defaults to linear range min.
|
||
|
||
**`relative_to`**
|
||
```python
|
||
relative_to(other: BallJoint, *, angles: Rotation | tuple[float, float, float] | None = None)
|
||
relative_to(other: CylindricalJoint, *, position: float | None = None, angle: float | None = None)
|
||
relative_to(other: LinearJoint, *, position: float | None = None)
|
||
relative_to(other: RevoluteJoint, *, angle: float | None = None)
|
||
relative_to(other: RigidJoint)
|
||
```
|
||
Relative location of `RigidJoint` to another `Joint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (RigidJoint): Relative to joint.
|
||
* `angle` (float, optional): Angle in degrees. Defaults to range min.
|
||
* `angles` (RotationLike, optional): Angles about axes in degrees. Defaults to range minimums.
|
||
* `position` (float, optional): Linear position. Defaults to linear range min.
|
||
* **Raises:**
|
||
* `TypeError`: `other` must be of a type in: `BallJoint`, `CylindricalJoint`, `LinearJoint`, `RevoluteJoint`, `RigidJoint`.
|
||
|
||
#### Properties
|
||
|
||
* **`location`**: `Location`
|
||
* Location of joint.
|
||
* **`symbol`**: `Compound`
|
||
* A CAD symbol (XYZ indicator) as bound to part.
|
||
|
||
## Revolute Joint
|
||
|
||
A **Revolute Joint** functions effectively as a hinge, allowing a component to rotate around a specific axis.
|
||
|
||
> **Reference:** The Joint Tutorial covers Revolute Joints in detail.
|
||
|
||
During the instantiation of a `RevoluteJoint`, there are three additional parameters compared to `RigidJoints` that allow the circular motion to be fully defined:
|
||
* `axis`: Defines the line around which rotation occurs.
|
||
* `angle_reference`: Defines the starting point (0 degrees) for rotation.
|
||
* `range`: Limits the rotation (min, max).
|
||
|
||
When using `connect_to()` with a Revolute Joint, an extra `angle` parameter is available. This allows you to change the relative position of the joined parts by modifying a single value.
|
||
|
||
|
||
|
||
### API Reference
|
||
|
||
#### `class RevoluteJoint`
|
||
|
||
```python
|
||
class RevoluteJoint(label: str, to_part: Solid | Compound | None = None, axis: Axis = Axis((0, 0, 0), (0, 0, 1)), angle_reference: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float] | None = None, angular_range: tuple[float, float] = (0, 360))
|
||
```
|
||
|
||
Component rotates around axis like a hinge.
|
||
|
||
**Parameters:**
|
||
* `label` (str): Joint label.
|
||
* `to_part` (Union[Solid, Compound], optional): Object to attach joint to.
|
||
* `axis` (Axis): Axis of rotation.
|
||
* `angle_reference` (VectorLike, optional): Direction normal to axis defining where angles will be measured from. Defaults to None.
|
||
* `range` (tuple[float, float], optional): (min, max) angle of joint. Defaults to (0, 360).
|
||
|
||
**Variables:**
|
||
* `angle` (float): Current angle of the joint.
|
||
* `angle_reference` (Vector): Reference vector for angular positions.
|
||
* `angular_range` (tuple[float, float]): Min and max angular position of joint.
|
||
* `relative_axis` (Axis): Joint axis relative to the bound part.
|
||
|
||
**Raises:**
|
||
* `ValueError`: If `angle_reference` is not normal to `axis`.
|
||
|
||
---
|
||
|
||
#### Methods
|
||
|
||
**`connect_to`**
|
||
|
||
```python
|
||
connect_to(other: RigidJoint, *, angle: float | None = None)
|
||
```
|
||
|
||
Connect `RevoluteJoint` and `RigidJoint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (RigidJoint): The joint to connect to.
|
||
* `angle` (float, optional): Angle in degrees. Defaults to range min.
|
||
* **Raises:**
|
||
* `TypeError`: If `other` is not of type `RigidJoint`.
|
||
* `ValueError`: If `angle` is out of the specified range.
|
||
|
||
**`relative_to`**
|
||
|
||
```python
|
||
relative_to(other: RigidJoint, *, angle: float | None = None)
|
||
```
|
||
|
||
Relative location of `RevoluteJoint` to `RigidJoint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (RigidJoint): The joint to connect to.
|
||
* `angle` (float, optional): Angle in degrees. Defaults to range min.
|
||
* **Raises:**
|
||
* `TypeError`: If `other` is not of type `RigidJoint`.
|
||
* `ValueError`: If `angle` is out of the specified range.
|
||
|
||
---
|
||
|
||
#### Properties
|
||
|
||
* **`location`**: `Location`
|
||
* Global location of the joint.
|
||
* **`symbol`**: `Compound`
|
||
* A CAD symbol representing the axis of rotation as bound to the part.
|
||
|
||
## Linear Joint
|
||
|
||
A **Linear Joint** constrains a component to move along a single axis, similar to a sliding latch.
|
||
|
||
|
||
|
||
### Example: Sliding Latch
|
||
|
||
The code below demonstrates how to generate a latch and a slider, and then connect them using a `LinearJoint` for the latch and a `RigidJoint` for the slider.
|
||
|
||
```python
|
||
from build123d import *
|
||
from ocp_vscode import *
|
||
|
||
with BuildPart() as latch:
|
||
# Basic box shape to start with filleted corners
|
||
Box(70, 30, 14)
|
||
end = latch.faces().sort_by(Axis.X)[-1] # save the end with the hole
|
||
fillet(latch.edges().filter_by(Axis.Z), 2)
|
||
fillet(latch.edges().sort_by(Axis.Z)[-1], 1)
|
||
# Make screw tabs
|
||
with BuildSketch(latch.faces().sort_by(Axis.Z)[0]) as l4:
|
||
with Locations((-30, 0), (30, 0)):
|
||
SlotOverall(50, 10, rotation=90)
|
||
Rectangle(50, 30)
|
||
fillet(l4.vertices(Select.LAST), radius=2)
|
||
extrude(amount=-2)
|
||
with GridLocations(60, 40, 2, 2):
|
||
Hole(2)
|
||
# Create the hole from the end saved previously
|
||
with BuildSketch(end) as slide_hole:
|
||
add(end)
|
||
offset(amount=-2)
|
||
fillet(slide_hole.vertices(), 1)
|
||
extrude(amount=-68, mode=Mode.SUBTRACT)
|
||
# Slot for the handle to slide in
|
||
with BuildSketch(latch.faces().sort_by(Axis.Z)[-1]):
|
||
SlotOverall(32, 8)
|
||
extrude(amount=-2, mode=Mode.SUBTRACT)
|
||
|
||
# The slider will move align the x axis 12mm in each direction
|
||
LinearJoint("latch", axis=Axis.X, linear_range=(-12, 12))
|
||
|
||
with BuildPart() as slide:
|
||
# The slide will be a little smaller than the hole
|
||
with BuildSketch() as s1:
|
||
add(slide_hole.sketch)
|
||
offset(amount=-0.25)
|
||
# The extrusions aren't symmetric
|
||
extrude(amount=46)
|
||
extrude(slide.faces().sort_by(Axis.Z)[0], amount=20)
|
||
# Round off the ends
|
||
fillet(slide.edges().group_by(Axis.Z)[0], 1)
|
||
fillet(slide.edges().group_by(Axis.Z)[-1], 1)
|
||
# Create the knob
|
||
with BuildSketch() as s2:
|
||
with Locations((12, 0)):
|
||
SlotOverall(15, 4, rotation=90)
|
||
Rectangle(12, 7, align=(Align.MIN, Align.CENTER))
|
||
fillet(s2.vertices(Select.LAST), 1)
|
||
split(bisect_by=Plane.XZ)
|
||
revolve(axis=Axis.X)
|
||
|
||
# Align the joint to Plane.ZY flipped
|
||
RigidJoint("slide", joint_location=Location(-Plane.ZY))
|
||
|
||
# Position the slide in the latch: -12 >= position <= 12
|
||
latch.part.joints["latch"].connect_to(slide.part.joints["slide"], position=12)
|
||
|
||
show(latch.part, slide.part, render_joints=True)
|
||
```
|
||
|
||
**Key Concepts:**
|
||
|
||
1. **LinearJoint Definition:** The latch defines a `LinearJoint` with an axis (`Axis.X`) and movement limits (`linear_range=(-12, 12)`).
|
||
2. **RigidJoint Definition:** The slider uses a `RigidJoint` with a specific location/orientation (`Location(-Plane.ZY)`) so the knob points "up".
|
||
3. **Connection:** The `connect_to` method links the joints and specifies a `position` (12mm) which must be within the defined range.
|
||
4. **Movement:** The slider can be moved by changing the `position` value. Values outside the `linear_range` limits will raise an exception.
|
||
5. **Orientation:** Note that the slide is constructed in a different orientation than the direction of motion, which is handled by the joint definitions.
|
||
|
||
---
|
||
|
||
### API Reference
|
||
|
||
#### `class LinearJoint`
|
||
|
||
```python
|
||
class LinearJoint(label: str, to_part: Solid | Compound | None = None, axis: Axis = Axis((0, 0, 0), (0, 0, 1)), linear_range: tuple[float, float] = (0, inf))
|
||
```
|
||
|
||
Component moves along a single axis.
|
||
|
||
**Parameters:**
|
||
* `label` (str): Joint label.
|
||
* `to_part` (Union[Solid, Compound], optional): Object to attach joint to.
|
||
* `axis` (Axis): Axis of linear motion.
|
||
* `range` (tuple[float, float], optional): (min, max) position of joint. Defaults to (0, inf).
|
||
|
||
**Variables:**
|
||
* `axis` (Axis): Joint axis.
|
||
* `angle` (float): Angle of joint.
|
||
* `linear_range` (tuple[float, float]): Min and max positional values.
|
||
* `position` (float): Joint position.
|
||
* `relative_axis` (Axis): Joint axis relative to bound part.
|
||
|
||
---
|
||
|
||
#### Methods
|
||
|
||
**`connect_to`**
|
||
|
||
```python
|
||
connect_to(other: RevoluteJoint, *, position: float | None = None, angle: float | None = None)
|
||
connect_to(other: RigidJoint, *, position: float | None = None)
|
||
```
|
||
|
||
Connect `LinearJoint` to another `Joint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (Joint): Joint to connect to.
|
||
* `angle` (float, optional): Angle in degrees. Defaults to range min.
|
||
* `position` (float, optional): Linear position. Defaults to linear range min.
|
||
* **Raises:**
|
||
* `TypeError`: If `other` is not of type `RevoluteJoint` or `RigidJoint`.
|
||
* `ValueError`: If `position` is out of range.
|
||
* `ValueError`: If `angle` is out of range.
|
||
|
||
**`relative_to`**
|
||
|
||
```python
|
||
relative_to(other: RigidJoint, *, position: float | None = None)
|
||
relative_to(other: RevoluteJoint, *, position: float | None = None, angle: float | None = None)
|
||
```
|
||
|
||
Relative location of `LinearJoint` to `RevoluteJoint` or `RigidJoint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (Joint): Joint to connect to.
|
||
* `angle` (float, optional): Angle in degrees. Defaults to range min.
|
||
* `position` (float, optional): Linear position. Defaults to linear range min.
|
||
* **Raises:**
|
||
* `TypeError`: If `other` is not of type `RevoluteJoint` or `RigidJoint`.
|
||
* `ValueError`: If `position` is out of range.
|
||
* `ValueError`: If `angle` is out of range.
|
||
|
||
---
|
||
|
||
#### Properties
|
||
|
||
* **`location`**: `Location`
|
||
* Location of the joint.
|
||
* **`symbol`**: `Compound`
|
||
* A CAD symbol of the linear axis positioned relative to `to_part`.
|
||
|
||
## Cylindrical Joint
|
||
|
||
A **CylindricalJoint** allows a component to rotate around and move along a single axis, effectively acting like a screw. It combines the functionality of a `LinearJoint` and a `RevoluteJoint`.
|
||
|
||
|
||
|
||
The `connect_to` method for these joints accepts both `position` and `angle` parameters.
|
||
|
||
### API Reference
|
||
|
||
#### `class CylindricalJoint`
|
||
|
||
```python
|
||
class CylindricalJoint(label: str, to_part: Solid | Compound | None = None, axis: Axis = Axis((0, 0, 0), (0, 0, 1)), angle_reference: Vector | tuple[float, float] | tuple[float, float, float] | Sequence[float] | None = None, linear_range: tuple[float, float] = (0, inf), angular_range: tuple[float, float] = (0, 360))
|
||
```
|
||
|
||
Component rotates around and moves along a single axis like a screw.
|
||
|
||
**Parameters:**
|
||
* `label` (str): Joint label.
|
||
* `to_part` (Union[Solid, Compound], optional): Object to attach joint to.
|
||
* `axis` (Axis): Axis of rotation and linear motion.
|
||
* `angle_reference` (VectorLike, optional): Direction normal to axis defining where angles will be measured from. Defaults to None.
|
||
* `linear_range` (tuple[float, float], optional): (min, max) position of joint. Defaults to (0, inf).
|
||
* `angular_range` (tuple[float, float], optional): (min, max) angle of joint. Defaults to (0, 360).
|
||
|
||
**Variables:**
|
||
* `axis` (Axis): Joint axis.
|
||
* `linear_position` (float): Linear joint position.
|
||
* `rotational_position` (float): Revolute joint angle in degrees.
|
||
* `angle_reference` (Vector): Reference for angular positions.
|
||
* `angular_range` (tuple[float, float]): Min and max angular position of joint.
|
||
* `linear_range` (tuple[float, float]): Min and max positional values.
|
||
* `relative_axis` (Axis): Joint axis relative to bound part.
|
||
* `position` (float): Joint position.
|
||
* `angle` (float): Angle of joint.
|
||
|
||
**Raises:**
|
||
* `ValueError`: If `angle_reference` must be normal to axis.
|
||
|
||
---
|
||
|
||
#### Methods
|
||
|
||
**`connect_to`**
|
||
|
||
```python
|
||
connect_to(other: RigidJoint, *, position: float | None = None, angle: float | None = None)
|
||
```
|
||
|
||
Connect `CylindricalJoint` and `RigidJoint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (Joint): Joint to connect to.
|
||
* `position` (float, optional): Linear position. Defaults to linear range min.
|
||
* `angle` (float, optional): Angle in degrees. Defaults to range min.
|
||
* **Raises:**
|
||
* `TypeError`: If `other` is not of type `RigidJoint`.
|
||
* `ValueError`: If `position` is out of range.
|
||
* `ValueError`: If `angle` is out of range.
|
||
|
||
**`relative_to`**
|
||
|
||
```python
|
||
relative_to(other: RigidJoint, *, position: float | None = None, angle: float | None = None)
|
||
```
|
||
|
||
Relative location of `CylindricalJoint` to `RigidJoint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (Joint): Joint to connect to.
|
||
* `position` (float, optional): Linear position. Defaults to linear range min.
|
||
* `angle` (float, optional): Angle in degrees. Defaults to range min.
|
||
* **Raises:**
|
||
* `TypeError`: If `other` is not of type `RigidJoint`.
|
||
* `ValueError`: If `position` is out of range.
|
||
* `ValueError`: If `angle` is out of range.
|
||
|
||
---
|
||
|
||
#### Properties
|
||
|
||
* **`location`**: `Location`
|
||
* Location of joint.
|
||
* **`symbol`**: `Compound`
|
||
* A CAD symbol representing the cylindrical axis as bound to part.
|
||
|
||
---
|
||
|
||
## Ball Joint
|
||
|
||
A **Ball Joint** allows a component to rotate around all 3 axes using a gimbal system (3 nested rotations). A common example is a rod end.
|
||
|
||
|
||
|
||
### Example: Rod End
|
||
|
||
The following code demonstrates creating a rod end with a threaded shaft and a ball, connecting them via a `BallJoint`.
|
||
|
||
```python
|
||
from build123d import *
|
||
from bd_warehouse.thread import IsoThread
|
||
from ocp_vscode import *
|
||
|
||
# Create the thread so the min radius is available below
|
||
thread = IsoThread(major_diameter=6, pitch=1, length=20, end_finishes=("fade", "raw"))
|
||
inner_radius = 15.89 / 2
|
||
inner_gap = 0.2
|
||
|
||
with BuildPart() as rod_end:
|
||
# Create the outer shape
|
||
with BuildSketch():
|
||
Circle(22.25 / 2)
|
||
with Locations((0, -12)):
|
||
Rectangle(8, 1)
|
||
make_hull()
|
||
split(bisect_by=Plane.YZ)
|
||
revolve(axis=Axis.Y)
|
||
# Refine the shape
|
||
with BuildSketch(Plane.YZ) as s2:
|
||
Rectangle(25, 8, align=(Align.MIN, Align.CENTER))
|
||
Rectangle(9, 10, align=(Align.MIN, Align.CENTER))
|
||
chamfer(s2.vertices(), 0.5)
|
||
revolve(axis=Axis.Z, mode=Mode.INTERSECT)
|
||
# Add the screw shaft
|
||
Cylinder(
|
||
thread.min_radius,
|
||
30,
|
||
rotation=(90, 0, 0),
|
||
align=(Align.CENTER, Align.CENTER, Align.MIN),
|
||
)
|
||
# Cutout the ball socket
|
||
Sphere(inner_radius, mode=Mode.SUBTRACT)
|
||
# Add thread
|
||
with Locations((0, -30, 0)):
|
||
add(thread, rotation=(-90, 0, 0))
|
||
# Create the ball joint
|
||
BallJoint(
|
||
"socket",
|
||
joint_location=Location(),
|
||
angular_range=((-14, 14), (-14, 14), (0, 360)),
|
||
)
|
||
|
||
with BuildPart() as ball:
|
||
Sphere(inner_radius - inner_gap)
|
||
Box(50, 50, 13, mode=Mode.INTERSECT)
|
||
Hole(4)
|
||
ball.part.color = Color("aliceblue")
|
||
RigidJoint("ball", joint_location=Location())
|
||
|
||
rod_end.part.joints["socket"].connect_to(ball.part.joints["ball"], angles=(5, 10, 0))
|
||
|
||
show(rod_end.part, ball.part, s2)
|
||
```
|
||
|
||
**Key Observations:**
|
||
* **Limits:** Limits are defined during the instantiation of the `BallJoint` to ensure that the pin or bolt within the rod end does not interfere with the rod end itself.
|
||
* **Connection:** The `connect_to` method sets the three angles (`angles=(5, 10, 0)`), though in this specific example only two might be significant depending on the constraints.
|
||
|
||
### API Reference
|
||
|
||
#### `class BallJoint`
|
||
|
||
```python
|
||
class BallJoint(label: str, to_part: Solid | Compound | None = None, joint_location: Location | None = None, angular_range: tuple[tuple[float, float], tuple[float, float], tuple[float, float]] = ((0, 360), (0, 360), (0, 360)), angle_reference: Plane = Plane((0, 0, 0), (1, 0, 0), (0, 0, 1)))
|
||
```
|
||
|
||
A component rotates around all 3 axes using a gimbal system (3 nested rotations).
|
||
|
||
**Parameters:**
|
||
* `label` (str): Joint label.
|
||
* `to_part` (Union[Solid, Compound], optional): Object to attach joint to.
|
||
* `joint_location` (Location): Global location of joint.
|
||
* `angular_range` (tuple[tuple[float, float], ...], optional): X, Y, Z angle (min, max) pairs. Defaults to `((0, 360), (0, 360), (0, 360))`.
|
||
* `angle_reference` (Plane, optional): Plane relative to part defining zero degrees of rotation. Defaults to `Plane.XY`.
|
||
|
||
**Variables:**
|
||
* `relative_location` (Location): Joint location relative to bound part.
|
||
* `angular_range` (tuple): X, Y, Z angle (min, max) pairs.
|
||
* `angle_reference` (Plane): Plane relative to part defining zero degrees.
|
||
|
||
---
|
||
|
||
#### Methods
|
||
|
||
**`connect_to`**
|
||
|
||
```python
|
||
connect_to(other: RigidJoint, *, angles: Rotation | tuple[float, float, float] | None = None)
|
||
```
|
||
|
||
Connect `BallJoint` and `RigidJoint`.
|
||
|
||
* **Parameters:**
|
||
* `other` (RigidJoint): Joint to connect to.
|
||
* `angles` (RotationLike, optional): Angles about axes in degrees. Defaults to range minimums.
|
||
* **Raises:**
|
||
* `TypeError`: Invalid other joint type.
|
||
* `ValueError`: If angles are out of range.
|
||
|
||
**`relative_to`**
|
||
|
||
```python
|
||
relative_to(other: RigidJoint, *, angles: Rotation | tuple[float, float, float] | None = None)
|
||
```
|
||
|
||
Return the relative location from this joint to the `RigidJoint` of another object.
|
||
|
||
* **Parameters:**
|
||
* `other` (RigidJoint): Joint to connect to.
|
||
* `angles` (RotationLike, optional): Angles about axes in degrees. Defaults to range minimums.
|
||
* **Raises:**
|
||
* `TypeError`: Invalid other joint type.
|
||
* `ValueError`: If angles are out of range.
|
||
|
||
---
|
||
|
||
#### Properties
|
||
|
||
* **`location`**: `Location`
|
||
* Location of joint.
|
||
* **`symbol`**: `Compound`
|
||
* A CAD symbol representing joint as bound to part.
|
||
|