1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file Img3D/Model/PlottableBody.cpp
//! @brief Implements class PlottableBody.
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#include "Img3D/Model/PlottableBody.h"
#include "Img3D/Model/Geometry.h"
#include "Img3D/Model/GeometryStore.h"
#include <numbers>
using std::numbers::pi;
namespace {
QQuaternion EulerToQuaternion(const Img3D::F3& euler)
{
const float cpsi2 = std::cos(euler.x() / 2.0f);
const float spsi2 = std::sin(euler.x() / 2.0f);
const float cth2 = std::cos(euler.y() / 2.0f);
const float sth2 = std::sin(euler.y() / 2.0f);
const float cphi2 = std::cos(euler.z() / 2.0f);
const float sphi2 = std::sin(euler.z() / 2.0f);
const float a = cphi2 * cth2 * cpsi2 - sphi2 * cth2 * spsi2;
const float b = cphi2 * cpsi2 * sth2 + sphi2 * sth2 * spsi2;
const float c = cphi2 * sth2 * spsi2 - sphi2 * cpsi2 * sth2;
const float d = cphi2 * cth2 * spsi2 + cth2 * cpsi2 * sphi2;
return QQuaternion{a, b, c, d};
}
Img3D::F3 QuaternionToEuler(const QQuaternion& q)
{
auto qvec = q.toVector4D();
const float a = qvec.w(); // scalar part of quaternion
const float b = qvec.x();
const float c = qvec.y();
const float d = qvec.z();
const float term1 = std::atan(d / a);
const float term2 = b == 0 ? static_cast<float>((pi / 2)) : std::atan(c / b);
const float x = term1 + term2;
const float y = 2 * std::atan(std::sqrt((b * b + c * c) / (a * a + d * d)));
const float z = term1 - term2;
return {x, y, z};
}
} // namespace
namespace Img3D {
#ifdef Q_OS_LINUX
QColor const clrObject = Qt::lightGray;
#else
QColor const clrObject = Qt::black;
#endif
PlottableBody::PlottableBody(GeometricID::Key gky_, const double2d_t* top, const double2d_t* bottom,
bool drawBottom)
: isNull(false)
, m_color(clrObject)
, gky(gky_)
{
if (top || bottom)
m_geo = std::make_shared<Geometry>(gky, top, bottom, drawBottom);
}
PlottableBody::~PlottableBody()
{
releaseGeometry();
}
bool PlottableBody::isTransparent() const
{
return color().alpha() < 255;
}
void PlottableBody::transform(F3 scale, F3 rotate, F3 translate)
{
m_matrix.setToIdentity();
m_matrix.translate(translate);
m_matrix.rotate(EulerToQuaternion(rotate));
m_matrix.scale(scale);
}
void PlottableBody::transform(F3 turn, F3 scale, F3 rotate, F3 translate)
{
// 1. turn to align with x/y/z as needed
// 2. scale to desired x/y/z size
// 3. rotate as needed by the scene
// 4. move to the position
m_matrix.setToIdentity();
m_matrix.translate(translate);
m_matrix.rotate(EulerToQuaternion(rotate));
m_matrix.scale(scale);
m_matrix.rotate(EulerToQuaternion(turn));
}
// This method allows the addition of an extrinsic global rotation to an object i.e.
// it rotates the object about the global origin of the coordinate system
void PlottableBody::addExtrinsicRotation(F3 turn, F3 scale, F3& rotate, F3 rotateExtrinsic,
F3& translate)
{
m_matrix.setToIdentity();
m_matrix.rotate(EulerToQuaternion(rotateExtrinsic));
m_matrix.translate(translate);
m_matrix.rotate(EulerToQuaternion(rotate));
m_matrix.scale(scale);
m_matrix.rotate(EulerToQuaternion(turn));
// first apply the particle's intrinsic and then extrinsic rotations
QQuaternion q = EulerToQuaternion(rotateExtrinsic) * EulerToQuaternion(rotate);
rotate = QuaternionToEuler(q);
// translate the object to the extrinsically rotated translation vector
translate = EulerToQuaternion(rotateExtrinsic).rotatedVector(translate);
}
void PlottableBody::releaseGeometry()
{
m_geo.reset();
}
const Geometry& PlottableBody::geo() const
{
if (!m_geo)
m_geo = geometryStore().getGeometry(gky);
return *m_geo;
}
} // namespace Img3D
|