ProjectionSurface.h 14.8 KB
Newer Older
1
2
3
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4
5
//   NScD Oak Ridge National Laboratory, European Spallation Source,
//   Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6
// SPDX - License - Identifier: GPL - 3.0 +
7
#pragma once
8
9

#include "MantidGeometry/IComponent.h"
LamarMoore's avatar
LamarMoore committed
10
11
#include "MantidKernel/Quat.h"
#include "MantidKernel/V3D.h"
Roman Tolchenov's avatar
Roman Tolchenov committed
12
#include "MantidQtWidgets/Common/MantidAlgorithmMetatype.h"
13
14
15
16

#include "InstrumentActor.h"
#include "PeakOverlay.h"
#include "RectF.h"
LamarMoore's avatar
LamarMoore committed
17
#include "Shape2DCollection.h"
18

LamarMoore's avatar
LamarMoore committed
19
#include <QColor>
20
21
22
23
24
#include <QImage>
#include <QList>
#include <QMap>
#include <QStack>

25
#include <memory>
26

27
28
29
30
31
32
33
namespace Mantid {
namespace Geometry {
class IDetector;
}
namespace API {
class IPeaksWorkspace;
}
LamarMoore's avatar
LamarMoore committed
34
} // namespace Mantid
35
namespace MantidQt {
36
37
38
namespace MantidWidgets {
class InputController;
}
LamarMoore's avatar
LamarMoore committed
39
} // namespace MantidQt
40
41
42
43
44
45

class GLColor;

class QMouseEvent;
class QWheelEvent;

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
namespace MantidQt {
namespace MantidWidgets {
class MantidGLWidget;

/**
* @class ProjectionSurface
* @brief Performs projection of an instrument onto a plane.
* @author Roman Tolchenov, Tessella plc
* @date 13 May 2011

* Performs projection of an instrument onto a plane. Draws the resulting image
on the screen.
* Supports selection and zooming.
*
* Iherited classes must implement the pure virtual methods and set m_viewRect -
the bounding
* rectangle in surface coordinates.
*/

Roman Tolchenov's avatar
Roman Tolchenov committed
65
class EXPORT_OPT_MANTIDQT_INSTRUMENTVIEW ProjectionSurface : public QObject {
66
67
68
69
70
71
72
  Q_OBJECT
public:
  enum InteractionMode {
    MoveMode = 0,
    PickSingleMode,
    PickTubeMode,
    AddPeakMode,
73
    ComparePeakMode,
74
    AlignPeakMode,
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    DrawRegularMode,
    DrawFreeMode,
    ErasePeakMode,
    InteractionModeSize
  };
  /// Constructor
  explicit ProjectionSurface(const InstrumentActor *rootActor);
  /// Destructor
  ~ProjectionSurface() override;
  /// Resets the instrument actor.
  void resetInstrumentActor(const InstrumentActor *rootActor);

  //-----------------------------------
  //     Public virtual methods
  //-----------------------------------

  /// draw the surface onto a GL widget
  virtual void draw(MantidGLWidget *widget) const;
  /// draw the surface onto a normal widget
  virtual void drawSimple(QWidget *widget) const;
  /// called when the gl widget gets resized
96
  virtual void resize(int /*unused*/, int /*unused*/);
97
98
99
100
101
102
103
  /// redraw surface without recalulationg of colours, etc
  virtual void updateView(bool picking = true);
  /// full update and redraw of the surface
  virtual void updateDetectors();
  /// returns the bounding rectangle in the real coordinates
  virtual RectF getSurfaceBounds() const { return m_viewRect; }

104
105
106
107
108
109
110
  virtual void mousePressEvent(QMouseEvent * /*e*/);
  virtual void mouseMoveEvent(QMouseEvent * /*e*/);
  virtual void mouseReleaseEvent(QMouseEvent * /*e*/);
  virtual void wheelEvent(QWheelEvent * /*e*/);
  virtual void keyPressEvent(QKeyEvent * /*e*/);
  virtual void enterEvent(QEvent * /*e*/);
  virtual void leaveEvent(QEvent * /*e*/);
111
112
113
114
115

  /// return true if any of the detectors have been selected
  virtual bool hasSelection() const;

  virtual int getDetectorID(int x, int y) const;
Lamar Moore's avatar
Lamar Moore committed
116
  virtual size_t getDetector(int x, int y) const;
117
  /// NULL deselects components and selects the whole instrument
Lamar Moore's avatar
Lamar Moore committed
118
  virtual void componentSelected(size_t componentIndex) = 0;
Lamar Moore's avatar
Lamar Moore committed
119
120
121
122
123
  /// fill in a list of detector indices which were selected by the selction
  /// tool
  virtual void getSelectedDetectors(std::vector<size_t> &detIndices) = 0;
  /// fill in a list of detector indices which were masked by the mask shapes
  virtual void getMaskedDetectors(std::vector<size_t> &detIndices) const = 0;
124
125
126
127
128

  virtual QString getInfoText() const;
  /// Change the interaction mode
  virtual void setInteractionMode(int mode);

129
130
131
  /// Save masks to a table workspace
  virtual void saveShapesToTableWorkspace();

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  //-----------------------------------

  Mantid::Kernel::V3D getDetectorPos(int x, int y) const;
  /// Return the current interaction mode
  int getInteractionMode() const { return m_interactionMode; }
  /// Ask current input controller if a context menu is allowed
  bool canShowContextMenu() const;

  /// Set background colour
  void setBackgroundColor(const QColor &color) { m_backgroundColor = color; }
  /// Get background colour
  QColor getBackgroundColor() const { return m_backgroundColor; }
  /// Send a redraw request to the surface owner
  void requestRedraw(bool resetPeakVisibility = false);
  /// Enable lighting if the implementation allows it
  void enableLighting(bool on);
148
  /// Load settings for the projection surface from a project file
Samuel Jackson's avatar
Samuel Jackson committed
149
  virtual void loadFromProject(const std::string &lines);
150
  /// Save settings for the projection surface to a project file
Samuel Jackson's avatar
Samuel Jackson committed
151
  virtual std::string saveToProject() const;
152

153
  void setCurrentTab(QString currentTab) { m_currentTab = currentTab; }
154
  void freezeRotation(bool freeze);
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  //-----------------------------------
  //    Mask methods
  //-----------------------------------

  /// Return bounding rect of the currently selected shape in the "original"
  /// coord system.
  /// It doesn't depend on the zooming of the surface
  RectF getCurrentBoundingRect() const {
    return m_maskShapes.getCurrentBoundingRect();
  }

  /// Set new bounding rect of the currently selected shape in the "original"
  /// coord system.
  /// This method resizes the shape to fit into the new rectangle.
  void setCurrentBoundingRect(const RectF &rect) {
    m_maskShapes.setCurrentBoundingRect(rect);
  }

174
175
176
  /// Return bounding rotation of the currently selected shape in the "original"
  /// coord system.
  /// It doesn't depend on the zooming of the surface
177
  double getCurrentBoundingRotation() const { return m_maskShapes.getCurrentBoundingRotation(); }
178
179
180
181

  /// Set new bounding rect of the currently selected shape in the "original"
  /// coord system.
  /// This method resizes the shape to fit into the new rectangle.
182
  void setCurrentBoundingRotation(const double rotation) { m_maskShapes.setCurrentBoundingRotation(rotation); }
183

184
  std::string getCurrentShapeType() const { return m_maskShapes.getCurrentShapeType(); }
185

186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  /// Initialize interactive shape creation.
  /// @param type :: Type of the shape. For available types see code of
  /// Shape2DCollection::createShape(const QString& type,int x,int y) const
  /// @param borderColor :: The color of the shape outline.
  /// @param fillColor :: The fill color.
  void startCreatingShape2D(const QString &type, const QColor &borderColor,
                            const QColor &fillColor = QColor());

  /// Initialize interactive creation of a free draw shape.
  /// @param borderColor :: The color of the shape outline.
  /// @param fillColor :: The fill color.
  void startCreatingFreeShape(const QColor &borderColor,
                              const QColor &fillColor = QColor());

  // Properties methods which allow the mask shapes to be modified with a
  // property browser.

  /// Return a list of all properties of type double of the currently selected
  /// shape.
  QStringList getCurrentDoubleNames() const {
    return m_maskShapes.getCurrentDoubleNames();
  }

  /// Get value of a "double" property of the currently selected shape.
  /// @param prop :: Name of the property
  double getCurrentDouble(const QString &prop) const {
    return m_maskShapes.getCurrentDouble(prop);
  }

  /// Set value of a "double" property of the currently selected shape.
  /// @param prop :: Name of the property
  /// @param value :: New value
  void setCurrentDouble(const QString &prop, double value) {
    m_maskShapes.setCurrentDouble(prop, value);
  }

  /// Return a list of all properties of type QPointF of the currently selected
  /// shape.
  QStringList getCurrentPointNames() const {
    return m_maskShapes.getCurrentPointNames();
  }

  /// Get value of a "QPointF" property of the currently selected shape.
  /// @param prop :: Name of the property
  QPointF getCurrentPoint(const QString &prop) const {
    return m_maskShapes.getCurrentPoint(prop);
  }

  /// Set value of a "QPointF" property of the currently selected shape.
  /// @param prop :: Name of the property
  /// @param value :: New value
  void setCurrentPoint(const QString &prop, const QPointF &value) {
    m_maskShapes.setCurrentPoint(prop, value);
  }

  /// Check if a point on the scren is under any of the mask shapes
  bool isMasked(double x, double y) const {
    return m_maskShapes.isMasked(x, y);
  }
  /// Check if there are any masks defined
  bool hasMasks() const { return m_maskShapes.size() > 0; }
  /// Remove all mask shapes.
  void clearMask() { m_maskShapes.clear(); }
  /// Change all border colors.
  void changeBorderColor(const QColor &color) {
    m_maskShapes.changeBorderColor(color);
  }
253

254
  /// Load masks from a table workspace
David Fairbrother's avatar
David Fairbrother committed
255
256
  void loadShapesFromTableWorkspace(
      const Mantid::API::ITableWorkspace_const_sptr &ws);
257
258
259
260
261
262

  //-----------------------------------
  //    Peaks overlay methods
  //-----------------------------------

  QList<PeakMarker2D *> getMarkersWithID(int detID) const;
263
  std::shared_ptr<Mantid::API::IPeaksWorkspace> getEditPeaksWorkspace() const;
264
  QStringList getPeaksWorkspaceNames() const;
265
266
  void
  deletePeaksWorkspace(const std::shared_ptr<Mantid::API::IPeaksWorkspace> &ws);
267
  void clearPeakOverlays();
268
  void clearAlignmentPlane();
269
  void clearComparisonPeaks();
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  bool hasPeakOverlays() const { return !m_peakShapes.isEmpty(); }
  void setPeakLabelPrecision(int n);
  int getPeakLabelPrecision() const { return m_peakLabelPrecision; }
  void setShowPeakRowsFlag(bool on);
  bool getShowPeakRowsFlag() const { return m_showPeakRows; }
  void setShowPeakLabelsFlag(bool on);
  bool getShowPeakLabelsFlag() const { return m_showPeakLabels; }
  void setShowPeakRelativeIntensityFlag(bool on);
  bool getShowPeakRelativeIntensityFlag() const {
    return m_showPeakRelativeIntensity;
  }

signals:

  // detector selection
285
286
  void singleComponentTouched(size_t /*_t1*/);
  void singleComponentPicked(size_t /*_t1*/);
287
  void singleComponentPickedForMasking(size_t /*_t1*/);
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305

  // shape manipulation
  void signalToStartCreatingShape2D(const QString &type,
                                    const QColor &borderColor,
                                    const QColor &fillColor);
  void signalToStartCreatingFreeShape(const QColor &borderColor,
                                      const QColor &fillColor);
  void shapeCreated();
  void shapeSelected();
  void shapesDeselected();
  void shapeChanged();
  void shapesCleared();
  void shapesRemoved();
  void shapeChangeFinished();

  // peaks
  void peaksWorkspaceAdded();
  void peaksWorkspaceDeleted();
306
307
  void alignPeaks(const std::vector<Mantid::Kernel::V3D> & /*_t1*/,
                  const Mantid::Geometry::IPeak * /*_t2*/);
Tom Titcombe's avatar
Tom Titcombe committed
308
309
310
  void comparePeaks(
      const std::pair<std::vector<Mantid::Geometry::IPeak *>,
                      std::vector<Mantid::Geometry::IPeak *>> & /*_t1*/);
311
312
313
314
315

  // other
  void redrawRequired(); ///< request redrawing of self
  void updateInfoText(); ///< request update of the info string at bottom of
  /// InstrumentWindow
316
  void executeAlgorithm(Mantid::API::IAlgorithm_sptr /*_t1*/);
317
318
319
320
321
322
323
324
325

protected slots:

  void setSelectionRect(const QRect &rect);
  void emptySelectionRect();
  void selectMultipleMasks(const QRect &rect);
  void pickComponentAt(int x, int y);
  void touchComponentAt(int x, int y);
  void erasePeaks(const QRect &rect);
326
  void comparePeaks(const QRect &rect);
327
  void alignPeaks(const QRect &rect);
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

  void colorMapChanged();

protected:
  //-----------------------------------
  //     Protected virtual methods
  //-----------------------------------

  virtual void init() = 0;
  /// Draw the surface onto an OpenGL widget
  virtual void drawSurface(MantidGLWidget *widget,
                           bool picking = false) const = 0;
  /// Respond to a change of color map in m_instrActor
  virtual void changeColorMap() = 0;
  /// Draw the surface onto an image without OpenGL
  virtual void drawSimpleToImage(QImage *image, bool picking = false) const;

  //-----------------------------------

  void draw(MantidGLWidget *widget, bool picking) const;
  void clear();
  QRect selectionRect() const;
  RectF selectionRectUV() const;
  size_t getPickID(int x, int y) const;
  void setInputController(int mode,
                          MantidQt::MantidWidgets::InputController *controller);
  void setPeakVisibility() const;

  //-----------------------------------
  //     Protected data
  //-----------------------------------

  const InstrumentActor *m_instrActor;
  mutable QImage *m_viewImage; ///< storage for view image
  mutable QImage *m_pickImage; ///< storage for picking image
  QColor m_backgroundColor;    ///< The background colour
  RectF m_viewRect;            ///< Keeps the physical dimensions of the surface
  QRect m_selectRect;
  int m_interactionMode; ///< mode of interaction - index in m_inputControllers
  bool m_isLightingOn;   ///< Lighting on/off flag

  Shape2DCollection m_maskShapes;            ///< to draw mask shapes
  mutable QList<PeakOverlay *> m_peakShapes; ///< to draw peak labels
  mutable int m_peakLabelPrecision;
  mutable bool m_showPeakRows;      ///< flag to show peak row index
  mutable bool m_showPeakLabels;    ///< flag to show peak hkl labels
  bool m_showPeakRelativeIntensity; ///< flag to show peak hkl labels
  mutable int m_peakShapesStyle; ///< index of a default PeakMarker2D style to
376

377
378
379
  std::vector<std::pair<Mantid::Kernel::V3D, QPointF>> m_selectedAlignmentPlane;
  std::pair<Mantid::Geometry::IPeak *, QPointF> m_selectedAlignmentPeak;

380
  std::pair<std::vector<Mantid::Geometry::IPeak *>,
LamarMoore's avatar
LamarMoore committed
381
382
            std::vector<Mantid::Geometry::IPeak *>>
      m_selectedPeaks;
383
  std::pair<QPointF, QPointF> m_selectedMarkers;
384
385

private:
386
  /// Draw a line between two peak markers
387
  void drawPeakComparisonLine(QPainter &painter) const;
388
  /// Draw the peak markers on the surface
389
  void drawPeakMarkers(QPainter &painter) const;
390
  /// Draw the mask shapes on the surface
391
  void drawMaskShapes(QPainter &painter) const;
392
  /// Draw the selection rectangle to the surface
393
  void drawSelectionRect(QPainter &painter) const;
394
395
  /// Draw the alignment markers on the surface
  void drawPeakAlignmentMarkers(QPainter &painter) const;
396
397
  /// Check if a peak is visible at a given point
  bool peakVisibleAtPoint(const QPointF &point) const;
398
399
400
401
402
403
404
405
406
407
  /// Get the current input controller
  MantidQt::MantidWidgets::InputController *getController() const;

  QMap<int, MantidQt::MantidWidgets::InputController *>
      m_inputControllers; ///< controllers for mouse and keyboard input
                          /// Set when the image must be redrawn
  mutable bool m_viewChanged;
  /// Set when the picking image must be redrawn regardless of the interaction
  /// mode
  mutable bool m_redrawPicking;
408
  QString m_currentTab;
Samuel Jones's avatar
Samuel Jones committed
409
410

  friend class InstrumentWidgetEncoder;
Samuel Jones's avatar
Samuel Jones committed
411
  friend class InstrumentWidgetDecoder;
412
413
};

414
using ProjectionSurface_sptr = std::shared_ptr<ProjectionSurface>;
415

LamarMoore's avatar
LamarMoore committed
416
417
} // namespace MantidWidgets
} // namespace MantidQt