Added logging

This commit is contained in:
Roger Maitland 2022-08-04 14:40:35 -04:00
parent 56cc0888fd
commit 3252996a80
6 changed files with 192 additions and 89 deletions

View file

@ -26,9 +26,17 @@ license:
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
""" """
import logging
from cadquery import Plane from cadquery import Plane
from build123d import * from build123d import *
logging.basicConfig(
filename="din_rail.log",
level=logging.INFO,
format="%(name)s-%(levelname)s %(asctime)s - [%(filename)s:%(lineno)s - %(funcName)20s() ] - %(message)s",
)
logging.info("Starting to create din rail")
# 35x7.5mm DIN Rail Dimensions # 35x7.5mm DIN Rail Dimensions
overall_width, top_width, height, thickness, fillet = 35, 27, 7.5, 1, 0.8 overall_width, top_width, height, thickness, fillet = 35, 27, 7.5, 1, 0.8
rail_length = 1000 rail_length = 1000

View file

@ -37,6 +37,55 @@ from enum import Enum, auto
from cadquery import Edge, Wire, Vector, Location, Face, Solid, Compound, Shape, Vertex from cadquery import Edge, Wire, Vector, Location, Face, Solid, Compound, Shape, Vertex
from OCP.gp import gp_Pnt, gp_Ax1, gp_Dir, gp_Trsf from OCP.gp import gp_Pnt, gp_Ax1, gp_Dir, gp_Trsf
import cq_warehouse.extensions import cq_warehouse.extensions
import logging
# Create a build123d logger to distinguish these logs from application logs.
# If the user doesn't configure logging, all build123d logs will be discarded.
logging.getLogger("build123d").addHandler(logging.NullHandler())
logger = logging.getLogger("build123d")
# The recommended user log configuration is as follows:
# logging.basicConfig(
# filename="myapp.log",
# level=logging.INFO,
# format="%(name)s-%(levelname)s %(asctime)s - [%(filename)s:%(lineno)s - %(funcName)20s() ] - %(message)s",
# )
# Where using %(name)s in the log format will distinguish between user and build123d library logs
# Monkey patch Vertex to give it the x,y, and z property
def _vertex_x(self: Vertex):
return self.X
def _vertex_y(self: Vertex):
return self.Y
def _vertex_z(self: Vertex):
return self.Z
Vertex.x = property(_vertex_x)
Vertex.y = property(_vertex_y)
Vertex.z = property(_vertex_z)
# Monkey patch Vector to give it the X,Y, and Z property
def _vector_x(self: Vector):
return self.x
def _vector_y(self: Vector):
return self.x
def _vector_z(self: Vector):
return self.x
Vector.X = property(_vector_x)
Vector.Y = property(_vector_y)
Vector.Z = property(_vector_z)
z_axis = (Vector(0, 0, 0), Vector(0, 0, 1)) z_axis = (Vector(0, 0, 0), Vector(0, 0, 1))
@ -56,7 +105,6 @@ Edge.__mod__ = __mod__custom
Wire.__matmul__ = __matmul__custom Wire.__matmul__ = __matmul__custom
Wire.__mod__ = __mod__custom Wire.__mod__ = __mod__custom
# context_stack = []
# #
# ENUMs # ENUMs
@ -467,14 +515,20 @@ class Builder(ABC):
def __enter__(self): def __enter__(self):
"""Upon entering record the parent and a token to restore contextvars""" """Upon entering record the parent and a token to restore contextvars"""
self._parent = Builder._get_context() self._parent = Builder._get_context()
self._reset_tok = self._current.set(self) self._reset_tok = self._current.set(self)
logger.info(f"Entering {type(self).__name__} with mode={self.mode}")
return self return self
def __exit__(self, exception_type, exception_value, traceback): def __exit__(self, exception_type, exception_value, traceback):
"""Upon exiting restore context and send object to parent""" """Upon exiting restore context and send object to parent"""
self._current.reset(self._reset_tok) self._current.reset(self._reset_tok)
logger.info(f"Exiting {type(self).__name__}")
if self._parent is not None: if self._parent is not None:
logger.debug(
f"Transferring {len([o for o in self._obj])} to {type(self._parent).__name__}"
)
if isinstance(self._obj, Iterable): if isinstance(self._obj, Iterable):
self._parent._add_to_context(*self._obj, mode=self.mode) self._parent._add_to_context(*self._obj, mode=self.mode)
else: else:

View file

@ -56,7 +56,7 @@ class Add(Compound):
rotation: Union[float, RotationLike] = None, rotation: Union[float, RotationLike] = None,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context = Builder._get_context() context: Builder = Builder._get_context()
if isinstance(context, BuildPart): if isinstance(context, BuildPart):
rotation_value = (0, 0, 0) if rotation is None else rotation rotation_value = (0, 0, 0) if rotation is None else rotation
rotate = ( rotate = (
@ -84,8 +84,8 @@ class Add(Compound):
new_objects = [ new_objects = [
workplane.fromLocalCoords(solid.moved(location)) workplane.fromLocalCoords(solid.moved(location))
for solid in new_solids for solid in new_solids
for workplane in BuildPart._get_context().workplanes for workplane in context.workplanes
for location in BuildPart._get_context().locations for location in context.locations
] ]
context.locations = [Location(Vector())] context.locations = [Location(Vector())]
context._add_to_context(*new_objects, mode=mode) context._add_to_context(*new_objects, mode=mode)
@ -135,7 +135,7 @@ class BoundingBox(Compound):
*objects: Shape, *objects: Shape,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context = Builder._get_context() context: Builder = Builder._get_context()
if isinstance(context, BuildPart): if isinstance(context, BuildPart):
new_objects = [] new_objects = []
for obj in objects: for obj in objects:
@ -193,7 +193,7 @@ class Chamfer(Compound):
def __init__( def __init__(
self, *objects: Union[Edge, Vertex], length: float, length2: float = None self, *objects: Union[Edge, Vertex], length: float, length2: float = None
): ):
context = Builder._get_context() context: Builder = Builder._get_context()
if isinstance(context, BuildPart): if isinstance(context, BuildPart):
new_part = context.part.chamfer(length, length2, list(objects)) new_part = context.part.chamfer(length, length2, list(objects))
context._add_to_context(new_part, mode=Mode.REPLACE) context._add_to_context(new_part, mode=Mode.REPLACE)
@ -226,7 +226,7 @@ class Fillet(Compound):
""" """
def __init__(self, *objects: Union[Edge, Vertex], radius: float): def __init__(self, *objects: Union[Edge, Vertex], radius: float):
context = Builder._get_context() context: Builder = Builder._get_context()
if isinstance(context, BuildPart): if isinstance(context, BuildPart):
new_part = context.part.fillet(radius, list(objects)) new_part = context.part.fillet(radius, list(objects))
context._add_to_context(new_part, mode=Mode.REPLACE) context._add_to_context(new_part, mode=Mode.REPLACE)
@ -270,6 +270,7 @@ class HexArray:
yCount: int, yCount: int,
centered: tuple[bool, bool] = (True, True), centered: tuple[bool, bool] = (True, True),
): ):
context: Builder = Builder._get_context()
xSpacing = 3 * diagonal / 4 xSpacing = 3 * diagonal / 4
ySpacing = diagonal * sqrt(3) / 2 ySpacing = diagonal * sqrt(3) / 2
if xSpacing <= 0 or ySpacing <= 0 or xCount < 1 or yCount < 1: if xSpacing <= 0 or ySpacing <= 0 or xCount < 1 or yCount < 1:
@ -294,7 +295,7 @@ class HexArray:
# convert to locations # convert to locations
new_locations = [Location(pt) for pt in lpoints] new_locations = [Location(pt) for pt in lpoints]
Builder._get_context().locations = new_locations context.locations = new_locations
class Mirror(Compound): class Mirror(Compound):
@ -314,6 +315,7 @@ class Mirror(Compound):
axis: Axis = Axis.X, axis: Axis = Axis.X,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: Builder = Builder._get_context()
new_edges = [obj for obj in objects if isinstance(obj, Edge)] new_edges = [obj for obj in objects if isinstance(obj, Edge)]
new_wires = [obj for obj in objects if isinstance(obj, Wire)] new_wires = [obj for obj in objects if isinstance(obj, Wire)]
new_faces = [obj for obj in objects if isinstance(obj, Face)] new_faces = [obj for obj in objects if isinstance(obj, Face)]
@ -327,7 +329,6 @@ class Mirror(Compound):
mirrored_faces = Plane.named("XY").mirrorInPlane(new_faces, axis=axis.name) mirrored_faces = Plane.named("XY").mirrorInPlane(new_faces, axis=axis.name)
# mirrored_solids = Plane.named("XY").mirrorInPlane(new_solids, axis=axis.name) # mirrored_solids = Plane.named("XY").mirrorInPlane(new_solids, axis=axis.name)
context = Builder._get_context()
if isinstance(context, BuildLine): if isinstance(context, BuildLine):
context._add_to_context(*mirrored_edges, mode=mode) context._add_to_context(*mirrored_edges, mode=mode)
context._add_to_context(*mirrored_wires, mode=mode) context._add_to_context(*mirrored_wires, mode=mode)
@ -375,6 +376,7 @@ class PolarArray:
count: int, count: int,
rotate: bool = True, rotate: bool = True,
): ):
context: Builder = Builder._get_context()
if count < 1: if count < 1:
raise ValueError(f"At least 1 elements required, requested {count}") raise ValueError(f"At least 1 elements required, requested {count}")
@ -390,7 +392,7 @@ class PolarArray:
for i in range(count) for i in range(count)
] ]
Builder._get_context().locations = new_locations context.locations = new_locations
class PushPoints: class PushPoints:
@ -403,6 +405,7 @@ class PushPoints:
""" """
def __init__(self, *pts: Union[VectorLike, Vertex, Location]): def __init__(self, *pts: Union[VectorLike, Vertex, Location]):
context: Builder = Builder._get_context()
new_locations = [] new_locations = []
for pt in pts: for pt in pts:
if isinstance(pt, Location): if isinstance(pt, Location):
@ -415,7 +418,7 @@ class PushPoints:
new_locations.append(Location(Vector(pt))) new_locations.append(Location(Vector(pt)))
else: else:
raise ValueError(f"PushPoints doesn't accept type {type(pt)}") raise ValueError(f"PushPoints doesn't accept type {type(pt)}")
Builder._get_context().locations = new_locations context.locations = new_locations
class RectangularArray: class RectangularArray:
@ -434,6 +437,7 @@ class RectangularArray:
""" """
def __init__(self, x_spacing: float, y_spacing: float, x_count: int, y_count: int): def __init__(self, x_spacing: float, y_spacing: float, x_count: int, y_count: int):
context: Builder = Builder._get_context()
if x_count < 1 or y_count < 1: if x_count < 1 or y_count < 1:
raise ValueError( raise ValueError(
f"At least 1 elements required, requested {x_count}, {y_count}" f"At least 1 elements required, requested {x_count}, {y_count}"
@ -446,4 +450,4 @@ class RectangularArray:
Location(Vector(i * x_spacing, j * y_spacing) - offset) Location(Vector(i * x_spacing, j * y_spacing) - offset)
) )
Builder._get_context().locations = new_locations context.locations = new_locations

View file

@ -25,6 +25,7 @@ license:
limitations under the License. limitations under the License.
""" """
import inspect
from math import sin, cos, radians, sqrt from math import sin, cos, radians, sqrt
from typing import Union, Iterable from typing import Union, Iterable
@ -127,6 +128,9 @@ class BuildLine(Builder):
new_wires = [obj for obj in objects if isinstance(obj, Wire)] new_wires = [obj for obj in objects if isinstance(obj, Wire)]
for wire in new_wires: for wire in new_wires:
new_edges.extend(wire.Edges()) new_edges.extend(wire.Edges())
if new_edges:
logger.debug(f"Add {len(new_edges)} Edge(s) into line with Mode={mode}")
self.line.extend(new_edges) self.line.extend(new_edges)
self.last_edges = objects self.last_edges = objects
self.last_vertices = list(set(v for e in objects for v in e.Vertices())) self.last_vertices = list(set(v for e in objects for v in e.Vertices()))
@ -134,6 +138,9 @@ class BuildLine(Builder):
@classmethod @classmethod
def _get_context(cls) -> "BuildLine": def _get_context(cls) -> "BuildLine":
"""Return the instance of the current builder""" """Return the instance of the current builder"""
logger.info(
f"Context requested by {type(inspect.currentframe().f_back.f_locals['self']).__name__}"
)
return cls._current.get(None) return cls._current.get(None)
@ -166,6 +173,8 @@ class CenterArc(Edge):
arc_size: float, arc_size: float,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildLine = BuildLine._get_context()
points = [] points = []
if abs(arc_size) >= 360: if abs(arc_size) >= 360:
arc = Edge.makeCircle( arc = Edge.makeCircle(
@ -200,7 +209,7 @@ class CenterArc(Edge):
) )
arc = Edge.makeThreePointArc(*points) arc = Edge.makeThreePointArc(*points)
BuildLine._get_context()._add_to_context(arc, mode=mode) context._add_to_context(arc, mode=mode)
super().__init__(arc.wrapped) super().__init__(arc.wrapped)
@ -231,10 +240,11 @@ class Helix(Wire):
lefhand: bool = False, lefhand: bool = False,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildLine = BuildLine._get_context()
helix = Wire.makeHelix( helix = Wire.makeHelix(
pitch, height, radius, Vector(center), Vector(direction), arc_size, lefhand pitch, height, radius, Vector(center), Vector(direction), arc_size, lefhand
) )
BuildLine._get_context()._add_to_context(*helix.Edges(), mode=mode) context._add_to_context(*helix.Edges(), mode=mode)
super().__init__(helix.wrapped) super().__init__(helix.wrapped)
@ -252,13 +262,14 @@ class Line(Edge):
""" """
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD): def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD):
context: BuildLine = BuildLine._get_context()
if len(pts) != 2: if len(pts) != 2:
raise ValueError("Line requires two pts") raise ValueError("Line requires two pts")
lines_pts = [Vector(p) for p in pts] lines_pts = [Vector(p) for p in pts]
new_edge = Edge.makeLine(lines_pts[0], lines_pts[1]) new_edge = Edge.makeLine(lines_pts[0], lines_pts[1])
BuildLine._get_context()._add_to_context(new_edge, mode=mode) context._add_to_context(new_edge, mode=mode)
super().__init__(new_edge.wrapped) super().__init__(new_edge.wrapped)
@ -286,6 +297,7 @@ class PolarLine(Edge):
direction: VectorLike = None, direction: VectorLike = None,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildLine = BuildLine._get_context()
if angle is not None: if angle is not None:
x = cos(radians(angle)) * length x = cos(radians(angle)) * length
y = sin(radians(angle)) * length y = sin(radians(angle)) * length
@ -297,7 +309,7 @@ class PolarLine(Edge):
else: else:
raise ValueError("Either angle or direction must be provided") raise ValueError("Either angle or direction must be provided")
BuildLine._get_context()._add_to_context(new_edge, mode=mode) context._add_to_context(new_edge, mode=mode)
super().__init__(new_edge.wrapped) super().__init__(new_edge.wrapped)
@ -315,6 +327,7 @@ class Polyline(Wire):
""" """
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD): def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD):
context: BuildLine = BuildLine._get_context()
if len(pts) < 3: if len(pts) < 3:
raise ValueError("polyline requires three or more pts") raise ValueError("polyline requires three or more pts")
@ -324,7 +337,7 @@ class Polyline(Wire):
Edge.makeLine(lines_pts[i], lines_pts[i + 1]) Edge.makeLine(lines_pts[i], lines_pts[i + 1])
for i in range(len(lines_pts) - 1) for i in range(len(lines_pts) - 1)
] ]
BuildLine._get_context()._add_to_context(*new_edges, mode=mode) context._add_to_context(*new_edges, mode=mode)
super().__init__(Wire.combine(new_edges)[0].wrapped) super().__init__(Wire.combine(new_edges)[0].wrapped)
@ -350,6 +363,7 @@ class RadiusArc(Edge):
radius: float, radius: float,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildLine = BuildLine._get_context()
start = Vector(start_point) start = Vector(start_point)
end = Vector(end_point) end = Vector(end_point)
@ -368,7 +382,7 @@ class RadiusArc(Edge):
else: else:
arc = SagittaArc(start, end, -sagitta, mode=Mode.PRIVATE) arc = SagittaArc(start, end, -sagitta, mode=Mode.PRIVATE)
BuildLine._get_context()._add_to_context(arc, mode=mode) context._add_to_context(arc, mode=mode)
super().__init__(arc.wrapped) super().__init__(arc.wrapped)
@ -391,6 +405,7 @@ class SagittaArc(Edge):
sagitta: float, sagitta: float,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildLine = BuildLine._get_context()
start = Vector(start_point) start = Vector(start_point)
end = Vector(end_point) end = Vector(end_point)
mid_point = (end + start) * 0.5 mid_point = (end + start) * 0.5
@ -410,7 +425,7 @@ class SagittaArc(Edge):
sag_point = mid_point + sagitta_vector sag_point = mid_point + sagitta_vector
arc = ThreePointArc(start, sag_point, end, mode=Mode.PRIVATE) arc = ThreePointArc(start, sag_point, end, mode=Mode.PRIVATE)
BuildLine._get_context()._add_to_context(arc, mode=mode) context._add_to_context(arc, mode=mode)
super().__init__(arc.wrapped) super().__init__(arc.wrapped)
@ -436,6 +451,7 @@ class Spline(Edge):
periodic: bool = False, periodic: bool = False,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildLine = BuildLine._get_context()
spline_pts = [Vector(pt) for pt in pts] spline_pts = [Vector(pt) for pt in pts]
if tangents: if tangents:
spline_tangents = [Vector(tangent) for tangent in tangents] spline_tangents = [Vector(tangent) for tangent in tangents]
@ -458,7 +474,7 @@ class Spline(Edge):
periodic=periodic, periodic=periodic,
scale=tangent_scalars is None, scale=tangent_scalars is None,
) )
BuildLine._get_context()._add_to_context(spline, mode=mode) context._add_to_context(spline, mode=mode)
super().__init__(spline.wrapped) super().__init__(spline.wrapped)
@ -485,6 +501,7 @@ class TangentArc(Edge):
tangent_from_first: bool = True, tangent_from_first: bool = True,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildLine = BuildLine._get_context()
arc_pts = [Vector(p) for p in pts] arc_pts = [Vector(p) for p in pts]
if len(arc_pts) != 2: if len(arc_pts) != 2:
raise ValueError("tangent_arc requires two points") raise ValueError("tangent_arc requires two points")
@ -495,7 +512,7 @@ class TangentArc(Edge):
arc_pts[point_indices[0]], arc_tangent, arc_pts[point_indices[1]] arc_pts[point_indices[0]], arc_tangent, arc_pts[point_indices[1]]
) )
BuildLine._get_context()._add_to_context(arc, mode=mode) context._add_to_context(arc, mode=mode)
super().__init__(arc.wrapped) super().__init__(arc.wrapped)
@ -513,9 +530,10 @@ class ThreePointArc(Edge):
""" """
def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD): def __init__(self, *pts: VectorLike, mode: Mode = Mode.ADD):
context: BuildLine = BuildLine._get_context()
if len(pts) != 3: if len(pts) != 3:
raise ValueError("ThreePointArc requires three points") raise ValueError("ThreePointArc requires three points")
points = [Vector(p) for p in pts] points = [Vector(p) for p in pts]
arc = Edge.makeThreePointArc(*points) arc = Edge.makeThreePointArc(*points)
BuildLine._get_context()._add_to_context(arc, mode=mode) context._add_to_context(arc, mode=mode)
super().__init__(arc.wrapped) super().__init__(arc.wrapped)

