Mantid
Loading...
Searching...
No Matches
MantidGLWidget.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//-----------------------------------------
8// Includes
9//-----------------------------------------
12
13#include <QMessageBox>
14#include <QtOpenGL>
15
16#include <cfloat>
17#include <utility>
18
19using namespace MantidQt::CustomDialogs;
20
21//---------------------------------------
22// Public member functions
23//---------------------------------------
28 : QGLWidget(QGLFormat(QGL::DepthBuffer | QGL::NoAlphaChannel | QGL::SampleBuffers), parent),
29 m_display_object(std::shared_ptr<Mantid::Geometry::CSGObject>()), m_x_rot(0.0), m_y_rot(0.0), m_z_rot(0.0),
30 m_scale_factor(1.0) {
31 setAutoFillBackground(false);
32 m_bb_widths[0] = 0.0;
33 m_bb_widths[1] = 0.0;
34 m_bb_widths[2] = 0.0;
35
36 m_bb_centres[0] = 0.0;
37 m_bb_centres[1] = 0.0;
38 m_bb_centres[2] = 0.0;
39}
40
45
50void MantidGLWidget::setDisplayObject(std::shared_ptr<Mantid::Geometry::IObject> object) {
51 m_display_object = std::move(object);
52 m_x_rot = 0.0;
53 m_y_rot = 0.0;
54 m_z_rot = 0.0;
55
56 auto boundingBox = m_display_object->getBoundingBox();
57 double bbox[6] = {boundingBox.xMax(), boundingBox.yMax(), boundingBox.zMax(),
58 boundingBox.xMin(), boundingBox.yMin(), boundingBox.zMin()};
59
60 // Calculate the widths and save for resize events
61 for (int i = 0; i < 3; ++i) {
62
63 m_bb_widths[i] = 1.1 * (bbox[i] - bbox[i + 3]);
64 if (m_bb_widths[i] < 0.0)
65 m_bb_widths[i] *= -1.0;
66 if (std::fabs(bbox[i]) < 1e10 && std::fabs(bbox[i + 3]) < 1e10) {
67 m_bb_centres[i] = (bbox[i] + bbox[i + 3]) / 2.0;
68 } else {
69 m_bb_centres[i] = 0.0;
70 }
71 if (m_bb_centres[i] < 0.0)
72 m_bb_centres[i] *= -1.0;
73 }
74
75 GLdouble aspect_ratio((GLdouble)this->width() / (GLdouble)this->height());
76 setOrthoProjectionMatrix(aspect_ratio);
77
78 updateGL();
79}
80
81//---------------------------------------
82// Protected member functions
83//---------------------------------------
88 // Without this the initial display draws random rubbish from the graphics
89 // memory
90 glClearColor(0.0, 0.0, 0.0, 0.0);
91 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
92
93 setCursor(Qt::PointingHandCursor); // This is to set the initial window mouse
94 // cursor to Hand icon
95 glEnable(GL_DEPTH_TEST); // Enable opengl depth test to render 3D object properly
96 glShadeModel(GL_SMOOTH); // Shade model is smooth (expensive but looks pleasing)
97 glEnable(GL_LINE_SMOOTH); // Set line should be drawn smoothly
98
99 // glEnable(GL_NORMALIZE);
100
101 glEnable(GL_LIGHTING); // Enable light
102 glEnable(GL_LIGHT0); // Enable opengl first light
103 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,
104 GL_TRUE); // This model lits both sides of the triangle
105 // Set Light0 Attributes, Ambient, diffuse,specular and position
106 // Its a directional light which follows camera position
107 GLfloat lamp_ambient[4] = {0.40f, 0.0f, 1.0f, 0.0f};
108 GLfloat lamp_diffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
109 GLfloat lamp_specular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
110
111 glLightfv(GL_LIGHT0, GL_AMBIENT, lamp_ambient);
112 glLightfv(GL_LIGHT0, GL_DIFFUSE, lamp_diffuse);
113 glLightfv(GL_LIGHT0, GL_SPECULAR, lamp_specular);
114 GLfloat lamp_pos[4] = {0.0f, 0.0f, 1.0f, 0.0};
115 glLightfv(GL_LIGHT0, GL_POSITION, lamp_pos);
116}
117
122 // Nothing to draw
123 if (m_display_object == std::shared_ptr<Mantid::Geometry::CSGObject>())
124 return;
125 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
126
127 glMatrixMode(GL_MODELVIEW);
128 glLoadIdentity();
129 glPushMatrix();
130
131 // The factor of 16 is due to Qt using angles that are in
132 // 1/16ths of a degree
133 glRotated(m_x_rot / 16.0, 1.0, 0.0, 0.0);
134 glRotated(m_y_rot / 16.0, 0.0, 1.0, 0.0);
135 glRotated(m_z_rot / 16.0, 0.0, 0.0, 1.0);
136
137 try {
138 m_display_object->draw();
139 } catch (...) {
140 QMessageBox::information(this, "MantidGLWidget",
141 QString("An error occurred while attempting to render the shape.\n") +
142 "Please check that all objects intersect each other.");
143 }
144 glPopMatrix();
145}
146
152void MantidGLWidget::resizeGL(int width, int height) {
153 glViewport(0, 0, (GLsizei)width, (GLsizei)height);
154 if (height == 0)
155 height = 1;
156
157 GLdouble aspect_ratio = (GLdouble)width / (GLdouble)height;
158 setOrthoProjectionMatrix(aspect_ratio);
159}
160
165void MantidGLWidget::mousePressEvent(QMouseEvent *event) { m_click_point = event->pos(); }
166
171void MantidGLWidget::mouseMoveEvent(QMouseEvent *event) {
172 int dx = event->x() - m_click_point.x();
173 int dy = event->y() - m_click_point.y();
174 // Points in Qt only have integer precision
175 int x_rot = static_cast<int>(m_x_rot);
176
177 if (event->buttons() & Qt::LeftButton) {
178 setXRotation(x_rot + 8 * dy);
179 setYRotation(static_cast<int>(m_y_rot) + 8 * dx);
180 } else if (event->buttons() & Qt::RightButton) {
181 setXRotation(x_rot + 8 * dy);
182 setZRotation(static_cast<int>(m_z_rot) + 8 * dx);
183 }
184 m_click_point = event->pos();
185}
186
192 normalizeAngle(&angle);
193 if (angle != m_x_rot) {
194 m_x_rot = angle;
195 updateGL();
196 }
197}
198
204 normalizeAngle(&angle);
205 if (angle != m_y_rot) {
206 m_y_rot = angle;
207 updateGL();
208 }
209}
210
216 normalizeAngle(&angle);
217 if (angle != m_z_rot) {
218 m_z_rot = angle;
219 updateGL();
220 }
221}
222
223void MantidGLWidget::setOrthoProjectionMatrix(GLdouble aspect_ratio) {
224 GLdouble left = -m_bb_widths[0] / 2.0;
225 GLdouble right = m_bb_widths[0] / 2.0;
226 GLdouble bottom = -m_bb_widths[1] / 2.0;
227 GLdouble top = +m_bb_widths[1] / 2.0;
228
229 // std::cerr << "Projection volume points: " << left << " " << right << " " <<
230 // bottom << " " << top << '\n';
231
232 // width / height ratio in world coordinates must be equal to aspect_ratio
233 auto ratio = m_bb_widths[0] / m_bb_widths[1];
234
235 if (ratio < aspect_ratio) {
236 auto width = m_bb_widths[1] * aspect_ratio;
237 left = -width / 2.0;
238 right = width / 2.0;
239 } else {
240 auto height = m_bb_widths[0] / aspect_ratio;
241 bottom = -height / 2.0;
242 top = height / 2.0;
243 }
244
245 left += m_bb_centres[0];
246 right += m_bb_centres[0];
247 bottom += m_bb_centres[1];
248 top += m_bb_centres[1];
249
250 // std::cerr << "Projection volume points 2: " << left << " " << right << " "
251 // << bottom << " " << top << '\n';
252 // std::cerr << "Aspect ratio: " << aspect_ratio << " == " << (right - left) /
253 // (top - bottom) << '\n';
254
255 // Set the correct projection
256 glMatrixMode(GL_PROJECTION);
257 glLoadIdentity();
258 glOrtho(left, right, bottom, top, -10.0, 10000.0);
259 glMatrixMode(GL_MODELVIEW);
260}
261
268 while (*angle < 0)
269 *angle += 360 * 16;
270 while (*angle > 360 * 16)
271 *angle -= 360 * 16;
272}
double height
Definition: GetAllEi.cpp:155
double bottom
Definition: LineProfile.cpp:79
double top
Definition: LineProfile.cpp:78
double left
Definition: LineProfile.cpp:80
double right
Definition: LineProfile.cpp:81
void setYRotation(int angle)
Set the rotation angle around the Y-axis.
GLdouble m_bb_centres[3]
The centre of the bounding box.
void paintGL() override
Render the scene.
void resizeGL(int width, int height) override
Set up the viewport.
GLdouble m_x_rot
The current X, Y and Z rotations.
QPoint m_click_point
The location of the cursor when the mouse button was clicked.
void initializeGL() override
Initialize the renderer.
void setXRotation(int angle)
Set the rotation angle around the X-axis.
void mouseMoveEvent(QMouseEvent *event) override
Handle a MouseMoveEvent.
void setOrthoProjectionMatrix(GLdouble aspect_ratio)
Calculate and set the orthographic projection matrix.
void setZRotation(int angle)
Set the rotation angle around the Z-axis.
void setDisplayObject(std::shared_ptr< Mantid::Geometry::IObject > object)
Set the Mantid geometry object.
GLdouble m_bb_widths[3]
The separation of the bounding box sides in x,y,z respectively.
void mousePressEvent(QMouseEvent *event) override
Handle a MousePressEvent.
MantidGLWidget(QWidget *parent=nullptr)
Default constructor.
std::shared_ptr< Mantid::Geometry::IObject > m_display_object
A Mantid geometry object.
void normalizeAngle(int *angle)
Ensure the angle is in the range 0 < angle < 360.
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.