Skip to content

Commit 057763e

Browse files
committed
A few functionality changes, docstring changes.
- Removed NotImplemented from __float__ and __int__ methods, as they were used improperly. - Docstring changes for sphinx. - Changed scalar property to return a Quaternion object to match the vector property in functionality. - Changed unit_quaternion method to return the zero quaternion when the norm of self is zero (0). - Changed docstrings of properties so they don't have "Return" in them.
1 parent 12631ef commit 057763e

File tree

1 file changed

+42
-56
lines changed

1 file changed

+42
-56
lines changed

quaternions/quaternions.py

Lines changed: 42 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -104,18 +104,22 @@ def __init__(self, real: float = 0.0, i_component: float = 0.0,
104104
# Make all the components read-only attributes.
105105
@property
106106
def real(self) -> float:
107+
"""The real component of the Quaternion."""
107108
return self._real
108109

109110
@property
110111
def i(self) -> float:
112+
"""The i component of the Quaternion."""
111113
return self._i
112114

113115
@property
114116
def j(self) -> float:
117+
"""The j component of the Quaternion."""
115118
return self._j
116119

117120
@property
118121
def k(self) -> float:
122+
"""The k component of the Quaternion."""
119123
return self._k
120124

121125
### Magic methods. ###
@@ -127,7 +131,7 @@ def __complex__(self) -> complex:
127131
"""
128132
Return complex(self).
129133
130-
If only one of the vector components is nonzero, this returns the
134+
If only one of the vector components is nonzero, return the
131135
quaternion as a complex number.
132136
"""
133137
if self.is_complex():
@@ -139,18 +143,18 @@ def __complex__(self) -> complex:
139143
real, imag = self.real, 0.0
140144
return complex(real, imag)
141145

142-
return NotImplemented
146+
raise ValueError(f"{self.__class__.__qualname__} is not scalar or complex.")
143147

144148
def __float__(self) -> float:
145149
"""
146150
Return float(self).
147151
148-
If the quaternion is scalar, returns the scalar component.
152+
If the quaternion is scalar, return the scalar component.
149153
"""
150154
if self.is_scalar():
151155
return self.real
152156

153-
return NotImplemented
157+
raise ValueError(f"{self.__class__.__qualname__} is not scalar.")
154158

155159
def __hash__(self) -> int:
156160
"""
@@ -172,13 +176,13 @@ def __int__(self) -> int:
172176
"""
173177
Return int(self).
174178
175-
If the quaternion is scalar, this returns the real component as
179+
If the quaternion is scalar, return the real component as
176180
an integer.
177181
"""
178182
if self.is_scalar():
179183
return int(self.real)
180184

181-
return NotImplemented
185+
raise ValueError(f"{self.__class__.__qualname__} is not scalar.")
182186

183187
def __iter__(self) -> Iterator[float]:
184188
"""
@@ -232,7 +236,7 @@ def _sign(x: float) -> str:
232236
def _num_to_str(x: float) -> str:
233237
"""
234238
Return a string of x as an integer if x is a positive or
235-
negative whole number, otherwise returns a float string.
239+
negative whole number, otherwise return a float string.
236240
"""
237241
if x.is_integer():
238242
return str(int(x))
@@ -460,7 +464,7 @@ def __floordiv__(self, other: Quaternion or float or complex) -> Quaternion:
460464
"""
461465
Return self // other.
462466
463-
If other is an int or float, returns the quaternion with each
467+
If other is an int or float, return the quaternion with each
464468
component floor divided by other.
465469
"""
466470
if isinstance(other, (int, float)):
@@ -572,7 +576,7 @@ def get_imag(self) -> float:
572576
"""
573577
Return the imaginary component of the quaternion if only one
574578
of the imaginary components is nonzero. If the quaternion is
575-
scalar, this returns 0.0. Otherwise, returns None.
579+
scalar, return ``0.0``. Otherwise, return ``None``.
576580
"""
577581
if self.is_complex():
578582
for component in (self.i, self.j, self.k):
@@ -586,9 +590,7 @@ def get_imag(self) -> float:
586590
def get_vector_components(self) -> Tuple[float]:
587591
"""
588592
Return the vector components of the Quaternion as a tuple
589-
formatted as
590-
591-
(i, j, k).
593+
formatted as ``(i, j, k)``.
592594
"""
593595
return (self.i, self.j, self.k)
594596

@@ -598,9 +600,7 @@ def inverse(self) -> Quaternion:
598600
599601
Return the inverse of the quaternion. The inverse of a
600602
quaternion is defined as the conjugate divided by the norm
601-
squared:
602-
603-
.. code-block:: python
603+
squared::
604604
605605
q.inverse() = q.conjugate()/(q.norm)**2
606606
@@ -627,16 +627,16 @@ def inverse(self) -> Quaternion:
627627

628628
return q_inverse
629629

630-
def unit_quaternion(self) -> Quaternion or None:
630+
def unit_quaternion(self) -> Quaternion:
631631
"""
632-
Return the quaternion normalized to unity (1).
632+
Return the quaternion normalized to magnitude one (1).
633633
634-
If the quaternion is a zero (0) quaternion, returns None.
634+
If the quaternion is a zero (0) quaternion, return the zero quaternion.
635635
"""
636636
if self.__abs__() != 0.0:
637637
return self.versor
638638

639-
return None
639+
return Quaternion(0)
640640

641641
def unit_vector(self) -> Quaternion:
642642
"""
@@ -654,8 +654,8 @@ def unit_vector(self) -> Quaternion:
654654
#####################
655655
def is_complex(self) -> bool:
656656
"""
657-
Return True if only one of the i, j, and k components is
658-
nonzero. Otherwise, returns False.
657+
Return ``True`` if only one of the *i*, *j*, and *k* components is
658+
nonzero. Otherwise, return ``False``.
659659
"""
660660
if (self.i, self.j, self.k) != (0.0, 0.0, 0.0):
661661
if (0.0, 0.0) in (
@@ -666,8 +666,8 @@ def is_complex(self) -> bool:
666666

667667
def is_scalar(self) -> bool:
668668
"""
669-
Return True if the vector components all equal zero.
670-
Otherwise, returns False.
669+
Return ``True`` if the vector components all equal zero.
670+
Otherwise, return ``False``.
671671
"""
672672
if (self.i, self.j, self.k) == (0.0, 0.0, 0.0):
673673
return True
@@ -676,8 +676,8 @@ def is_scalar(self) -> bool:
676676

677677
def is_vector(self) -> bool:
678678
"""
679-
Return True if the scalar part is zero and at least one of
680-
the vector components is nonzero. Otherwise, returns False.
679+
Return ``True`` if the scalar part is zero and at least one of
680+
the vector components is nonzero. Otherwise, return ``False``.
681681
"""
682682
if self.real == 0.0 and (
683683
self.i != 0.0 or self.j != 0.0 or self.k != 0.0):
@@ -689,60 +689,49 @@ def is_vector(self) -> bool:
689689
################
690690
@property
691691
def angle(self) -> float:
692-
"""
693-
Return the angle of the quaternion in radians.
694-
695-
Quaternions can be expressed as
696-
697-
``norm*(cos(theta) + u*sin(theta))``
698-
699-
where u is a 3D unit vector. This returns the angle theta from
700-
this expression. Can also be called with ``Quaternion.angle_in_radians``.
701-
"""
692+
"""The angle of the quaternion in radians."""
702693
return _atan2(self.vector.__abs__(), self.real)
703694

704695
@property
705696
def angle_in_degrees(self) -> float:
706-
"""Return the angle of the quaternion in degrees."""
697+
"""The angle of the quaternion in degrees."""
707698
return self.angle * 180 / _pi
708699

709700
angle_in_radians = angle
710701

711702
@property
712703
def components(self) -> Tuple[float]:
713704
"""
714-
Return the components of the quaternion as a tuple in the order
715-
`real, i, j, k`.
705+
The components of the quaternion as a tuple in the order
706+
``(real, i, j, k)``.
716707
"""
717708
return (self.real, self.i, self.j, self.k)
718709

719710
@property
720711
def norm(self) -> float:
721-
"""Return the norm (magnitude) of the quaternion. Same as using the abs() function."""
712+
"""
713+
The norm (magnitude) of the quaternion.
714+
"""
722715
return self.__abs__()
723716

724717
@property
725-
def scalar(self) -> float:
726-
"""Return the real part of the quaternion."""
727-
return self.real
718+
def scalar(self) -> Quaternion:
719+
"""The real part of the quaternion."""
720+
return Quaternion(self.real, 0, 0, 0)
728721

729722
@property
730723
def vector(self) -> Quaternion:
731-
"""Return the vector part of the quaternion."""
724+
"""The vector part of the quaternion."""
732725
return Quaternion(0, self.i, self.j, self.k)
733726

734727
@property
735728
def vector_norm(self) -> float:
736-
"""Return the norm of the vector part of the quaternion."""
729+
"""The norm of the vector part of the quaternion."""
737730
return self.vector.__abs__()
738731

739732
@property
740733
def versor(self) -> Quaternion:
741-
"""
742-
Return the quaternion normalized to a magnitude of one (1). The rounds
743-
parameter determines the maximum number of times the quaternion is
744-
divided by its norm to get a versor with norm one (1).
745-
"""
734+
"""The quaternion normalized to a magnitude of one (1)."""
746735
versor = self
747736
for _ in range(10): # Prevents an infinite loop.
748737
# Doesn't always divide to norm 1 on the first division.
@@ -760,14 +749,11 @@ def from_angle(
760749
"""
761750
Return a quaternion from an angle and vector.
762751
763-
Quaternions can be expressed as
764-
765-
norm*(cos(theta) + u*sin(theta)),
766-
767-
where u is a 3D unit vector. This function takes an angle and a vector to
752+
Quaternions can be expressed as ``norm*(cos(theta) + u*sin(theta))``,
753+
where ``u`` is a 3D unit vector. This function takes an angle and a vector to
768754
create a quaternion. If you want a quaternion with a different norm than
769-
one (1), you can change the 'norm' argument. By default, angles are entered
770-
in degrees. If you want to enter an angle in radians, set 'degrees' to
755+
one (1), you can change the ``norm`` argument. By default, angles are entered
756+
in degrees. If you want to enter an angle in radians, set ``degrees`` to
771757
False.
772758
"""
773759
if degrees:

0 commit comments

Comments
 (0)