Last active
October 15, 2022 09:13
-
-
Save bernhard-42/962a3a9dc0a26790fe898d6e990bdccf to your computer and use it in GitHub Desktop.
A PEP8 facade for CadQuery Vector class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
from typing import Union, Sequence, overload | |
import cadquery as cq | |
from OCP.gp import gp, gp_Vec, gp_Pnt, gp_Dir, gp_XYZ | |
class Vector: | |
"""Create a 3-dimensional vector | |
Args: | |
args: a 3D vector, with x-y-z parts. | |
you can either provide: | |
* nothing (in which case the null vector is return) | |
* a gp_Vec | |
* a vector ( in which case it is copied ) | |
* a 3-tuple | |
* a 2-tuple (z assumed to be 0) | |
* three float values: x, y, and z | |
* two float values: x,y | |
Returns: | |
""" | |
@overload | |
def __init__(self, X: float, Y: float, Z: float) -> None: | |
... | |
@overload | |
def __init__(self, X: float, Y: float) -> None: | |
... | |
@overload | |
def __init__(self, v: "Vector") -> None: | |
... | |
@overload | |
def __init__(self, v: Sequence[float]) -> None: | |
... | |
@overload | |
def __init__(self, v: Union[gp_Vec, gp_Pnt, gp_Dir, gp_XYZ]) -> None: | |
... | |
@overload | |
def __init__(self) -> None: | |
... | |
# ADDITIONAL | |
@overload | |
def __init__(self, v: cq.Vector) -> None: # cq.Vector => Vector | |
... | |
def __init__(self, *args): | |
# ADDITIONAL | |
if len(args) == 1 and isinstance(args[0], cq.Vector): # cq.Vector => Vector | |
v = args[0] | |
self._vector = cq.Vector(v.x, v.y, v.z) | |
else: | |
self._vector = cq.Vector(*args) | |
@property | |
def X(self) -> float: | |
return self._vector.x | |
@X.setter | |
def X(self, value: float) -> None: | |
self._compound = value | |
@property | |
def Y(self) -> float: | |
return self._vector.y | |
@Y.setter | |
def Y(self, value: float) -> None: | |
self._vector.y = value | |
@property | |
def Z(self) -> float: | |
return self._vector.z | |
@Z.setter | |
def Z(self, value: float) -> None: | |
self._vector.z = value | |
@property | |
def length(self) -> float: | |
return self._vector.length | |
@property | |
def wrapped(self) -> gp_Vec: | |
return self._vector._wrapped | |
def to_tuple(self) -> tuple[float, float, float]: | |
return self._vector.toTuple() | |
def cross(self, v: "Vector") -> "Vector": | |
return Vector(self._vector.cross(v._vector)) | |
def dot(self, v: "Vector") -> float: | |
return self._vector.dot(v._vector) | |
def sub(self, v: "Vector") -> "Vector": | |
return Vector(self._vector.sub(v._vector)) | |
def __sub__(self, v: "Vector") -> "Vector": | |
return Vector(self._vector.__sub__(v._vector)) | |
def add(self, v: "Vector") -> "Vector": | |
return Vector(self._vector.add(v._vector)) | |
def __add__(self, v: "Vector") -> "Vector": | |
return self._vector.__add__(v._vector) | |
def multiply(self, scale: float) -> "Vector": | |
return Vector(self._vector.multiply(scale)) | |
def __mul__(self, scale: float) -> "Vector": | |
return Vector(self._vector.__mul__(scale)) | |
def __truediv__(self, denom: float) -> "Vector": | |
return Vector(self._vector.__truediv__(denom)) | |
def __rmul__(self, scale: float) -> "Vector": | |
return Verctor(self._vector.__rmul__(scale)) | |
def normalized(self) -> "Vector": | |
return Vector(self._vector.normalized()) | |
def center(self) -> "Vector": | |
return self | |
def get_angle(self, v: "Vector") -> float: | |
return self._vector.getAngle(v._vector) | |
def get_signed_angle(self, v: "Vector", normal: "Vector" = None) -> float: | |
"""Signed Angle Between Vectors | |
Return the signed angle in RADIANS between two vectors with the given normal | |
based on this math: angle = atan2((Va × Vb) ⋅ Vn, Va ⋅ Vb) | |
Args: | |
v: Second Vector | |
normal: Vector | |
v: Vector: | |
normal: Vector: (Default value = None) | |
Returns: | |
Angle between vectors | |
""" | |
return self._vector.get_signed_angle(v._vector, normal._vector) | |
def distance_to_line(self): | |
return self._vector.distanceToLine() | |
def project_to_line(self, line: "Vector") -> "Vector": | |
"""Returns a new vector equal to the projection of this Vector onto the line | |
represented by Vector <line> | |
Args: | |
args: Vector | |
Returns the projected vector. | |
line: Vector: | |
Returns: | |
""" | |
return Vector(self._vector(line._vector)) | |
def distance_to_plane(self): | |
return self._vector.distanceToPlane() | |
def project_to_plane(self, plane: cq.Plane) -> "Vector": # to be changed when Matrix is available | |
"""Vector is projected onto the plane provided as input. | |
Args: | |
args: Plane object | |
Returns the projected vector. | |
plane: Plane: | |
Returns: | |
""" | |
return Vector(self._vector.projectToLine(plane)) | |
def __neg__(self) -> "Vector": | |
return Vector(self._vector.__neg__()) | |
def __abs__(self) -> float: | |
return self._vector.__abs__() | |
def __repr__(self) -> str: | |
return "Vector: " + str((self.X, self.Y, self.Z)) | |
def __str__(self) -> str: | |
return "Vector: " + str((self.X, self.Y, self.Z)) | |
def __eq__(self, other: "Vector") -> bool: # type: ignore[override] | |
return self._vector == other._vector | |
def to_pnt(self) -> gp_Pnt: | |
return self._vector.toPnt() | |
def to_dir(self) -> gp_Dir: | |
return self._vector.toDir() | |
def transform(self, t: cq.Matrix) -> "Vector": # to be changed when Matrix is available | |
return Vector(self._vector.transform(t)) | |
def rotate_x(self, angle: float) -> "Vector": | |
"""Rotate Vector about X-Axis | |
Args: | |
angle: Angle in degrees | |
angle: float: | |
Returns: | |
: Rotated Vector | |
""" | |
return Vector(gp_Vec(self.X, self.Y, self.Z).Rotated(gp.OX_s(), math.pi * angle / 180)) | |
def rotate_y(self, angle: float) -> "Vector": | |
"""Rotate Vector about Y-Axis | |
Args: | |
angle: Angle in degrees | |
angle: float: | |
Returns: | |
: Rotated Vector | |
""" | |
return Vector(gp_Vec(self.X, self.Y, self.Z).Rotated(gp.OY_s(), math.pi * angle / 180)) | |
def rotate_z(self, angle: float) -> "Vector": | |
"""Rotate Vector about Z-Axis | |
Args: | |
angle: Angle in degrees | |
angle: float: | |
Returns: | |
: Rotated Vector | |
""" | |
return Vector(gp_Vec(self.X, self.Y, self.Z).Rotated(gp.OZ_s(), math.pi * angle / 180)) | |
if __name__ == "__main__": | |
v1 = Vector(1, 2, 3) | |
v2 = Vector(3, 2, 1) | |
v3 = Vector(1, 2, 3) | |
print(v1) | |
print(v1.to_tuple()) | |
print(v1 * 3) | |
print(v1 + v2) | |
print(v1.cross(v2)) | |
print(v1.dot(v2)) | |
print(v1 == v2) | |
print(v1 == v1) | |
print(v1 == v3) | |
print(v1.to_dir()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment