diff --git a/Code/Mantid/MantidQt/SliceViewer/CMakeLists.txt b/Code/Mantid/MantidQt/SliceViewer/CMakeLists.txt index 77a080d010cda3d959e2130ede0f2fe57bc7bdb0..683b7f64dc6a69109bc8e9fb91949a5cc0800349 100644 --- a/Code/Mantid/MantidQt/SliceViewer/CMakeLists.txt +++ b/Code/Mantid/MantidQt/SliceViewer/CMakeLists.txt @@ -72,6 +72,7 @@ set ( INC_FILES inc/MantidQtSliceViewer/SliceViewerWindow.h inc/MantidQtSliceViewer/SnapToGridDialog.h inc/MantidQtSliceViewer/XYLimitsDialog.h + inc/MantidQtSliceViewer/ZoomablePeaksView.h ) set ( MOC_FILES diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/CompositePeaksPresenter.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/CompositePeaksPresenter.h index 8d72f212b21c62bb63715a8e91d37f48ed2f8e77..20ea2d2f84fd5361749efeddea659e341655a7a3 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/CompositePeaksPresenter.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/CompositePeaksPresenter.h @@ -4,6 +4,7 @@ #include "MantidQtSliceViewer/PeaksPresenter.h" #include "MantidQtSliceViewer/NullPeaksPresenter.h" #include "MantidQtSliceViewer/PeakPalette.h" +#include "MantidQtSliceViewer/ZoomablePeaksView.h" #include <vector> #include <stdexcept> #include <boost/shared_ptr.hpp> @@ -35,7 +36,7 @@ namespace MantidQt virtual std::string getTransformName() const; /// Constructor - CompositePeaksPresenter(PeaksPresenter_sptr defaultPresenter = PeaksPresenter_sptr(new NullPeaksPresenter)); + CompositePeaksPresenter(ZoomablePeaksView* const zoomablePlottingWidget, PeaksPresenter_sptr defaultPresenter = PeaksPresenter_sptr(new NullPeaksPresenter)); /// Destructor ~CompositePeaksPresenter(); /// Add a peaks presenter onto the composite. @@ -59,7 +60,9 @@ namespace MantidQt /// Remove the workspace and corresponding presenter. void remove(boost::shared_ptr<const Mantid::API::IPeaksWorkspace> peaksWS); /// Hide these peaks in the plot. - void CompositePeaksPresenter::setShown(boost::shared_ptr<const Mantid::API::IPeaksWorkspace> peaksWS, const bool shown); + void setShown(boost::shared_ptr<const Mantid::API::IPeaksWorkspace> peaksWS, const bool shown); + /// zoom in on a peak. + void zoomToPeak(boost::shared_ptr<const Mantid::API::IPeaksWorkspace> peaksWS, const int peakIndex); private: /// Alias for container of subjects type. typedef std::vector<PeaksPresenter_sptr> SubjectContainer; @@ -75,6 +78,8 @@ namespace MantidQt SubjectContainer::const_iterator getPresenterIteratorFromWorkspace(boost::shared_ptr<const Mantid::API::IPeaksWorkspace> ws) const; /// Colour pallette. PeakPalette m_palette; + /// Zoomable peaks view. + ZoomablePeaksView* const m_zoomablePlottingWidget; }; } } diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlayCross.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlayCross.h index f10b8e574554016f734dd9bbf2ceff3868fc5849..f60b89f0694362234cb0cc86d7aabe19cc6b53f3 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlayCross.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlayCross.h @@ -66,6 +66,8 @@ namespace SliceViewer virtual void changeForegroundColour(const QColor); /// Change background colour virtual void changeBackgroundColour(const QColor); + /// Get a bounding box for this peak. + virtual RectangleType getBoundingBox() const; private: diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlaySphere.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlaySphere.h index 7f91b3551168139b3762af6498f95e9052399f43..0931f6fec10af44ad1eda89ed159b4d8ea5260ef 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlaySphere.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlaySphere.h @@ -68,6 +68,8 @@ namespace SliceViewer virtual void changeBackgroundColour(const QColor); /// Show the background radius virtual void showBackgroundRadius(const bool show); + /// Get a bounding box for this peak. + virtual RectangleType getBoundingBox() const; private: diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlayView.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlayView.h index 0c4627c9a159679f0359595d1321a85b042fd49f..637411539437748bd23b31be893d559713008372 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlayView.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeakOverlayView.h @@ -2,16 +2,20 @@ #define MANTID_SLICEVIEWER_PEAKOVERLAY_VIEW_H_ #include "MantidKernel/System.h" +#include "MantidKernel/V2D.h" #include "MantidQtSliceViewer/PeakTransform.h" #include "MantidQtSliceViewer/PeakPalette.h" #include <QPointF> #include <boost/shared_ptr.hpp> +#include <boost/tuple/tuple.hpp> namespace MantidQt { namespace SliceViewer { + typedef boost::tuple<Mantid::Kernel::V2D, Mantid::Kernel::V2D> RectangleType; + /** Abstract view in MVP model representing a PeakOverlay. @date 2012-08-24 @@ -55,6 +59,8 @@ namespace MantidQt virtual void changeBackgroundColour(const QColor) = 0; /// Show the background radius virtual void showBackgroundRadius(const bool){} + /// Get a bounding box around the peak in windows coordinates. + virtual RectangleType getBoundingBox() const = 0; /// Destructor virtual ~PeakOverlayView() { diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeaksWorkspaceWidget.ui b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeaksWorkspaceWidget.ui index 1f3f56f54ce7fd127ec02c0da064c5da92653042..b17b54652ca32bcaca83238b0d1af829ac193926 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeaksWorkspaceWidget.ui +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PeaksWorkspaceWidget.ui @@ -218,84 +218,80 @@ </spacer> </item> <item> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Peak Color</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="btnPeakColor"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>20</width> - <height>0</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>20</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>8</width> - <height>8</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="label_3"> - <property name="minimumSize"> - <size> - <width>110</width> - <height>0</height> - </size> - </property> - <property name="text"> - <string>Peak Background Color</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="btnBackgroundColor"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>20</width> - <height>16777215</height> - </size> - </property> - <property name="text"> - <string/> - </property> - </widget> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Peak Color</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnPeakColor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>20</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_3"> + <property name="minimumSize"> + <size> + <width>110</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Peak Background Color</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnBackgroundColor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>20</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + </layout> </item> <item> <spacer name="horizontalSpacer_4"> diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PhysicalCrossPeak.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PhysicalCrossPeak.h index 9c8c413af987c9341f96185f27d90f3773addff2..ce92cec43ffdb76396c5cbdffb60130f901e410b 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PhysicalCrossPeak.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PhysicalCrossPeak.h @@ -5,6 +5,7 @@ #include "MantidKernel/V3D.h" #include "MantidKernel/ClassMacros.h" #include "MantidQtSliceViewer/PeakTransform.h" +#include "MantidQtSliceViewer/PeakOverlayView.h" namespace MantidQt { @@ -44,6 +45,11 @@ namespace MantidQt { return (m_opacityAtDistance != m_opacityMin); } + /// Get the bounding box. + RectangleType getBoundingBox() const; + /// Get the bounding box in windows coordinates. + RectangleType getBoundingBox(const double& windowHeight, const double& windowWidth, const double& viewWidth, const double& viewHeight) const; + private: /// Original origin x=h, y=k, z=l const Mantid::Kernel::V3D m_originalOrigin; diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PhysicalSphericalPeak.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PhysicalSphericalPeak.h index 35646d67ab4ba753f91c6204cb3f899b5ebfe543..c72be1a2d570c1d0309f0537dfda7b35e4107786 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PhysicalSphericalPeak.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/PhysicalSphericalPeak.h @@ -5,6 +5,7 @@ #include "MantidKernel/V3D.h" #include "MantidKernel/ClassMacros.h" #include "MantidQtSliceViewer/PeakTransform.h" +#include "MantidQtSliceViewer/PeakOverlayView.h" #include <boost/optional.hpp> namespace MantidQt @@ -78,6 +79,12 @@ namespace MantidQt /// Setter to command whether the background radius should also be shown. void showBackgroundRadius(const bool show); + /// Get the bounding box in natural coordinates. + RectangleType getBoundingBox() const; + + /// Get the bounding box in windows coordinates. + RectangleType getBoundingBox(const double& windowHeight, const double& windowWidth, const double& viewWidth, const double& viewHeight) const; + private: /// Original origin x=h, y=k, z=l const Mantid::Kernel::V3D m_originalOrigin; diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h index d642004e38c0c9041a129c9d8a45a5aada7ccef1..c1c1e8411eef9df118d63ab45cbbfed01d7e4dd6 100644 --- a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/SliceViewer.h @@ -14,6 +14,7 @@ #include "MantidQtSliceViewer/LineOverlay.h" #include "MantidQtSliceViewer/PeakTransformSelector.h" #include "MantidQtSliceViewer/PeaksPresenter.h" +#include "MantidQtSliceViewer/ZoomablePeaksView.h" #include "QwtRasterDataMD.h" #include "ui_SliceViewer.h" #include <QtCore/QtCore> @@ -43,7 +44,7 @@ class ProxyCompositePeaksPresenter; * along the other dimension(s). * */ -class EXPORT_OPT_MANTIDQT_SLICEVIEWER SliceViewer : public QWidget +class EXPORT_OPT_MANTIDQT_SLICEVIEWER SliceViewer : public QWidget, public ZoomablePeaksView { friend class SliceViewerWindow; @@ -99,6 +100,9 @@ public: /// Methods relating to peaks overlays. boost::shared_ptr<ProxyCompositePeaksPresenter> getPeaksPresenter() const; + /// Methods from implementation of ZoomablePeaksView. + virtual void zoomToRectangle(Mantid::Kernel::V2D& lowerLeft, Mantid::Kernel::V2D& upperRight); + signals: /// Signal emitted when the X/Y index of the shown dimensions is changed void changedShownDim(size_t dimX, size_t dimY); diff --git a/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/ZoomablePeaksView.h b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/ZoomablePeaksView.h new file mode 100644 index 0000000000000000000000000000000000000000..cd81aa73c26761944eaa19c07ead1c0fba93ea27 --- /dev/null +++ b/Code/Mantid/MantidQt/SliceViewer/inc/MantidQtSliceViewer/ZoomablePeaksView.h @@ -0,0 +1,70 @@ +#ifndef MANTID_SLICEVIEWER_ZOOMABLE_PEAKS_VIEW_H_ +#define MANTID_SLICEVIEWER_ZOOMABLE_PEAKS_VIEW_H_ + +#include "MantidKernel/System.h" +#include "MantidKernel/V2D.h" + +namespace MantidQt +{ + namespace SliceViewer + { + + /** Abstract view in Representing a view that can be zoomed in upon. + + @date 2013-01-08 + + Copyright © 2011 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + This file is part of Mantid. + + Mantid is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Mantid is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + File change history is stored at: <https://github.com/mantidproject/mantid> + Code Documentation is available at: <http://doxygen.mantidproject.org> + */ + class DLLExport ZoomablePeaksView + { + public: + /// Zoom to a peak position provided by a boundary rectangle in the windows coordinate system. + virtual void zoomToRectangle(Mantid::Kernel::V2D& lowerLeft, Mantid::Kernel::V2D& upperRight) = 0; + /// Destructor + virtual ~ZoomablePeaksView(){ } + }; + + /** + @class ZoomableAdapter + Templated adapter to zoom to peak. Alows objects from outside this type hierachy to be made to work seamlessly with it. + */ + template <class Adaptee> + class DLLExport ZoomableAdapter : public ZoomablePeaksView + { + private: + Adaptee * const _adaptee; + ZoomableAdapter& operator=(const ZoomableAdapter& other); + ZoomableAdapter(const ZoomableAdapter& other); + public: + ZoomableAdapter(Adaptee* const adaptee) : _adaptee(adaptee) + { + } + + void zoomToRectangle(Mantid::Kernel::V2D& lowerLeft, Mantid::Kernel::V2D& upperRight) + { + _adaptee.zoomToRectange(lowerLeft, upperRight); + } + virtual ~ZoomableAdapter(){ } + }; + } +} + +#endif /* MANTID_SLICEVIEWER_PEAKOVERLAY_VIEW_H_ */ \ No newline at end of file diff --git a/Code/Mantid/MantidQt/SliceViewer/src/CompositePeaksPresenter.cpp b/Code/Mantid/MantidQt/SliceViewer/src/CompositePeaksPresenter.cpp index 807df9429751782d9ff0e8354f7df3f19ea8118a..9ced43e0e9485a2745b00ceb8689398f715a4ba0 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/CompositePeaksPresenter.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/CompositePeaksPresenter.cpp @@ -8,8 +8,13 @@ namespace MantidQt /** Constructor */ - CompositePeaksPresenter::CompositePeaksPresenter(PeaksPresenter_sptr defaultPresenter) : m_default(defaultPresenter) + CompositePeaksPresenter::CompositePeaksPresenter(ZoomablePeaksView* const zoomablePlottingWidget, PeaksPresenter_sptr defaultPresenter) : m_zoomablePlottingWidget(zoomablePlottingWidget), + m_default(defaultPresenter) { + if(m_zoomablePlottingWidget == NULL) + { + throw std::runtime_error("Zoomable Plotting Widget is NULL"); + } } /** @@ -291,5 +296,10 @@ namespace MantidQt auto iterator = getPresenterIteratorFromWorkspace(peaksWS); (*iterator)->setShown(shown); } + + void CompositePeaksPresenter::zoomToPeak(boost::shared_ptr<const Mantid::API::IPeaksWorkspace> peaksWS, const int peakIndex) + { + //TODO + } } } diff --git a/Code/Mantid/MantidQt/SliceViewer/src/PeakOverlayCross.cpp b/Code/Mantid/MantidQt/SliceViewer/src/PeakOverlayCross.cpp index 3cce19d1f5b0b45944ba05c2ab6ae8cde0f67e48..3b0fe249945b3b272e5878e57ac1a786831736f1 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/PeakOverlayCross.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/PeakOverlayCross.cpp @@ -133,5 +133,13 @@ namespace SliceViewer // Do nothing with the background colour for a peak widget of this type. } + /** + @return bounding box for peak in windows coordinates. + */ + RectangleType PeakOverlayCross::getBoundingBox() const + { + throw std::runtime_error("Not implemented"); + } + } // namespace Mantid } // namespace SliceViewer \ No newline at end of file diff --git a/Code/Mantid/MantidQt/SliceViewer/src/PeakOverlaySphere.cpp b/Code/Mantid/MantidQt/SliceViewer/src/PeakOverlaySphere.cpp index f927e3a34860eeea63c0b5cb69db77dd8efa2d25..de610ad559acc86c0df71a7456df785998131933 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/PeakOverlaySphere.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/PeakOverlaySphere.cpp @@ -137,5 +137,13 @@ namespace SliceViewer m_physicalPeak.showBackgroundRadius(show); } + /** + @return bounding box for peak in windows coordinates. + */ + RectangleType PeakOverlaySphere::getBoundingBox() const + { + throw std::runtime_error("Not implemented"); + } + } // namespace Mantid } // namespace SliceViewer diff --git a/Code/Mantid/MantidQt/SliceViewer/src/PhysicalCrossPeak.cpp b/Code/Mantid/MantidQt/SliceViewer/src/PhysicalCrossPeak.cpp index 97944fd86fbd69975befb31530e53bc1f11a5282..bb2584c5fc97292e346a27b0b259a379e3ae95ac 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/PhysicalCrossPeak.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/PhysicalCrossPeak.cpp @@ -80,5 +80,44 @@ namespace MantidQt } return drawingObjects; } + + /** + @return bounding box for peak in natural coordinates. + */ + RectangleType PhysicalCrossPeak::getBoundingBox() const + { + using Mantid::Kernel::V2D; + V2D lowerLeft(m_origin.X() - m_effectiveRadius, m_origin.Y() - m_effectiveRadius); + V2D upperRight(m_origin.X() + m_effectiveRadius, m_origin.Y() + m_effectiveRadius); + return RectangleType(boost::make_tuple(lowerLeft, upperRight)); + } + + /** + @param windowHeight : height of the window in px + @param windowWidth : height of the window in px + @param viewWidth : width of the view area in natural coodinates + @param viewHeight : height of the view area in natural coordinates + @return bounding box for peak in windows coordinates. + */ + RectangleType PhysicalCrossPeak::getBoundingBox(const double& windowHeight, const double& windowWidth, const double& viewWidth, const double& viewHeight) const + { + using Mantid::Kernel::V2D; + // Scale factor for going from viewX to windowX + const double scaleYFactor = windowHeight/viewHeight; + // Scale factor for going from viewY to windowY + const double scaleXFactor = windowWidth/viewWidth; + + // Get the box in natural coordinates. + RectangleType boxInNaturalCoords = this->getBoundingBox(); + + const double expectedLowerLeftX = boxInNaturalCoords.get<0>().X() * scaleXFactor; + const double expectedLowerLeftY = boxInNaturalCoords.get<0>().Y() * scaleYFactor; + const double expectedUpperRightX = boxInNaturalCoords.get<1>().X() * scaleXFactor; + const double expectedUpperRightY = boxInNaturalCoords.get<1>().Y() * scaleYFactor; + + // Apply scaling. + return RectangleType(V2D(expectedLowerLeftX, expectedLowerLeftY), V2D(expectedUpperRightX, expectedUpperRightY)); + } + } } diff --git a/Code/Mantid/MantidQt/SliceViewer/src/PhysicalSphericalPeak.cpp b/Code/Mantid/MantidQt/SliceViewer/src/PhysicalSphericalPeak.cpp index c75b1cc190ef780e72fbe3a8653e3a6d93180132..837affebd38d253321126893e3c962b0ae5d1435 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/PhysicalSphericalPeak.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/PhysicalSphericalPeak.cpp @@ -117,9 +117,51 @@ namespace MantidQt return drawingObjects; } + /** + Setter for showing/hiding the background radius. + @param show: Flag indicating what to do. + */ void PhysicalSphericalPeak::showBackgroundRadius(const bool show) { m_showBackgroundRadius = show; } + + /** + @return bounding box for peak in natural coordinates. + */ + RectangleType PhysicalSphericalPeak::getBoundingBox() const + { + using Mantid::Kernel::V2D; + V2D lowerLeft(m_origin.X() - m_backgroundOuterRadius, m_origin.Y() - m_backgroundOuterRadius); + V2D upperRight(m_origin.X() + m_backgroundOuterRadius, m_origin.Y() + m_backgroundOuterRadius); + return RectangleType(boost::make_tuple(lowerLeft, upperRight)); + } + + /** + @param windowHeight : height of the window in px + @param windowWidth : height of the window in px + @param viewWidth : width of the view area in natural coodinates + @param viewHeight : height of the view area in natural coordinates + @return bounding box for peak in windows coordinates. + */ + RectangleType PhysicalSphericalPeak::getBoundingBox(const double& windowHeight, const double& windowWidth, const double& viewWidth, const double& viewHeight) const + { + using Mantid::Kernel::V2D; + // Scale factor for going from viewX to windowX + const double scaleYFactor = windowHeight/viewHeight; + // Scale factor for going from viewY to windowY + const double scaleXFactor = windowWidth/viewWidth; + + // Get the box in natural coordinates. + RectangleType boxInNaturalCoords = this->getBoundingBox(); + + const double expectedLowerLeftX = boxInNaturalCoords.get<0>().X() * scaleXFactor; + const double expectedLowerLeftY = boxInNaturalCoords.get<0>().Y() * scaleYFactor; + const double expectedUpperRightX = boxInNaturalCoords.get<1>().X() * scaleXFactor; + const double expectedUpperRightY = boxInNaturalCoords.get<1>().Y() * scaleYFactor; + + // Apply scaling. + return RectangleType(V2D(expectedLowerLeftX, expectedLowerLeftY), V2D(expectedUpperRightX, expectedUpperRightY)); + } } } \ No newline at end of file diff --git a/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp b/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp index 772dea9077f2ca099f057e070fb31023ccf5b892..05272ea2898020b42e9a623e52e6bec9a6ecb235 100644 --- a/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp +++ b/Code/Mantid/MantidQt/SliceViewer/src/SliceViewer.cpp @@ -102,7 +102,7 @@ SliceViewer::SliceViewer(QWidget *parent) m_fastRender(true), m_rebinMode(false), m_rebinLocked(true), - m_peaksPresenter(boost::make_shared<CompositePeaksPresenter>()), + m_peaksPresenter(boost::make_shared<CompositePeaksPresenter>(this)), m_peaksSliderWidget(NULL) { ui.setupUi(this); @@ -2272,6 +2272,16 @@ boost::shared_ptr<ProxyCompositePeaksPresenter> SliceViewer::getPeaksPresenter() return boost::make_shared<ProxyCompositePeaksPresenter>(m_peaksPresenter); } +/** +Zoom in upon a rectangle +@parm lower Left: rectangle lower left +@param upperRight, rectangle upper right +*/ +void SliceViewer::zoomToRectangle(Mantid::Kernel::V2D& lowerLeft, Mantid::Kernel::V2D& upperRight) +{ + this->setXYLimits(lowerLeft.X(), upperRight.X(), upperRight.Y(), lowerLeft.Y()); +} + } //namespace } diff --git a/Code/Mantid/MantidQt/SliceViewer/test/CompositePeaksPresenterTest.h b/Code/Mantid/MantidQt/SliceViewer/test/CompositePeaksPresenterTest.h index d86a0bef00277fdc8f11d137343ab1ede7f10d61..e3b4e0392c228cdaaf086a020c39b784cdf57010 100644 --- a/Code/Mantid/MantidQt/SliceViewer/test/CompositePeaksPresenterTest.h +++ b/Code/Mantid/MantidQt/SliceViewer/test/CompositePeaksPresenterTest.h @@ -16,14 +16,43 @@ using Mantid::API::IPeaksWorkspace_sptr; class CompositePeaksPresenterTest : public CxxTest::TestSuite { +private: + + class FakeZoomablePeaksView : public ZoomablePeaksView + { + public: + void zoomToRectangle(Mantid::Kernel::V2D&, Mantid::Kernel::V2D&) + { + } + virtual ~FakeZoomablePeaksView(){} + }; + + FakeZoomablePeaksView* _fakeZoomableView; + public: + CompositePeaksPresenterTest() : _fakeZoomableView(new FakeZoomablePeaksView) + { + } + + ~CompositePeaksPresenterTest() + { + delete _fakeZoomableView; + } + + + void test_construction_throws_if_zoomablePeakView__NULL() + { + TS_ASSERT_THROWS(CompositePeaksPresenter composite(NULL), std::runtime_error); + } + + void test_construction() { - CompositePeaksPresenter composite; - TSM_ASSERT_EQUALS("Should default construct with a NullPeaksPresenter", 0, composite.size()); + CompositePeaksPresenter composite(_fakeZoomableView); + TSM_ASSERT_EQUALS("Should default construct with a _fakeZoomableViewPeaksPresenter", 0, composite.size()); - /*After default construction, the composite presenter should behave identically to a NullPeaks presenter.*/ + /*After default construction, the composite presenter should behave identically to a NULL peaks presenter.*/ NullPeaksPresenter expected; TS_ASSERT_THROWS_NOTHING(expected.update()); TS_ASSERT_THROWS_NOTHING(composite.update()); @@ -35,7 +64,7 @@ public: void test_add_peaks_presenter() { - CompositePeaksPresenter presenter; + CompositePeaksPresenter presenter(_fakeZoomableView); const size_t initialSize = presenter.size(); presenter.addPeaksPresenter( boost::make_shared<MockPeaksPresenter>() ); TSM_ASSERT_EQUALS("Expected one item to be added.", initialSize + 1, presenter.size()); @@ -43,7 +72,7 @@ public: void test_keep_presenters_unique() { - CompositePeaksPresenter presenter; + CompositePeaksPresenter presenter(_fakeZoomableView); const size_t initialSize = presenter.size(); auto presenterToAdd = boost::make_shared<MockPeaksPresenter>(); presenter.addPeaksPresenter( presenterToAdd ); @@ -53,7 +82,7 @@ public: void test_clear() { - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); const size_t initialSize = composite.size(); composite.addPeaksPresenter( boost::make_shared<MockPeaksPresenter>() ); // Add one subject composite.addPeaksPresenter( boost::make_shared<MockPeaksPresenter>() ); // Add another subject @@ -62,7 +91,7 @@ public: TSM_ASSERT_EQUALS("Should be back to initial size after clearing.", initialSize, composite.size()); - /*After clearing, the composite presenter should behave identically to a NullPeaks presenter.*/ + /*After clearing, the composite presenter should behave identically to a _fakeZoomableViewPeaks presenter.*/ NullPeaksPresenter expected; TS_ASSERT_THROWS_NOTHING(expected.update()); TS_ASSERT_THROWS_NOTHING(composite.update()); @@ -83,7 +112,7 @@ public: EXPECT_CALL(*mockDefault, updateWithSlicePoint(_)).Times(1); // Expect the method on the default to be called. // Create the composite. - CompositePeaksPresenter composite(defaultPresenter); + CompositePeaksPresenter composite(_fakeZoomableView, defaultPresenter); // Call the method on the composite. composite.updateWithSlicePoint(0); @@ -97,7 +126,7 @@ public: EXPECT_CALL(*mockPresenter, updateWithSlicePoint(_)).Times(1); // Expect the method on the default to be called. // Create the composite. - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); // add the subject presenter. composite.addPeaksPresenter(presenter); // Call the method on the composite. @@ -124,7 +153,7 @@ public: EXPECT_CALL(*mockPresenter, getTransformName()).Times(1).WillOnce(Return("")); // Create the composite. - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); // add the subject presenter. composite.addPeaksPresenter(presenter); // Call the method on the composite. @@ -144,7 +173,7 @@ public: EXPECT_CALL(*mockDefault, update()).Times(1); // Expect the method on the default to be called. // Create the composite. - CompositePeaksPresenter composite(defaultPresenter); + CompositePeaksPresenter composite(_fakeZoomableView, defaultPresenter); // Call the method on the composite. composite.update(); @@ -158,7 +187,7 @@ public: EXPECT_CALL(*mockPresenter, update()).Times(1); // Expect the method on the default to be called. // Create the composite. - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); // add the subject presenter. composite.addPeaksPresenter(presenter); // Call the method on the composite. @@ -182,7 +211,7 @@ public: EXPECT_CALL(*pB, presentedWorkspaces()).WillOnce(Return(setB)); // Create the composite. - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); // add the subject presenter. composite.addPeaksPresenter(A); composite.addPeaksPresenter(B); @@ -198,7 +227,7 @@ public: const bool PASS = true; const bool FAIL = false; - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); MockPeaksPresenter* A = new MockPeaksPresenter; MockPeaksPresenter* B = new MockPeaksPresenter; @@ -246,7 +275,7 @@ public: const bool PASS = true; const bool FAIL = false; - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); MockPeaksPresenter* A = new MockPeaksPresenter; MockPeaksPresenter* B = new MockPeaksPresenter; @@ -291,7 +320,7 @@ public: void test_maximum_allowed_peaks() { - CompositePeaksPresenter presenter; + CompositePeaksPresenter presenter(_fakeZoomableView); // Add peaksWS const int limit = 10; for(int i = 0; i < limit; ++i) @@ -306,7 +335,7 @@ public: { PeakPalette actualDefaultPalette; - CompositePeaksPresenter presenter; + CompositePeaksPresenter presenter(_fakeZoomableView); PeakPalette presenterDefaultPalette = presenter.getPalette(); TSM_ASSERT_EQUALS("CompositePeaksPresenter should be using a default palette until changed.", actualDefaultPalette, presenterDefaultPalette); @@ -326,7 +355,7 @@ public: EXPECT_CALL(*pSubject, presentedWorkspaces()).WillOnce(Return(set)); // Set a background colour on the composite. - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); composite.addPeaksPresenter(subject); composite.setBackgroundColour(peaksWS, newColour); @@ -352,7 +381,7 @@ public: EXPECT_CALL(*pSubject, presentedWorkspaces()).WillOnce(Return(set)); // Set a background colour on the composite. - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); composite.addPeaksPresenter(subject); composite.setForegroundColour(peaksWS, newColour); @@ -396,7 +425,7 @@ public: EXPECT_CALL(*B, presentedWorkspaces()).WillRepeatedly(Return(setB)); // Set a background colour on the composite. - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); composite.addPeaksPresenter(subjectA); composite.addPeaksPresenter(subjectB); @@ -416,7 +445,7 @@ public: void test_remove_default() { - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); auto peaksWorkspace = boost::make_shared<Mantid::DataObjects::PeaksWorkspace>(); //Try to remove a peaks workspace & associated presenter that doesn't exist from a default constructed composite. @@ -435,7 +464,7 @@ public: EXPECT_CALL(*pSubject, presentedWorkspaces()).WillOnce(Return(set)); // Create the composite and add the test presenter. - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); composite.addPeaksPresenter(subject); // execute setshown(...) @@ -464,7 +493,7 @@ public: EXPECT_CALL(*mockDefault, setShown(expectedFlag)).Times(1); // Expect the method on the default to be called. // Create the composite. - CompositePeaksPresenter composite(defaultPresenter); + CompositePeaksPresenter composite(_fakeZoomableView, defaultPresenter); // Call the method on the composite. composite.setShown(boost::make_shared<Mantid::DataObjects::PeaksWorkspace>(), expectedFlag); @@ -481,7 +510,7 @@ public: EXPECT_CALL(*mockDefault, showBackgroundRadius(expectedFlag)).Times(1); // Expect the method on the default to be called. // Create the composite. - CompositePeaksPresenter composite(defaultPresenter); + CompositePeaksPresenter composite(_fakeZoomableView, defaultPresenter); // Call the method on the composite. composite.setBackgroundRadiusShown(boost::make_shared<Mantid::DataObjects::PeaksWorkspace>(), expectedFlag); @@ -490,13 +519,13 @@ public: void test_getBackroundColour_default() { - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); TSM_ASSERT_THROWS("Cannot fetch background colours until nested presenters have been added.", composite.getBackgroundColour(boost::make_shared<Mantid::DataObjects::PeaksWorkspace>()), std::runtime_error); } void test_getForegroundColour_default() { - CompositePeaksPresenter composite; + CompositePeaksPresenter composite(_fakeZoomableView); TSM_ASSERT_THROWS("Cannot fetch foreground colours until nested presenters have been added.", composite.getForegroundColour(boost::make_shared<Mantid::DataObjects::PeaksWorkspace>()), std::runtime_error); } diff --git a/Code/Mantid/MantidQt/SliceViewer/test/MockObjects.h b/Code/Mantid/MantidQt/SliceViewer/test/MockObjects.h index 20bc21083e21147bb194d5152f22f8c26e1a2066..06c48c62eaa26705f64c912e4b1e63da33eec339 100644 --- a/Code/Mantid/MantidQt/SliceViewer/test/MockObjects.h +++ b/Code/Mantid/MantidQt/SliceViewer/test/MockObjects.h @@ -8,6 +8,7 @@ #include "MantidQtSliceViewer/PeakTransformFactory.h" #include "MantidQtSliceViewer/PeakOverlayView.h" #include "MantidQtSliceViewer/PeakOverlayViewFactory.h" +#include "MantidQtSliceViewer/ZoomablePeaksView.h" #include "MantidAPI/IPeak.h" #include <boost/regex.hpp> #include <gmock/gmock.h> @@ -20,6 +21,16 @@ using boost::regex; namespace { + /*------------------------------------------------------------ + Zoomable Peaks View + ------------------------------------------------------------*/ + class MockZoomablePeaksView : public ZoomablePeaksView + { + public: + MOCK_METHOD2(zoomToRectangle, void(Mantid::Kernel::V2D&, Mantid::Kernel::V2D&)); + virtual ~MockZoomablePeaksView(){} + }; + /*------------------------------------------------------------ Mock Peaks Presenter ------------------------------------------------------------*/ @@ -83,6 +94,7 @@ class MockPeakTransformFactory : public PeakTransformFactory MOCK_METHOD1(changeForegroundColour, void(const QColor)); MOCK_METHOD1(changeBackgroundColour, void(const QColor)); MOCK_METHOD1(showBackgroundRadius, void(const bool)); + MOCK_CONST_METHOD0(getBoundingBox, RectangleType()); ~MockPeakOverlayView(){} }; diff --git a/Code/Mantid/MantidQt/SliceViewer/test/PhysicalCrossPeakTest.h b/Code/Mantid/MantidQt/SliceViewer/test/PhysicalCrossPeakTest.h index 426808340850f7b7d1d5c7529a7b89f38fed0d8a..7bc6491a8846547e9b8efef26eb8cf7e7218351d 100644 --- a/Code/Mantid/MantidQt/SliceViewer/test/PhysicalCrossPeakTest.h +++ b/Code/Mantid/MantidQt/SliceViewer/test/PhysicalCrossPeakTest.h @@ -119,6 +119,117 @@ public: TS_ASSERT(Mock::VerifyAndClearExpectations(pMockTransform)); } + + void test_getBoundingBox() + { + /* + + width = height = effectiveradius * 2 + |---------------| + | | + | | + | (0,0) | + | | + | | + |---------------| + + */ + V3D origin(0, 0, 0); + const double maxZ = 1; + const double minZ = 0; + PhysicalCrossPeak physicalPeak(origin, maxZ, minZ); + + // Pre-calculate the effective radius. + const double effectiveRadius = 0.015 * (maxZ - minZ); + + auto boundingBox = physicalPeak.getBoundingBox(); + auto lowerLeft = boundingBox.get<0>(); + auto upperRight = boundingBox.get<1>(); + + TS_ASSERT_EQUALS(V2D(-effectiveRadius, -effectiveRadius), lowerLeft); + TS_ASSERT_EQUALS(V2D(effectiveRadius, effectiveRadius), upperRight); + } + + void test_getBoundingBox_with_offset_origin() + { + /* + + width = height = effectiveradius * 2 + |---------------| + | | + | | + | (-1,1) | + | | + | | + |---------------| + + */ + + V3D origin(0, 0, 0); + const double maxZ = 1; + const double minZ = 0; + PhysicalCrossPeak physicalPeak(origin, maxZ, minZ); + + auto boundingBox = physicalPeak.getBoundingBox(); + auto lowerLeft = boundingBox.get<0>(); + auto upperRight = boundingBox.get<1>(); + + // Pre-calculate the effective radius. + const double effectiveRadius = 0.015 * (maxZ - minZ); + + const V2D expectedLowerLeft(origin.X() - effectiveRadius, origin.Y() - effectiveRadius); + const V2D expectedUpperRight(origin.X() + effectiveRadius, origin.Y() + effectiveRadius); + + TS_ASSERT_EQUALS(expectedLowerLeft, lowerLeft); + TS_ASSERT_EQUALS(expectedUpperRight, upperRight); + } + + void test_getBoundingBox_windows_coordinates() + { + /* + calculated in natural coords: width = height = outerradius * 2 + in windows coords: window height = 100, window width = 50 + |---------------| + | | + | | + | (0,0) | + | | + | | + |---------------| + + */ + + V3D origin(0, 0, 0); // Offset origin from (0, 0, 0) + const double maxZ = 1; + const double minZ = 0; + PhysicalCrossPeak physicalPeak(origin, maxZ, minZ); + + const double viewHeight = 1; + const double viewWidth = 1; + const double windowHeight = 100; + const double windowWidth = 50; + + auto boundingBox = physicalPeak.getBoundingBox(windowHeight, windowWidth, viewWidth, viewHeight); + auto lowerLeft = boundingBox.get<0>(); + auto upperRight = boundingBox.get<1>(); + + double scaleXFactor = windowWidth/viewWidth; // To convert the box into windows coordinates + double scaleYFactor = windowHeight/viewHeight; // To convert the box into windows coordinates + + // Pre-calculate the effective radius. + const double effectiveRadius = 0.015 * (maxZ - minZ); + + const double expectedLowerLeftX = (origin.X() - effectiveRadius) * scaleXFactor; + const double expectedLowerLeftY = (origin.Y() - effectiveRadius) * scaleYFactor; + const double expectedUpperRightX = (origin.X() + effectiveRadius) * scaleXFactor; + const double expectedUpperRightY = (origin.Y() + effectiveRadius) * scaleYFactor; + + TS_ASSERT_EQUALS(expectedLowerLeftX, lowerLeft.X()); + TS_ASSERT_EQUALS(expectedLowerLeftY, lowerLeft.Y()); + TS_ASSERT_EQUALS(expectedUpperRightX, upperRight.X()); + TS_ASSERT_EQUALS(expectedUpperRightY, upperRight.Y()); + } + }; //===================================================================================== diff --git a/Code/Mantid/MantidQt/SliceViewer/test/PhysicalSphericalPeakTest.h b/Code/Mantid/MantidQt/SliceViewer/test/PhysicalSphericalPeakTest.h index b2f46fe8654d7e14f157d1748e164c49e8a6f786..af480e50189748b47aec8e69a2aed8ae8036901f 100644 --- a/Code/Mantid/MantidQt/SliceViewer/test/PhysicalSphericalPeakTest.h +++ b/Code/Mantid/MantidQt/SliceViewer/test/PhysicalSphericalPeakTest.h @@ -166,6 +166,109 @@ public: TS_ASSERT(!physicalPeak.isViewableBackground()); } + void test_getBoundingBox() + { + /* + + width = height = outerradius * 2 + |---------------| + | | + | | + | (0,0) | + | | + | | + |---------------| + + */ + V3D origin(0, 0, 0); + const double radius = 1; // Not important + const double innerBackgroundRadius = 2; // Not important + const double outerBackgroundRadius = 3; // This should be used to control the bounding box. + PhysicalSphericalPeak physicalPeak(origin, radius, innerBackgroundRadius, outerBackgroundRadius); + + auto boundingBox = physicalPeak.getBoundingBox(); + auto lowerLeft = boundingBox.get<0>(); + auto upperRight = boundingBox.get<1>(); + + TS_ASSERT_EQUALS(V2D(-3, -3), lowerLeft); + TS_ASSERT_EQUALS(V2D(3, 3), upperRight); + } + + void test_getBoundingBox_with_offset_origin() + { + /* + + width = height = outerradius * 2 + |---------------| + | | + | | + | (-1,1) | + | | + | | + |---------------| + + */ + V3D origin(-1, 1, 0); // Offset origin from (0, 0, 0) + const double radius = 1; // Not important + const double innerBackgroundRadius = 2; // Not important + const double outerBackgroundRadius = 3; // This should be used to control the bounding box. + PhysicalSphericalPeak physicalPeak(origin, radius, innerBackgroundRadius, outerBackgroundRadius); + + auto boundingBox = physicalPeak.getBoundingBox(); + auto lowerLeft = boundingBox.get<0>(); + auto upperRight = boundingBox.get<1>(); + + const V2D expectedLowerLeft(origin.X() - outerBackgroundRadius, origin.Y() - outerBackgroundRadius); + const V2D expectedUpperRight(origin.X() + outerBackgroundRadius, origin.Y() + outerBackgroundRadius); + + TS_ASSERT_EQUALS(expectedLowerLeft, lowerLeft); + TS_ASSERT_EQUALS(expectedUpperRight, upperRight); + } + + void test_getBoundingBox_windows_coordinates() + { + /* + calculated in natural coords: width = height = outerradius * 2 + in windows coords: window height = 100, window width = 50 + |---------------| + | | + | | + | (0,0) | + | | + | | + |---------------| + + */ + + V3D origin(0, 0, 0); // Offset origin from (0, 0, 0) + const double radius = 1; // Not important + const double innerBackgroundRadius = 2; // Not important + const double outerBackgroundRadius = 3; // This should be used to control the bounding box. + PhysicalSphericalPeak physicalPeak(origin, radius, innerBackgroundRadius, outerBackgroundRadius); + + const double viewHeight = 1; + const double viewWidth = 1; + const double windowHeight = 100; + const double windowWidth = 50; + + auto boundingBox = physicalPeak.getBoundingBox(windowHeight, windowWidth, viewWidth, viewHeight); + auto lowerLeft = boundingBox.get<0>(); + auto upperRight = boundingBox.get<1>(); + + double scaleXFactor = windowWidth/viewWidth; // To convert the box into windows coordinates + double scaleYFactor = windowHeight/viewHeight; // To convert the box into windows coordinates + + const double expectedLowerLeftX = (origin.X() - outerBackgroundRadius) * scaleXFactor; + const double expectedLowerLeftY = (origin.Y() - outerBackgroundRadius) * scaleYFactor; + const double expectedUpperRightX = (origin.X() + outerBackgroundRadius) * scaleXFactor; + const double expectedUpperRightY = (origin.Y() + outerBackgroundRadius) * scaleYFactor; + + TS_ASSERT_EQUALS(expectedLowerLeftX, lowerLeft.X()); + TS_ASSERT_EQUALS(expectedLowerLeftY, lowerLeft.Y()); + TS_ASSERT_EQUALS(expectedUpperRightX, upperRight.X()); + TS_ASSERT_EQUALS(expectedUpperRightY, upperRight.Y()); + } + }; //=====================================================================================