Skip to content

REFACTOR: Refactored quaternion implementation #6151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
May 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2f41793
First implementation of the new class Quaternions
Alberto-DM May 7, 2025
e776c10
implemented Quaternion division
Alberto-DM May 7, 2025
8f408dd
completed Quaternion class implementation
Alberto-DM May 8, 2025
60dee31
added _is_valid_rotation_sequence and inverse_rotate_vector
Alberto-DM May 8, 2025
f2b9f91
added from_rotation_matrix, to_rotation_matrix, rotation_matrix_to_ax…
Alberto-DM May 9, 2025
79aec95
updated docstring
Alberto-DM May 9, 2025
7428197
removed the old quaternions and changed the unit tests.
Alberto-DM May 9, 2025
3127bcf
added __eq__ to Quaternion
Alberto-DM May 12, 2025
7542bf9
commented old operation and tests
Alberto-DM May 12, 2025
c7588bf
added unit tests for Quaternion and MathUtils
Alberto-DM May 12, 2025
4896287
added GeometryOperators is_vector_equal and unitest
Alberto-DM May 12, 2025
3e43aa2
changed MathUtils.EPSILON
Alberto-DM May 12, 2025
d17a66d
fixed 3DModeler unittests
Alberto-DM May 12, 2025
061729a
bug fixes
Alberto-DM May 13, 2025
334fb79
fixed unit tests
Alberto-DM May 13, 2025
2b9035e
removed version 2 of the methods
Alberto-DM May 13, 2025
7e6303d
added test_bug_6037
Alberto-DM May 13, 2025
7cf6e5e
added pyaedt_function_handler
Alberto-DM May 13, 2025
89b8002
run pre-commit
Alberto-DM May 13, 2025
72381db
removed commented code
Alberto-DM May 13, 2025
361b00b
chore: adding changelog file 6151.miscellaneous.md [dependabot-skip]
pyansys-ci-bot May 13, 2025
b687951
chore: adding changelog file 6151.miscellaneous.md [dependabot-skip]
pyansys-ci-bot May 13, 2025
e9e638b
moved test_pointing_to_axis
Alberto-DM May 13, 2025
285ad39
Merge remote-tracking branch 'origin/Fix_coordinate_system_mode_chang…
Alberto-DM May 13, 2025
c9fe3c8
Merge branch 'main' into Fix_coordinate_system_mode_change
Alberto-DM May 13, 2025
6d86a9c
Merge branch 'main' into Fix_coordinate_system_mode_change
Alberto-DM May 14, 2025
bdd6019
added documentation
Alberto-DM May 14, 2025
3338752
DOCS: Update section title to fix vale
SMoraisAnsys May 15, 2025
d1bb587
Merge branch 'main' into Fix_coordinate_system_mode_change
Alberto-DM May 15, 2025
61f1d99
fixed documentation
Alberto-DM May 15, 2025
79b4212
increase test coverage
Alberto-DM May 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/changelog.d/6151.miscellaneous.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactored quaternion implementation
32 changes: 32 additions & 0 deletions doc/source/API/generic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,35 @@ The following methods allows to read and parse files.
read_configuration_file
write_configuration_file
compute_fft


Quaternion
~~~~~~~~~~

PyAEDT contains an implementation of fundamental quaternion operations.

Quaternions are only used to represent rotations in 3D space. They are not used to represent translations or other transformations.
Only methods related to rotations are implemented.

.. currentmodule:: ansys.aedt.core.generic.quaternion

.. autosummary::
:toctree: _autosummary
:nosignatures:

Quaternion


Math utils
~~~~~~~~~~

MathUtils is a class that provides mathematical utility methods like numerical comparisons and checks.

.. currentmodule:: ansys.aedt.core.generic.math_utils

.. autosummary::
:toctree: _autosummary
:nosignatures:

MathUtils

162 changes: 162 additions & 0 deletions src/ansys/aedt/core/generic/math_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2021 - 2025 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import math
from sys import float_info

from ansys.aedt.core.generic.general_methods import pyaedt_function_handler


class MathUtils:
"""MathUtils is a utility class that provides methods for numerical comparisons and checks."""

EPSILON = float_info.epsilon * 10.0

@staticmethod
@pyaedt_function_handler()
def is_zero(x: float, eps: float = EPSILON) -> bool:
"""Check if a number is close to zero within a small epsilon tolerance.

Parameters:
x: float
Number to check.
eps : float
Tolerance for the comparison. Default is ``EPSILON``.

Returns:
bool
``True`` if the number is numerically zero, ``False`` otherwise.

"""
return abs(x) < eps

@staticmethod
@pyaedt_function_handler()
def is_close(a: float, b: float, relative_tolerance: float = 1e-9, absolute_tolerance: float = 0.0) -> bool:
"""Whether two numbers are close to each other given relative and absolute tolerances.

Parameters
----------
a : float, int
First number to compare.
b : float, int
Second number to compare.
relative_tolerance : float
Relative tolerance. The default value is ``1e-9``.
absolute_tolerance : float
Absolute tolerance. The default value is ``0.0``.

Returns
-------
bool
``True`` if the two numbers are closed, ``False`` otherwise.
"""
return abs(a - b) <= max(relative_tolerance * max(abs(a), abs(b)), absolute_tolerance)

@staticmethod
@pyaedt_function_handler()
def is_equal(a: float, b: float, eps: float = EPSILON) -> bool:
"""
Return True if numbers a and b are equal within a small epsilon tolerance.

Parameters:
a: float
First number.
b: float
Second number.
eps : float
Tolerance for the comparison. Default is ``EPSILON``.

Returns:
bool
``True`` if the absolute difference between a and b is less than epsilon, ``False`` otherwise.
"""
return abs(a - b) < eps

@staticmethod
@pyaedt_function_handler()
def atan2(y: float, x: float) -> float:
"""Implementation of atan2 that does not suffer from the following issues:
math.atan2(0.0, 0.0) = 0.0
math.atan2(-0.0, 0.0) = -0.0
math.atan2(0.0, -0.0) = 3.141592653589793
math.atan2(-0.0, -0.0) = -3.141592653589793
and returns always 0.0.

Parameters
----------
y : float
Y-axis value for atan2.

x : float
X-axis value for atan2.

Returns
-------
float

"""
if abs(y) < MathUtils.EPSILON:
y = 0.0
if abs(x) < MathUtils.EPSILON:
x = 0.0
return math.atan2(y, x)

@staticmethod
@pyaedt_function_handler()
def is_scalar_number(x):
"""Check if a value is a scalar number (int or float).

Parameters
----------
x : object
Value to check.

Returns
-------
bool
``True`` if x is a scalar number, ``False`` otherwise.
"""
return isinstance(x, (int, float))

@staticmethod
@pyaedt_function_handler()
def fix_negative_zero(value):
"""Fix the negative zero.
It supports lists (and nested lists).

Parameters
----------
value : float, List
Value to be fixed.

Returns
-------
float, List
Fixed value.

"""
if isinstance(value, list):
return [MathUtils.fix_negative_zero(item) for item in value]
return 0.0 if value == 0.0 and math.copysign(1.0, value) == -1.0 else value
Loading