mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
Refactored returned objects to Line, Sketch, Part & added BuildSketch/Fillet
This commit is contained in:
parent
7b971e3eaa
commit
02a579a728
5 changed files with 108 additions and 99 deletions
|
|
@ -23,56 +23,35 @@ from build_part import BuildPart
|
|||
|
||||
class BuildLine:
|
||||
@property
|
||||
def working_line(self) -> Wire:
|
||||
return Wire.assembleEdges(self.edge_list)
|
||||
def line_as_wire(self) -> Wire:
|
||||
return Wire.assembleEdges(self.line)
|
||||
|
||||
def __init__(self, mode: Mode = Mode.ADDITION):
|
||||
self.edge_list = []
|
||||
self.line = []
|
||||
self.tags: dict[str, Edge] = {}
|
||||
self.mode = mode
|
||||
|
||||
# def __enter__(self):
|
||||
# if "context_stack" in globals():
|
||||
# context_stack.append(self)
|
||||
# else:
|
||||
# globals()["context_stack"] = [self]
|
||||
# return self
|
||||
def __enter__(self):
|
||||
context_stack.append(self)
|
||||
return self
|
||||
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
# if self.parent is not None:
|
||||
# self.parent.add(*self.edge_list, mode=self.mode)
|
||||
# if "context_stack" in globals():
|
||||
# context_stack.pop()
|
||||
# if context_stack:
|
||||
# if isinstance(context_stack[-1], Build2D):
|
||||
# for edge in self.edge_list:
|
||||
# Build2D.add_to_context(edge, mode=self.mode)
|
||||
# elif isinstance(context_stack[-1], Build3D):
|
||||
# for edge in self.edge_list:
|
||||
# Build3D.add_to_context(edge, mode=self.mode)
|
||||
|
||||
# if not context_stack:
|
||||
# del globals()["context_stack"]
|
||||
|
||||
context_stack.pop()
|
||||
if context_stack:
|
||||
if isinstance(context_stack[-1], BuildSketch):
|
||||
for edge in self.edge_list:
|
||||
for edge in self.line:
|
||||
BuildSketch.add_to_context(edge, mode=self.mode)
|
||||
elif isinstance(context_stack[-1], BuildPart):
|
||||
for edge in self.edge_list:
|
||||
for edge in self.line:
|
||||
BuildPart.add_to_context(edge, mode=self.mode)
|
||||
|
||||
def edges(self) -> EdgeList:
|
||||
# return EdgeList(*self.edge_list)
|
||||
return self.edge_list
|
||||
return self.line
|
||||
|
||||
def vertices(self) -> list[Vertex]:
|
||||
vertex_list = []
|
||||
for e in self.edge_list:
|
||||
for e in self.line:
|
||||
vertex_list.extend(e.Vertices())
|
||||
return list(set(vertex_list))
|
||||
|
||||
|
|
@ -87,7 +66,7 @@ class BuildLine:
|
|||
# if not isinstance(edge, Edge):
|
||||
# if not issubclass(type(edge),Edge):
|
||||
# raise ValueError("Build1D.add only accepts edges")
|
||||
context_stack[-1].edge_list.append(edge)
|
||||
context_stack[-1].line.append(edge)
|
||||
|
||||
@staticmethod
|
||||
def get_context() -> "BuildLine":
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ with BuildLine() as roller_coaster:
|
|||
Spline(screw @ 1, (-100, 30, 10), powerup @ 0, tangents=(screw % 1, powerup % 0))
|
||||
|
||||
if "show_object" in locals():
|
||||
show_object(ml.edge_list, "maple leaf")
|
||||
show_object(mirror_example.edge_list, "mirror_example")
|
||||
show_object(mirror_example2.edge_list, "mirror_example2")
|
||||
show_object(private_example.edge_list, "private_example")
|
||||
show_object(roller_coaster.edge_list, "roller coaster")
|
||||
show_object(ml.line, "maple leaf")
|
||||
show_object(mirror_example.line, "mirror_example")
|
||||
show_object(mirror_example2.line, "mirror_example2")
|
||||
show_object(private_example.line, "private_example")
|
||||
show_object(roller_coaster.line, "roller coaster")
|
||||
|
|
|
|||
|
|
@ -44,13 +44,12 @@ class BuildPart:
|
|||
workplane: Plane = Plane.named("XY"),
|
||||
):
|
||||
self.parent = parent
|
||||
self.working_volume: Solid = None
|
||||
self.part: Solid = None
|
||||
self.workplanes: list[Plane] = [workplane]
|
||||
self.pending_faces: dict[int : list[Face]] = {0: []}
|
||||
self.pending_edges: dict[int : list[Edge]] = {0: []}
|
||||
self.locations: dict[int : list[Location]] = {0: []}
|
||||
self.last_operation: dict[CqObject : list[Shape]] = {}
|
||||
# self.last_operation_edges: list[Edge] = []
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
|
@ -103,40 +102,40 @@ class BuildPart:
|
|||
|
||||
def edges(self, sort_by: SortBy = SortBy.NONE, reverse: bool = False) -> list[Edge]:
|
||||
if sort_by == SortBy.NONE:
|
||||
edges = self.working_volume.Edges()
|
||||
edges = self.part.Edges()
|
||||
elif sort_by == SortBy.X:
|
||||
edges = sorted(
|
||||
self.working_volume.Edges(),
|
||||
self.part.Edges(),
|
||||
key=lambda obj: obj.Center().x,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.Y:
|
||||
edges = sorted(
|
||||
self.working_volume.Edges(),
|
||||
self.part.Edges(),
|
||||
key=lambda obj: obj.Center().y,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.Z:
|
||||
edges = sorted(
|
||||
self.working_volume.Edges(),
|
||||
self.part.Edges(),
|
||||
key=lambda obj: obj.Center().z,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.LENGTH:
|
||||
edges = sorted(
|
||||
self.working_volume.Edges(),
|
||||
self.part.Edges(),
|
||||
key=lambda obj: obj.Length(),
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.RADIUS:
|
||||
edges = sorted(
|
||||
self.working_volume.Edges(),
|
||||
self.part.Edges(),
|
||||
key=lambda obj: obj.radius(),
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.DISTANCE:
|
||||
edges = sorted(
|
||||
self.working_volume.Edges(),
|
||||
self.part.Edges(),
|
||||
key=lambda obj: obj.Center().Length,
|
||||
reverse=reverse,
|
||||
)
|
||||
|
|
@ -147,32 +146,32 @@ class BuildPart:
|
|||
|
||||
def faces(self, sort_by: SortBy = SortBy.NONE, reverse: bool = False) -> list[Face]:
|
||||
if sort_by == SortBy.NONE:
|
||||
faces = self.working_volume.Faces()
|
||||
faces = self.part.Faces()
|
||||
elif sort_by == SortBy.X:
|
||||
faces = sorted(
|
||||
self.working_volume.Faces(),
|
||||
self.part.Faces(),
|
||||
key=lambda obj: obj.Center().x,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.Y:
|
||||
faces = sorted(
|
||||
self.working_volume.Faces(),
|
||||
self.part.Faces(),
|
||||
key=lambda obj: obj.Center().y,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.Z:
|
||||
faces = sorted(
|
||||
self.working_volume.Faces(),
|
||||
self.part.Faces(),
|
||||
key=lambda obj: obj.Center().z,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.AREA:
|
||||
faces = sorted(
|
||||
self.working_volume.Faces(), key=lambda obj: obj.Area(), reverse=reverse
|
||||
self.part.Faces(), key=lambda obj: obj.Area(), reverse=reverse
|
||||
)
|
||||
elif sort_by == SortBy.DISTANCE:
|
||||
faces = sorted(
|
||||
self.working_volume.Faces(),
|
||||
self.part.Faces(),
|
||||
key=lambda obj: obj.Center().Length,
|
||||
reverse=reverse,
|
||||
)
|
||||
|
|
@ -184,28 +183,28 @@ class BuildPart:
|
|||
self, sort_by: SortBy = SortBy.NONE, reverse: bool = False
|
||||
) -> list[Vertex]:
|
||||
if sort_by == SortBy.NONE:
|
||||
vertices = self.working_volume.Vertices()
|
||||
vertices = self.part.Vertices()
|
||||
elif sort_by == SortBy.X:
|
||||
vertices = sorted(
|
||||
self.working_volume.Vertices(),
|
||||
self.part.Vertices(),
|
||||
key=lambda obj: obj.Center().x,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.Y:
|
||||
vertices = sorted(
|
||||
self.working_volume.Vertices(),
|
||||
self.part.Vertices(),
|
||||
key=lambda obj: obj.Center().y,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.Z:
|
||||
vertices = sorted(
|
||||
self.working_volume.Vertices(),
|
||||
self.part.Vertices(),
|
||||
key=lambda obj: obj.Center().z,
|
||||
reverse=reverse,
|
||||
)
|
||||
elif sort_by == SortBy.DISTANCE:
|
||||
vertices = sorted(
|
||||
self.working_volume.Vertices(),
|
||||
self.part.Vertices(),
|
||||
key=lambda obj: obj.Center().Length,
|
||||
reverse=reverse,
|
||||
)
|
||||
|
|
@ -223,44 +222,32 @@ class BuildPart:
|
|||
Solid.clean_op = Solid.clean if clean else Solid.null
|
||||
Compound.clean_op = Compound.clean if clean else Compound.null
|
||||
|
||||
before_vertices = (
|
||||
set()
|
||||
if self.working_volume is None
|
||||
else set(self.working_volume.Vertices())
|
||||
)
|
||||
before_edges = (
|
||||
set() if self.working_volume is None else set(self.working_volume.Edges())
|
||||
)
|
||||
before_faces = (
|
||||
set() if self.working_volume is None else set(self.working_volume.Faces())
|
||||
)
|
||||
before_vertices = set() if self.part is None else set(self.part.Vertices())
|
||||
before_edges = set() if self.part is None else set(self.part.Edges())
|
||||
before_faces = set() if self.part is None else set(self.part.Faces())
|
||||
|
||||
if mode == Mode.ADDITION:
|
||||
if self.working_volume is None:
|
||||
if self.part is None:
|
||||
if len(new_solids) == 1:
|
||||
self.working_volume = new_solids[0]
|
||||
self.part = new_solids[0]
|
||||
else:
|
||||
self.working_volume = new_solids.pop().fuse(*new_solids)
|
||||
self.part = new_solids.pop().fuse(*new_solids)
|
||||
else:
|
||||
self.working_volume = self.working_volume.fuse(*new_solids).clean_op()
|
||||
self.part = self.part.fuse(*new_solids).clean_op()
|
||||
elif mode == Mode.SUBTRACTION:
|
||||
if self.working_volume is None:
|
||||
if self.part is None:
|
||||
raise ValueError("Nothing to subtract from")
|
||||
self.working_volume = self.working_volume.cut(*new_solids).clean_op()
|
||||
self.part = self.part.cut(*new_solids).clean_op()
|
||||
elif mode == Mode.INTERSECTION:
|
||||
if self.working_volume is None:
|
||||
if self.part is None:
|
||||
raise ValueError("Nothing to intersect with")
|
||||
self.working_volume = self.working_volume.intersect(*new_solids).clean_op()
|
||||
self.part = self.part.intersect(*new_solids).clean_op()
|
||||
|
||||
self.last_operation[CqObject.VERTEX] = list(
|
||||
set(self.working_volume.Vertices()) - before_vertices
|
||||
)
|
||||
self.last_operation[CqObject.EDGE] = list(
|
||||
set(self.working_volume.Edges()) - before_edges
|
||||
)
|
||||
self.last_operation[CqObject.FACE] = list(
|
||||
set(self.working_volume.Faces()) - before_faces
|
||||
set(self.part.Vertices()) - before_vertices
|
||||
)
|
||||
self.last_operation[CqObject.EDGE] = list(set(self.part.Edges()) - before_edges)
|
||||
self.last_operation[CqObject.FACE] = list(set(self.part.Faces()) - before_faces)
|
||||
|
||||
def extrude(
|
||||
self,
|
||||
|
|
@ -385,7 +372,7 @@ class BuildPart:
|
|||
return new_solids
|
||||
|
||||
def fillet(self, *edges: Sequence[Edge], radius: float):
|
||||
self.working_volume = self.working_volume.fillet(radius, [e for e in edges])
|
||||
self.part = self.part.fillet(radius, [e for e in edges])
|
||||
|
||||
def chamfer(self, *edges: Sequence[Edge], length1: float, length2: float = None):
|
||||
self.working_volume = self.working_volume.chamfer(length1, length2, list(edges))
|
||||
self.part = self.part.chamfer(length1, length2, list(edges))
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ from build_part import BuildPart
|
|||
|
||||
class BuildSketch:
|
||||
def __init__(self, mode: Mode = Mode.ADDITION):
|
||||
self.surface = Compound.makeCompound(())
|
||||
self.sketch = Compound.makeCompound(())
|
||||
self.pending_edges: list[Edge] = []
|
||||
self.locations: list[Location] = [Location(Vector())]
|
||||
self.mode = mode
|
||||
|
|
@ -35,25 +35,33 @@ class BuildSketch:
|
|||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
context_stack.pop()
|
||||
if context_stack:
|
||||
if isinstance(context_stack[-1], Build3D):
|
||||
if isinstance(context_stack[-1], BuildPart):
|
||||
for edge in self.edge_list:
|
||||
Build3D.add_to_context(edge, mode=self.mode)
|
||||
BuildPart.add_to_context(edge, mode=self.mode)
|
||||
|
||||
def edges(self) -> list[Edge]:
|
||||
return self.surface.Edges()
|
||||
return self.sketch.Edges()
|
||||
|
||||
def vertices(self) -> list[Vertex]:
|
||||
vertex_list = []
|
||||
for e in self.surface.Edges():
|
||||
for e in self.sketch.Edges():
|
||||
vertex_list.extend(e.Vertices())
|
||||
return list(set(vertex_list))
|
||||
|
||||
def consolidate_edges(self) -> Wire:
|
||||
return Wire.combine(self.pending_edges)[0]
|
||||
|
||||
# def add(self, f: Face, mode: Mode = Mode.ADDITION):
|
||||
# new_faces = self.place_face(f, mode)
|
||||
# return new_faces if len(new_faces) > 1 else new_faces[0]
|
||||
def _matchFacesToVertices(self) -> dict[Face, list[Vertex]]:
|
||||
|
||||
rv = {}
|
||||
|
||||
for f in self.sketch.Faces():
|
||||
f_vertices = f.Vertices()
|
||||
rv[f] = [
|
||||
v for v in self._selection if isinstance(v, Vertex) and v in f_vertices
|
||||
]
|
||||
|
||||
return rv
|
||||
|
||||
@staticmethod
|
||||
def add_to_context(*objects: Union[Edge, Face], mode: Mode = Mode.ADDITION):
|
||||
|
|
@ -63,16 +71,16 @@ class BuildSketch:
|
|||
new_edges = [obj for obj in objects if isinstance(obj, Edge)]
|
||||
|
||||
if mode == Mode.ADDITION:
|
||||
context_stack[-1].surface = (
|
||||
context_stack[-1].surface.fuse(*new_faces).clean()
|
||||
context_stack[-1].sketch = (
|
||||
context_stack[-1].sketch.fuse(*new_faces).clean()
|
||||
)
|
||||
elif mode == Mode.SUBTRACTION:
|
||||
context_stack[-1].surface = (
|
||||
context_stack[-1].surface.cut(*new_faces).clean()
|
||||
context_stack[-1].sketch = (
|
||||
context_stack[-1].sketch.cut(*new_faces).clean()
|
||||
)
|
||||
elif mode == Mode.INTERSECTION:
|
||||
context_stack[-1].surface = (
|
||||
context_stack[-1].surface.intersect(*new_faces).clean()
|
||||
context_stack[-1].sketch = (
|
||||
context_stack[-1].sketch.intersect(*new_faces).clean()
|
||||
)
|
||||
elif mode == Mode.CONSTRUCTION or mode == Mode.PRIVATE:
|
||||
pass
|
||||
|
|
@ -88,7 +96,6 @@ class BuildSketch:
|
|||
|
||||
class BuildFace:
|
||||
def __init__(self, *edges: Edge, mode: Mode = Mode.ADDITION):
|
||||
# pending_face = Face.makeFromWires(Build2D.get_context().consolidate_edges())
|
||||
pending_face = Face.makeFromWires(Wire.combine(edges)[0])
|
||||
BuildSketch.get_context().add_to_context(pending_face, mode)
|
||||
BuildSketch.get_context().pending_edges = []
|
||||
|
|
@ -115,6 +122,20 @@ class PushPoints:
|
|||
BuildSketch.get_context().locations = new_locations
|
||||
|
||||
|
||||
class Fillet(Compound):
|
||||
def __init__(self, *vertices: Vertex, radius: float):
|
||||
new_faces = []
|
||||
for face in BuildSketch.get_context().sketch.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
|
||||
super().__init__(new_sketch.wrapped)
|
||||
|
||||
|
||||
class Rect(Compound):
|
||||
def __init__(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,28 @@ with BuildSketch() as flag:
|
|||
Mirror(*leaf.edges(), axis=Axis.Y)
|
||||
BuildFace(*flag.pending_edges)
|
||||
|
||||
with BuildSketch() as din:
|
||||
PushPoints((0, 0.5))
|
||||
Rect(35, 1)
|
||||
PushPoints((0, 7.5 / 2))
|
||||
Rect(27, 7.5)
|
||||
PushPoints((0, 6.5 / 2))
|
||||
Rect(25, 6.5, mode=Mode.SUBTRACTION)
|
||||
inside_vertices = list(
|
||||
filter(
|
||||
lambda v: 7.5 > v.Y > 0 and -17.5 < v.X < 17.5,
|
||||
din.vertices(),
|
||||
)
|
||||
)
|
||||
Fillet(*inside_vertices, radius=0.8)
|
||||
outside_vertices = list(
|
||||
filter(
|
||||
lambda v: (v.Y == 0.0 or v.Y == 7.5) and -17.5 < v.X < 17.5,
|
||||
din.vertices(),
|
||||
)
|
||||
)
|
||||
Fillet(*outside_vertices, radius=1.8)
|
||||
|
||||
if "show_object" in locals():
|
||||
show_object(flag.surface, "pending_face")
|
||||
# show_object(flag.pending_edges, "pending_edges")
|
||||
show_object(flag.sketch, name="flag")
|
||||
show_object(din.sketch, name="din rail")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue