File: object.cpp

package info (click to toggle)
bornagain 1.18.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 118,800 kB
  • sloc: cpp: 469,684; python: 38,920; xml: 805; awk: 630; sh: 286; ansic: 37; makefile: 25
file content (150 lines) | stat: -rw-r--r-- 4,237 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
143
144
145
146
147
148
149
150
// ************************************************************************** //
//
//  BornAgain: simulate and fit scattering at grazing incidence
//
//! @file      GUI/ba3d/model/object.cpp
//! @brief     Implements Object class
//!
//! @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 "GUI/ba3d/model/geometry.h"
#include "GUI/ba3d/model/model.h"
#include "GUI/ba3d/view/canvas.h"
#include <cmath>

namespace
{
QQuaternion EulerToQuaternion(const RealSpace::Vector3D& euler);

RealSpace::Vector3D QuaternionToEuler(const QQuaternion& q);
} // namespace

namespace RealSpace
{

#ifdef Q_OS_LINUX
QColor const clrObject = Qt::lightGray;
#else
QColor const clrObject = Qt::black;
#endif

Object::Object(GeometricID::Key gky_) : color(clrObject), isNull(false), model(nullptr), gky(gky_)
{
}

Object::~Object()
{
    releaseGeometry();
    if (model)
        model->rem(this);
}

void Object::transform(float scale, Vector3D rotate, Vector3D translate)
{
    transform(Vector3D(scale, scale, scale), rotate, translate);
}

void Object::transform(Vector3D scale, Vector3D rotate, Vector3D translate)
{
    mat.setToIdentity();
    mat.translate(translate);
    mat.rotate(EulerToQuaternion(rotate));
    mat.scale(scale);
}

void Object::transform(Vector3D turn, Vector3D scale, Vector3D rotate, Vector3D 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
    mat.setToIdentity();
    mat.translate(translate);
    mat.rotate(EulerToQuaternion(rotate));
    mat.scale(scale);
    mat.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 Object::addExtrinsicRotation(Vector3D turn, Vector3D scale, Vector3D& rotate,
                                  Vector3D rotateExtrinsic, Vector3D& translate)
{
    mat.setToIdentity();
    mat.rotate(EulerToQuaternion(rotateExtrinsic));
    mat.translate(translate);
    mat.rotate(EulerToQuaternion(rotate));
    mat.scale(scale);
    mat.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 Object::releaseGeometry()
{
    geo.reset();
}

void Object::draw(Canvas& canvas)
{
    if (isNull)
        return;

    if (!geo)
        geo = geometryStore().getGeometry(gky);
    canvas.draw(color, mat, *geo);
}

} // namespace RealSpace

namespace
{
QQuaternion EulerToQuaternion(const RealSpace::Vector3D& euler)
{
    float cpsi2 = std::cos(euler.x / 2.0f);
    float spsi2 = std::sin(euler.x / 2.0f);
    float cth2 = std::cos(euler.y / 2.0f);
    float sth2 = std::sin(euler.y / 2.0f);
    float cphi2 = std::cos(euler.z / 2.0f);
    float sphi2 = std::sin(euler.z / 2.0f);
    auto a = cphi2 * cth2 * cpsi2 - sphi2 * cth2 * spsi2;
    auto b = cphi2 * cpsi2 * sth2 + sphi2 * sth2 * spsi2;
    auto c = cphi2 * sth2 * spsi2 - sphi2 * cpsi2 * sth2;
    auto d = cphi2 * cth2 * spsi2 + cth2 * cpsi2 * sphi2;
    return QQuaternion{a, b, c, d};
}

RealSpace::Vector3D QuaternionToEuler(const QQuaternion& q)
{
    auto qvec = q.toVector4D();

    float a = qvec.w(); // scalar part of quaternion
    float b = qvec.x();
    float c = qvec.y();
    float d = qvec.z();

    float term1 = std::atan(d / a);
    float term2 = 0;

    if (b == 0)
        term2 = static_cast<float>(M_PI_2);
    else
        term2 = std::atan(c / b);

    float x = term1 + term2;
    float y = 2 * std::atan(std::sqrt((b * b + c * c) / (a * a + d * d)));
    float z = term1 - term2;

    return RealSpace::Vector3D(x, y, z);
}
} // namespace