Listing the "Blender Foundation" as copyright holder implied the Blender Foundation holds copyright to files which may include work from many developers. While keeping copyright on headers makes sense for isolated libraries, Blender's own code may be refactored or moved between files in a way that makes the per file copyright holders less meaningful. Copyright references to the "Blender Foundation" have been replaced with "Blender Authors", with the exception of `./extern/` since these this contains libraries which are more isolated, any changed to license headers there can be handled on a case-by-case basis. Some directories in `./intern/` have also been excluded: - `./intern/cycles/` it's own `AUTHORS` file is planned. - `./intern/opensubdiv/`. An "AUTHORS" file has been added, using the chromium projects authors file as a template. Design task: #110784 Ref !110783.
157 lines
4.9 KiB
C++
157 lines
4.9 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup bli
|
|
*/
|
|
|
|
#include "BLI_math_base.h"
|
|
#include "BLI_math_matrix.h"
|
|
#include "BLI_math_matrix.hh"
|
|
#include "BLI_math_rotation.h"
|
|
#include "BLI_math_rotation.hh"
|
|
#include "BLI_math_rotation_legacy.hh"
|
|
#include "BLI_math_vector.h"
|
|
#include "BLI_math_vector.hh"
|
|
|
|
namespace blender::math {
|
|
|
|
template EulerXYZ to_euler(const AxisAngle &);
|
|
template EulerXYZ to_euler(const AxisAngleCartesian &);
|
|
template EulerXYZ to_euler(const Quaternion &);
|
|
template Euler3 to_euler(const AxisAngle &, EulerOrder);
|
|
template Euler3 to_euler(const AxisAngleCartesian &, EulerOrder);
|
|
template Euler3 to_euler(const Quaternion &, EulerOrder);
|
|
template Quaternion to_quaternion(const AxisAngle &);
|
|
template Quaternion to_quaternion(const AxisAngleCartesian &);
|
|
template Quaternion to_quaternion(const Euler3 &);
|
|
template Quaternion to_quaternion(const EulerXYZ &);
|
|
template AxisAngleCartesian to_axis_angle(const Euler3 &);
|
|
template AxisAngleCartesian to_axis_angle(const EulerXYZ &);
|
|
template AxisAngleCartesian to_axis_angle(const Quaternion &);
|
|
template AxisAngle to_axis_angle(const Euler3 &);
|
|
template AxisAngle to_axis_angle(const EulerXYZ &);
|
|
template AxisAngle to_axis_angle(const Quaternion &);
|
|
|
|
#if 0 /* Only for reference. */
|
|
void generate_axes_to_quaternion_switch_cases()
|
|
{
|
|
std::cout << "default: *this = identity(); break;" << std::endl;
|
|
/* Go through all 32 cases. Only 23 valid and 1 is identity. */
|
|
for (int i : IndexRange(6)) {
|
|
for (int j : IndexRange(6)) {
|
|
const AxisSigned forward = AxisSigned(i);
|
|
const AxisSigned up = AxisSigned(j);
|
|
/* Filter the 12 invalid cases. Fall inside the default case. */
|
|
if (Axis(forward) == Axis(up)) {
|
|
continue;
|
|
}
|
|
/* Filter the identity case. Fall inside the default case. */
|
|
if (forward == AxisSigned::Y_POS && up == AxisSigned::Z_POS) {
|
|
continue;
|
|
}
|
|
|
|
VecBase<AxisSigned, 3> axes{cross(forward, up), forward, up};
|
|
|
|
float3x3 mat;
|
|
mat.x_axis() = float3(axes.x);
|
|
mat.y_axis() = float3(axes.y);
|
|
mat.z_axis() = float3(axes.z);
|
|
|
|
math::Quaternion q = to_quaternion(mat);
|
|
/* Create a integer value out of the 4 possible component values (+sign). */
|
|
int4 p = int4(round(sign(float4(q)) * min(pow(float4(q), 2.0f), float4(0.75)) * 4.0));
|
|
|
|
auto format_component = [](int value) {
|
|
switch (abs(value)) {
|
|
default:
|
|
case 0:
|
|
return "T(0)";
|
|
case 1:
|
|
return (value > 0) ? "T(0.5)" : "T(-0.5)";
|
|
case 2:
|
|
return (value > 0) ? "T(M_SQRT1_2)" : "T(-M_SQRT1_2)";
|
|
case 3:
|
|
return (value > 0) ? "T(1)" : "T(-1)";
|
|
}
|
|
};
|
|
auto format_axis = [](AxisSigned axis) {
|
|
switch (axis) {
|
|
default:
|
|
case AxisSigned::X_POS:
|
|
return "AxisSigned::X_POS";
|
|
case AxisSigned::Y_POS:
|
|
return "AxisSigned::Y_POS";
|
|
case AxisSigned::Z_POS:
|
|
return "AxisSigned::Z_POS";
|
|
case AxisSigned::X_NEG:
|
|
return "AxisSigned::X_NEG";
|
|
case AxisSigned::Y_NEG:
|
|
return "AxisSigned::Y_NEG";
|
|
case AxisSigned::Z_NEG:
|
|
return "AxisSigned::Z_NEG";
|
|
}
|
|
};
|
|
/* Use same code function as in the switch case. */
|
|
std::cout << "case ";
|
|
std::cout << format_axis(axes.x) << " << 16 | ";
|
|
std::cout << format_axis(axes.y) << " << 8 | ";
|
|
std::cout << format_axis(axes.z);
|
|
std::cout << ": *this = {";
|
|
std::cout << format_component(p.x) << ", ";
|
|
std::cout << format_component(p.y) << ", ";
|
|
std::cout << format_component(p.z) << ", ";
|
|
std::cout << format_component(p.w) << "}; break;";
|
|
std::cout << std::endl;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, const float angle)
|
|
{
|
|
BLI_ASSERT_UNIT_V3(direction);
|
|
BLI_ASSERT_UNIT_V3(axis);
|
|
|
|
const float3 axis_scaled = axis * math::dot(direction, axis);
|
|
const float3 diff = direction - axis_scaled;
|
|
const float3 cross = math::cross(axis, diff);
|
|
|
|
return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
|
|
}
|
|
|
|
float3 rotate_around_axis(const float3 &vector,
|
|
const float3 ¢er,
|
|
const float3 &axis,
|
|
const float angle)
|
|
|
|
{
|
|
float3 result = vector - center;
|
|
float mat[3][3];
|
|
axis_angle_normalized_to_mat3(mat, axis, angle);
|
|
mul_m3_v3(mat, result);
|
|
return result + center;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &stream, EulerOrder order)
|
|
{
|
|
switch (order) {
|
|
default:
|
|
case XYZ:
|
|
return stream << "XYZ";
|
|
case XZY:
|
|
return stream << "XZY";
|
|
case YXZ:
|
|
return stream << "YXZ";
|
|
case YZX:
|
|
return stream << "YZX";
|
|
case ZXY:
|
|
return stream << "ZXY";
|
|
case ZYX:
|
|
return stream << "ZYX";
|
|
}
|
|
}
|
|
|
|
} // namespace blender::math
|