Updated mode

This commit is contained in:
Roger Maitland 2022-07-14 20:20:29 -04:00
parent 052b4fb3ed
commit 89c8292773
9 changed files with 291 additions and 134 deletions

View file

@ -80,25 +80,25 @@ Almost all objects or operations have a `mode` parameter which is defined by the
.. code-block:: python
class Mode(Enum):
ADDITION = auto()
SUBTRACTION = auto()
INTERSECTION = auto()
CONSTRUCTION = auto()
ADD = auto()
SUBTRACT = auto()
INTERSECT = auto()
REPLACE = auto()
PRIVATE = auto()
The `mode` parameter describes how the user would like the object or operation to
interact with the object within the builder. For example, `Mode.ADDITION` will
interact with the object within the builder. For example, `Mode.ADD` will
integrate a new object(s) in with an existing `part`. Note that a part doesn't
necessarily have to be a single object so multiple distinct objects could be added
resulting is multiple objects stored as a `Compound` object. As one might expect
`Mode.SUBTRACTION` and `Mode.INTERSECTION` subtract from or intersect and object
with the builder's object. `Mode.PRIVATE` instructs the builder that this object
`Mode.SUBTRACT`, `Mode.INTERSECT`, and `Mode.REPLACE` subtract, intersect, or replace
(from) the builder's object. `Mode.PRIVATE` instructs the builder that this object
should not be combined with the builder's object in any way.
Most commonly, the default `mode` is `Mode.ADDITION` but this isn't always true.
For example, the `Hole` classes use a default `Mode.SUBTRACTION` as they remove
Most commonly, the default `mode` is `Mode.ADD` but this isn't always true.
For example, the `Hole` classes use a default `Mode.SUBTRACT` as they remove
a volume from the part under normal circumstances. However, the `mode` used in
the `Hole` classes can be specified as `Mode.ADDITION` or `Mode.INTERSECTION` to
the `Hole` classes can be specified as `Mode.ADD` or `Mode.INTERSECT` to
help in inspection or debugging.
*********************************

View file

@ -1,3 +1,30 @@
"""
name: canadian_flag.py
by: Gumyr
date: July 14th 2022
desc:
This example demonstrates building complex lines that snap to
existing features.
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from cadquery import Vector
from build123d.build123d_common import *
from build123d.build_sketch import *
@ -30,7 +57,7 @@ with BuildSketch() as east_field:
with BuildSketch() as centre_field:
Rectangle(1, 1, centered=(True, False))
AddToSketch(leaf.sketch, mode=Mode.SUBTRACTION)
AddToSketch(leaf.sketch, mode=Mode.SUBTRACT)
if "show_object" in locals():
show_object(

View file

@ -1,3 +1,31 @@
"""
name: din_rail.py
by: Gumyr
date: July 14th 2022
desc:
This example demonstrates multiple vertex filtering techniques including
a fully custom filter. It also shows how a workplane can be replaced
with another in a different orientation for further work.
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from build123d.build123d_common import *
from build123d.build_sketch import *
from build123d.build_part import *
@ -15,7 +43,7 @@ with BuildPart(workplane=Plane.named("XZ")) as rail:
top_width - 2 * thickness,
height - thickness,
centered=(True, False),
mode=Mode.SUBTRACTION,
mode=Mode.SUBTRACT,
)
inside_vertices = (
din.vertices()
@ -41,7 +69,7 @@ with BuildPart(workplane=Plane.named("XZ")) as rail:
with BuildSketch() as slots:
RectangularArrayToSketch(0, slot_pitch, 1, rail_length // slot_pitch - 1)
SlotOverall(slot_length, slot_width, rotation=90)
slot_holes = Extrude(-height, mode=Mode.SUBTRACTION)
slot_holes = Extrude(-height, mode=Mode.SUBTRACT)
if "show_object" in locals():
show_object(rail.part, name="rail")

View file

@ -1,3 +1,30 @@
"""
name: intersecting_pipes.py
by: Gumyr
date: July 14th 2022
desc:
This example demonstrates working on multiple planes created from object
faces and using a Select.LAST selector to return edges to be filleted.
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from build123d.build123d_common import *
from build123d.build_sketch import *
from build123d.build_part import *
@ -7,10 +34,10 @@ with BuildPart() as pipes:
WorkplanesFromFaces(*pipes.faces(), replace=True)
with BuildSketch() as pipe:
Circle(4)
Extrude(-5, mode=Mode.SUBTRACTION)
Extrude(-5, mode=Mode.SUBTRACT)
with BuildSketch() as pipe:
Circle(4.5)
Circle(4, mode=Mode.SUBTRACTION)
Circle(4, mode=Mode.SUBTRACT)
Extrude(10)
FilletPart(*pipes.edges(Select.LAST), radius=0.2)

View file

@ -1,3 +1,30 @@
"""
name: pillow_block.py
by: Gumyr
date: July 14th 2022
desc:
This example demonstrates placing holes in a part in a rectangular
array.
license:
Copyright 2022 Gumyr
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from build123d.build123d_common import *
from build123d.build_sketch import *
from build123d.build_part import *

View file

@ -80,10 +80,10 @@ class Keep(Enum):
class Mode(Enum):
"""Combination Mode"""
ADDITION = auto()
SUBTRACTION = auto()
INTERSECTION = auto()
CONSTRUCTION = auto()
ADD = auto()
SUBTRACT = auto()
INTERSECT = auto()
REPLACE = auto()
PRIVATE = auto()

View file

@ -27,6 +27,20 @@ license:
"""
from math import sin, cos, radians, sqrt
from typing import Union, Iterable
# from .occ_impl.geom import Vector, Matrix, Plane, Location, BoundBox
# from .occ_impl.shapes import (
# Shape,
# Vertex,
# Edge,
# Wire,
# Face,
# Shell,
# Solid,
# Compound,
# VectorLike,
# )
from cadquery import (
Edge,
Wire,
@ -47,7 +61,7 @@ class BuildLine:
Create lines (objects with length but not area or volume) from edges or wires.
Args:
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
@property
@ -56,7 +70,7 @@ class BuildLine:
wires = Wire.combine(self.line)
return wires if len(wires) > 1 else wires[0]
def __init__(self, mode: Mode = Mode.ADDITION):
def __init__(self, mode: Mode = Mode.ADD):
self.line = []
self.tags: dict[str, Edge] = {}
self.mode = mode
@ -115,7 +129,7 @@ class BuildLine:
return edge_list
@staticmethod
def add_to_context(*edges: Edge, mode: Mode = Mode.ADDITION):
def add_to_context(*edges: Edge, mode: Mode = Mode.ADD):
"""Add objects to BuildSketch instance
Core method to interface with BuildLine instance. Input sequence of edges are
@ -127,11 +141,10 @@ class BuildLine:
Args:
edges (Edge): sequence of edges to add
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
if context_stack and mode != Mode.PRIVATE:
for edge in edges:
edge.forConstruction = mode == Mode.CONSTRUCTION
context_stack[-1].line.append(edge)
context_stack[-1].last_edges = edges
context_stack[-1].last_vertices = list(
@ -156,10 +169,10 @@ class MirrorToLine:
Args:
edges (Edge): sequence of edges to mirror
axis (Axis, optional): axis to mirror about. Defaults to Axis.X.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(self, *edges: Edge, axis: Axis = Axis.X, mode: Mode = Mode.ADDITION):
def __init__(self, *edges: Edge, axis: Axis = Axis.X, mode: Mode = Mode.ADD):
mirrored_edges = Plane.named("XY").mirrorInPlane(edges, axis=axis.name)
BuildLine.add_to_context(*mirrored_edges, mode=mode)
@ -177,7 +190,7 @@ class CenterArc(Edge):
radius (float): arc radius
start_angle (float): arc staring angle
arc_size (float): arc size
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -186,7 +199,7 @@ class CenterArc(Edge):
radius: float,
start_angle: float,
arc_size: float,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
points = []
if abs(arc_size) >= 360:
@ -239,7 +252,7 @@ class Helix(Wire):
direction (VectorLike, optional): direction of central axis. Defaults to (0, 0, 1).
arc_size (float, optional): rotational angle. Defaults to 360.
lefhand (bool, optional): left handed helix. Defaults to False.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -251,7 +264,7 @@ class Helix(Wire):
direction: VectorLike = (0, 0, 1),
arc_size: float = 360,
lefhand: bool = False,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
helix = Wire.makeHelix(
pitch, height, radius, Vector(center), Vector(direction), arc_size, lefhand
@ -267,13 +280,13 @@ class Line(Edge):
Args:
pts (VectorLike): sequence of two points
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Two point not provided
"""
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADDITION):
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD):
if len(pts) != 2:
raise ValueError("Line requires two pts")
@ -294,7 +307,7 @@ class PolarLine(Edge):
length (float): line length
angle (float, optional): angle from +v X axis. Defaults to None.
direction (VectorLike, optional): vector direction. Defaults to None.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Either angle or direction must be provided
@ -306,7 +319,7 @@ class PolarLine(Edge):
length: float,
angle: float = None,
direction: VectorLike = None,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
if angle is not None:
x = cos(radians(angle)) * length
@ -330,13 +343,13 @@ class Polyline(Wire):
Args:
pts (VectorLike): sequence of three or more points
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Three or more points not provided
"""
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADDITION):
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD):
if len(pts) < 3:
raise ValueError("polyline requires three or more pts")
@ -359,7 +372,7 @@ class RadiusArc(Edge):
start_point (VectorLike): start
end_point (VectorLike): end
radius (float): radius
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Insufficient radius to connect end points
@ -370,7 +383,7 @@ class RadiusArc(Edge):
start_point: VectorLike,
end_point: VectorLike,
radius: float,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
start = Vector(start_point)
end = Vector(end_point)
@ -403,7 +416,7 @@ class SagittaArc(Edge):
start_point (VectorLike): start
end_point (VectorLike): end
sagitta (float): arc height
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -411,7 +424,7 @@ class SagittaArc(Edge):
start_point: VectorLike,
end_point: VectorLike,
sagitta: float,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
start = Vector(start_point)
end = Vector(end_point)
@ -447,7 +460,7 @@ class Spline(Edge):
tangent_scalars (Iterable[float], optional): change shape by amplifying tangent.
Defaults to None.
periodic (bool, optional): make the spline periodic. Defaults to False.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -456,7 +469,7 @@ class Spline(Edge):
tangents: Iterable[VectorLike] = None,
tangent_scalars: Iterable[float] = None,
periodic: bool = False,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
spline_pts = [Vector(pt) for pt in pts]
if tangents:
@ -494,7 +507,7 @@ class TangentArc(Edge):
tangent (VectorLike): tanget to constrain arc
tangent_from_first (bool, optional): apply tangent to first point. Note, applying
tangent to end point will flip the orientation of the arc. Defaults to True.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Two points are required
@ -505,7 +518,7 @@ class TangentArc(Edge):
*pts: VectorLike,
tangent: VectorLike,
tangent_from_first: bool = True,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
arc_pts = [Vector(p) for p in pts]
if len(arc_pts) != 2:
@ -528,13 +541,13 @@ class ThreePointArc(Edge):
Args:
pts (VectorLike): sequence of three points
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Three points must be provided
"""
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADDITION):
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD):
if len(pts) != 3:
raise ValueError("ThreePointArc requires three points")
points = [Vector(p) for p in pts]

View file

@ -35,6 +35,20 @@ from math import radians, sin, cos, tan
from tkinter import TOP
from typing import Union
from itertools import product
# from .occ_impl.geom import Vector, Matrix, Plane, Location, BoundBox
# from .occ_impl.shapes import (
# Shape,
# Vertex,
# Edge,
# Wire,
# Face,
# Shell,
# Solid,
# Compound,
# VectorLike,
# )
from cadquery import (
Edge,
Face,
@ -57,7 +71,7 @@ class BuildPart:
Create 3D parts (objects with the property of volume) from sketches or 3D objects.
Args:
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
workplane (Plane, optional): initial plane to work on. Defaults to Plane.named("XY").
"""
@ -83,7 +97,7 @@ class BuildPart:
def __init__(
self,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
workplane: Plane = Plane.named("XY"),
):
self.part: Compound = None
@ -216,7 +230,7 @@ class BuildPart:
def add_to_context(
self,
*objects: Union[Edge, Wire, Face, Solid, Compound],
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
"""Add objects to BuildPart instance
@ -230,7 +244,7 @@ class BuildPart:
Args:
objects (Union[Edge, Wire, Face, Solid, Compound]): sequence of objects to add
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Nothing to subtract from
@ -254,7 +268,7 @@ class BuildPart:
pre_solids = set() if self.part is None else set(self.part.Solids())
if new_solids:
if mode == Mode.ADDITION:
if mode == Mode.ADD:
if self.part is None:
if len(new_solids) == 1:
self.part = new_solids[0]
@ -262,16 +276,16 @@ class BuildPart:
self.part = new_solids.pop().fuse(*new_solids)
else:
self.part = self.part.fuse(*new_solids).clean()
elif mode == Mode.SUBTRACTION:
elif mode == Mode.SUBTRACT:
if self.part is None:
raise ValueError("Nothing to subtract from")
self.part = self.part.cut(*new_solids).clean()
elif mode == Mode.INTERSECTION:
elif mode == Mode.INTERSECT:
if self.part is None:
raise ValueError("Nothing to intersect with")
self.part = self.part.intersect(*new_solids).clean()
elif mode == Mode.CONSTRUCTION:
pass
elif mode == Mode.REPLACE:
self.part = Compound.makeCompound(new_solids).clean()
else:
raise ValueError(f"Invalid mode: {mode}")
@ -325,7 +339,8 @@ class ChamferPart(Compound):
def __init__(self, *edges: Edge, length1: float, length2: float = None):
new_part = BuildPart.get_context().part.chamfer(length1, length2, list(edges))
BuildPart.get_context().part = new_part
# BuildPart.get_context().part = new_part
BuildPart.get_context().add_to_context(new_part, mode=Mode.REPLACE)
super().__init__(new_part.wrapped)
@ -339,7 +354,7 @@ class CounterBoreHole(Compound):
counter_bore_radius (float): counter bore size
counter_bore_depth (float): counter bore depth
depth (float, optional): hole depth - None implies through part. Defaults to None.
mode (Mode, optional): combination mode. Defaults to Mode.SUBTRACTION.
mode (Mode, optional): combination mode. Defaults to Mode.SUBTRACT.
"""
def __init__(
@ -348,7 +363,7 @@ class CounterBoreHole(Compound):
counter_bore_radius: float,
counter_bore_depth: float,
depth: float = None,
mode: Mode = Mode.SUBTRACTION,
mode: Mode = Mode.SUBTRACT,
):
hole_depth = (
BuildPart.get_context().part.BoundingBox().DiagonalLength
@ -383,7 +398,7 @@ class CounterSinkHole(Compound):
counter_sink_radius (float): counter sink size
depth (float, optional): hole depth - None implies through part. Defaults to None.
counter_sink_angle (float, optional): cone angle. Defaults to 82.
mode (Mode, optional): combination mode. Defaults to Mode.SUBTRACTION.
mode (Mode, optional): combination mode. Defaults to Mode.SUBTRACT.
"""
def __init__(
@ -392,7 +407,7 @@ class CounterSinkHole(Compound):
counter_sink_radius: float,
depth: float = None,
counter_sink_angle: float = 82, # Common tip angle
mode: Mode = Mode.SUBTRACTION,
mode: Mode = Mode.SUBTRACT,
):
hole_depth = (
BuildPart.get_context().part.BoundingBox().DiagonalLength
@ -428,7 +443,7 @@ class Extrude(Compound):
until (Union[float, Until, Face]): depth of extrude or extrude limit
both (bool, optional): extrude in both directions. Defaults to False.
taper (float, optional): taper during extrusion. Defaults to None.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -436,7 +451,7 @@ class Extrude(Compound):
until: Union[float, Until, Face],
both: bool = False,
taper: float = None,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
new_solids: list[Solid] = []
for plane_index, faces in BuildPart.get_context().pending_faces.items():
@ -476,7 +491,8 @@ class FilletPart(Compound):
def __init__(self, *edges: Edge, radius: float):
new_part = BuildPart.get_context().part.fillet(radius, list(edges))
BuildPart.get_context().part = new_part
# BuildPart.get_context().part = new_part
BuildPart.get_context().add_to_context(new_part, mode=Mode.REPLACE)
super().__init__(new_part.wrapped)
@ -488,14 +504,14 @@ class Hole(Compound):
Args:
radius (float): hole size
depth (float, optional): hole depth - None implies through part. Defaults to None.
mode (Mode, optional): combination mode. Defaults to Mode.SUBTRACTION.
mode (Mode, optional): combination mode. Defaults to Mode.SUBTRACT.
"""
def __init__(
self,
radius: float,
depth: float = None,
mode: Mode = Mode.SUBTRACTION,
mode: Mode = Mode.SUBTRACT,
):
hole_depth = (
BuildPart.get_context().part.BoundingBox().DiagonalLength
@ -520,10 +536,10 @@ class Loft(Solid):
Args:
ruled (bool, optional): discontiguous layer tangents. Defaults to False.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(self, ruled: bool = False, mode: Mode = Mode.ADDITION):
def __init__(self, ruled: bool = False, mode: Mode = Mode.ADD):
loft_wires = []
for i in range(len(BuildPart.get_context().workplanes)):
@ -643,7 +659,7 @@ class Revolve(Compound):
revolution_arc (float, optional): angular size of revolution. Defaults to 360.0.
axis_start (VectorLike, optional): axis start in local coordinates. Defaults to None.
axis_end (VectorLike, optional): axis end in local coordinates. Defaults to None.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -651,7 +667,7 @@ class Revolve(Compound):
revolution_arc: float = 360.0,
axis_start: VectorLike = None,
axis_end: VectorLike = None,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
# Make sure we account for users specifying angles larger than 360 degrees, and
# for OCCT not assuming that a 0 degree revolve means a 360 degree revolve
@ -699,7 +715,8 @@ class Shell(Compound):
new_part = BuildPart.get_context().part.shell(
faces, thickness, kind=kind.name.lower()
)
BuildPart.get_context().part = new_part
# BuildPart.get_context().part = new_part
BuildPart.get_context().add_to_context(new_part, mode=Mode.REPLACE)
super().__init__(new_part.wrapped)
@ -735,7 +752,7 @@ class Split(Compound):
else:
cutters.append(build_cutter(keep))
BuildPart.get_context().add_to_context(*cutters, mode=Mode.INTERSECTION)
BuildPart.get_context().add_to_context(*cutters, mode=Mode.INTERSECT)
super().__init__(BuildPart.get_context().part.wrapped)
@ -753,7 +770,7 @@ class Sweep(Compound):
Defaults to Transition.RIGHT.
normal (VectorLike, optional): fixed normal. Defaults to None.
binormal (Union[Edge, Wire], optional): guide rotation along path. Defaults to None.
mode (Mode, optional): combination. Defaults to Mode.ADDITION.
mode (Mode, optional): combination. Defaults to Mode.ADD.
"""
def __init__(
@ -765,7 +782,7 @@ class Sweep(Compound):
transition: Transition = Transition.RIGHT,
normal: VectorLike = None,
binormal: Union[Edge, Wire] = None,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
path_wire = Wire.assembleEdges([path]) if isinstance(path, Edge) else path
if binormal is None:
@ -839,14 +856,14 @@ class AddToPart(Compound):
Args:
objects (Union[Edge, Wire, Face, Solid, Compound]): sequence of objects to add
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
mode (Mode, optional): combine mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
def __init__(
self,
*objects: Union[Edge, Wire, Face, Solid, Compound],
rotation: RotationLike = (0, 0, 0),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
rotate = Rotation(*rotation) if isinstance(rotation, tuple) else rotation
new_faces = [obj for obj in objects if isinstance(obj, Face)]
@ -887,7 +904,7 @@ class Box(Compound):
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
centered (tuple[bool, bool, bool], optional): center about axes.
Defaults to (True, True, True).
mode (Mode, optional): combine mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
def __init__(
@ -897,7 +914,7 @@ class Box(Compound):
height: float,
rotation: RotationLike = (0, 0, 0),
centered: tuple[bool, bool, bool] = (True, True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
rotate = Rotation(*rotation) if isinstance(rotation, tuple) else rotation
location_planes = BuildPart.get_context().get_and_clear_locations()
@ -933,7 +950,7 @@ class Cone(Compound):
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
centered (tuple[bool, bool, bool], optional): center about axes.
Defaults to (True, True, True).
mode (Mode, optional): combine mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
def __init__(
@ -944,7 +961,7 @@ class Cone(Compound):
arc_size: float = 360,
rotation: RotationLike = (0, 0, 0),
centered: tuple[bool, bool, bool] = (True, True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
rotate = Rotation(*rotation) if isinstance(rotation, tuple) else rotation
location_planes = BuildPart.get_context().get_and_clear_locations()
@ -980,7 +997,7 @@ class Cylinder(Compound):
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
centered (tuple[bool, bool, bool], optional): center about axes.
Defaults to (True, True, True).
mode (Mode, optional): combine mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
def __init__(
@ -990,7 +1007,7 @@ class Cylinder(Compound):
arc_size: float = 360,
rotation: RotationLike = (0, 0, 0),
centered: tuple[bool, bool, bool] = (True, True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
rotate = Rotation(*rotation) if isinstance(rotation, tuple) else rotation
location_planes = BuildPart.get_context().get_and_clear_locations()
@ -1026,7 +1043,7 @@ class Sphere(Compound):
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
centered (tuple[bool, bool, bool], optional): center about axes.
Defaults to (True, True, True).
mode (Mode, optional): combine mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
def __init__(
@ -1037,7 +1054,7 @@ class Sphere(Compound):
arc_size3: float = 360,
rotation: RotationLike = (0, 0, 0),
centered: tuple[bool, bool, bool] = (True, True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
rotate = Rotation(*rotation) if isinstance(rotation, tuple) else rotation
location_planes = BuildPart.get_context().get_and_clear_locations()
@ -1075,7 +1092,7 @@ class Torus(Compound):
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
centered (tuple[bool, bool, bool], optional): center about axes.
Defaults to (True, True, True).
mode (Mode, optional): combine mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
def __init__(
@ -1086,7 +1103,7 @@ class Torus(Compound):
minor_arc_size: float = 360,
rotation: RotationLike = (0, 0, 0),
centered: tuple[bool, bool, bool] = (True, True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
rotate = Rotation(*rotation) if isinstance(rotation, tuple) else rotation
location_planes = BuildPart.get_context().get_and_clear_locations()
@ -1124,7 +1141,7 @@ class Wedge(Compound):
xmax (float): maximum X location
zmax (float): maximum Z location
rotation (RotationLike, optional): angles to rotate about axes. Defaults to (0, 0, 0).
mode (Mode, optional): combine mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
def __init__(
@ -1137,7 +1154,7 @@ class Wedge(Compound):
xmax: float,
zmax: float,
rotation: RotationLike = (0, 0, 0),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
rotate = Rotation(*rotation) if isinstance(rotation, tuple) else rotation
location_planes = BuildPart.get_context().get_and_clear_locations()

View file

@ -41,6 +41,20 @@ license:
from math import pi, sin, cos, tan, radians
from typing import Union
from itertools import product
# from .hull import find_hull
# from .occ_impl.geom import Vector, Matrix, Plane, Location, BoundBox
# from .occ_impl.shapes import (
# Shape,
# Vertex,
# Edge,
# Wire,
# Face,
# Shell,
# Solid,
# Compound,
# VectorLike,
# )
from cadquery.hull import find_hull
from cadquery import Edge, Face, Wire, Vector, Shape, Location, Vertex, Compound, Plane
from cadquery.occ_impl.shapes import VectorLike
@ -55,10 +69,10 @@ class BuildSketch:
Create planar 2D sketches (objects with area but not volume) from faces or lines.
Args:
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(self, mode: Mode = Mode.ADDITION):
def __init__(self, mode: Mode = Mode.ADD):
self.sketch = None
self.pending_edges: list[Edge] = []
self.locations: list[Location] = [Location(Vector())]
@ -140,7 +154,7 @@ class BuildSketch:
return wires if len(wires) > 1 else wires[0]
def add_to_context(
self, *objects: Union[Edge, Wire, Face, Compound], mode: Mode = Mode.ADDITION
self, *objects: Union[Edge, Wire, Face, Compound], mode: Mode = Mode.ADD
):
"""Add objects to BuildSketch instance
@ -154,7 +168,7 @@ class BuildSketch:
Args:
objects (Union[Edge, Wire, Face, Compound]): sequence of objects to add
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Nothing to subtract from
@ -172,21 +186,21 @@ class BuildSketch:
pre_vertices = set() if self.sketch is None else set(self.sketch.Vertices())
pre_edges = set() if self.sketch is None else set(self.sketch.Edges())
pre_faces = set() if self.sketch is None else set(self.sketch.Faces())
if mode == Mode.ADDITION:
if mode == Mode.ADD:
if self.sketch is None:
self.sketch = Compound.makeCompound(new_faces)
else:
self.sketch = self.sketch.fuse(*new_faces).clean()
elif mode == Mode.SUBTRACTION:
elif mode == Mode.SUBTRACT:
if self.sketch is None:
raise RuntimeError("No sketch to subtract from")
self.sketch = self.sketch.cut(*new_faces).clean()
elif mode == Mode.INTERSECTION:
elif mode == Mode.INTERSECT:
if self.sketch is None:
raise RuntimeError("No sketch to intersect with")
self.sketch = self.sketch.intersect(*new_faces).clean()
elif mode == Mode.CONSTRUCTION:
pass
elif mode == Mode.REPLACE:
self.sketch = Compound.makeCompound(new_faces).clean()
else:
raise ValueError(f"Invalid mode: {mode}")
@ -218,13 +232,13 @@ class BoundingBoxSketch(Compound):
Args:
objects (Shape): sequence of objects
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
self,
*objects: Shape,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
new_faces = []
for obj in objects:
@ -253,10 +267,10 @@ class BuildFace:
Args:
edges (Edge): sequence of perimeter edges
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(self, *edges: Edge, mode: Mode = Mode.ADDITION):
def __init__(self, *edges: Edge, mode: Mode = Mode.ADD):
pending_face = Face.makeFromWires(Wire.combine(edges)[0])
BuildSketch.get_context().add_to_context(pending_face, mode)
BuildSketch.get_context().pending_edges = []
@ -269,10 +283,10 @@ class BuildHull:
Args:
edges (Edge): sequence of edges to hull
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(self, *edges: Edge, mode: Mode = Mode.ADDITION):
def __init__(self, *edges: Edge, mode: Mode = Mode.ADD):
pending_face = find_hull(edges)
BuildSketch.get_context().add_to_context(pending_face, mode)
BuildSketch.get_context().pending_edges = []
@ -290,14 +304,16 @@ class ChamferSketch(Compound):
def __init__(self, *vertices: Vertex, length: float):
new_faces = []
for face in BuildSketch.get_context().sketch.Faces():
# for face in BuildSketch.get_context().sketch.Faces():
for face in BuildSketch.get_context().faces():
vertices_in_face = filter(lambda v: v in face.Vertices(), vertices)
if vertices_in_face:
new_faces.append(face.chamfer2D(length, vertices_in_face))
else:
new_faces.append(face)
new_sketch = Compound.makeCompound(new_faces)
BuildSketch.get_context().sketch = new_sketch
# BuildSketch.get_context().sketch = new_sketch
BuildSketch.get_context().add_to_context(new_sketch, mode=Mode.REPLACE)
super().__init__(new_sketch.wrapped)
@ -313,14 +329,16 @@ class FilletSketch(Compound):
def __init__(self, *vertices: Vertex, radius: float):
new_faces = []
for face in BuildSketch.get_context().sketch.Faces():
# for face in BuildSketch.get_context().sketch.Faces():
for face in BuildSketch.get_context().faces():
vertices_in_face = filter(lambda v: v in face.Vertices(), vertices)
if vertices_in_face:
new_faces.append(face.fillet2D(radius, vertices_in_face))
else:
new_faces.append(face)
new_sketch = Compound.makeCompound(new_faces)
BuildSketch.get_context().sketch = new_sketch
# BuildSketch.get_context().sketch = new_sketch
BuildSketch.get_context().add_to_context(new_sketch, mode=Mode.REPLACE)
super().__init__(new_sketch.wrapped)
@ -332,14 +350,14 @@ class MirrorToSketch:
Args:
objects (Union[Face,Compound]): sequence of faces to mirror
axis (Axis, optional): axis to mirror about. Defaults to Axis.X.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
self,
*objects: Union[Face, Compound],
axis: Axis = Axis.X,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
new_faces = [obj for obj in objects if isinstance(obj, Face)]
for compound in filter(lambda o: isinstance(o, Compound), objects):
@ -357,7 +375,7 @@ class Offset(Compound):
Args:
amount (float): positive values external, negative internal
kind (Kind, optional): transition shape. Defaults to Kind.ARC.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: Only Compounds of Faces valid
@ -368,7 +386,7 @@ class Offset(Compound):
*objects: Union[Face, Compound],
amount: float,
kind: Kind = Kind.ARC,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
faces = []
for obj in objects:
@ -500,14 +518,14 @@ class AddToSketch(Compound):
Args:
objects (Union[Edge, Wire, Face, Solid, Compound]): sequence of objects to add
rotation (float, optional): angles to rotate objects. Defaults to 0.
mode (Mode, optional): combine mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combine mode. Defaults to Mode.ADD.
"""
def __init__(
self,
*objects: Union[Edge, Wire, Face, Compound],
rotation: float = 0,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
new_objects = []
for obj in objects:
@ -533,14 +551,14 @@ class Circle(Compound):
Args:
radius (float): circle size
centered (tuple[bool, bool], optional): center options. Defaults to (True, True).
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
self,
radius: float,
centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
center_offset = Vector(
0 if centered[0] else radius,
@ -568,7 +586,7 @@ class Ellipse(Compound):
y_radius (float): vertical radius
rotation (float, optional): angles to rotate objects. Defaults to 0.
centered (tuple[bool, bool], optional): center options. Defaults to (True, True).
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -577,7 +595,7 @@ class Ellipse(Compound):
y_radius: float,
rotation: float = 0,
centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
face = Face.makeFromWires(
Wire.makeEllipse(
@ -614,7 +632,7 @@ class Polygon(Compound):
pts (VectorLike): sequence of points defining the vertices of polygon
rotation (float, optional): angles to rotate objects. Defaults to 0.
centered (tuple[bool, bool], optional): center options. Defaults to (True, True).
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -622,7 +640,7 @@ class Polygon(Compound):
*pts: VectorLike,
rotation: float = 0,
centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
poly_pts = [Vector(p) for p in pts]
face = Face.makeFromWires(Wire.makePolygon(poly_pts)).rotate(*z_axis, rotation)
@ -651,7 +669,7 @@ class Rectangle(Compound):
height (float): vertical size
rotation (float, optional): angles to rotate objects. Defaults to 0.
centered (tuple[bool, bool], optional): center options. Defaults to (True, True).
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -660,7 +678,7 @@ class Rectangle(Compound):
height: float,
rotation: float = 0,
centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
face = Face.makePlane(height, width).rotate(*z_axis, rotation)
bounding_box = face.BoundingBox()
@ -689,7 +707,7 @@ class RegularPolygon(Compound):
side_count (int): number of polygon sides
rotation (float, optional): angles to rotate objects. Defaults to 0.
centered (tuple[bool, bool], optional): center options. Defaults to (True, True).
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -698,7 +716,7 @@ class RegularPolygon(Compound):
side_count: int,
rotation: float = 0,
centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
pts = [
Vector(
@ -733,7 +751,7 @@ class SlotArc(Compound):
arc (Union[Edge, Wire]): center line of slot
height (float): diameter of end circles
rotation (float, optional): angles to rotate objects. Defaults to 0.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
Raises:
ValueError: arc defined by a single edge is currently unsupported
@ -744,7 +762,7 @@ class SlotArc(Compound):
arc: Union[Edge, Wire],
height: float,
rotation: float = 0,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
if isinstance(arc, Edge):
raise ValueError("Bug - Edges aren't supported by offset")
@ -771,7 +789,7 @@ class SlotCenterPoint(Compound):
point (VectorLike): slot center of arc point
height (float): diameter of end circles
rotation (float, optional): angles to rotate objects. Defaults to 0.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -780,7 +798,7 @@ class SlotCenterPoint(Compound):
point: VectorLike,
height: float,
rotation: float = 0,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
center_v = Vector(center)
point_v = Vector(point)
@ -812,7 +830,7 @@ class SlotCenterToCenter(Compound):
center_separation (float): distance between two arc centers
height (float): diameter of end circles
rotation (float, optional): angles to rotate objects. Defaults to 0.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -820,7 +838,7 @@ class SlotCenterToCenter(Compound):
center_separation: float,
height: float,
rotation: float = 0,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
face = Face.makeFromWires(
Wire.assembleEdges(
@ -848,7 +866,7 @@ class SlotOverall(Compound):
width (float): overall width of the slot
height (float): diameter of end circles
rotation (float, optional): angles to rotate objects. Defaults to 0.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -856,7 +874,7 @@ class SlotOverall(Compound):
width: float,
height: float,
rotation: float = 0,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
face = Face.makeFromWires(
Wire.assembleEdges(
@ -892,7 +910,7 @@ class Text(Compound):
position_on_path (float, optional): the relative location on path to position the
text, values must be between 0.0 and 1.0. Defaults to 0.0.
rotation (float, optional): angles to rotate objects. Defaults to 0.
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -907,7 +925,7 @@ class Text(Compound):
path: Union[Edge, Wire] = None,
position_on_path: float = 0.0,
rotation: float = 0,
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
) -> Compound:
text_string = Compound.make2DText(
txt,
@ -944,7 +962,7 @@ class Trapezoid(Compound):
Defaults to None.
rotation (float, optional): angles to rotate objects. Defaults to 0.
centered (tuple[bool, bool], optional): center options. Defaults to (True, True).
mode (Mode, optional): combination mode. Defaults to Mode.ADDITION.
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
"""
def __init__(
@ -955,7 +973,7 @@ class Trapezoid(Compound):
right_side_angle: float = None,
rotation: float = 0,
centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADDITION,
mode: Mode = Mode.ADD,
):
pts = []
pts.append(Vector(-width / 2, -height / 2))