View file

@ -29,6 +29,7 @@ license:
limitations under the License. limitations under the License.
""" """
import inspect
from math import radians, tan from math import radians, tan
from typing import Union from typing import Union
from cadquery import ( from cadquery import (
@ -43,9 +44,6 @@ from cadquery import (
Plane, Plane,
) )
from cadquery.occ_impl.shapes import VectorLike from cadquery.occ_impl.shapes import VectorLike
# import cq_warehouse.extensions
from build123d.build_common import * from build123d.build_common import *
@ -203,14 +201,20 @@ class BuildPart(Builder):
for i, workplane in enumerate(self.workplanes): for i, workplane in enumerate(self.workplanes):
for loc in self.locations: for loc in self.locations:
localized_obj = workplane.fromLocalCoords(obj.moved(loc)) localized_obj = workplane.fromLocalCoords(obj.moved(loc))
if i in self.pending_faces:
if isinstance(obj, Face): if isinstance(obj, Face):
logger.debug(
f"Adding localized Face to pending_faces at {localized_obj.location()}"
)
if i in self.pending_faces:
self.pending_faces[i].append(localized_obj) self.pending_faces[i].append(localized_obj)
else: else:
self.pending_edges[i].append(localized_obj)
else:
if isinstance(obj, Face):
self.pending_faces[i] = [localized_obj] self.pending_faces[i] = [localized_obj]
else:
logger.debug(
f"Adding localized Edge to pending_edges at {localized_obj.location()}"
)
if i in self.pending_edges:
self.pending_edges[i].append(localized_obj)
else: else:
self.pending_edges[i] = [localized_obj] self.pending_edges[i] = [localized_obj]
@ -224,6 +228,7 @@ class BuildPart(Builder):
for location in self.locations for location in self.locations
] ]
) )
logger.debug("Clearing locations")
self.locations = [Location(Vector())] self.locations = [Location(Vector())]
return location_planes return location_planes
@ -273,6 +278,10 @@ class BuildPart(Builder):
pre_solids = set() if self.part is None else set(self.part.Solids()) pre_solids = set() if self.part is None else set(self.part.Solids())
if new_objects: if new_objects:
logger.debug(
f"Attempting to integrate {len(new_objects)} object(s) into part"
f" with Mode={mode}"
)
if mode == Mode.ADD: if mode == Mode.ADD:
if self.part is None: if self.part is None:
if len(new_objects) == 1: if len(new_objects) == 1:
@ -292,6 +301,11 @@ class BuildPart(Builder):
elif mode == Mode.REPLACE: elif mode == Mode.REPLACE:
self.part = Compound.makeCompound(new_objects).clean() self.part = Compound.makeCompound(new_objects).clean()
logger.info(
f"Completed integrating {len(new_objects)} object(s) into part"
f" with Mode={mode}"
)
post_vertices = set() if self.part is None else set(self.part.Vertices()) post_vertices = set() if self.part is None else set(self.part.Vertices())
post_edges = set() if self.part is None else set(self.part.Edges()) post_edges = set() if self.part is None else set(self.part.Edges())
post_faces = set() if self.part is None else set(self.part.Faces()) post_faces = set() if self.part is None else set(self.part.Faces())
@ -307,6 +321,9 @@ class BuildPart(Builder):
@classmethod @classmethod
def _get_context(cls) -> "BuildPart": def _get_context(cls) -> "BuildPart":
"""Return the instance of the current builder""" """Return the instance of the current builder"""
logger.info(
f"Context requested by {type(inspect.currentframe().f_back.f_locals['self']).__name__}"
)
return cls._current.get(None) return cls._current.get(None)

View file

@ -38,6 +38,7 @@ license:
limitations under the License. limitations under the License.
""" """
import inspect
from math import pi, sin, cos, tan, radians from math import pi, sin, cos, tan, radians
from turtle import Shape from turtle import Shape
from typing import Union from typing import Union
@ -173,6 +174,10 @@ class BuildSketch(Builder):
pre_edges = set() if self.sketch is None else set(self.sketch.Edges()) 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()) pre_faces = set() if self.sketch is None else set(self.sketch.Faces())
if new_faces: if new_faces:
logger.debug(
f"Attempting to integrate {len(new_faces)} Face(s) into sketch"
f" with Mode={mode}"
)
if mode == Mode.ADD: if mode == Mode.ADD:
if self.sketch is None: if self.sketch is None:
self.sketch = Compound.makeCompound(new_faces) self.sketch = Compound.makeCompound(new_faces)
@ -189,6 +194,11 @@ class BuildSketch(Builder):
elif mode == Mode.REPLACE: elif mode == Mode.REPLACE:
self.sketch = Compound.makeCompound(new_faces).clean() self.sketch = Compound.makeCompound(new_faces).clean()
logger.info(
f"Completed integrating {len(new_faces)} Face(s) into sketch"
f" with Mode={mode}"
)
post_vertices = ( post_vertices = (
set() if self.sketch is None else set(self.sketch.Vertices()) set() if self.sketch is None else set(self.sketch.Vertices())
) )
@ -203,6 +213,9 @@ class BuildSketch(Builder):
@classmethod @classmethod
def _get_context(cls) -> "BuildSketch": def _get_context(cls) -> "BuildSketch":
"""Return the instance of the current builder""" """Return the instance of the current builder"""
logger.info(
f"Context requested by {type(inspect.currentframe().f_back.f_locals['self']).__name__}"
)
return cls._current.get(None) return cls._current.get(None)
@ -222,10 +235,11 @@ class BuildFace(Face):
""" """
def __init__(self, *edges: Edge, mode: Mode = Mode.ADD): def __init__(self, *edges: Edge, mode: Mode = Mode.ADD):
outer_edges = edges if edges else BuildSketch._get_context().pending_edges context: BuildSketch = BuildSketch._get_context()
outer_edges = edges if edges else context.pending_edges
pending_face = Face.makeFromWires(Wire.combine(outer_edges)[0]) pending_face = Face.makeFromWires(Wire.combine(outer_edges)[0])
BuildSketch._get_context()._add_to_context(pending_face, mode) context._add_to_context(pending_face, mode)
BuildSketch._get_context().pending_edges = ShapeList() context.pending_edges = ShapeList()
super().__init__(pending_face.wrapped) super().__init__(pending_face.wrapped)
@ -313,6 +327,7 @@ class Circle(Compound):
centered: tuple[bool, bool] = (True, True), centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
center_offset = Vector( center_offset = Vector(
0 if centered[0] else radius, 0 if centered[0] else radius,
0 if centered[1] else radius, 0 if centered[1] else radius,
@ -320,12 +335,10 @@ class Circle(Compound):
face = Face.makeFromWires(Wire.makeCircle(radius, *z_axis)).moved( face = Face.makeFromWires(Wire.makeCircle(radius, *z_axis)).moved(
Location(center_offset) Location(center_offset)
) )
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -350,6 +363,7 @@ class Ellipse(Compound):
centered: tuple[bool, bool] = (True, True), centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
face = Face.makeFromWires( face = Face.makeFromWires(
Wire.makeEllipse( Wire.makeEllipse(
x_radius, x_radius,
@ -367,12 +381,10 @@ class Ellipse(Compound):
) )
face = face.moved(Location(center_offset)) face = face.moved(Location(center_offset))
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -395,6 +407,7 @@ class Polygon(Compound):
centered: tuple[bool, bool] = (True, True), centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
poly_pts = [Vector(p) for p in pts] poly_pts = [Vector(p) for p in pts]
face = Face.makeFromWires(Wire.makePolygon(poly_pts)).rotate(*z_axis, rotation) face = Face.makeFromWires(Wire.makePolygon(poly_pts)).rotate(*z_axis, rotation)
bounding_box = face.BoundingBox() bounding_box = face.BoundingBox()
@ -403,12 +416,10 @@ class Polygon(Compound):
0 if centered[1] else bounding_box.ylen / 2, 0 if centered[1] else bounding_box.ylen / 2,
) )
face = face.moved(Location(center_offset)) face = face.moved(Location(center_offset))
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -433,6 +444,7 @@ class Rectangle(Compound):
centered: tuple[bool, bool] = (True, True), centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
face = Face.makePlane(height, width).rotate(*z_axis, rotation) face = Face.makePlane(height, width).rotate(*z_axis, rotation)
bounding_box = face.BoundingBox() bounding_box = face.BoundingBox()
center_offset = Vector( center_offset = Vector(
@ -441,12 +453,10 @@ class Rectangle(Compound):
) )
face = face.moved(Location(center_offset)) face = face.moved(Location(center_offset))
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -471,6 +481,7 @@ class RegularPolygon(Compound):
centered: tuple[bool, bool] = (True, True), centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
pts = [ pts = [
Vector( Vector(
radius * sin(i * 2 * pi / side_count), radius * sin(i * 2 * pi / side_count),
@ -486,12 +497,10 @@ class RegularPolygon(Compound):
) )
face = face.moved(Location(center_offset)) face = face.moved(Location(center_offset))
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -517,16 +526,15 @@ class SlotArc(Compound):
rotation: float = 0, rotation: float = 0,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
if isinstance(arc, Edge): if isinstance(arc, Edge):
raise ValueError("Bug - Edges aren't supported by offset") raise ValueError("Bug - Edges aren't supported by offset")
# arc_wire = arc if isinstance(arc, Wire) else Wire.assembleEdges([arc]) # arc_wire = arc if isinstance(arc, Wire) else Wire.assembleEdges([arc])
face = Face.makeFromWires(arc.offset2D(height / 2)[0]).rotate(*z_axis, rotation) face = Face.makeFromWires(arc.offset2D(height / 2)[0]).rotate(*z_axis, rotation)
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -553,6 +561,7 @@ class SlotCenterPoint(Compound):
rotation: float = 0, rotation: float = 0,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
center_v = Vector(center) center_v = Vector(center)
point_v = Vector(point) point_v = Vector(point)
half_line = point_v - center_v half_line = point_v - center_v
@ -564,12 +573,10 @@ class SlotCenterPoint(Compound):
] ]
)[0].offset2D(height / 2)[0] )[0].offset2D(height / 2)[0]
).rotate(*z_axis, rotation) ).rotate(*z_axis, rotation)
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -593,6 +600,7 @@ class SlotCenterToCenter(Compound):
rotation: float = 0, rotation: float = 0,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
face = Face.makeFromWires( face = Face.makeFromWires(
Wire.assembleEdges( Wire.assembleEdges(
[ [
@ -601,12 +609,10 @@ class SlotCenterToCenter(Compound):
] ]
).offset2D(height / 2)[0] ).offset2D(height / 2)[0]
).rotate(*z_axis, rotation) ).rotate(*z_axis, rotation)
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -629,6 +635,7 @@ class SlotOverall(Compound):
rotation: float = 0, rotation: float = 0,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
face = Face.makeFromWires( face = Face.makeFromWires(
Wire.assembleEdges( Wire.assembleEdges(
[ [
@ -637,12 +644,10 @@ class SlotOverall(Compound):
] ]
).offset2D(height / 2)[0] ).offset2D(height / 2)[0]
).rotate(*z_axis, rotation) ).rotate(*z_axis, rotation)
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -680,6 +685,7 @@ class Text(Compound):
rotation: float = 0, rotation: float = 0,
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
) -> Compound: ) -> Compound:
context: BuildSketch = BuildSketch._get_context()
text_string = Compound.make2DText( text_string = Compound.make2DText(
txt, txt,
fontsize, fontsize,
@ -691,14 +697,11 @@ class Text(Compound):
position_on_path, position_on_path,
path, path,
).rotate(Vector(), Vector(0, 0, 1), rotation) ).rotate(Vector(), Vector(0, 0, 1), rotation)
new_compounds = [ new_compounds = [text_string.moved(location) for location in context.locations]
text_string.moved(location)
for location in BuildSketch._get_context().locations
]
new_faces = [face for compound in new_compounds for face in compound] new_faces = [face for compound in new_compounds for face in compound]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)
@ -728,6 +731,7 @@ class Trapezoid(Compound):
centered: tuple[bool, bool] = (True, True), centered: tuple[bool, bool] = (True, True),
mode: Mode = Mode.ADD, mode: Mode = Mode.ADD,
): ):
context: BuildSketch = BuildSketch._get_context()
pts = [] pts = []
pts.append(Vector(-width / 2, -height / 2)) pts.append(Vector(-width / 2, -height / 2))
pts.append(Vector(width / 2, -height / 2)) pts.append(Vector(width / 2, -height / 2))
@ -754,10 +758,8 @@ class Trapezoid(Compound):
0 if centered[1] else bounding_box.ylen / 2, 0 if centered[1] else bounding_box.ylen / 2,
) )
face = face.moved(Location(center_offset)) face = face.moved(Location(center_offset))
new_faces = [ new_faces = [face.moved(location) for location in context.locations]
face.moved(location) for location in BuildSketch._get_context().locations
]
for face in new_faces: for face in new_faces:
BuildSketch._get_context()._add_to_context(face, mode=mode) context._add_to_context(face, mode=mode)
BuildSketch._get_context().locations = [Location(Vector())] context.locations = [Location(Vector())]
super().__init__(Compound.makeCompound(new_faces).wrapped) super().__init__(Compound.makeCompound(new_faces).wrapped)