diff --git a/build_line.py b/build_line.py index b27872f..607234c 100644 --- a/build_line.py +++ b/build_line.py @@ -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": diff --git a/build_line_test.py b/build_line_test.py index ac4a181..daaf607 100644 --- a/build_line_test.py +++ b/build_line_test.py @@ -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") diff --git a/build_part.py b/build_part.py index 8bed6fc..69045cb 100644 --- a/build_part.py +++ b/build_part.py @@ -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)) diff --git a/build_sketch.py b/build_sketch.py index 97a4096..8fbba6a 100644 --- a/build_sketch.py +++ b/build_sketch.py @@ -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, diff --git a/build_sketch_test.py b/build_sketch_test.py index 737c7b1..bbebd41 100644 --- a/build_sketch_test.py +++ b/build_sketch_test.py @@ -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")