mirror of
https://github.com/gumyr/build123d.git
synced 2026-01-30 04:10:34 -08:00
Pylint changes - (mostly) not functional changes
This commit is contained in:
parent
b50d6d5fe1
commit
d642920243
11 changed files with 307 additions and 352 deletions
|
|
@ -29,13 +29,13 @@ import cadquery as cq
|
|||
|
||||
with BuildSketch() as logo_text:
|
||||
Text("123d", fontsize=10, valign=Valign.BOTTOM)
|
||||
font_height = (logo_text.vertices() >> Axis.Y).y
|
||||
font_height = (logo_text.vertices() >> Axis.Y).Y
|
||||
|
||||
with BuildSketch() as build_text:
|
||||
Text("build", fontsize=5, halign=Halign.CENTER)
|
||||
build_bb = BoundingBox(build_text.sketch, mode=Mode.PRIVATE)
|
||||
build_vertices = build_bb.vertices() > Axis.X
|
||||
build_width = build_vertices[-1].x - build_vertices[0].x
|
||||
build_width = build_vertices[-1].X - build_vertices[0].X
|
||||
|
||||
with BuildLine() as one:
|
||||
l1 = Line((font_height * 0.3, 0), (font_height * 0.3, font_height))
|
||||
|
|
@ -50,7 +50,7 @@ with BuildPart() as three_d:
|
|||
with BuildSketch():
|
||||
Text("3d", fontsize=10, valign=Valign.BOTTOM)
|
||||
Extrude(amount=font_height * 0.3)
|
||||
logo_width = (three_d.vertices() >> Axis.X).x
|
||||
logo_width = (three_d.vertices() >> Axis.X).X
|
||||
|
||||
with BuildLine() as arrow_left:
|
||||
t1 = TangentArc((0, 0), (1, 0.75), tangent=(1, 0))
|
||||
|
|
@ -75,7 +75,7 @@ with BuildLine() as extension_lines:
|
|||
with BuildSketch() as build:
|
||||
with Locations(
|
||||
(l1 @ 0.5 + l2 @ 0.5) / 2
|
||||
- cq.Vector((build_vertices[-1].x + build_vertices[0].x) / 2, 0)
|
||||
- cq.Vector((build_vertices[-1].X + build_vertices[0].X) / 2, 0)
|
||||
):
|
||||
Add(build_text.sketch)
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ with BuildPart() as art:
|
|||
with BuildSketch() as slice:
|
||||
Circle(10 * sin(i * pi / slice_count) + 5)
|
||||
Loft()
|
||||
top_bottom = art.faces().filter_by_type(Type.PLANE)
|
||||
top_bottom = art.faces().filter_by_type(GeomType.PLANE)
|
||||
Offset(openings=top_bottom, amount=0.5)
|
||||
|
||||
if "show_object" in locals():
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ with BuildPart() as vase:
|
|||
# Offset(openings=vase.faces().filter_by_axis(Axis.Y)[-1], amount=-1)
|
||||
Offset(openings=(vase.faces() | Axis.Y) >> Axis.Y, amount=-1)
|
||||
top_edges = (
|
||||
vase.edges().filter_by_position(Axis.Y, 60, 62).filter_by_type(Type.CIRCLE)
|
||||
vase.edges().filter_by_position(Axis.Y, 60, 62).filter_by_type(GeomType.CIRCLE)
|
||||
)
|
||||
Fillet(*top_edges, radius=0.25)
|
||||
Fillet(vase.edges() << Axis.Y, radius=0.5)
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ __all__ = [
|
|||
"Until",
|
||||
"Axis",
|
||||
"SortBy",
|
||||
"Type",
|
||||
"GeomType",
|
||||
# Classes
|
||||
"Rotation",
|
||||
"ShapeList",
|
||||
"Builder",
|
||||
# "Builder",
|
||||
"Add",
|
||||
"BoundingBox",
|
||||
"Chamfer",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ from abc import ABC, abstractmethod
|
|||
from math import radians, sqrt, pi
|
||||
from typing import Iterable, Union
|
||||
from enum import Enum, auto
|
||||
import logging
|
||||
from cadquery import (
|
||||
Edge,
|
||||
Wire,
|
||||
|
|
@ -47,7 +48,7 @@ from cadquery import (
|
|||
Shape,
|
||||
Vertex,
|
||||
Plane,
|
||||
Matrix,
|
||||
Shell,
|
||||
)
|
||||
from cadquery.occ_impl.shapes import VectorLike
|
||||
from OCP.gp import gp_Pnt, gp_Ax1, gp_Dir, gp_Trsf
|
||||
|
|
@ -55,7 +56,6 @@ from OCP.BRepTools import BRepTools
|
|||
from OCP.TopAbs import TopAbs_ShapeEnum
|
||||
from OCP.TopoDS import TopoDS_Iterator
|
||||
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.
|
||||
|
|
@ -66,28 +66,12 @@ logger = logging.getLogger("build123d")
|
|||
# logging.basicConfig(
|
||||
# filename="myapp.log",
|
||||
# level=logging.INFO,
|
||||
# format="%(name)s-%(levelname)s %(asctime)s - [%(filename)s:%(lineno)s - %(funcName)20s() ] - %(message)s",
|
||||
# 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
|
||||
|
|
@ -117,12 +101,12 @@ Vertex.__eq__ = vertex_eq_
|
|||
#
|
||||
# Operators
|
||||
#
|
||||
def __matmul__custom(e: Union[Edge, Wire], p: float):
|
||||
return e.positionAt(p)
|
||||
def __matmul__custom(wire_edge: Union[Edge, Wire], position: float):
|
||||
return wire_edge.positionAt(position)
|
||||
|
||||
|
||||
def __mod__custom(e: Union[Edge, Wire], p: float):
|
||||
return e.tangentAt(p)
|
||||
def __mod__custom(wire_edge: Union[Edge, Wire], position: float):
|
||||
return wire_edge.tangentAt(position)
|
||||
|
||||
|
||||
Edge.__matmul__ = __matmul__custom
|
||||
|
|
@ -132,8 +116,19 @@ Wire.__mod__ = __mod__custom
|
|||
|
||||
|
||||
def compound_get_type(
|
||||
self: Compound, obj_type: Union[Edge, Face, Solid]
|
||||
) -> list[Union[Edge, Face, Solid]]:
|
||||
self: Compound, obj_type: Union[Edge, Wire, Face, Solid]
|
||||
) -> list[Union[Edge, Wire, Face, Solid]]:
|
||||
"""get_type
|
||||
|
||||
Extract the objects of the given type from a Compound. Note that this
|
||||
isn't the same as Faces() etc. which will extract Faces from Solids.
|
||||
|
||||
Args:
|
||||
obj_type (Union[Edge, Face, Solid]): Object types to extract
|
||||
|
||||
Returns:
|
||||
list[Union[Edge, Face, Solid]]: Extracted objects
|
||||
"""
|
||||
iterator = TopoDS_Iterator()
|
||||
iterator.Initialize(self.wrapped)
|
||||
|
||||
|
|
@ -175,7 +170,7 @@ class Select(Enum):
|
|||
LAST = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class Kind(Enum):
|
||||
|
|
@ -186,7 +181,7 @@ class Kind(Enum):
|
|||
TANGENT = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class Keep(Enum):
|
||||
|
|
@ -197,7 +192,7 @@ class Keep(Enum):
|
|||
BOTH = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class Mode(Enum):
|
||||
|
|
@ -210,7 +205,7 @@ class Mode(Enum):
|
|||
PRIVATE = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class Transition(Enum):
|
||||
|
|
@ -221,7 +216,7 @@ class Transition(Enum):
|
|||
TRANSFORMED = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class FontStyle(Enum):
|
||||
|
|
@ -232,7 +227,7 @@ class FontStyle(Enum):
|
|||
ITALIC = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class Halign(Enum):
|
||||
|
|
@ -243,7 +238,7 @@ class Halign(Enum):
|
|||
RIGHT = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class Valign(Enum):
|
||||
|
|
@ -254,7 +249,7 @@ class Valign(Enum):
|
|||
BOTTOM = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class Until(Enum):
|
||||
|
|
@ -264,7 +259,7 @@ class Until(Enum):
|
|||
LAST = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class SortBy(Enum):
|
||||
|
|
@ -277,11 +272,11 @@ class SortBy(Enum):
|
|||
DISTANCE = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
class Type(Enum):
|
||||
"""CAD object type"""
|
||||
class GeomType(Enum):
|
||||
"""CAD geometry object type"""
|
||||
|
||||
PLANE = auto()
|
||||
CYLINDER = auto()
|
||||
|
|
@ -301,12 +296,15 @@ class Type(Enum):
|
|||
OTHER = auto()
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s>" % (self.__class__.__name__, self.name)
|
||||
return f"<{self.__class__.__name__}.{self.name}>"
|
||||
|
||||
|
||||
def validate_inputs(validating_class, builder_context, objects=[]):
|
||||
def validate_inputs(validating_class, builder_context, objects: Shape = None):
|
||||
"""Validate that objects/operations and parameters apply"""
|
||||
|
||||
if not objects:
|
||||
objects = []
|
||||
|
||||
# Check for builder / object matches
|
||||
if not builder_context:
|
||||
builder_dict = {
|
||||
|
|
@ -319,9 +317,9 @@ def validate_inputs(validating_class, builder_context, objects=[]):
|
|||
f"{validating_class.__class__.__name__} doesn't have an active builder, "
|
||||
f"did you miss a with {builder_dict[validating_class.__module__]}:"
|
||||
)
|
||||
elif not (
|
||||
builder_context.__module__ == validating_class.__module__
|
||||
or validating_class.__module__ == "build123d.build_generic"
|
||||
if not (
|
||||
validating_class.__module__
|
||||
in [builder_context.__module__, "build123d.build_generic"]
|
||||
):
|
||||
raise RuntimeError(
|
||||
f"{builder_context.__class__.__name__} doesn't have a "
|
||||
|
|
@ -360,13 +358,13 @@ class Rotation(Location):
|
|||
self.about_z = about_z
|
||||
|
||||
# Compute rotation matrix.
|
||||
rx = gp_Trsf()
|
||||
rx.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)), radians(about_x))
|
||||
ry = gp_Trsf()
|
||||
ry.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), radians(about_y))
|
||||
rz = gp_Trsf()
|
||||
rz.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), radians(about_z))
|
||||
super().__init__(Location(rx * ry * rz).wrapped)
|
||||
rot_x = gp_Trsf()
|
||||
rot_x.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)), radians(about_x))
|
||||
rot_y = gp_Trsf()
|
||||
rot_y.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), radians(about_y))
|
||||
rot_z = gp_Trsf()
|
||||
rot_z.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), radians(about_z))
|
||||
super().__init__(Location(rot_x * rot_y * rot_z).wrapped)
|
||||
|
||||
|
||||
#:TypeVar("RotationLike"): Three tuple of angles about x, y, z or Rotation
|
||||
|
|
@ -381,17 +379,20 @@ class Axis:
|
|||
|
||||
@classmethod
|
||||
@property
|
||||
def X(self) -> Axis:
|
||||
def X(cls) -> Axis:
|
||||
"""X Axis"""
|
||||
return Axis((0, 0, 0), (1, 0, 0))
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def Y(self) -> Axis:
|
||||
def Y(cls) -> Axis:
|
||||
"""Y Axis"""
|
||||
return Axis((0, 0, 0), (0, 1, 0))
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def Z(self) -> Axis:
|
||||
def Z(cls) -> Axis:
|
||||
"""Z Axis"""
|
||||
return Axis((0, 0, 0), (0, 0, 1))
|
||||
|
||||
def __init__(self, origin: VectorLike, direction: VectorLike):
|
||||
|
|
@ -484,8 +485,9 @@ class Axis:
|
|||
def is_opposite(self, other: Axis, angular_tolerance: float = 1e-5) -> bool:
|
||||
"""are axes opposite
|
||||
|
||||
Returns True if the direction of this and another axis are parallel with opposite orientation.
|
||||
That is, if the angle between the two axes is equal to 180° within the angular_tolerance.
|
||||
Returns True if the direction of this and another axis are parallel with
|
||||
opposite orientation. That is, if the angle between the two axes is equal
|
||||
to 180° within the angular_tolerance.
|
||||
|
||||
Args:
|
||||
other (Axis): axis to compare to
|
||||
|
|
@ -582,8 +584,8 @@ class ShapeList(list):
|
|||
def filter_by_position(
|
||||
self,
|
||||
axis: Axis,
|
||||
min: float,
|
||||
max: float,
|
||||
minimum: float,
|
||||
maximum: float,
|
||||
inclusive: tuple[bool, bool] = (True, True),
|
||||
):
|
||||
"""filter by position
|
||||
|
|
@ -593,36 +595,48 @@ class ShapeList(list):
|
|||
|
||||
Args:
|
||||
axis (Axis): axis to sort by
|
||||
min (float): minimum value
|
||||
max (float): maximum value
|
||||
inclusive (tuple[bool, bool], optional): include min,max values. Defaults to (True, True).
|
||||
minimum (float): minimum value
|
||||
maximum (float): maximum value
|
||||
inclusive (tuple[bool, bool], optional): include min,max values.
|
||||
Defaults to (True, True).
|
||||
|
||||
Returns:
|
||||
ShapeList: filtered object list
|
||||
"""
|
||||
if inclusive == (True, True):
|
||||
objects = filter(
|
||||
lambda o: min <= axis.to_plane().toLocalCoords(o).Center().z <= max,
|
||||
lambda o: minimum
|
||||
<= axis.to_plane().toLocalCoords(o).Center().z
|
||||
<= maximum,
|
||||
self,
|
||||
)
|
||||
elif inclusive == (True, False):
|
||||
objects = filter(
|
||||
lambda o: min <= axis.to_plane().toLocalCoords(o).Center().z < max, self
|
||||
lambda o: minimum
|
||||
<= axis.to_plane().toLocalCoords(o).Center().z
|
||||
< maximum,
|
||||
self,
|
||||
)
|
||||
elif inclusive == (False, True):
|
||||
objects = filter(
|
||||
lambda o: min < axis.to_plane().toLocalCoords(o).Center().z <= max, self
|
||||
lambda o: minimum
|
||||
< axis.to_plane().toLocalCoords(o).Center().z
|
||||
<= maximum,
|
||||
self,
|
||||
)
|
||||
elif inclusive == (False, False):
|
||||
objects = filter(
|
||||
lambda o: min < axis.to_plane().toLocalCoords(o).Center().z < max, self
|
||||
lambda o: minimum
|
||||
< axis.to_plane().toLocalCoords(o).Center().z
|
||||
< maximum,
|
||||
self,
|
||||
)
|
||||
|
||||
return ShapeList(objects).sort_by(axis)
|
||||
|
||||
def filter_by_type(
|
||||
self,
|
||||
type: Type,
|
||||
geom_type: GeomType,
|
||||
):
|
||||
"""filter by type
|
||||
|
||||
|
|
@ -635,7 +649,7 @@ class ShapeList(list):
|
|||
Returns:
|
||||
ShapeList: filtered list of objects
|
||||
"""
|
||||
result = filter(lambda o: o.geomType() == type.name, self)
|
||||
result = filter(lambda o: o.geomType() == geom_type.name, self)
|
||||
return ShapeList(result)
|
||||
|
||||
def sort_by(self, sort_by: Union[Axis, SortBy] = Axis.Z, reverse: bool = False):
|
||||
|
|
@ -714,9 +728,9 @@ class ShapeList(list):
|
|||
"""Filter by axis operator"""
|
||||
return self.filter_by_axis(axis)
|
||||
|
||||
def __mod__(self, type: Type):
|
||||
"""Filter by type operator"""
|
||||
return self.filter_by_type(type)
|
||||
def __mod__(self, geom_type: GeomType):
|
||||
"""Filter by geometry type operator"""
|
||||
return self.filter_by_type(geom_type)
|
||||
|
||||
|
||||
def _vertices(self: Shape) -> ShapeList[Vertex]:
|
||||
|
|
@ -767,7 +781,7 @@ class Builder(ABC):
|
|||
mode (Mode, optional): combination mode. Defaults to Mode.ADD.
|
||||
"""
|
||||
|
||||
"""Context variable used to by Objects and Operations to link to current builder instance"""
|
||||
# Context variable used to by Objects and Operations to link to current builder instance
|
||||
_current: contextvars.ContextVar["Builder"] = contextvars.ContextVar(
|
||||
"Builder._current"
|
||||
)
|
||||
|
|
@ -779,6 +793,7 @@ class Builder(ABC):
|
|||
self._parent = None
|
||||
self.last_vertices = []
|
||||
self.last_edges = []
|
||||
self.workplane_generator = None
|
||||
|
||||
def __enter__(self):
|
||||
"""Upon entering record the parent and a token to restore contextvars"""
|
||||
|
|
@ -789,19 +804,19 @@ class Builder(ABC):
|
|||
# Push an initial plane and point
|
||||
self.workplane_generator = Workplanes(self.initial_plane).__enter__()
|
||||
|
||||
logger.info(f"Entering {type(self).__name__} with mode={self.mode}")
|
||||
logger.info("Entering %s with mode=%s", type(self).__name__, self.mode)
|
||||
return self
|
||||
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
"""Upon exiting restore context and send object to parent"""
|
||||
self._current.reset(self._reset_tok)
|
||||
logger.info(f"Exiting {type(self).__name__}")
|
||||
logger.info("Exiting %s", type(self).__name__)
|
||||
|
||||
# Pop the initial plane and point
|
||||
self.workplane_generator.__exit__(None, None, None)
|
||||
|
||||
if self._parent is not None:
|
||||
logger.debug(f"Transferring line to {type(self._parent).__name__}")
|
||||
logger.debug("Transferring line to %s", type(self._parent).__name__)
|
||||
if isinstance(self._obj, Iterable):
|
||||
self._parent._add_to_context(*self._obj, mode=self.mode)
|
||||
else:
|
||||
|
|
@ -836,6 +851,59 @@ class Builder(ABC):
|
|||
"""
|
||||
return cls._current.get(None)
|
||||
|
||||
def vertices(self, select: Select = Select.ALL) -> ShapeList[Vertex]:
|
||||
"""Return Vertices from Part
|
||||
|
||||
Return either all or the vertices created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Vertex selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
VertexList[Vertex]: Vertices extracted
|
||||
"""
|
||||
vertex_list = []
|
||||
if select == Select.ALL:
|
||||
for edge in self._obj.Edges():
|
||||
vertex_list.extend(edge.Vertices())
|
||||
elif select == Select.LAST:
|
||||
vertex_list = self.last_vertices
|
||||
return ShapeList(set(vertex_list))
|
||||
|
||||
def edges(self, select: Select = Select.ALL) -> ShapeList[Edge]:
|
||||
"""Return Edges from Part
|
||||
|
||||
Return either all or the edges created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Edge selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
ShapeList[Edge]: Edges extracted
|
||||
"""
|
||||
if select == Select.ALL:
|
||||
edge_list = self._obj.Edges()
|
||||
elif select == Select.LAST:
|
||||
edge_list = self.last_edges
|
||||
return ShapeList(edge_list)
|
||||
|
||||
def faces(self, select: Select = Select.ALL) -> ShapeList[Face]:
|
||||
"""Return Faces from Sketch
|
||||
|
||||
Return either all or the faces created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Face selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
ShapeList[Face]: Faces extracted
|
||||
"""
|
||||
if select == Select.ALL:
|
||||
face_list = self._obj.Faces()
|
||||
elif select == Select.LAST:
|
||||
face_list = self.last_faces
|
||||
return ShapeList(face_list)
|
||||
|
||||
|
||||
class LocationList:
|
||||
|
||||
|
|
@ -853,13 +921,13 @@ class LocationList:
|
|||
def __enter__(self):
|
||||
"""Upon entering create a token to restore contextvars"""
|
||||
self._reset_tok = self._current.set(self)
|
||||
logger.info(f"{type(self).__name__} is pushing {len(self.locations)} points")
|
||||
logger.info("%s is pushing %d points", type(self).__name__, len(self.locations))
|
||||
return self
|
||||
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
"""Upon exiting restore context"""
|
||||
self._current.reset(self._reset_tok)
|
||||
logger.info(f"{type(self).__name__} is popping {len(self.locations)} points")
|
||||
logger.info("%s is popping %d points", type(self).__name__, len(self.locations))
|
||||
|
||||
@classmethod
|
||||
def _get_context(cls):
|
||||
|
|
@ -885,37 +953,39 @@ class HexLocations(LocationList):
|
|||
def __init__(
|
||||
self,
|
||||
diagonal: float,
|
||||
xCount: int,
|
||||
yCount: int,
|
||||
x_count: int,
|
||||
y_count: int,
|
||||
centered: tuple[bool, bool] = (True, True),
|
||||
):
|
||||
xSpacing = 3 * diagonal / 4
|
||||
ySpacing = diagonal * sqrt(3) / 2
|
||||
if xSpacing <= 0 or ySpacing <= 0 or xCount < 1 or yCount < 1:
|
||||
x_spacing = 3 * diagonal / 4
|
||||
y_spacing = diagonal * sqrt(3) / 2
|
||||
if x_spacing <= 0 or y_spacing <= 0 or x_count < 1 or y_count < 1:
|
||||
raise ValueError("Spacing and count must be > 0 ")
|
||||
|
||||
points = [] # coordinates relative to bottom left point
|
||||
for x in range(0, xCount, 2):
|
||||
for y in range(yCount):
|
||||
points.append(Vector(xSpacing * x, ySpacing * y + ySpacing / 2))
|
||||
for x in range(1, xCount, 2):
|
||||
for y in range(yCount):
|
||||
points.append(Vector(xSpacing * x, ySpacing * y + ySpacing))
|
||||
for x_val in range(0, x_count, 2):
|
||||
for y_val in range(y_count):
|
||||
points.append(
|
||||
Vector(x_spacing * x_val, y_spacing * y_val + y_spacing / 2)
|
||||
)
|
||||
for x_val in range(1, x_count, 2):
|
||||
for y_val in range(y_count):
|
||||
points.append(Vector(x_spacing * x_val, y_spacing * y_val + y_spacing))
|
||||
|
||||
# shift points down and left relative to origin if requested
|
||||
offset = Vector()
|
||||
if centered[0]:
|
||||
offset += Vector(-xSpacing * (xCount - 1) * 0.5, 0)
|
||||
offset += Vector(-x_spacing * (x_count - 1) * 0.5, 0)
|
||||
if centered[1]:
|
||||
offset += Vector(0, -ySpacing * yCount * 0.5)
|
||||
offset += Vector(0, -y_spacing * y_count * 0.5)
|
||||
points = [x + offset for x in points]
|
||||
|
||||
# convert to locations and store the reference plane
|
||||
self.locations = []
|
||||
self.planes = []
|
||||
for plane in WorkplaneList._get_context().workplanes:
|
||||
for pt in points:
|
||||
self.locations.append(Location(plane) * Location(pt))
|
||||
for point in points:
|
||||
self.locations.append(Location(plane) * Location(point))
|
||||
self.planes.append(plane)
|
||||
|
||||
super().__init__(self.locations, self.planes)
|
||||
|
|
@ -980,19 +1050,19 @@ class Locations(LocationList):
|
|||
self.locations = []
|
||||
self.planes = []
|
||||
for plane in WorkplaneList._get_context().workplanes:
|
||||
for pt in pts:
|
||||
if isinstance(pt, Location):
|
||||
self.locations.append(Location(plane) * pt)
|
||||
elif isinstance(pt, Vector):
|
||||
self.locations.append(Location(plane) * Location(pt))
|
||||
elif isinstance(pt, Vertex):
|
||||
for point in pts:
|
||||
if isinstance(point, Location):
|
||||
self.locations.append(Location(plane) * point)
|
||||
elif isinstance(point, Vector):
|
||||
self.locations.append(Location(plane) * Location(point))
|
||||
elif isinstance(point, Vertex):
|
||||
self.locations.append(
|
||||
Location(plane) * Location(Vector(pt.toTuple()))
|
||||
Location(plane) * Location(Vector(point.toTuple()))
|
||||
)
|
||||
elif isinstance(pt, tuple):
|
||||
self.locations.append(Location(plane) * Location(Vector(pt)))
|
||||
elif isinstance(point, tuple):
|
||||
self.locations.append(Location(plane) * Location(Vector(point)))
|
||||
else:
|
||||
raise ValueError(f"Locations doesn't accept type {type(pt)}")
|
||||
raise ValueError(f"Locations doesn't accept type {type(point)}")
|
||||
self.planes.append(plane)
|
||||
super().__init__(self.locations, self.planes)
|
||||
|
||||
|
|
@ -1062,13 +1132,14 @@ class WorkplaneList:
|
|||
def __init__(self, planes: list[Plane]):
|
||||
self._reset_tok = None
|
||||
self.workplanes = planes
|
||||
self.point_generator = None
|
||||
|
||||
def __enter__(self):
|
||||
"""Upon entering create a token to restore contextvars"""
|
||||
self._reset_tok = self._current.set(self)
|
||||
self.point_generator = Locations((0, 0, 0)).__enter__()
|
||||
logger.info(
|
||||
f"{type(self).__name__} is pushing {len(self.workplanes)} workplanes"
|
||||
"%s is pushing %d workplanes", type(self).__name__, len(self.workplanes)
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -1077,7 +1148,7 @@ class WorkplaneList:
|
|||
self._current.reset(self._reset_tok)
|
||||
self.point_generator.__exit__(None, None, None)
|
||||
logger.info(
|
||||
f"{type(self).__name__} is popping {len(self.workplanes)} workplanes"
|
||||
"%s is popping %d workplanes", type(self).__name__, len(self.workplanes)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ license:
|
|||
limitations under the License.
|
||||
|
||||
"""
|
||||
import inspect
|
||||
from typing import Union
|
||||
import logging
|
||||
from cadquery import Matrix
|
||||
from build123d import (
|
||||
BuildLine,
|
||||
BuildSketch,
|
||||
|
|
@ -35,16 +36,11 @@ from build123d import (
|
|||
Mode,
|
||||
RotationLike,
|
||||
Rotation,
|
||||
Axis,
|
||||
Builder,
|
||||
LocationList,
|
||||
Kind,
|
||||
Keep,
|
||||
PlaneLike,
|
||||
Matrix,
|
||||
validate_inputs,
|
||||
)
|
||||
from cadquery import (
|
||||
Shape,
|
||||
Vertex,
|
||||
Plane,
|
||||
|
|
@ -55,8 +51,8 @@ from cadquery import (
|
|||
Solid,
|
||||
Location,
|
||||
Vector,
|
||||
validate_inputs,
|
||||
)
|
||||
import logging
|
||||
|
||||
logging.getLogger("build123d").addHandler(logging.NullHandler())
|
||||
logger = logging.getLogger("build123d")
|
||||
|
|
|
|||
|
|
@ -28,26 +28,21 @@ license:
|
|||
import inspect
|
||||
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, Vector, Vertex
|
||||
from cadquery.occ_impl.shapes import VectorLike
|
||||
|
||||
# import cq_warehouse.extensions
|
||||
|
||||
from build123d.build_common import *
|
||||
from build123d.build_common import (
|
||||
Edge,
|
||||
Wire,
|
||||
Vector,
|
||||
Vertex,
|
||||
Compound,
|
||||
Location,
|
||||
Builder,
|
||||
VectorLike,
|
||||
Select,
|
||||
ShapeList,
|
||||
Mode,
|
||||
logger,
|
||||
validate_inputs,
|
||||
)
|
||||
|
||||
|
||||
class BuildLine(Builder):
|
||||
|
|
@ -72,42 +67,6 @@ class BuildLine(Builder):
|
|||
self.locations: list[Location] = [Location(Vector())]
|
||||
super().__init__(mode)
|
||||
|
||||
def vertices(self, select: Select = Select.ALL) -> ShapeList[Vertex]:
|
||||
"""Return Vertices from Line
|
||||
|
||||
Return either all or the vertices created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Vertex selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
VertexList[Vertex]: Vertices extracted
|
||||
"""
|
||||
vertex_list = []
|
||||
if select == Select.ALL:
|
||||
for edge in self.line.Edges():
|
||||
vertex_list.extend(edge.Vertices())
|
||||
elif select == Select.LAST:
|
||||
vertex_list = self.last_vertices
|
||||
return ShapeList(set(vertex_list))
|
||||
|
||||
def edges(self, select: Select = Select.ALL) -> ShapeList[Edge]:
|
||||
"""Return Edges from Line
|
||||
|
||||
Return either all or the edges created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Edge selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
ShapeList[Edge]: Edges extracted
|
||||
"""
|
||||
if select == Select.ALL:
|
||||
edge_list = self.line.Edges()
|
||||
elif select == Select.LAST:
|
||||
edge_list = self.last_edges
|
||||
return ShapeList(edge_list)
|
||||
|
||||
def wires(self, select: Select = Select.ALL) -> ShapeList[Wire]:
|
||||
"""Return Wires from Line
|
||||
|
||||
|
|
@ -149,7 +108,9 @@ class BuildLine(Builder):
|
|||
for wire in new_wires:
|
||||
new_edges.extend(wire.Edges())
|
||||
if new_edges:
|
||||
logger.debug(f"Add {len(new_edges)} Edge(s) into line with Mode={mode}")
|
||||
logger.debug(
|
||||
"Add %d Edge(s) into line with Mode=%s", len(new_edges), mode
|
||||
)
|
||||
|
||||
if mode == Mode.ADD:
|
||||
if self.line:
|
||||
|
|
@ -167,7 +128,8 @@ class BuildLine(Builder):
|
|||
def _get_context(cls) -> "BuildLine":
|
||||
"""Return the instance of the current builder"""
|
||||
logger.info(
|
||||
f"Context requested by {type(inspect.currentframe().f_back.f_locals['self']).__name__}"
|
||||
"Context requested by %s",
|
||||
type(inspect.currentframe().f_back.f_locals["self"]).__name__,
|
||||
)
|
||||
return cls._current.get(None)
|
||||
|
||||
|
|
@ -331,9 +293,11 @@ class PolarLine(Edge):
|
|||
context: BuildLine = BuildLine._get_context()
|
||||
validate_inputs(self, context)
|
||||
if angle is not None:
|
||||
x = cos(radians(angle)) * length
|
||||
y = sin(radians(angle)) * length
|
||||
new_edge = Edge.makeLine(Vector(start), Vector(start) + Vector(x, y, 0))
|
||||
x_val = cos(radians(angle)) * length
|
||||
y_val = sin(radians(angle)) * length
|
||||
new_edge = Edge.makeLine(
|
||||
Vector(start), Vector(start) + Vector(x_val, y_val, 0)
|
||||
)
|
||||
elif direction is not None:
|
||||
new_edge = Edge.makeLine(
|
||||
Vector(start), Vector(start) + Vector(direction).normalized() * length
|
||||
|
|
@ -410,10 +374,10 @@ class RadiusArc(Edge):
|
|||
length = end.sub(start).Length / 2.0
|
||||
try:
|
||||
sagitta = abs(radius) - sqrt(radius**2 - length**2)
|
||||
except ValueError as e:
|
||||
except ValueError as exception:
|
||||
raise ValueError(
|
||||
"Arc radius is not large enough to reach the end point."
|
||||
) from e
|
||||
) from exception
|
||||
|
||||
# Return a sagitta arc
|
||||
if radius > 0:
|
||||
|
|
|
|||
|
|
@ -31,23 +31,34 @@ license:
|
|||
"""
|
||||
import inspect
|
||||
from warnings import warn
|
||||
from math import radians, tan
|
||||
from typing import Union
|
||||
from cadquery import (
|
||||
from math import radians, tan, sqrt
|
||||
from typing import Union, Iterable
|
||||
from OCP.gp import gp_Pln, gp_Lin
|
||||
from build123d.build_common import (
|
||||
Edge,
|
||||
Face,
|
||||
Wire,
|
||||
Vector,
|
||||
Location,
|
||||
Vertex,
|
||||
Compound,
|
||||
Solid,
|
||||
Plane,
|
||||
Shell,
|
||||
VectorLike,
|
||||
Builder,
|
||||
Mode,
|
||||
PlaneLike,
|
||||
Select,
|
||||
ShapeList,
|
||||
Until,
|
||||
Axis,
|
||||
Transition,
|
||||
RotationLike,
|
||||
logger,
|
||||
validate_inputs,
|
||||
Rotation,
|
||||
LocationList,
|
||||
WorkplaneList,
|
||||
)
|
||||
from cadquery.occ_impl.shapes import VectorLike
|
||||
from build123d.build_common import *
|
||||
from OCP.gp import gp_Pln, gp_Lin
|
||||
|
||||
|
||||
class BuildPart(Builder):
|
||||
|
|
@ -92,59 +103,6 @@ class BuildPart(Builder):
|
|||
self.last_solids = []
|
||||
super().__init__(mode, initial_plane)
|
||||
|
||||
def vertices(self, select: Select = Select.ALL) -> ShapeList[Vertex]:
|
||||
"""Return Vertices from Part
|
||||
|
||||
Return either all or the vertices created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Vertex selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
VertexList[Vertex]: Vertices extracted
|
||||
"""
|
||||
vertex_list = []
|
||||
if select == Select.ALL:
|
||||
for edge in self.part.Edges():
|
||||
vertex_list.extend(edge.Vertices())
|
||||
elif select == Select.LAST:
|
||||
vertex_list = self.last_vertices
|
||||
return ShapeList(set(vertex_list))
|
||||
|
||||
def edges(self, select: Select = Select.ALL) -> ShapeList[Edge]:
|
||||
"""Return Edges from Part
|
||||
|
||||
Return either all or the edges created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Edge selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
ShapeList[Edge]: Edges extracted
|
||||
"""
|
||||
if select == Select.ALL:
|
||||
edge_list = self.part.Edges()
|
||||
elif select == Select.LAST:
|
||||
edge_list = self.last_edges
|
||||
return ShapeList(edge_list)
|
||||
|
||||
def faces(self, select: Select = Select.ALL) -> ShapeList[Face]:
|
||||
"""Return Faces from Part
|
||||
|
||||
Return either all or the faces created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Face selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
ShapeList[Face]: Faces extracted
|
||||
"""
|
||||
if select == Select.ALL:
|
||||
face_list = self.part.Faces()
|
||||
elif select == Select.LAST:
|
||||
face_list = self.last_faces
|
||||
return ShapeList(face_list)
|
||||
|
||||
def solids(self, select: Select = Select.ALL) -> ShapeList[Solid]:
|
||||
"""Return Solids from Part
|
||||
|
||||
|
|
@ -174,13 +132,15 @@ class BuildPart(Builder):
|
|||
localized_obj = obj.moved(loc)
|
||||
if isinstance(obj, Face):
|
||||
logger.debug(
|
||||
f"Adding localized Face to pending_faces at {localized_obj.location()}"
|
||||
"Adding localized Face to pending_faces at %s",
|
||||
localized_obj.location(),
|
||||
)
|
||||
self.pending_faces.append(localized_obj)
|
||||
self.pending_face_planes.append(plane)
|
||||
else:
|
||||
logger.debug(
|
||||
f"Adding localized Edge to pending_edges at {localized_obj.location()}"
|
||||
"Adding localized Edge to pending_edges at %s",
|
||||
localized_obj.location(),
|
||||
)
|
||||
self.pending_edges.append(localized_obj)
|
||||
self.pending_edge_planes.append(plane)
|
||||
|
|
@ -241,8 +201,9 @@ class BuildPart(Builder):
|
|||
|
||||
if new_solids:
|
||||
logger.debug(
|
||||
f"Attempting to integrate {len(new_solids)} object(s) into part"
|
||||
f" with Mode={mode}"
|
||||
"Attempting to integrate %d object(s) into part with Mode=%s",
|
||||
len(new_solids),
|
||||
mode,
|
||||
)
|
||||
if mode == Mode.ADD:
|
||||
if self.part is None:
|
||||
|
|
@ -264,8 +225,9 @@ class BuildPart(Builder):
|
|||
self.part = Compound.makeCompound(list(new_solids)).clean()
|
||||
|
||||
logger.info(
|
||||
f"Completed integrating {len(new_solids)} object(s) into part"
|
||||
f" with Mode={mode}"
|
||||
"Completed integrating %d object(s) into part with Mode=%s",
|
||||
len(new_solids),
|
||||
mode,
|
||||
)
|
||||
|
||||
post_vertices = set() if self.part is None else set(self.part.Vertices())
|
||||
|
|
@ -284,7 +246,8 @@ class BuildPart(Builder):
|
|||
def _get_context(cls) -> "BuildPart":
|
||||
"""Return the instance of the current builder"""
|
||||
logger.info(
|
||||
f"Context requested by {type(inspect.currentframe().f_back.f_locals['self']).__name__}"
|
||||
"Context requested by %s",
|
||||
type(inspect.currentframe().f_back.f_locals["self"]).__name__,
|
||||
)
|
||||
return cls._current.get(None)
|
||||
|
||||
|
|
@ -436,7 +399,7 @@ class Extrude(Compound):
|
|||
if to_extrude:
|
||||
list_context = LocationList._get_context()
|
||||
faces = [to_extrude.moved(loc) for loc in list_context.locations]
|
||||
face_planes = [plane for plane in list_context.planes]
|
||||
face_planes = list_context.planes
|
||||
else:
|
||||
faces = context.pending_faces
|
||||
face_planes = context.pending_face_planes
|
||||
|
|
@ -458,12 +421,12 @@ class Extrude(Compound):
|
|||
part_faces = context.part.Faces()
|
||||
|
||||
for face, plane in zip(faces, face_planes):
|
||||
for dir in [1, -1] if both else [1]:
|
||||
for direction in [1, -1] if both else [1]:
|
||||
if amount:
|
||||
new_solids.append(
|
||||
Solid.extrudeLinear(
|
||||
face,
|
||||
plane.zDir * amount * dir,
|
||||
plane.zDir * amount * direction,
|
||||
taper,
|
||||
)
|
||||
)
|
||||
|
|
@ -493,10 +456,12 @@ class Extrude(Compound):
|
|||
|
||||
# Determine which surface is "next" or "last"
|
||||
surface_dirs = []
|
||||
for s in trim_shells:
|
||||
for trim_shell in trim_shells:
|
||||
face_directions = Vector(0, 0, 0)
|
||||
for f in s.Faces():
|
||||
face_directions = face_directions + f.normalAt(f.Center())
|
||||
for trim_face in trim_shell.Faces():
|
||||
face_directions = face_directions + trim_face.normalAt(
|
||||
trim_face.Center()
|
||||
)
|
||||
surface_dirs.append(face_directions.getAngle(plane.zDir))
|
||||
if until == Until.NEXT:
|
||||
surface_index = surface_dirs.index(max(surface_dirs))
|
||||
|
|
@ -513,10 +478,11 @@ class Extrude(Compound):
|
|||
)
|
||||
for f in trim_faces
|
||||
]
|
||||
for o, f in zip(trim_objects, trim_faces):
|
||||
if not o.isValid():
|
||||
for trim_object, trim_face in zip(trim_objects, trim_faces):
|
||||
if not trim_object.isValid():
|
||||
warn(
|
||||
message=f"Part face with area {f.Area()} creates an invalid extrusion",
|
||||
message=f"Part face with area {trim_face.Area()} "
|
||||
f"creates an invalid extrusion",
|
||||
category=Warning,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -41,24 +41,25 @@ license:
|
|||
import inspect
|
||||
from math import pi, sin, cos, tan, radians
|
||||
from typing import Union
|
||||
|
||||
# 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, Location, Vertex, Compound
|
||||
from cadquery.occ_impl.shapes import VectorLike
|
||||
from build123d.build_common import *
|
||||
from build123d.build_common import (
|
||||
Edge,
|
||||
Face,
|
||||
Wire,
|
||||
Vector,
|
||||
Location,
|
||||
Compound,
|
||||
VectorLike,
|
||||
Builder,
|
||||
Mode,
|
||||
ShapeList,
|
||||
FontStyle,
|
||||
Halign,
|
||||
Valign,
|
||||
logger,
|
||||
validate_inputs,
|
||||
LocationList,
|
||||
)
|
||||
|
||||
|
||||
class BuildSketch(Builder):
|
||||
|
|
@ -85,59 +86,6 @@ class BuildSketch(Builder):
|
|||
self.last_faces = []
|
||||
super().__init__(mode)
|
||||
|
||||
def vertices(self, select: Select = Select.ALL) -> ShapeList[Vertex]:
|
||||
"""Return Vertices from Sketch
|
||||
|
||||
Return either all or the vertices created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Vertex selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
VertexList[Vertex]: Vertices extracted
|
||||
"""
|
||||
vertex_list = []
|
||||
if select == Select.ALL:
|
||||
for edge in self.sketch.Edges():
|
||||
vertex_list.extend(edge.Vertices())
|
||||
elif select == Select.LAST:
|
||||
vertex_list = self.last_vertices
|
||||
return ShapeList(set(vertex_list))
|
||||
|
||||
def edges(self, select: Select = Select.ALL) -> ShapeList[Edge]:
|
||||
"""Return Edges from Sketch
|
||||
|
||||
Return either all or the edges created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Edge selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
ShapeList[Edge]: Edges extracted
|
||||
"""
|
||||
if select == Select.ALL:
|
||||
edge_list = self.sketch.Edges()
|
||||
elif select == Select.LAST:
|
||||
edge_list = self.last_edges
|
||||
return ShapeList(edge_list)
|
||||
|
||||
def faces(self, select: Select = Select.ALL) -> ShapeList[Face]:
|
||||
"""Return Faces from Sketch
|
||||
|
||||
Return either all or the faces created during the last operation.
|
||||
|
||||
Args:
|
||||
select (Select, optional): Face selector. Defaults to Select.ALL.
|
||||
|
||||
Returns:
|
||||
ShapeList[Face]: Faces extracted
|
||||
"""
|
||||
if select == Select.ALL:
|
||||
face_list = self.sketch.Faces()
|
||||
elif select == Select.LAST:
|
||||
face_list = self.last_faces
|
||||
return ShapeList(face_list)
|
||||
|
||||
def consolidate_edges(self) -> Union[Wire, list[Wire]]:
|
||||
"""Unify pending edges into one or more Wires"""
|
||||
wires = Wire.combine(self.pending_edges)
|
||||
|
|
@ -179,8 +127,9 @@ class BuildSketch(Builder):
|
|||
pre_faces = set() if self.sketch is None else set(self.sketch.Faces())
|
||||
if new_faces:
|
||||
logger.debug(
|
||||
f"Attempting to integrate {len(new_faces)} Face(s) into sketch"
|
||||
f" with Mode={mode}"
|
||||
"Attempting to integrate %d Face(s) into sketch with Mode=%s",
|
||||
len(new_faces),
|
||||
mode,
|
||||
)
|
||||
if mode == Mode.ADD:
|
||||
if self.sketch is None:
|
||||
|
|
@ -198,9 +147,10 @@ class BuildSketch(Builder):
|
|||
elif mode == Mode.REPLACE:
|
||||
self.sketch = Compound.makeCompound(new_faces).clean()
|
||||
|
||||
logger.info(
|
||||
f"Completed integrating {len(new_faces)} Face(s) into sketch"
|
||||
f" with Mode={mode}"
|
||||
logger.debug(
|
||||
"Completed integrating %d Face(s) into sketch with Mode=%s",
|
||||
len(new_faces),
|
||||
mode,
|
||||
)
|
||||
|
||||
post_vertices = (
|
||||
|
|
@ -220,7 +170,8 @@ class BuildSketch(Builder):
|
|||
def _get_context(cls) -> "BuildSketch":
|
||||
"""Return the instance of the current builder"""
|
||||
logger.info(
|
||||
f"Context requested by {type(inspect.currentframe().f_back.f_locals['self']).__name__}"
|
||||
"Context requested by %s",
|
||||
type(inspect.currentframe().f_back.f_locals["self"]).__name__,
|
||||
)
|
||||
return cls._current.get(None)
|
||||
|
||||
|
|
|
|||
|
|
@ -53,10 +53,6 @@ class TestCommonOperations(unittest.TestCase):
|
|||
|
||||
|
||||
class TestProperties(unittest.TestCase):
|
||||
def test_vertex_properties(self):
|
||||
v = Vertex.makeVertex(1, 2, 3)
|
||||
self.assertTupleAlmostEquals((v.x, v.y, v.z), (1, 2, 3), 5)
|
||||
|
||||
def test_vector_properties(self):
|
||||
v = Vector(1, 2, 3)
|
||||
self.assertTupleAlmostEquals((v.X, v.Y, v.Z), (1, 2, 3), 5)
|
||||
|
|
@ -168,8 +164,8 @@ class TestShapeList(unittest.TestCase):
|
|||
Box(2, 2, 2)
|
||||
objects = test.faces()
|
||||
objects.extend(test.edges())
|
||||
self.assertEqual(len(objects.filter_by_type(Type.PLANE)), 6)
|
||||
self.assertEqual(len(objects.filter_by_type(Type.LINE)), 12)
|
||||
self.assertEqual(len(objects.filter_by_type(GeomType.PLANE)), 6)
|
||||
self.assertEqual(len(objects.filter_by_type(GeomType.LINE)), 12)
|
||||
|
||||
def test_sort_by_type(self):
|
||||
"""test sorting by different attributes"""
|
||||
|
|
@ -206,7 +202,9 @@ class TestShapeList(unittest.TestCase):
|
|||
with self.subTest(sort_by=SortBy.RADIUS):
|
||||
with BuildPart() as test:
|
||||
Cone(1, 0.5, 2)
|
||||
edges = test.edges().filter_by_type(Type.CIRCLE).sort_by(SortBy.RADIUS)
|
||||
edges = (
|
||||
test.edges().filter_by_type(GeomType.CIRCLE).sort_by(SortBy.RADIUS)
|
||||
)
|
||||
self.assertEqual(edges[0].radius(), 0.5)
|
||||
self.assertEqual(edges[-1].radius(), 1)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import unittest
|
|||
from math import pi
|
||||
from build123d import *
|
||||
from cadquery import Compound, Vector, Edge, Face, Solid, Wire, Location
|
||||
from build123d import LocationList
|
||||
from build123d import LocationList, Builder
|
||||
|
||||
|
||||
def _assertTupleAlmostEquals(self, expected, actual, places, msg=None):
|
||||
|
|
@ -216,7 +216,8 @@ class ChamferTests(unittest.TestCase):
|
|||
with Locations((-10, 0), (10, 0)):
|
||||
Rectangle(10, 10)
|
||||
Chamfer(
|
||||
*test.vertices().filter_by_position(Axis.X, min=0, max=20), length=1
|
||||
*test.vertices().filter_by_position(Axis.X, minimum=0, maximum=20),
|
||||
length=1
|
||||
)
|
||||
self.assertAlmostEqual(test.sketch.Area(), 200 - 4 * 0.5, 5)
|
||||
|
||||
|
|
@ -242,7 +243,10 @@ class FilletTests(unittest.TestCase):
|
|||
with BuildSketch() as test:
|
||||
with Locations((-10, 0), (10, 0)):
|
||||
Rectangle(10, 10)
|
||||
Fillet(*test.vertices().filter_by_position(Axis.X, min=0, max=20), radius=1)
|
||||
Fillet(
|
||||
*test.vertices().filter_by_position(Axis.X, minimum=0, maximum=20),
|
||||
radius=1
|
||||
)
|
||||
self.assertAlmostEqual(test.sketch.Area(), 200 - 4 + pi, 5)
|
||||
|
||||
def test_errors(self):
|
||||
|
|
@ -275,9 +279,11 @@ class MirrorTests(unittest.TestCase):
|
|||
wire = Wire.makeCircle(1, center=(5, 0, 0), normal=(0, 0, 1))
|
||||
with BuildLine() as test:
|
||||
Mirror(edge, wire, about="YZ")
|
||||
self.assertEqual(len(test.edges().filter_by_position(Axis.X, min=0, max=10)), 0)
|
||||
self.assertEqual(
|
||||
len(test.edges().filter_by_position(Axis.X, min=-10, max=0)), 2
|
||||
len(test.edges().filter_by_position(Axis.X, minimum=0, maximum=10)), 0
|
||||
)
|
||||
self.assertEqual(
|
||||
len(test.edges().filter_by_position(Axis.X, minimum=-10, maximum=0)), 2
|
||||
)
|
||||
with BuildLine() as test:
|
||||
Line((1, 0), (2, 0))
|
||||
|
|
@ -297,14 +303,17 @@ class MirrorTests(unittest.TestCase):
|
|||
with BuildSketch() as test:
|
||||
Mirror(edge, wire, face, compound, about="YZ")
|
||||
self.assertEqual(
|
||||
len(test.pending_edges.filter_by_position(Axis.X, min=0, max=10)), 0
|
||||
)
|
||||
self.assertEqual(len(test.faces().filter_by_position(Axis.X, min=0, max=10)), 0)
|
||||
self.assertEqual(
|
||||
len(test.pending_edges.filter_by_position(Axis.X, min=-10, max=0)), 2
|
||||
len(test.pending_edges.filter_by_position(Axis.X, minimum=0, maximum=10)), 0
|
||||
)
|
||||
self.assertEqual(
|
||||
len(test.faces().filter_by_position(Axis.X, min=-10, max=0)), 3
|
||||
len(test.faces().filter_by_position(Axis.X, minimum=0, maximum=10)), 0
|
||||
)
|
||||
self.assertEqual(
|
||||
len(test.pending_edges.filter_by_position(Axis.X, minimum=-10, maximum=0)),
|
||||
2,
|
||||
)
|
||||
self.assertEqual(
|
||||
len(test.faces().filter_by_position(Axis.X, minimum=-10, maximum=0)), 3
|
||||
)
|
||||
|
||||
def test_mirror_part(self):
|
||||
|
|
@ -312,7 +321,7 @@ class MirrorTests(unittest.TestCase):
|
|||
with BuildPart() as test:
|
||||
Mirror(cone, about="YZ")
|
||||
self.assertEqual(
|
||||
len(test.solids().filter_by_position(Axis.X, min=-10, max=0)), 1
|
||||
len(test.solids().filter_by_position(Axis.X, minimum=-10, maximum=0)), 1
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue