File: PlottableBody.cpp

package info (click to toggle)
bornagain 23.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 103,948 kB
  • sloc: cpp: 423,131; python: 40,997; javascript: 11,167; awk: 630; sh: 318; ruby: 173; xml: 130; makefile: 51; ansic: 24
file content (142 lines) | stat: -rw-r--r-- 4,320 bytes parent folder | download
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