Skip to content
Snippets Groups Projects
Commit 3d0a695f authored by Roman Tolchenov's avatar Roman Tolchenov
Browse files

Added labels to peak markers. re #3583

parent 7410d693
No related merge requests found
Showing
with 590 additions and 36 deletions
......@@ -204,6 +204,8 @@ set ( MANTID_SRCS src/Mantid/AbstractMantidLog.cpp
src/Mantid/InstrumentWidget/UnwrappedSurface.cpp
src/Mantid/InstrumentWidget/ProjectionSurface.cpp
src/Mantid/InstrumentWidget/Projection3D.cpp
src/Mantid/InstrumentWidget/PeakMarker2D.cpp
src/Mantid/InstrumentWidget/PeakOverlay.cpp
src/Mantid/InstrumentWidget/OneCurvePlot.cpp
src/Mantid/InstrumentWidget/CollapsiblePanel.cpp
src/Mantid/InstrumentWidget/DetSelector.cpp
......@@ -411,6 +413,8 @@ set ( MANTID_HDRS src/Mantid/AbstractMantidLog.h
src/Mantid/InstrumentWidget/UnwrappedCylinder.h
src/Mantid/InstrumentWidget/UnwrappedSphere.h
src/Mantid/InstrumentWidget/UnwrappedSurface.h
src/Mantid/InstrumentWidget/PeakMarker2D.h
src/Mantid/InstrumentWidget/PeakOverlay.h
src/Mantid/InstrumentWidget/ProjectionSurface.h
src/Mantid/InstrumentWidget/Projection3D.h
src/Mantid/InstrumentWidget/OneCurvePlot.h
......@@ -653,6 +657,7 @@ set ( MANTID_MOC_FILES src/Mantid/AlgMonitor.h
src/Mantid/InstrumentWidget/OneCurvePlot.h
src/Mantid/InstrumentWidget/CollapsiblePanel.h
src/Mantid/InstrumentWidget/InstrumentActor.h
src/Mantid/InstrumentWidget/PeakOverlay.h
src/Mantid/InstrumentWidget/ProjectionSurface.h
src/Mantid/InstrumentWidget/Shape2DCollection.h
)
......
......@@ -4,6 +4,7 @@
#include "CollapsiblePanel.h"
#include "InstrumentActor.h"
#include "ProjectionSurface.h"
#include "PeakMarker2D.h"
#include "MantidKernel/ConfigService.h"
#include "MantidAPI/AnalysisDataService.h"
......@@ -344,8 +345,13 @@ void InstrumentWindowPickTab::getBinMinMaxIndex(size_t wi,size_t& imin, size_t&
}
}
/**
* Plot data for a detector.
* @param detid :: ID of the detector to be plotted.
*/
void InstrumentWindowPickTab::plotSingle(int detid)
{
m_plot->clearLabels();
InstrumentActor* instrActor = m_instrWindow->getInstrumentActor();
Mantid::API::MatrixWorkspace_const_sptr ws = instrActor->getWorkspace();
size_t wi;
......@@ -354,8 +360,11 @@ void InstrumentWindowPickTab::plotSingle(int detid)
} catch (Mantid::Kernel::Exception::NotFoundError) {
return; // Detector doesn't have a workspace index relating to it
}
// get the data
const Mantid::MantidVec& x = ws->readX(wi);
const Mantid::MantidVec& y = ws->readY(wi);
// find min and max for x
size_t imin,imax;
getBinMinMaxIndex(wi,imin,imax);
......@@ -364,16 +373,26 @@ void InstrumentWindowPickTab::plotSingle(int detid)
m_plot->setXScale(x[imin],x[imax]);
// fins min and max for y
Mantid::MantidVec::const_iterator min_it = std::min_element(y_begin,y_end);
Mantid::MantidVec::const_iterator max_it = std::max_element(y_begin,y_end);
// set the data
m_plot->setData(&x[0],&y[0],static_cast<int>(y.size()));
m_plot->setYScale(*min_it,*max_it);
// find any markers
ProjectionSurface* surface = mInstrumentDisplay->getSurface();
if (surface)
{
QList<PeakMarker2D*> markers = surface->getPeakOverlay().getMarkersWithID(detid);
foreach(PeakMarker2D* marker,markers)
{
m_plot->addLabel(new PeakLabel(marker));
//std::cerr << marker->getLabel().toStdString() << std::endl;
}
}
}
//void InstrumentWindowPickTab::plotBox(const Instrument3DWidget::DetInfo & /*cursorPos*/)
//{
//}
//
void InstrumentWindowPickTab::plotTube(int detid)
{
InstrumentActor* instrActor = m_instrWindow->getInstrumentActor();
......
#include "OneCurvePlot.h"
#include "PeakMarker2D.h"
#include <qwt_plot_curve.h>
#include <qwt_scale_div.h>
......@@ -11,6 +12,7 @@
#include <QFontMetrics>
#include <QMouseEvent>
#include <QContextMenuEvent>
#include <QPainter>
#include <iostream>
......@@ -182,3 +184,39 @@ void OneCurvePlot::setYLinearScale()
update();
}
/**
* Add new peak label
* @param label :: A pointer to a PeakLabel, becomes owned by OneCurvePlot
*/
void OneCurvePlot::addLabel(PeakLabel* label)
{
label->attach(this);
m_peakLabels.append(label);
}
/**
* Removes all peak labels.
*/
void OneCurvePlot::clearLabels()
{
foreach(PeakLabel* label, m_peakLabels)
{
label->detach();
delete label;
}
m_peakLabels.clear();
}
/**
* Draw PeakLabel on a plot
*/
void PeakLabel::draw(QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRect &canvasRect) const
{
int x = xMap.transform(m_marker->getTOF());
int y = canvasRect.top() + m_marker->getLabelRect().height();
painter->drawText(x,y,m_marker->getLabel());
//std::cerr << x << ' ' << y << ' ' << m_marker->getLabel().toStdString() << std::endl;
}
......@@ -2,11 +2,13 @@
#define ONECURVEPLOT_H_
#include <qwt_plot.h>
#include <qwt_plot_item.h>
#include <QList>
class QwtPlotCurve;
class QwtPlotZoomer;
class PeakLabel;
class PeakMarker2D;
/**
* Implements a simple widget for plotting a single curve.
*/
......@@ -17,6 +19,8 @@ public:
OneCurvePlot(QWidget* parent);
void setData(const double* x,const double* y,int dataSize);
void setYAxisLabelRotation(double degrees);
void addLabel(PeakLabel*);
void clearLabels();
public slots:
void setXScale(double from, double to);
void setYScale(double from, double to);
......@@ -37,7 +41,18 @@ private:
QwtPlotZoomer* m_zoomer; ///< does zooming
int m_x0; ///< save x coord of last left mouse click
int m_y0; ///< save y coord of last left mouse click
QList<PeakLabel*> m_peakLabels;
};
class PeakLabel: public QwtPlotItem
{
public:
PeakLabel(const PeakMarker2D* m):m_marker(m){}
void draw(QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRect &canvasRect) const;
private:
const PeakMarker2D* m_marker;
};
#endif /*ONECURVEPLOT_H_*/
#include "PeakMarker2D.h"
#include <QPainter>
#include <QPainterPath>
#include <QFontMetrics>
#include <QMouseEvent>
#include <QWheelEvent>
#include <iostream>
#include <algorithm>
#include <stdexcept>
#include <cmath>
/// Default size in screen pixels of the marker's symbol
const int PeakMarker2D::g_defaultMarkerSize = 5;
/**
* Constructor.
* @param centre :: Centre of the marker. Represents the peak position.
* @param symbol :: Symbol to draw. One of: Circle, Diamond, or Square
* @param markerSize :: Optional size of marker's symbol.
*/
PeakMarker2D::PeakMarker2D(const QPointF& centre,Symbol symbol,int markerSize):
m_symbol(symbol)
{
if (markerSize > 0)
{
m_markerSize = markerSize;
}
else
{
m_markerSize = g_defaultMarkerSize;
}
m_boundingRect = QRectF(centre - QPointF((qreal)m_markerSize/2,(qreal)m_markerSize/2),
QSizeF((qreal)m_markerSize,(qreal)m_markerSize));
setScalable(false);
}
bool PeakMarker2D::selectAt(const QPointF& p)const
{
return contains(p);
}
void PeakMarker2D::drawShape(QPainter& painter) const
{
// draw the symbol
switch(m_symbol)
{
case Circle: drawCircle(painter); break;
case Diamond: drawDiamond(painter); break;
case Square: drawSquare(painter); break;
default:
drawCircle(painter);
}
// calculate label's area on the screen
QFontMetrics fm(painter.font());
QRect r = fm.boundingRect(m_label);
m_labelRect = QRectF(r);
m_labelRect.moveTo(m_boundingRect.right() + m_markerSize,m_boundingRect.top() - m_markerSize);
}
void PeakMarker2D::addToPath(QPainterPath& path) const
{
path.addRect(m_boundingRect);
}
/// Set new marker size to s
void PeakMarker2D::setMarkerSize(const int& s)
{
if (s > 0)
{
m_markerSize = s;
}
}
/// Draw marker as a circle
void PeakMarker2D::drawCircle(QPainter& painter)const
{
QPainterPath path;
path.addEllipse(m_boundingRect);
painter.fillPath(path,m_color);
}
/// Draw marker as a diamond
void PeakMarker2D::drawDiamond(QPainter& painter)const
{
QPointF dp = origin();
QPointF mdp(-dp.x(),-dp.y());
// draw a diamond as a square rotated by 45 degrees
painter.save();
painter.translate(dp);
painter.rotate(45);
painter.translate(mdp);
QPainterPath path;
path.addRect(m_boundingRect);
painter.fillPath(path,m_color);
painter.restore();
}
/// Draw marker as a square
void PeakMarker2D::drawSquare(QPainter& painter)const
{
QPainterPath path;
path.addRect(m_boundingRect);
painter.fillPath(path,m_color);
}
/**
* Save some peak information.
*/
void PeakMarker2D::setPeak(const Mantid::API::IPeak& peak)
{
m_h = peak.getH();
m_k = peak.getK();
m_l = peak.getL();
m_label = QString("%1 %2 %3").arg(QString::number(m_h),QString::number(m_k),QString::number(m_l));
m_detID = peak.getDetectorID();
m_tof = peak.getTOF();
}
#ifndef MANTIDPLOT_PEAKMARKER2D_H_
#define MANTIDPLOT_PEAKMARKER2D_H_
#include "Shape2D.h"
#include "MantidAPI/IPeak.h"
/**
* Shape representing a peak marker on un unwrapped surface.
* A marker consists of a symbol marking location of a peak
* and a text label.
*/
class PeakMarker2D: public Shape2D
{
public:
enum Symbol {Circle = 0,Diamond,Square};
PeakMarker2D(const QPointF& centre,Symbol symbol = Circle,int markerSize = 0);
/* --- Implemented Shape2D virtual methods --- */
virtual Shape2D* clone()const{return new PeakMarker2D(*this);}
virtual bool selectAt(const QPointF& p)const;
virtual bool contains(const QPointF& p)const{return m_boundingRect.contains(p);}
virtual void addToPath(QPainterPath& path) const;
/* --- Own public methods --- */
/// Set new marker size to s
void setMarkerSize(const int& s);
/// Get marker size
int getMarkerSize()const{return m_markerSize;}
/// Get default marker size
static const int getDefaultMarkerSize(){return g_defaultMarkerSize;}
Symbol getSymbol()const{return m_symbol;}
void setSymbol(Symbol s){m_symbol=s;}
void setPeak(const Mantid::API::IPeak& peak);
double getH()const{return m_h;}
double getK()const{return m_k;}
double getL()const{return m_l;}
int getDetectorID()const{return m_detID;}
double getTOF()const{return m_tof;}
/// Get label's area on the screen
const QRectF& getLabelRect()const{return m_labelRect;}
/// Allows PeakOverlay to move the label to avoid overlapping
void moveLabelRectTo(const QPointF& p)const{m_labelRect.moveTo(p);}
QString getLabel()const{return m_label;}
protected:
/* --- Implemented Shape2D protected virtual methods --- */
virtual void drawShape(QPainter& painter) const;
virtual void refit(){}
/* --- Own protected methods --- */
void drawCircle(QPainter& painter)const;
void drawDiamond(QPainter& painter)const;
void drawSquare(QPainter& painter)const;
private:
int m_markerSize;
static const int g_defaultMarkerSize;
Symbol m_symbol; ///< Shape of the marker
double m_h, m_k, m_l; ///< Peak's h,k,l
int m_detID;
double m_tof;
QString m_label;
mutable QRectF m_labelRect; ///< label's area on the screen
};
#endif /*MANTIDPLOT_PEAKMARKER2D_H_*/
#include "PeakOverlay.h"
#include "PeakMarker2D.h"
#include <QPainter>
#include <QList>
/**
* Constructor.
*/
PeakHKL::PeakHKL(PeakMarker2D* m,const QRectF& trect):
p(m->origin()),
rect(trect),
//rectTopLeft(m->getLabelRect().topLeft()),
h(m->getH()),
k(m->getK()),
l(m->getL()),
nh(true),
nk(true),
nl(true)
{}
/**
* Check if this rect intersects with marker's and if it does combine the labels
* @param marker :: A marker to check for intersection
* @param trect :: Transformed marker's label rect
* @return True if labels were combined, false otherwise.
*/
bool PeakHKL::add(PeakMarker2D* marker,const QRectF& trect)
{
if ( !rect.intersects(trect) )
{
return false;
}
if (nh && marker->getH() != h)
{
nh = false;
}
if (nk && marker->getK() != k)
{
nk = false;
}
if (nl && marker->getL() != l)
{
nl = false;
}
return true;
}
/**
* Draw the label
* @param painter :: QPainter to draw with
* @param transform :: Current transform
*/
void PeakHKL::draw(QPainter& painter,const QTransform& transform)
{
QString label;
if (nh) label = QString::number(h) + " ";
else
label = "h ";
if (nk) label += QString::number(k) + " ";
else
label += "k ";
if (nl) label += QString::number(l);
else
label += "l";
painter.drawText(rect.bottomLeft(),label);
}
void PeakHKL::print()const
{
std::cerr << " " << p.x() << ' ' << p.y() << '('<<h<<','<<k<<','<<l<<")("<<nh<<','<<nk<<','<<nl<<')' << std::endl;
}
/**
* Add new marker to the overlay.
* @param m :: Pointer to the new marker
*/
void PeakOverlay::addMarker(PeakMarker2D* m)
{
addShape(m,false);
m_det2marker.insert(m->getDetectorID(),m);
}
void PeakOverlay::draw(QPainter& painter) const
{
// Draw symbols
Shape2DCollection::draw(painter);
// Sort the labels to avoid overlapping
QColor color;
QRectF clipRect(painter.viewport());
m_labels.clear();
foreach(Shape2D* shape,m_shapes)
{
if (!clipRect.contains(m_transform.map(shape->origin()))) continue;
PeakMarker2D* marker = dynamic_cast<PeakMarker2D*>(shape);
if (!marker) continue;
color = marker->getColor();
QPointF p0 = marker->origin();
QPointF p1 = m_transform.map(p0);
QRectF rect = marker->getLabelRect();
QPointF dp = rect.topLeft() - p0;
p1 += dp;
rect.moveTo(p1);
//painter.setPen(color);
//painter.drawRect(rect);
bool overlap = false;
// if current label overlaps with another
// combine them substituting differing numbers with letter 'h','k', or 'l'
for(int i = 0; i < m_labels.size(); ++i)
{
PeakHKL& hkl = m_labels[i];
overlap = hkl.add(marker,rect);
}
if (!overlap)
{
PeakHKL hkl(marker,rect);
m_labels.append(hkl);
}
}
//std::cerr << m_labels.size() << " labels\n";
painter.setPen(color);
for(int i = 0; i < m_labels.size(); ++i)
{
PeakHKL& hkl = m_labels[i];
hkl.draw(painter,m_transform);
//hkl.print();
}
}
/**
* Return a list of markers put onto a detector
* @param detID :: A detector ID for which markers are to be returned.
* @return :: A list of zero ot more markers.
*/
QList<PeakMarker2D*> PeakOverlay::getMarkersWithID(int detID)const
{
return m_det2marker.values(detID);
}
#ifndef MANTIDPLOT_PEAKOVERLAY_H_
#define MANTIDPLOT_PEAKOVERLAY_H_
#include "Shape2DCollection.h"
#include <QHash>
class PeakMarker2D;
/**
* Class for managing overlapping peak labels and drawing them on screen.
* If labels of two or more peaks overlap they are combined into a single label.
* A label shows three numbers h,k, and l. A combined label replaces non-equal
* numbers of included markers with its letter.
*/
class PeakHKL
{
public:
PeakHKL(PeakMarker2D* m,const QRectF& trect);
bool add(PeakMarker2D* marker,const QRectF& trect);
void draw(QPainter& painter,const QTransform& transform);
void print()const;
private:
QPointF p; ///< untransformed marker origin
QRectF rect; ///< label's screen area in transformed coords
double h,k,l; ///< h,k, and l
bool nh,nk,nl; ///< true if h, k, or l is numeric
};
/**
* Class for managing peak markers.
*/
class PeakOverlay: public Shape2DCollection
{
public:
PeakOverlay():Shape2DCollection(){}
~PeakOverlay(){}
/// Override the drawing method
void draw(QPainter& painter) const;
void addMarker(PeakMarker2D* m);
QList<PeakMarker2D*> getMarkersWithID(int detID)const;
private:
QMultiHash<int,PeakMarker2D*> m_det2marker; ///< detector ID to PeakMarker2D map
mutable QList<PeakHKL> m_labels;
};
#endif /*MANTIDPLOT_PEAKOVERLAY_H_*/
......@@ -7,6 +7,7 @@
#include "InstrumentActor.h"
#include "Shape2DCollection.h"
#include "PeakOverlay.h"
#include <QImage>
#include <QList>
......@@ -109,6 +110,8 @@ public:
bool isMasked(double x,double y)const{return m_maskShapes.isMasked(x,y);}
void clearMask(){m_maskShapes.clear();}
PeakOverlay& getPeakOverlay(){return m_peakShapes;}
signals:
void singleDetectorTouched(int);
......@@ -173,7 +176,7 @@ protected:
bool m_leftButtonDown;
Shape2DCollection m_maskShapes; ///< to draw mask shapes
mutable Shape2DCollection m_peakShapes; ///< to draw peak labels
mutable PeakOverlay m_peakShapes; ///< to draw peak labels
};
......
......@@ -16,6 +16,7 @@ const qreal Shape2D::sizeCP = 2;
Shape2D::Shape2D():
m_color(Qt::red),
m_scalable(true),
m_editing(false)
{
......
......@@ -24,10 +24,13 @@ public:
virtual Shape2D* clone()const = 0;
// modify path so painter.drawPath(path) could be used to draw the shape. needed for filling in complex shapes
virtual void addToPath(QPainterPath& path) const = 0;
// make sure the shape is withing the bounding box
// make sure the shape is within the bounding box
virtual void refit() = 0;
// --- Public virtual methods --- //
virtual void draw(QPainter& painter) const;
virtual QPointF origin() const {return m_boundingRect.center();}
virtual void moveBy(const QPointF& pos);
virtual size_t getNControlPoints() const;
virtual QPointF getControlPoint(size_t i) const;
......@@ -37,11 +40,6 @@ public:
// by dx1, dy1, dx2, and dy2 correspondingly
virtual void adjustBoundingRect(qreal dx1,qreal dy1,qreal dx2,qreal dy2);
virtual void setBoundingRect(const QRectF& rect);
void setColor(const QColor& color){m_color = color;}
void setFillColor(const QColor& color){m_fill_color = color;}
void edit(bool on){m_editing = on;}
bool isEditing()const{return m_editing;}
// will the shape be selected if clicked at a point
virtual bool selectAt(const QPointF& )const{return false;}
// is a point inside the shape (closed line)
......@@ -49,6 +47,16 @@ public:
// is a point "masked" by the shape. Only filled regians of a shape mask a point
virtual bool isMasked(const QPointF& )const;
// --- Public methods --- //
void setColor(const QColor& color){m_color = color;}
QColor getColor()const{return m_color;}
void setFillColor(const QColor& color){m_fill_color = color;}
void setScalable(bool on){m_scalable = on;}
bool isScalable() const {return m_scalable;}
void edit(bool on){m_editing = on;}
bool isEditing()const{return m_editing;}
// --- Properties. for gui interaction --- //
// double properties
......@@ -66,6 +74,8 @@ protected:
virtual void drawShape(QPainter& painter) const = 0;
// --- Protected virtual methods --- //
// return number of control points specific to this shape
virtual size_t getShapeNControlPoints() const{return 0;}
// returns position of a shape specific control point, 0 < i < getShapeNControlPoints()
......@@ -75,14 +85,19 @@ protected:
// make sure the bounding box is correct
virtual void resetBoundingRect() {}
// --- Protected methods --- //
// make sure that width and heigth are positive
void correctBoundingRect();
// --- Protected data --- //
static const size_t NCommonCP;
static const qreal sizeCP;
QRectF m_boundingRect;
QColor m_color;
QColor m_fill_color;
bool m_scalable; ///< shape cann be scaled when zoomed
bool m_editing;
};
......
......@@ -32,18 +32,56 @@ Shape2DCollection::~Shape2DCollection()
}
}
/**
* Draw the collection on screen.
*/
void Shape2DCollection::draw(QPainter& painter) const
{
if (m_shapes.isEmpty()) return;
// separate scalable and nonscalable shapes
QList<Shape2D*> scalable;
QList<Shape2D*> nonscalable;
foreach(Shape2D* shape,m_shapes)
{
if (shape->isScalable())
{
scalable << shape;
}
else
{
nonscalable << shape;
}
}
// first draw the scalable ones
painter.save();
painter.setTransform(m_transform);
foreach(const Shape2D* shape,m_shapes)
foreach(const Shape2D* shape,scalable)
{
shape->draw(painter);
}
painter.restore();
// now the nonscalable
foreach(const Shape2D* shape,nonscalable)
{
QPointF p0 = shape->origin();
QPointF p1 = m_transform.map(p0);
QPointF dp = p1 - p0;
painter.save();
painter.translate(dp);
shape->draw(painter);
painter.restore();
}
//std::cerr << m_transform.m11() << ' ' << m_transform.m22() << ' ' << m_transform.m33() << std::endl;
}
/**
* Add a new shape to collection.
* @param shape :: A pointer to the new shape.
* @param slct :: A bool flag to select the shape after it's added.
*/
void Shape2DCollection::addShape(Shape2D* shape,bool slct)
{
m_shapes.push_back(shape);
......@@ -55,23 +93,37 @@ void Shape2DCollection::addShape(Shape2D* shape,bool slct)
emit shapeCreated();
}
void Shape2DCollection::setWindow(const QRectF& rect,const QRect& viewport) const
/**
* Remove a shape from collection
* @param shape :: Pointer to the shape to remove.
*/
void Shape2DCollection::removeShape(Shape2D* shape)
{
if (shape && m_shapes.contains(shape))
{
m_shapes.removeOne(shape);
}
}
/**
*/
void Shape2DCollection::setWindow(const QRectF& window,const QRect& viewport) const
{
m_transform.reset();
m_viewport = viewport;
if ( m_windowRect.isNull() )
{
m_windowRect = rect;
m_windowRect = window;
m_h = viewport.height();
m_wx = viewport.width() / rect.width();
m_wy = m_h / rect.height();
m_wx = viewport.width() / window.width();
m_wy = m_h / window.height();
}
else
{
double wx = viewport.width() / rect.width();
double wy = viewport.height() / rect.height();
double rx = m_windowRect.left() - rect.left();
double ry = m_windowRect.top() - rect.top();
double wx = viewport.width() / window.width();
double wy = viewport.height() / window.height();
double rx = m_windowRect.left() - window.left();
double ry = m_windowRect.top() - window.top();
qreal sx = wx / m_wx;
qreal sy = wy / m_wy;
qreal dx = rx * wx;
......@@ -320,7 +372,7 @@ void Shape2DCollection::removeCurrentShape()
{
if (m_currentShape)
{
m_shapes.removeOne(m_currentShape);
this->removeShape(m_currentShape);
m_currentShape = NULL;
emit shapesDeselected();
}
......@@ -448,11 +500,21 @@ void Shape2DCollection::getMaskedPixels(QList<QPoint>& pixels)const
void Shape2DCollection::setCurrentBoundingRectReal(const QRectF& rect)
{
if (!m_currentShape) return;
// convert rect from real to original screen coordinates
// convert rect from real to original screen coordinates (unaffected by m_transform)
double x = (rect.x() - m_windowRect.left()) * m_wx;
double y = m_h - (rect.bottom() - m_windowRect.y()) * m_wy;
double width = rect.width() * m_wx;
double height = rect.height() * m_wy;
//QPointF c = QRectF(x,y,width,height).center();
//std::cerr << "setCurrentBoundingRectReal: " << c.x() << ' ' << c.y() << std::endl << std::endl;
m_currentShape->setBoundingRect(QRectF(x,y,width,height));
}
QPointF Shape2DCollection::realToUntransformed(const QPointF& point)const
{
qreal x = (point.x() - m_windowRect.left()) * m_wx;
qreal y = m_h - (point.y() - m_windowRect.y()) * m_wy;
//std::cerr << "realToUntransformed: " << x << ' ' << y << std::endl;
return QPointF(x,y);
}
......@@ -13,6 +13,21 @@ class QKeyEvent;
/**
* Class Shape2DCollection is a collection of 2D shapes.
* It supports operations on teh shapes such as adding, removing, and aditting either
* with the mouse via control points (CPs) or via properties.
*
* The shapes operate in three coordinate systems:
* 1. Some 'real' or logical coordinates
* 2. Current or transformed screen coordinates
* 3. Untransformed screen coordinates
*
* Shape2DCollection must know the boundaries of the drawing area in logical and transformed screen coords.
* They are set by calling setWindow(...) method. The first argument is the logical drawing rectangle and
* the second one is the corresponding screen viewport in pixels. The first screen viewport set with setWindow
* defines the Untransformed screen coordinates. The individual shapes draw themselves in the untransformed
* screen coords and unaware of the logical ones at all. If the size of the screen/widget changes setWindow
* must be called again. Changing the logical drawing bounds translates and zooms the picture.
* The transformation is done by Qt's QTransform object.
*/
class Shape2DCollection: public QObject, public Shape2D
{
......@@ -21,9 +36,10 @@ public:
Shape2DCollection();
~Shape2DCollection();
Shape2D* clone()const{return NULL;}
void setWindow(const QRectF& rect,const QRect& viewport) const;
void setWindow(const QRectF& window,const QRect& viewport) const;
virtual void draw(QPainter& painter) const;
virtual void addShape(Shape2D*,bool slct = false);
virtual void removeShape(Shape2D*);
void mousePressEvent(QMouseEvent*);
void mouseMoveEvent(QMouseEvent*);
......@@ -58,7 +74,12 @@ public:
// collect all screen pixels that are masked by the shapes
void getMaskedPixels(QList<QPoint>& pixels)const;
// --- coordinate transformations --- //
// set the bounding rect of the current shape such that its real rect is given by the argument
void setCurrentBoundingRectReal(const QRectF& rect);
// convert a real point to the untransformed screen coordinates
QPointF realToUntransformed(const QPointF& point)const;
signals:
......@@ -79,15 +100,15 @@ protected:
void select(Shape2D* shape);
QList<Shape2D*> m_shapes;
mutable QRectF m_windowRect; // original surface window in "real" cooerdinates
mutable QRectF m_windowRect; // original surface window in "real" coordinates
mutable double m_wx,m_wy;
mutable int m_h; // original screen viewport height
mutable QRect m_viewport; // current screen viewport
mutable QTransform m_transform; // current transform
bool m_creating;
bool m_editing;
bool m_moving;
bool m_creating; ///< a shape is being created with a mouse
bool m_editing; ///< current shape is being edited with a mouse. CPs are visible
bool m_moving; ///< current shape is being moved with a mouse.
int m_x,m_y;
QString m_shapeType;
QColor m_borderColor, m_fillColor;
......
......@@ -2,6 +2,7 @@
#include "GLColor.h"
#include "MantidGLWidget.h"
#include "OpenGLError.h"
#include "PeakMarker2D.h"
#include "MantidGeometry/IDetector.h"
#include "MantidGeometry/Objects/Object.h"
......@@ -12,6 +13,7 @@
#include <QSet>
#include <QMenu>
#include <QMouseEvent>
#include <QApplication>
#include <cfloat>
#include <limits>
......@@ -170,7 +172,7 @@ void UnwrappedSurface::drawSurface(MantidGLWidget *widget,bool picking)const
if (m_startPeakShapes)
{
ceatePeakShapes(widget->rect());
createPeakShapes(widget->rect());
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
......@@ -632,9 +634,10 @@ void UnwrappedSurface::setPeaksWorkspace(boost::shared_ptr<Mantid::API::IPeaksWo
* Create the peak labels from the peaks set by setPeaksWorkspace. The method is called from the draw(...) method
* @param window :: The screen window rectangle in pixels.
*/
void UnwrappedSurface::ceatePeakShapes(const QRect& viewport)const
void UnwrappedSurface::createPeakShapes(const QRect& window)const
{
m_peakShapes.setWindow(getSurfaceBounds(),viewport);
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
m_peakShapes.setWindow(getSurfaceBounds(),window);
int nPeaks = m_peaksWorkspace->getNumberPeaks();
for(int i = 0; i < nPeaks; ++i)
{
......@@ -645,12 +648,12 @@ void UnwrappedSurface::ceatePeakShapes(const QRect& viewport)const
Mantid::Geometry::IDetector_const_sptr det = udet.detector;
if (! det ) continue;
if (det->getID() != detID) continue;
Shape2DRectangle* r = new Shape2DRectangle();
r->setFillColor(QColor(255,255,255,100));
m_peakShapes.addShape(r,true);
m_peakShapes.setCurrentBoundingRectReal(QRectF(udet.u-udet.width/2,udet.v-udet.height/2,udet.width,udet.height));
PeakMarker2D* r = new PeakMarker2D(m_peakShapes.realToUntransformed(QPointF(udet.u,udet.v)));
r->setPeak(peak);
m_peakShapes.addMarker(r);
}
}
m_peakShapes.deselectAll();
m_startPeakShapes = false;
QApplication::restoreOverrideCursor();
}
......@@ -97,7 +97,7 @@ protected:
void showPickedDetector();
void calcAssemblies(boost::shared_ptr<const Mantid::Geometry::IComponent> comp,const QRectF& compRect);
void findAndCorrectUGap();
void ceatePeakShapes(const QRect& viewport)const;
void createPeakShapes(const QRect& viewport)const;
const InstrumentActor* m_instrActor;
double m_u_min; ///< Minimum u
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment