build123d/build123d_common.py
2022-07-11 20:50:36 -04:00

359 lines
10 KiB
Python

"""
OK, fwiw, the reason translate() creates a copy is because the use of copy=True in Shape._apply_transform(): https://github.com/CadQuery/cadquery/blob/c9d3f1e693d8d3b59054c8f10027c46a55342b22/cadquery/occ_impl/shapes.py#L846. I tried setting it to False and my original example passes.
Thanks. Playing around a bit more, it seems like translate() makes the underlying TShapes unequal, but Shape.moved() preserves TShape. This returns true, which could be useful:
x1 = cq.Workplane().box(3,4,5)
x2 = cq.Workplane(x1.findSolid().moved(cq.Location(cq.Vector(1,2,3),cq.Vector(4,5,6),7)))
f1 = x1.faces(">Z").val()
f2 = x2.faces(">Z").val()
f1.wrapped.TShape() == f2.wrapped.TShape() <=== TRUE
@fpq473 - cadquery newbie
Thanks. Playing around a bit more, it seems like translate() makes the underlying TShapes unequal, but Shape.moved() preserves TShape. This returns true, which could be useful: x1 = cq.Workplane().box(3,4,5) x2 = cq.Workplane(x1.findSolid().moved(cq.Location(cq.Vector(1,2,3),cq.Vector(4,5,6),7))) f1 = x1.faces(">Z").val() f2 = x2.faces(">Z").val() f1.wrapped.TShape() == f2.wrapped.TShape() <=== TRUE
"""
from math import radians
from typing import Union
from enum import Enum, auto
from cadquery import (
Edge,
Wire,
Vector,
Shape,
Location,
Compound,
Solid,
)
from cadquery.occ_impl.shapes import VectorLike, Real
from OCP.gp import gp_Vec, gp_Pnt, gp_Ax1, gp_Dir, gp_Trsf
import cq_warehouse.extensions
z_axis = (Vector(0, 0, 0), Vector(0, 0, 1))
#
# Operators
#
def __matmul__custom(e: Union[Edge, Wire], p: float):
return e.positionAt(p)
def __mod__custom(e: Union[Edge, Wire], p: float):
return e.tangentAt(p)
Edge.__matmul__ = __matmul__custom
Edge.__mod__ = __mod__custom
Wire.__matmul__ = __matmul__custom
Wire.__mod__ = __mod__custom
context_stack = []
#
# ENUMs
#
class Select(Enum):
ALL = auto()
LAST = auto()
class Kind(Enum):
ARC = auto()
INTERSECTION = auto()
TANGENT = auto()
class Keep(Enum):
TOP = auto()
BOTTOM = auto()
class FilterBy(Enum):
LAST_OPERATION = auto()
class Mode(Enum):
"""Combination Mode"""
ADDITION = auto()
SUBTRACTION = auto()
INTERSECTION = auto()
CONSTRUCTION = auto()
PRIVATE = auto()
class Transition(Enum):
RIGHT = auto()
ROUND = auto()
TRANSFORMED = auto()
class Font_Style(Enum):
"""Text Font Styles"""
REGULAR = auto()
BOLD = auto()
ITALIC = auto()
class Halign(Enum):
"""Horizontal Alignment"""
CENTER = auto()
LEFT = auto()
RIGHT = auto()
class Valign(Enum):
"""Vertical Alignment"""
CENTER = auto()
TOP = auto()
BOTTOM = auto()
class Until(Enum):
NEXT = auto()
LAST = auto()
class Axis(Enum):
X = auto()
Y = auto()
Z = auto()
class CqObject(Enum):
EDGE = auto()
FACE = auto()
VERTEX = auto()
class BuildAssembly:
def add(self):
pass
class SortBy(Enum):
X = auto()
Y = auto()
Z = auto()
LENGTH = auto()
RADIUS = auto()
AREA = auto()
VOLUME = auto()
DISTANCE = auto()
#
# DirectAPI Classes
#
class Rotation(Location):
def __init__(self, about_x: float = 0, about_y: float = 0, about_z: float = 0):
self.about_x = about_x
self.about_y = about_y
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)
RotationLike = Union[tuple[float, float, float], Rotation]
class ShapeList(list):
axis_map = {
Axis.X: ((1, 0, 0), (-1, 0, 0)),
Axis.Y: ((0, 1, 0), (0, -1, 0)),
Axis.Z: ((0, 0, 1), (0, 0, -1)),
}
def __init_subclass__(cls) -> None:
return super().__init_subclass__()
def filter_by_normal(self, axis: Axis):
result = filter(
lambda o: o.normalAt(o.Center()) == Vector(*ShapeList.axis_map[axis][0])
or o.normalAt(o.Center()) == Vector(*ShapeList.axis_map[axis][1]),
self,
)
if axis == Axis.X:
result = sorted(result, key=lambda obj: obj.Center().x)
elif axis == Axis.Y:
result = sorted(result, key=lambda obj: obj.Center().y)
elif axis == Axis.Z:
result = sorted(result, key=lambda obj: obj.Center().z)
return ShapeList(result)
def filter_by_position(
self,
axis: Axis,
min: float,
max: float,
inclusive: tuple[bool, bool] = (True, True),
):
if axis == Axis.X:
if inclusive == (True, True):
result = filter(lambda o: min <= o.Center().x <= max, self)
elif inclusive == (True, False):
result = filter(lambda o: min <= o.Center().x < max, self)
elif inclusive == (False, True):
result = filter(lambda o: min < o.Center().x <= max, self)
elif inclusive == (False, False):
result = filter(lambda o: min < o.Center().x < max, self)
elif axis == Axis.Y:
if inclusive == (True, True):
result = filter(lambda o: min <= o.Center().y <= max, self)
elif inclusive == (True, False):
result = filter(lambda o: min <= o.Center().y < max, self)
elif inclusive == (False, True):
result = filter(lambda o: min < o.Center().y <= max, self)
elif inclusive == (False, False):
result = filter(lambda o: min < o.Center().y < max, self)
elif axis == Axis.Z:
if inclusive == (True, True):
result = filter(lambda o: min <= o.Center().z <= max, self)
elif inclusive == (True, False):
result = filter(lambda o: min <= o.Center().z < max, self)
elif inclusive == (False, True):
result = filter(lambda o: min < o.Center().z <= max, self)
elif inclusive == (False, False):
result = filter(lambda o: min < o.Center().z < max, self)
return ShapeList(result)
def sort_by(self, sort_by: SortBy = SortBy.Z, reverse: bool = False):
if sort_by == SortBy.X:
obj = sorted(
self,
key=lambda obj: obj.Center().x,
reverse=reverse,
)
elif sort_by == SortBy.Y:
obj = sorted(
self,
key=lambda obj: obj.Center().y,
reverse=reverse,
)
elif sort_by == SortBy.Z:
obj = sorted(
self,
key=lambda obj: obj.Center().z,
reverse=reverse,
)
elif sort_by == SortBy.LENGTH:
obj = sorted(
self,
key=lambda obj: obj.Length(),
reverse=reverse,
)
elif sort_by == SortBy.RADIUS:
obj = sorted(
self,
key=lambda obj: obj.radius(),
reverse=reverse,
)
elif sort_by == SortBy.DISTANCE:
obj = sorted(
self,
key=lambda obj: obj.Center().Length,
reverse=reverse,
)
elif sort_by == SortBy.AREA:
obj = sorted(
self,
key=lambda obj: obj.Area(),
reverse=reverse,
)
elif sort_by == SortBy.VOLUME:
obj = sorted(
self,
key=lambda obj: obj.Volume(),
reverse=reverse,
)
else:
raise ValueError(f"Unable to sort shapes by {sort_by}")
return ShapeList(obj)
class VertexList(list):
def __init_subclass__(cls) -> None:
return super().__init_subclass__()
def filter_by_position(
self,
axis: Axis,
min: float,
max: float,
inclusive: tuple[bool, bool] = (True, True),
):
if axis == Axis.X:
if inclusive == (True, True):
result = filter(lambda v: min <= v.X <= max, self)
elif inclusive == (True, False):
result = filter(lambda v: min <= v.X < max, self)
elif inclusive == (False, True):
result = filter(lambda v: min < v.X <= max, self)
elif inclusive == (False, False):
result = filter(lambda v: min < v.X < max, self)
elif axis == Axis.Y:
if inclusive == (True, True):
result = filter(lambda v: min <= v.Y <= max, self)
elif inclusive == (True, False):
result = filter(lambda v: min <= v.Y < max, self)
elif inclusive == (False, True):
result = filter(lambda v: min < v.Y <= max, self)
elif inclusive == (False, False):
result = filter(lambda v: min < v.Y < max, self)
elif axis == Axis.Z:
if inclusive == (True, True):
result = filter(lambda v: min <= v.Z <= max, self)
elif inclusive == (True, False):
result = filter(lambda v: min <= v.Z < max, self)
elif inclusive == (False, True):
result = filter(lambda v: min < v.Z <= max, self)
elif inclusive == (False, False):
result = filter(lambda v: min < v.Z < max, self)
return VertexList(result)
def sort_by(self, sort_by: SortBy = SortBy.Z, reverse: bool = False):
if sort_by == SortBy.X:
vertices = sorted(
self,
key=lambda obj: obj.X,
reverse=reverse,
)
elif sort_by == SortBy.Y:
vertices = sorted(
self,
key=lambda obj: obj.Y,
reverse=reverse,
)
elif sort_by == SortBy.Z:
vertices = sorted(
self,
key=lambda obj: obj.Z,
reverse=reverse,
)
elif sort_by == SortBy.DISTANCE:
vertices = sorted(
self,
key=lambda obj: obj.toVector().Length,
reverse=reverse,
)
else:
raise ValueError(f"Unable to sort vertices by {sort_by}")
return VertexList(vertices)