Skip to content

Commit

Permalink
Add vector primitives (#18)
Browse files Browse the repository at this point in the history
Co-authored-by: Maxime Rey <87315832+MaxJPRey@users.noreply.github.com>
Co-authored-by: Roberto Pastor Muela <roberto.pastormuela@ansys.com>
  • Loading branch information
3 people committed Aug 31, 2022
1 parent 37c259d commit 1d1cbb0
Show file tree
Hide file tree
Showing 7 changed files with 393 additions and 112 deletions.
5 changes: 2 additions & 3 deletions src/ansys/geometry/core/primitives/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""PyGeometry primitives subpackage."""

from ansys.geometry.core.primitives.direction import Direction2D, Direction3D
from ansys.geometry.core.primitives.point import Point2D, Point3D
from ansys.geometry.core.primitives.vector import UnitVector2D, UnitVector3D, Vector2D, Vector3D

__all__ = ["Direction2D", "Direction3D", "Point2D", "Point3D"]
__all__ = ["Point2D", "Point3D", "UnitVector2D", "UnitVector3D", "Vector2D", "Vector3D"]
103 changes: 0 additions & 103 deletions src/ansys/geometry/core/primitives/direction.py

This file was deleted.

186 changes: 186 additions & 0 deletions src/ansys/geometry/core/primitives/vector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
"""``Vector`` class module"""
import numpy as np


class Vector3D(np.ndarray):
"""A three-dimensional vector with Cartesian coordinates.
Parameters
----------
input : np.ndarray or list
One dimensional numpy.ndarray with shape(3,)
"""

def __new__(cls, input):
"""Constructor for ``Vector3D``"""

Vector3D = np.asarray(input).view(cls)

if len(Vector3D) != 3:
raise ValueError("Vector3D must have three coordinates.")

if not np.issubdtype(Vector3D.dtype, np.number) or not all(
isinstance(data, (int, float)) for data in Vector3D.data
):
raise ValueError("The parameters of 'inputs' should be integer or float.")

return Vector3D

@property
def x(self) -> float:
"""X coordinate of ``Vector3D``"""
return self[0]

@x.setter
def x(self, value) -> None:
if not isinstance(value, (int, float)):
raise ValueError("The parameter 'x' should be a float or an integer value.")
self[0] = value

@property
def y(self) -> float:
"""Y coordinate of ``Vector3D``"""
return self[1]

@y.setter
def y(self, value) -> None:
if not isinstance(value, (int, float)):
raise ValueError("The parameter 'y' should be a float or an integer value.")
self[1] = value

@property
def z(self) -> float:
"""Z coordinate of ``Vector3D``"""
return self[2]

@z.setter
def z(self, value) -> None:
if not isinstance(value, (int, float)):
raise ValueError("The parameter 'z' should be a float or an integer value.")
self[2] = value

@property
def norm(self):
return np.linalg.norm(self)

def normalize(self):
"""Return a normalized version of the ``Vector3D``"""
norm = self.norm
if norm > 0:
return self / norm
else:
raise ValueError("The norm of the Vector3D is not valid.")

def cross(self, v: "Vector3D") -> "Vector3D":
"""Return cross product of Vector3D"""
return Vector3D(np.cross(self, v))

def __eq__(self, other: object) -> bool:
"""Equals operator for ``Vector3D``."""
if not isinstance(other, Vector3D):
raise ValueError(f"Comparison of {self} against {other} is not possible.")

return np.array_equal(self, other)

def __ne__(self, other) -> bool:
"""Not equals operator for ``Vector3D``."""
return not self.__eq__(other)


class Vector2D(np.ndarray):
"""A two-dimensional vector with Cartesian coordinates.
Parameters
----------
input : np.ndarray
One dimensional numpy.ndarray with shape(2,)
"""

def __new__(cls, input):

vector = np.asarray(input).view(cls)

if len(vector) != 2:
raise ValueError("Vector2D must have two coordinates.")

if not np.issubdtype(vector.dtype, np.number) or not all(
isinstance(data, (int, float)) for data in vector.data
):
raise ValueError("The parameters of 'input' should be integer or float.")

return vector

@property
def x(self) -> float:
"""X coordinate of ``Vector2D``"""
return self[0]

@x.setter
def x(self, value) -> None:
if not isinstance(value, (int, float)):
raise ValueError("The parameter 'x' should be a float or an integer value.")
self[0] = value

@property
def y(self) -> float:
"""Y coordinate of ``Vector2D``"""
return self[1]

@y.setter
def y(self, value) -> None:
if not isinstance(value, (int, float)):
raise ValueError("The parameter 'y' should be a float or an integer value.")
self[1] = value

@property
def norm(self):
return np.linalg.norm(self)

def normalize(self):
"""Return a normalized version of the ``Vector2D``"""
norm = self.norm
if norm > 0:
return self / norm
else:
raise ValueError("The norm of the Vector2D is not valid.")

def __eq__(self, other: object) -> bool:
"""Equals operator for ``Vector2D``."""
if not isinstance(other, Vector2D):
raise ValueError(f"Comparison of {self} against {other} is not possible.")

return np.array_equal(self, other)

def __ne__(self, other) -> bool:
"""Not equals operator for ``Vector2D``."""
return not self.__eq__(other)


class UnitVector3D(Vector3D):
"""A three-dimensional ``UnitVector`` class.
Parameters
----------
input : np.ndarray, ``Vector3D``
* One dimensional numpy.ndarray with shape(3,)
* Vector3D
"""

def __new__(cls, input):
obj = Vector3D(input)
return obj.normalize()


class UnitVector2D(Vector2D):
"""A two-dimensional ``UnitVector`` with Cartesian coordinates.
Parameters
----------
input : np.ndarray, Vector2D
* One dimensional numpy.ndarray with shape(2,)
* Vector2D
"""

def __new__(cls, input):
obj = Vector2D(input)
return obj.normalize()
4 changes: 2 additions & 2 deletions src/ansys/geometry/core/sketch/circle.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""``CircleSketch`` class module."""

from ansys.geometry.core.primitives.direction import Direction2D
from ansys.geometry.core.primitives.point import Point3D
from ansys.geometry.core.primitives.vector import UnitVector2D
from ansys.geometry.core.sketch.curve import SketchCurve


Expand All @@ -21,7 +21,7 @@ class CircleSketch(SketchCurve):
Circle radius.
"""

def __init__(self, origin: Point3D, dir_x: Direction2D, dir_y: Direction2D, radius: float):
def __init__(self, origin: Point3D, dir_x: UnitVector2D, dir_y: UnitVector2D, radius: float):
"""Constructor method for ``CircleSketch``."""
self._origin = origin
self._dir_x = dir_x
Expand Down
4 changes: 2 additions & 2 deletions src/ansys/geometry/core/sketch/sketch.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""``Sketch`` class module."""


from ansys.geometry.core.primitives.direction import Direction2D
from ansys.geometry.core.primitives.point import Point3D
from ansys.geometry.core.primitives.vector import UnitVector2D
from ansys.geometry.core.sketch.circle import CircleSketch
from ansys.geometry.core.sketch.line import LineSketch

Expand Down Expand Up @@ -40,7 +40,7 @@ def circle(self, origin: Point3D, radius: float) -> CircleSketch:
CircleSketch object added to the sketch.
"""

circle = CircleSketch(origin, Direction2D(0, 1), Direction2D(0, 1), radius)
circle = CircleSketch(origin, UnitVector2D([0, 1]), UnitVector2D([0, 1]), radius)

self._sketch_curves.append(circle)

Expand Down
12 changes: 11 additions & 1 deletion tests/test_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@


def test_pkg_version():
assert __version__ == "0.1.dev0"

try:
import importlib.metadata as importlib_metadata
except ModuleNotFoundError: # pragma: no cover
import importlib_metadata

# Read from the pyproject.toml
# major, minor, patch
read_version = importlib_metadata.version("ansys-geometry-core")

assert __version__ == read_version
Loading

0 comments on commit 1d1cbb0

Please sign in to comment.