mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
Refactored to be class based
This commit is contained in:
parent
b8c76c7954
commit
b2d19f8e13
1 changed files with 200 additions and 200 deletions
400
build_part.py
400
build_part.py
|
|
@ -1,8 +1,7 @@
|
||||||
from math import pi, sin, cos, radians, sqrt
|
from math import pi, sin, cos, radians, sqrt
|
||||||
from typing import Union, Iterable, Sequence, Callable
|
from typing import Union, Iterable, Callable
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
import cadquery as cq
|
import cadquery as cq
|
||||||
from cadquery.hull import find_hull
|
|
||||||
from cadquery import (
|
from cadquery import (
|
||||||
Edge,
|
Edge,
|
||||||
Face,
|
Face,
|
||||||
|
|
@ -26,64 +25,46 @@ class BuildPart:
|
||||||
return len(self.workplanes)
|
return len(self.workplanes)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pending_face_count(self) -> int:
|
def pending_faces_count(self) -> int:
|
||||||
return len(self.pending_faces.values())
|
return len(self.pending_faces.values())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pending_edge_count(self) -> int:
|
def pending_edges_count(self) -> int:
|
||||||
return len(self.pending_edges.values())
|
return len(self.pending_edges.values())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pending_solids_count(self) -> int:
|
||||||
|
return len(self.pending_solids.values())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pending_location_count(self) -> int:
|
def pending_location_count(self) -> int:
|
||||||
return len(self.locations.values())
|
return len(self.locations.values())
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
parent: BuildAssembly = None,
|
|
||||||
mode: Mode = Mode.ADDITION,
|
mode: Mode = Mode.ADDITION,
|
||||||
workplane: Plane = Plane.named("XY"),
|
workplane: Plane = Plane.named("XY"),
|
||||||
):
|
):
|
||||||
self.parent = parent
|
self.part: Compound = None
|
||||||
self.part: Solid = None
|
|
||||||
self.workplanes: list[Plane] = [workplane]
|
self.workplanes: list[Plane] = [workplane]
|
||||||
self.pending_faces: dict[int : list[Face]] = {0: []}
|
self.pending_faces: dict[int : list[Face]] = {0: []}
|
||||||
self.pending_edges: dict[int : list[Edge]] = {0: []}
|
self.pending_edges: dict[int : list[Edge]] = {0: []}
|
||||||
|
self.pending_solids: dict[int : list[Solid]] = {0: []}
|
||||||
self.locations: dict[int : list[Location]] = {0: []}
|
self.locations: dict[int : list[Location]] = {0: []}
|
||||||
self.last_operation: dict[CqObject : list[Shape]] = {}
|
self.last_operation: dict[CqObject : list[Shape]] = {}
|
||||||
|
self.mode = mode
|
||||||
|
self.last_vertices = []
|
||||||
|
self.last_edges = []
|
||||||
|
self.last_faces = []
|
||||||
|
self.last_solids = []
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
|
context_stack.append(self)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, exception_type, exception_value, traceback):
|
def __exit__(self, exception_type, exception_value, traceback):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def push_points(self, *pts: Union[VectorLike, Location]):
|
|
||||||
new_locations = [
|
|
||||||
Location(Vector(pt)) if not isinstance(pt, Location) else pt for pt in pts
|
|
||||||
]
|
|
||||||
for i in range(len(self.workplanes)):
|
|
||||||
self.locations[i].extend(new_locations)
|
|
||||||
print(f"{len(self.locations[i])=}")
|
|
||||||
return new_locations[0] if len(new_locations) == 1 else new_locations
|
|
||||||
|
|
||||||
def add(self, obj: Union[Edge, Face], mode: Mode = Mode.ADDITION):
|
|
||||||
for i, workplane in enumerate(self.workplanes):
|
|
||||||
# If no locations have been defined, add one to the workplane center
|
|
||||||
if not self.locations[i]:
|
|
||||||
self.locations[i].append(Location(Vector()))
|
|
||||||
for loc in self.locations[i]:
|
|
||||||
localized_obj = workplane.fromLocalCoords(obj.moved(loc))
|
|
||||||
if i in self.pending_faces:
|
|
||||||
if isinstance(obj, Face):
|
|
||||||
self.pending_faces[i].append(localized_obj)
|
|
||||||
else:
|
|
||||||
self.pending_edges[i].append(localized_obj)
|
|
||||||
else:
|
|
||||||
if isinstance(obj, Face):
|
|
||||||
self.pending_faces[i] = [localized_obj]
|
|
||||||
else:
|
|
||||||
self.pending_edges[i] = [localized_obj]
|
|
||||||
|
|
||||||
def workplane(self, workplane: Plane = Plane.named("XY"), replace=True):
|
def workplane(self, workplane: Plane = Plane.named("XY"), replace=True):
|
||||||
if replace:
|
if replace:
|
||||||
self.workplanes = [workplane]
|
self.workplanes = [workplane]
|
||||||
|
|
@ -92,7 +73,7 @@ class BuildPart:
|
||||||
self.locations[len(self.workplanes) - 1] = [Location()]
|
self.locations[len(self.workplanes) - 1] = [Location()]
|
||||||
return workplane
|
return workplane
|
||||||
|
|
||||||
def faces_to_workplanes(self, *faces: Sequence[Face], replace=False):
|
def faces_to_workplanes(self, *faces: Face, replace=False):
|
||||||
new_planes = []
|
new_planes = []
|
||||||
for face in faces:
|
for face in faces:
|
||||||
new_plane = Plane(origin=face.Center(), normal=face.normalAt(face.Center()))
|
new_plane = Plane(origin=face.Center(), normal=face.normalAt(face.Center()))
|
||||||
|
|
@ -100,192 +81,189 @@ class BuildPart:
|
||||||
self.workplane(new_plane, replace)
|
self.workplane(new_plane, replace)
|
||||||
return new_planes[0] if len(new_planes) == 1 else new_planes
|
return new_planes[0] if len(new_planes) == 1 else new_planes
|
||||||
|
|
||||||
def edges(self, sort_by: SortBy = SortBy.NONE, reverse: bool = False) -> list[Edge]:
|
def vertices(self, select: Select = Select.ALL) -> list[Vertex]:
|
||||||
if sort_by == SortBy.NONE:
|
vertex_list = []
|
||||||
edges = self.part.Edges()
|
if select == Select.ALL:
|
||||||
elif sort_by == SortBy.X:
|
for e in self.part.Edges():
|
||||||
edges = sorted(
|
vertex_list.extend(e.Vertices())
|
||||||
self.part.Edges(),
|
elif select == Select.LAST:
|
||||||
key=lambda obj: obj.Center().x,
|
vertex_list = self.last_vertices
|
||||||
reverse=reverse,
|
return list(set(vertex_list))
|
||||||
)
|
|
||||||
elif sort_by == SortBy.Y:
|
|
||||||
edges = sorted(
|
|
||||||
self.part.Edges(),
|
|
||||||
key=lambda obj: obj.Center().y,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.Z:
|
|
||||||
edges = sorted(
|
|
||||||
self.part.Edges(),
|
|
||||||
key=lambda obj: obj.Center().z,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.LENGTH:
|
|
||||||
edges = sorted(
|
|
||||||
self.part.Edges(),
|
|
||||||
key=lambda obj: obj.Length(),
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.RADIUS:
|
|
||||||
edges = sorted(
|
|
||||||
self.part.Edges(),
|
|
||||||
key=lambda obj: obj.radius(),
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.DISTANCE:
|
|
||||||
edges = sorted(
|
|
||||||
self.part.Edges(),
|
|
||||||
key=lambda obj: obj.Center().Length,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Unable to sort edges by {sort_by}")
|
|
||||||
|
|
||||||
return edges
|
def edges(self, select: Select = Select.ALL) -> list[Edge]:
|
||||||
|
if select == Select.ALL:
|
||||||
|
edge_list = self.part.Edges()
|
||||||
|
elif select == Select.LAST:
|
||||||
|
edge_list = self.last_edges
|
||||||
|
return edge_list
|
||||||
|
|
||||||
def faces(self, sort_by: SortBy = SortBy.NONE, reverse: bool = False) -> list[Face]:
|
def faces(self, select: Select = Select.ALL) -> list[Face]:
|
||||||
if sort_by == SortBy.NONE:
|
if select == Select.ALL:
|
||||||
faces = self.part.Faces()
|
face_list = self.part.Faces()
|
||||||
elif sort_by == SortBy.X:
|
elif select == Select.LAST:
|
||||||
faces = sorted(
|
face_list = self.last_edges
|
||||||
self.part.Faces(),
|
return face_list
|
||||||
key=lambda obj: obj.Center().x,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.Y:
|
|
||||||
faces = sorted(
|
|
||||||
self.part.Faces(),
|
|
||||||
key=lambda obj: obj.Center().y,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.Z:
|
|
||||||
faces = sorted(
|
|
||||||
self.part.Faces(),
|
|
||||||
key=lambda obj: obj.Center().z,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.AREA:
|
|
||||||
faces = sorted(
|
|
||||||
self.part.Faces(), key=lambda obj: obj.Area(), reverse=reverse
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.DISTANCE:
|
|
||||||
faces = sorted(
|
|
||||||
self.part.Faces(),
|
|
||||||
key=lambda obj: obj.Center().Length,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Unable to sort edges by {sort_by}")
|
|
||||||
return faces
|
|
||||||
|
|
||||||
def vertices(
|
def solids(self, select: Select = Select.ALL) -> list[Solid]:
|
||||||
self, sort_by: SortBy = SortBy.NONE, reverse: bool = False
|
if select == Select.ALL:
|
||||||
) -> list[Vertex]:
|
solid_list = self.part.Solids()
|
||||||
if sort_by == SortBy.NONE:
|
elif select == Select.LAST:
|
||||||
vertices = self.part.Vertices()
|
solid_list = self.last_solids
|
||||||
elif sort_by == SortBy.X:
|
return solid_list
|
||||||
vertices = sorted(
|
|
||||||
self.part.Vertices(),
|
|
||||||
key=lambda obj: obj.Center().x,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.Y:
|
|
||||||
vertices = sorted(
|
|
||||||
self.part.Vertices(),
|
|
||||||
key=lambda obj: obj.Center().y,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.Z:
|
|
||||||
vertices = sorted(
|
|
||||||
self.part.Vertices(),
|
|
||||||
key=lambda obj: obj.Center().z,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
elif sort_by == SortBy.DISTANCE:
|
|
||||||
vertices = sorted(
|
|
||||||
self.part.Vertices(),
|
|
||||||
key=lambda obj: obj.Center().Length,
|
|
||||||
reverse=reverse,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Unable to sort edges by {sort_by}")
|
|
||||||
return vertices
|
|
||||||
|
|
||||||
def place_solids(
|
@staticmethod
|
||||||
|
def get_context() -> "BuildPart":
|
||||||
|
return context_stack[-1]
|
||||||
|
|
||||||
|
def add_to_pending(self, *objects: Union[Edge, Face]):
|
||||||
|
for obj in objects:
|
||||||
|
for i, workplane in enumerate(self.workplanes):
|
||||||
|
# If no locations have been defined, add one to the workplane center
|
||||||
|
if not self.locations[i]:
|
||||||
|
self.locations[i].append(Location(Vector()))
|
||||||
|
for loc in self.locations[i]:
|
||||||
|
localized_obj = workplane.fromLocalCoords(obj.moved(loc))
|
||||||
|
if i in self.pending_faces:
|
||||||
|
if isinstance(obj, Face):
|
||||||
|
self.pending_faces[i].append(localized_obj)
|
||||||
|
else:
|
||||||
|
self.pending_edges[i].append(localized_obj)
|
||||||
|
else:
|
||||||
|
if isinstance(obj, Face):
|
||||||
|
self.pending_faces[i] = [localized_obj]
|
||||||
|
else:
|
||||||
|
self.pending_edges[i] = [localized_obj]
|
||||||
|
|
||||||
|
def add_to_context(
|
||||||
self,
|
self,
|
||||||
new_solids: list[Solid, Compound],
|
*objects: Union[Edge, Wire, Face, Solid, Compound],
|
||||||
mode: Mode = Mode.ADDITION,
|
mode: Mode = Mode.ADDITION,
|
||||||
clean: bool = True,
|
|
||||||
):
|
):
|
||||||
|
if context_stack and mode != Mode.PRIVATE:
|
||||||
|
# Sort the provided objects into edges, faces and solids
|
||||||
|
new_faces = [obj for obj in objects if isinstance(obj, Face)]
|
||||||
|
new_solids = [obj for obj in objects if isinstance(obj, Solid)]
|
||||||
|
for compound in filter(lambda o: isinstance(o, Compound), objects):
|
||||||
|
new_faces.extend(compound.Faces())
|
||||||
|
new_solids.extend(compound.Solids())
|
||||||
|
new_edges = [obj for obj in objects if isinstance(obj, Edge)]
|
||||||
|
for compound in filter(lambda o: isinstance(o, Wire), objects):
|
||||||
|
new_edges.extend(compound.Edges())
|
||||||
|
|
||||||
Solid.clean_op = Solid.clean if clean else Solid.null
|
pre_vertices = set() if self.part is None else set(self.part.Vertices())
|
||||||
Compound.clean_op = Compound.clean if clean else Compound.null
|
pre_edges = set() if self.part is None else set(self.part.Edges())
|
||||||
|
pre_faces = set() if self.part is None else set(self.part.Faces())
|
||||||
|
pre_solids = set() if self.part is None else set(self.part.Solids())
|
||||||
|
|
||||||
before_vertices = set() if self.part is None else set(self.part.Vertices())
|
if mode == Mode.ADDITION:
|
||||||
before_edges = set() if self.part is None else set(self.part.Edges())
|
if self.part is None:
|
||||||
before_faces = set() if self.part is None else set(self.part.Faces())
|
if len(new_solids) == 1:
|
||||||
|
self.part = new_solids[0]
|
||||||
if mode == Mode.ADDITION:
|
else:
|
||||||
if self.part is None:
|
self.part = new_solids.pop().fuse(*new_solids)
|
||||||
if len(new_solids) == 1:
|
|
||||||
self.part = new_solids[0]
|
|
||||||
else:
|
else:
|
||||||
self.part = new_solids.pop().fuse(*new_solids)
|
self.part = self.part.fuse(*new_solids).clean_op()
|
||||||
|
elif mode == Mode.SUBTRACTION:
|
||||||
|
if self.part is None:
|
||||||
|
raise ValueError("Nothing to subtract from")
|
||||||
|
self.part = self.part.cut(*new_solids).clean_op()
|
||||||
|
elif mode == Mode.INTERSECTION:
|
||||||
|
if self.part is None:
|
||||||
|
raise ValueError("Nothing to intersect with")
|
||||||
|
self.part = self.part.intersect(*new_solids).clean_op()
|
||||||
|
elif mode == Mode.CONSTRUCTION:
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
self.part = self.part.fuse(*new_solids).clean_op()
|
raise ValueError(f"Invalid mode: {mode}")
|
||||||
elif mode == Mode.SUBTRACTION:
|
|
||||||
if self.part is None:
|
|
||||||
raise ValueError("Nothing to subtract from")
|
|
||||||
self.part = self.part.cut(*new_solids).clean_op()
|
|
||||||
elif mode == Mode.INTERSECTION:
|
|
||||||
if self.part is None:
|
|
||||||
raise ValueError("Nothing to intersect with")
|
|
||||||
self.part = self.part.intersect(*new_solids).clean_op()
|
|
||||||
|
|
||||||
self.last_operation[CqObject.VERTEX] = list(
|
post_vertices = set(self.part.Vertices())
|
||||||
set(self.part.Vertices()) - before_vertices
|
post_edges = set(self.part.Edges())
|
||||||
)
|
post_faces = set(self.part.Faces())
|
||||||
self.last_operation[CqObject.EDGE] = list(set(self.part.Edges()) - before_edges)
|
post_solids = set(self.part.Solids())
|
||||||
self.last_operation[CqObject.FACE] = list(set(self.part.Faces()) - before_faces)
|
self.last_vertices = list(post_vertices - pre_vertices)
|
||||||
|
self.last_edges = list(post_edges - pre_edges)
|
||||||
|
self.last_faces = list(post_faces - pre_faces)
|
||||||
|
self.last_solids = list(post_solids - pre_solids)
|
||||||
|
|
||||||
def extrude(
|
self.add_to_pending(*new_edges)
|
||||||
|
self.add_to_pending(*new_faces)
|
||||||
|
|
||||||
|
|
||||||
|
class AddPart(Compound):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*objects: Union[Edge, Wire, Face, Solid, Compound],
|
||||||
|
mode: Mode = Mode.ADDITION,
|
||||||
|
):
|
||||||
|
new_faces = [obj for obj in objects if isinstance(obj, Face)]
|
||||||
|
new_solids = [obj for obj in objects if isinstance(obj, Solid)]
|
||||||
|
for compound in filter(lambda o: isinstance(o, Compound), objects):
|
||||||
|
new_faces.extend(compound.Faces())
|
||||||
|
new_solids.extend(compound.Solids())
|
||||||
|
new_edges = [obj for obj in objects if isinstance(obj, Edge)]
|
||||||
|
for compound in filter(lambda o: isinstance(o, Wire), objects):
|
||||||
|
new_edges.extend(compound.Edges())
|
||||||
|
|
||||||
|
# Add to pending faces and edges
|
||||||
|
BuildPart.get_context().add_to_pending(new_faces)
|
||||||
|
BuildPart.get_context().add_to_pending(new_edges)
|
||||||
|
|
||||||
|
# Locate the solids to the predefined positions
|
||||||
|
locations = [
|
||||||
|
location for location in BuildPart.get_context().locations.values()
|
||||||
|
]
|
||||||
|
# If no locations have been specified, use the origin
|
||||||
|
if not locations:
|
||||||
|
locations = [Location(Vector())]
|
||||||
|
|
||||||
|
located_solids = [
|
||||||
|
solid.moved(location) for solid in new_solids for location in locations
|
||||||
|
]
|
||||||
|
BuildPart.get_context().add_to_context(*located_solids, mode=mode)
|
||||||
|
super().__init__(Compound.makeCompound(located_solids).wrapped)
|
||||||
|
|
||||||
|
|
||||||
|
class Extrude(Compound):
|
||||||
|
def __init__(
|
||||||
self,
|
self,
|
||||||
until: Union[float, Until, Face],
|
until: Union[float, Until, Face],
|
||||||
both: bool = False,
|
both: bool = False,
|
||||||
taper: float = None,
|
taper: float = None,
|
||||||
mode: Mode = Mode.ADDITION,
|
mode: Mode = Mode.ADDITION,
|
||||||
clean: bool = True,
|
|
||||||
):
|
):
|
||||||
|
|
||||||
new_solids: list[Solid] = []
|
new_solids: list[Solid] = []
|
||||||
for plane_index, faces in self.pending_faces.items():
|
for plane_index, faces in BuildPart.get_context().pending_faces.items():
|
||||||
for face in faces:
|
for face in faces:
|
||||||
new_solids.append(
|
new_solids.append(
|
||||||
Solid.extrudeLinear(
|
Solid.extrudeLinear(
|
||||||
face, self.workplanes[plane_index].zDir * until, 0
|
face,
|
||||||
|
BuildPart.get_context().workplanes[plane_index].zDir * until,
|
||||||
|
0,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if both:
|
if both:
|
||||||
new_solids.append(
|
new_solids.append(
|
||||||
Solid.extrudeLinear(
|
Solid.extrudeLinear(
|
||||||
face,
|
face,
|
||||||
self.workplanes[plane_index].zDir * until * -1.0,
|
BuildPart.get_context().workplanes[plane_index].zDir
|
||||||
|
* until
|
||||||
|
* -1.0,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.place_solids(new_solids, mode, clean)
|
BuildPart.get_context().add_to_context(*new_solids, mode=mode)
|
||||||
|
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
||||||
|
|
||||||
return new_solids[0] if len(new_solids) == 1 else new_solids
|
|
||||||
|
|
||||||
def revolve(
|
class Revolve(Compound):
|
||||||
|
def __init__(
|
||||||
self,
|
self,
|
||||||
angle_degrees: float = 360.0,
|
angle_degrees: float = 360.0,
|
||||||
axis_start: VectorLike = None,
|
axis_start: VectorLike = None,
|
||||||
axis_end: VectorLike = None,
|
axis_end: VectorLike = None,
|
||||||
mode: Mode = Mode.ADDITION,
|
mode: Mode = Mode.ADDITION,
|
||||||
clean: bool = True,
|
|
||||||
):
|
):
|
||||||
# Make sure we account for users specifying angles larger than 360 degrees, and
|
# 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
|
# for OCCT not assuming that a 0 degree revolve means a 360 degree revolve
|
||||||
|
|
@ -293,7 +271,7 @@ class BuildPart:
|
||||||
angle = 360.0 if angle == 0 else angle
|
angle = 360.0 if angle == 0 else angle
|
||||||
|
|
||||||
new_solids = []
|
new_solids = []
|
||||||
for i, workplane in enumerate(self.workplanes):
|
for i, workplane in enumerate(BuildPart.get_context().workplanes):
|
||||||
axis = []
|
axis = []
|
||||||
if axis_start is None:
|
if axis_start is None:
|
||||||
axis.append(workplane.fromLocalCoords(Vector(0, 0, 0)))
|
axis.append(workplane.fromLocalCoords(Vector(0, 0, 0)))
|
||||||
|
|
@ -306,25 +284,28 @@ class BuildPart:
|
||||||
axis.append(workplane.fromLocalCoords(Vector(axis_end)))
|
axis.append(workplane.fromLocalCoords(Vector(axis_end)))
|
||||||
print(f"Revolve: {axis=}")
|
print(f"Revolve: {axis=}")
|
||||||
|
|
||||||
for face in self.pending_faces[i]:
|
for face in BuildPart.get_context().pending_faces[i]:
|
||||||
new_solids.append(Solid.revolve(face, angle, *axis))
|
new_solids.append(Solid.revolve(face, angle, *axis))
|
||||||
|
|
||||||
self.place_solids(new_solids, mode, clean)
|
BuildPart.get_context().add_to_context(*new_solids, mode=mode)
|
||||||
|
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
||||||
|
|
||||||
return new_solids[0] if len(new_solids) == 1 else new_solids
|
|
||||||
|
|
||||||
def loft(self, ruled: bool = False, mode: Mode = Mode.ADDITION, clean: bool = True):
|
class Loft(Solid):
|
||||||
|
def __init__(self, ruled: bool = False, mode: Mode = Mode.ADDITION):
|
||||||
|
|
||||||
loft_wires = []
|
loft_wires = []
|
||||||
for i in range(len(self.workplanes)):
|
for i in range(len(BuildPart.get_context().workplanes)):
|
||||||
for face in self.pending_faces[i]:
|
for face in BuildPart.get_context().pending_faces[i]:
|
||||||
loft_wires.append(face.outerWire())
|
loft_wires.append(face.outerWire())
|
||||||
new_solid = Solid.makeLoft(loft_wires, ruled)
|
new_solid = Solid.makeLoft(loft_wires, ruled)
|
||||||
self.place_solids([new_solid], mode, clean)
|
|
||||||
|
|
||||||
return new_solid
|
BuildPart.get_context().add_to_context(new_solid, mode=mode)
|
||||||
|
super().__init__(new_solid.wrapped)
|
||||||
|
|
||||||
def sweep(
|
|
||||||
|
class Sweep(Compound):
|
||||||
|
def __init__(
|
||||||
self,
|
self,
|
||||||
path: Union[Edge, Wire],
|
path: Union[Edge, Wire],
|
||||||
multisection: bool = False,
|
multisection: bool = False,
|
||||||
|
|
@ -334,7 +315,6 @@ class BuildPart:
|
||||||
normal: VectorLike = None,
|
normal: VectorLike = None,
|
||||||
binormal: Union[Edge, Wire] = None,
|
binormal: Union[Edge, Wire] = None,
|
||||||
mode: Mode = Mode.ADDITION,
|
mode: Mode = Mode.ADDITION,
|
||||||
clean: bool = True,
|
|
||||||
):
|
):
|
||||||
|
|
||||||
path_wire = Wire.assembleEdges([path]) if isinstance(path, Edge) else path
|
path_wire = Wire.assembleEdges([path]) if isinstance(path, Edge) else path
|
||||||
|
|
@ -346,9 +326,9 @@ class BuildPart:
|
||||||
binormal_mode = binormal
|
binormal_mode = binormal
|
||||||
|
|
||||||
new_solids = []
|
new_solids = []
|
||||||
for i, workplane in enumerate(self.workplanes):
|
for i, workplane in enumerate(BuildPart.get_context().workplanes):
|
||||||
if not multisection:
|
if not multisection:
|
||||||
for face in self.pending_faces[i]:
|
for face in BuildPart.get_context().pending_faces[i]:
|
||||||
new_solids.append(
|
new_solids.append(
|
||||||
Solid.sweep(
|
Solid.sweep(
|
||||||
face,
|
face,
|
||||||
|
|
@ -360,19 +340,39 @@ class BuildPart:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
sections = [face.outerWire() for face in self.pending_faces[i]]
|
sections = [
|
||||||
|
face.outerWire()
|
||||||
|
for face in BuildPart.get_context().pending_faces[i]
|
||||||
|
]
|
||||||
new_solids.append(
|
new_solids.append(
|
||||||
Solid.sweep_multi(
|
Solid.sweep_multi(
|
||||||
sections, path_wire, make_solid, is_frenet, binormal_mode
|
sections, path_wire, make_solid, is_frenet, binormal_mode
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.place_solids(new_solids, mode, clean)
|
BuildPart.get_context().add_to_context(*new_solids, mode=mode)
|
||||||
|
super().__init__(Compound.makeCompound(new_solids).wrapped)
|
||||||
|
|
||||||
return new_solids
|
|
||||||
|
|
||||||
def fillet(self, *edges: Sequence[Edge], radius: float):
|
class FilletPart(Compound):
|
||||||
self.part = self.part.fillet(radius, [e for e in edges])
|
def __init__(self, *edges: Edge, radius: float):
|
||||||
|
new_part = BuildPart.get_context().part.fillet(radius, list(edges))
|
||||||
|
BuildPart.get_context().part = new_part
|
||||||
|
super().__init__(new_part.wrapped)
|
||||||
|
|
||||||
def chamfer(self, *edges: Sequence[Edge], length1: float, length2: float = None):
|
|
||||||
self.part = self.part.chamfer(length1, length2, list(edges))
|
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
|
||||||
|
super().__init__(new_part.wrapped)
|
||||||
|
|
||||||
|
|
||||||
|
class PushPointsPart:
|
||||||
|
def __init__(self, *pts: Union[VectorLike, Location]):
|
||||||
|
new_locations = [
|
||||||
|
Location(Vector(pt)) if not isinstance(pt, Location) else pt for pt in pts
|
||||||
|
]
|
||||||
|
for i in range(len(BuildPart.get_context().workplanes)):
|
||||||
|
BuildPart.get_context().locations[i].extend(new_locations)
|
||||||
|
print(f"{len(BuildPart.get_context().locations[i])=}")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue