diff --git a/Core/Algorithms/inc/DetectorMask.h b/Core/Algorithms/inc/DetectorMask.h index 82afdddd92a3186e036cc4a45b76bc7deb2a050b..5635df084ae85cc3dfabcb7ef966259c85022791 100644 --- a/Core/Algorithms/inc/DetectorMask.h +++ b/Core/Algorithms/inc/DetectorMask.h @@ -35,6 +35,8 @@ class BA_CORE_API_ DetectorMask { public: DetectorMask(); + DetectorMask(const DetectorMask &other); + DetectorMask &operator=(const DetectorMask &other); //! Add mask to the stack of detector masks. The value "true" means that the area will //! be excluded from the analysis. @@ -49,9 +51,15 @@ public: const OutputData<bool>* getMaskData() const; + // clear all masks and return object to initial state + void clear(); + private: + //! swap function + void swapContent(DetectorMask &other); + SafePointerVector<Geometry::IShape2D> m_shapes; - std::map<const Geometry::IShape2D *, bool> m_shape_to_mask; + std::vector<bool> m_mask_of_shape; OutputData<bool> m_mask_data; }; diff --git a/Core/Algorithms/src/DetectorMask.cpp b/Core/Algorithms/src/DetectorMask.cpp index b1e085b72a076381e6a595048f9960f34062c160..c3c4c197d150427467289e49ccf1701cd6052dd2 100644 --- a/Core/Algorithms/src/DetectorMask.cpp +++ b/Core/Algorithms/src/DetectorMask.cpp @@ -16,6 +16,7 @@ #include "DetectorMask.h" #include "IShape2D.h" #include "Detector.h" +#include "BornAgainNamespace.h" // InfinitePlane, Line, VerticalLine, HorizontalLine, Ellipse, Rectangle @@ -24,34 +25,58 @@ // // Polygon stdvector<stdvector<double>> constructor +DetectorMask::DetectorMask() +{ + +} + +DetectorMask::DetectorMask(const DetectorMask &other) + : m_shapes(other.m_shapes) + , m_mask_of_shape(other.m_mask_of_shape) +{ + m_mask_data.copyFrom(other.m_mask_data); +} + +DetectorMask &DetectorMask::operator=(const DetectorMask &other) +{ + if (this != &other) { + DetectorMask tmp(other); + tmp.swapContent(*this); + } + return *this; + +} + void DetectorMask::addMask(const Geometry::IShape2D &shape, bool mask_value) { - Geometry::IShape2D *clone = shape.clone(); - m_shapes.push_back(clone); - m_shape_to_mask[clone] = mask_value; + m_shapes.push_back(shape.clone()); + m_mask_of_shape.push_back(mask_value); + m_mask_data.clear(); } void DetectorMask::initMaskData(const Detector &detector) { m_mask_data.clear(); - if(!m_shapes.size()) return; - - assert(m_shapes.size() == m_shape_to_mask.size()); for (size_t dim=0; dim<detector.getDimension(); ++dim) { m_mask_data.addAxis(detector.getAxis(dim)); } m_mask_data.setAllTo(false); - // setting mask to the data starting from last shape added + if(!m_shapes.size()) return; + assert(m_shapes.size() == m_mask_of_shape.size()); + for(size_t index=0; index<m_mask_data.getAllocatedSize(); ++index) { - double x = m_mask_data.getAxisValue(index, 0); - double y = m_mask_data.getAxisValue(index, 1); + Bin1D binx = m_mask_data.getAxisBin(index, BornAgain::X_AXIS_INDEX); + Bin1D biny = m_mask_data.getAxisBin(index, BornAgain::Y_AXIS_INDEX); + // setting mask to the data starting from last shape added for(size_t i_shape=m_shapes.size(); i_shape>0; --i_shape) { const Geometry::IShape2D *shape = m_shapes[i_shape-1]; - if(shape->contains(x, y)) { - m_mask_data[index] = m_shape_to_mask[shape]; + //std::cout << " index:" << index << " i_shape:" << i_shape << " number of shapes:" << m_shapes.size() << std::endl; + if(shape->contains(binx, biny)) { + m_mask_data[index] = m_mask_of_shape[i_shape-1]; // if given index is covered by the shape, stop looking further + //std::cout << " break! mask of shape" << m_mask_of_shape[i_shape-1] << std::endl; break; } } @@ -70,3 +95,17 @@ const OutputData<bool> *DetectorMask::getMaskData() const { return &m_mask_data; } + +void DetectorMask::clear() +{ + m_shapes.clear(); + m_mask_of_shape.clear(); + m_mask_data.clear(); +} + +void DetectorMask::swapContent(DetectorMask &other) +{ + std::swap(this->m_shapes, other.m_shapes); + std::swap(this->m_mask_of_shape, other.m_mask_of_shape); + this->m_mask_data.copyFrom(other.m_mask_data); +} diff --git a/Core/Geometry/src/Polygon.cpp b/Core/Geometry/src/Polygon.cpp index e61653ff5d8c6708ae78476e6acee5e055f12357..81ecef6dbe0b8311ed8c426756fed27a02adfbed 100644 --- a/Core/Geometry/src/Polygon.cpp +++ b/Core/Geometry/src/Polygon.cpp @@ -69,7 +69,7 @@ Polygon *Polygon::clone() const bool Polygon::contains(double x, double y) const { // return within(PolygonPrivate::point_t(x, y), m_d->polygon); // not including borders - return covered_by(PolygonPrivate::point_t(x, y), m_d->polygon); + return covered_by(PolygonPrivate::point_t(x, y), m_d->polygon); // including borders } bool Polygon::contains(const Bin1D &binx, const Bin1D &biny) const @@ -87,16 +87,6 @@ void Polygon::print(std::ostream &ostr) const ostr << wkt<PolygonPrivate::polygon_t>(m_d->polygon); } -//double Polygon::getData() const -//{ -// return m_d->m_x; -//} - -//void Polygon::setData(double value) const -//{ -// m_d->m_x = value; -//} - Polygon::Polygon(const Polygon &other) { m_d = new PolygonPrivate(*other.m_d); diff --git a/Core/Tools/inc/BornAgainNamespace.h b/Core/Tools/inc/BornAgainNamespace.h index c3f0120cda2bbf78ed4cdbfddea1af2d005da4fe..db4787a57e522e2ff68cb0c524a84753be58811a 100644 --- a/Core/Tools/inc/BornAgainNamespace.h +++ b/Core/Tools/inc/BornAgainNamespace.h @@ -24,6 +24,8 @@ namespace BornAgain static const std::string ALPHA_AXIS_NAME = "alpha_f"; static const size_t PHI_AXIS_INDEX = 0; static const size_t ALPHA_AXIS_INDEX = 1; + static const size_t X_AXIS_INDEX = 0; + static const size_t Y_AXIS_INDEX = 1; const std::string FTDistribution2DCauchyType = "FTDistribution2DCauchy"; const std::string FTDistribution2DGaussType = "FTDistribution2DGauss"; diff --git a/Core/Tools/inc/OutputData.h b/Core/Tools/inc/OutputData.h index b4d5dd96f6487e739831f19147041e6e9f6c01a4..70d8e2098de18ac38480f46e285919b2a23ff582 100644 --- a/Core/Tools/inc/OutputData.h +++ b/Core/Tools/inc/OutputData.h @@ -174,6 +174,12 @@ public: //! @return Vector of corresponding bin centers std::vector<double > getAxesValues(size_t global_index) const; + //! Returns bin of selected axis for given global_index. + //! @param global_index The global index of this data structure. + //! @param i_selected_axis Serial number of selected axis. + //! @return Corresponding Bin1D object + Bin1D getAxisBin(size_t global_index, size_t i_selected_axis) const; + //! Returns bin of selected axis for given global_index. //! @param global_index The global index of this data structure. //! @param axis_name The name of selected axis. @@ -561,18 +567,17 @@ std::vector<double> OutputData<T>::getAxesValues(size_t global_index) const return result; } +template <class T> +Bin1D OutputData<T>::getAxisBin(size_t global_index, size_t i_selected_axis) const +{ + int axis_index = getAxisBinIndex(global_index, i_selected_axis); + return m_value_axes[i_selected_axis]->getBin(axis_index); +} + template <class T> Bin1D OutputData<T>::getAxisBin(size_t global_index, const std::string& axis_name) const { - for (size_t i=0; i<m_value_axes.size(); ++i) { - if (m_value_axes[i]->getName() == axis_name) { - int axis_index = getAxisBinIndex(global_index, i); - return m_value_axes[i]->getBin(axis_index); - } - } - throw LogicErrorException( - "OutputData<T>::getAxisBin() -> " - "Error! Axis with given name not found '" + axis_name + "'"); + return getAxisBin(global_index, getAxisSerialNumber(axis_name)); } template<class T> @@ -648,6 +653,7 @@ bool OutputData<T>::isInitialized() const { if(!mp_ll_data) return false; if(getRank() != mp_ll_data->getRank()) return false; + if(!getRank()) return false; return true; } diff --git a/Tests/UnitTests/TestCore/DetectorMaskTest.h b/Tests/UnitTests/TestCore/DetectorMaskTest.h new file mode 100644 index 0000000000000000000000000000000000000000..c8a40037ea67a526eb15241fd85628b04a816820 --- /dev/null +++ b/Tests/UnitTests/TestCore/DetectorMaskTest.h @@ -0,0 +1,133 @@ +#ifndef DETECTORMASKTEST_H +#define DETECTORMASKTEST_H + +#include "DetectorMask.h" +#include "Detector.h" +#include "gtest/gtest.h" +#include <boost/scoped_ptr.hpp> +#include <boost/assign/list_of.hpp> + +class DetectorMaskTest : public ::testing::Test +{ +public: +}; + + +TEST_F(DetectorMaskTest, InitialState) +{ + DetectorMask test; + EXPECT_THROW(test.getMask(0), LogicErrorException); + EXPECT_FALSE(test.getMaskData()->isInitialized()); +} + + +// 4.0 ------------------------------------------------------------------------- +// | 5 | 11 | 17 | 23 | 29 | 35 | 41 | 47 | 53 | 59 | 65 | 71 | +// 3.0 ------------------------------------------------------------------------- +// | 4 | 10 | 16 | 22 | 28 | 34 | 40 | 46 | 52 | 58 | 64 | 70 | +// 2.0 ------------------------------------------------------------------------- +// | 3 | 9 | 15 | 21 | 27 | 33 | 39 | 45 | 51 | 57 | 63 | 69 | +// 1.0 ------------------------------------------------------------------------- +// | 2 | 8 | 14 | 20 | 26 | 32 | 38 | 44 | 50 | 56 | 62 | 68 | +// 0.0 ------------------------------------------------------------------------- +// | 1 | 7 | 13 | 19 | 25 | 31 | 37 | 43 | 49 | 55 | 61 | 67 | +// -1.0 ------------------------------------------------------------------------- +// | 0 | 6 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60 | 66 | +// -2.0 ------------------------------------------------------------------------- +// -4.0 -3.0 -2.0 -1.0 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 + +TEST_F(DetectorMaskTest, AddMask) +{ + DetectorMask detectorMask; + + std::vector<double> x = boost::assign::list_of(4.0)(-4.0)(-4.0)(4.0)(4.0); + std::vector<double> y = boost::assign::list_of(2.0)(2.0)(-2.0)(-2.0)(2.0); + Geometry::Polygon polygon(x, y); + + Detector detector; + detector.addAxis(FixedBinAxis("x-axis", 12, -4.0, 8.0)); + detector.addAxis(FixedBinAxis("y-axis", 6, -2.0, 4.0)); + + // initializing mask with detector and one shape + detectorMask.addMask(polygon, true); + detectorMask.initMaskData(detector); + + EXPECT_TRUE(detectorMask.getMaskData()->isInitialized()); + + for(size_t index=0; index<detectorMask.getMaskData()->getAllocatedSize(); ++index) { + double x = detectorMask.getMaskData()->getAxisValue(index, 0); + double y = detectorMask.getMaskData()->getAxisValue(index, 1); + if( x>= -4.0 && x <=4.0 && y>=-2.0 && y<=2.0) { + EXPECT_TRUE(detectorMask.getMask(index)); + } else { + EXPECT_FALSE(detectorMask.getMask(index)); + } + } + + // adding second mask of same size which discard previous one + detectorMask.addMask(polygon, false); + detectorMask.initMaskData(detector); + + for(size_t index=0; index<detectorMask.getMaskData()->getAllocatedSize(); ++index) { + EXPECT_FALSE(detectorMask.getMask(index)); + } + + // adding third mask + x = boost::assign::list_of(5.0)(5.0)(8.0)(8.0)(5.0); + y = boost::assign::list_of(2.0)(4.0)(4.0)(2.0)(2.0); + detectorMask.addMask(Geometry::Polygon(x, y), true); + detectorMask.initMaskData(detector); + for(size_t index=0; index<detectorMask.getMaskData()->getAllocatedSize(); ++index) { + double x = detectorMask.getMaskData()->getAxisValue(index, 0); + double y = detectorMask.getMaskData()->getAxisValue(index, 1); + if( x>= 5.0 && x <=8.0 && y>=2.0 && y<=4.0) { + EXPECT_TRUE(detectorMask.getMask(index)); + } else { + EXPECT_FALSE(detectorMask.getMask(index)); + } + } + + // clearing all masks + detectorMask.clear(); + detectorMask.initMaskData(detector); + for(size_t index=0; index<detectorMask.getMaskData()->getAllocatedSize(); ++index) { + EXPECT_FALSE(detectorMask.getMask(index)); + } + +} + + +TEST_F(DetectorMaskTest, AssignmentOperator) +{ + DetectorMask detectorMask; + + std::vector<double> x = boost::assign::list_of(4.0)(-4.0)(-4.0)(4.0)(4.0); + std::vector<double> y = boost::assign::list_of(2.0)(2.0)(-2.0)(-2.0)(2.0); + Geometry::Polygon polygon(x, y); + + Detector detector; + detector.addAxis(FixedBinAxis("x-axis", 12, -4.0, 8.0)); + detector.addAxis(FixedBinAxis("y-axis", 6, -2.0, 4.0)); + + // initializing mask with detector and one shape + detectorMask.addMask(polygon, true); + detectorMask.initMaskData(detector); + + DetectorMask mask = detectorMask; + + EXPECT_TRUE(mask.getMaskData()->isInitialized()); + + for(size_t index=0; index<mask.getMaskData()->getAllocatedSize(); ++index) { + double x = mask.getMaskData()->getAxisValue(index, 0); + double y = mask.getMaskData()->getAxisValue(index, 1); + if( x>= -4.0 && x <=4.0 && y>=-2.0 && y<=2.0) { + EXPECT_TRUE(mask.getMask(index)); + } else { + EXPECT_FALSE(mask.getMask(index)); + } + } + +} + + +#endif diff --git a/Tests/UnitTests/TestCore/OutputDataTest.h b/Tests/UnitTests/TestCore/OutputDataTest.h index b3b81c67e9f0d329264e5f243f974b22ddac82f1..616d3c50551660480c5ad673c4c3da41dfbd2dcc 100644 --- a/Tests/UnitTests/TestCore/OutputDataTest.h +++ b/Tests/UnitTests/TestCore/OutputDataTest.h @@ -89,15 +89,15 @@ TEST_F(OutputDataTest, DataInitialization) EXPECT_EQ(Eigen::Matrix2d::Identity(), matrix_data_2d[matrix_data_2d.toGlobalIndex(coordinates2)]); } -//TEST_F(OutputDataTest, isInitialized) -//{ -// OutputData<double> data1; -// EXPECT_FALSE(data1.isInitialized()); -// data1.addAxis("axis", 10, 0.0, 10.0); -// EXPECT_TRUE(data1.isInitialized()); -// data1.clear(); -// EXPECT_FALSE(data1.isInitialized()); -//} +TEST_F(OutputDataTest, isInitialized) +{ + OutputData<double> data1; + EXPECT_FALSE(data1.isInitialized()); + data1.addAxis("axis", 10, 0.0, 10.0); + EXPECT_TRUE(data1.isInitialized()); + data1.clear(); + EXPECT_FALSE(data1.isInitialized()); +} TEST_F(OutputDataTest, DataCopying) { @@ -224,6 +224,29 @@ TEST_F(OutputDataTest, ValueOfAxis) EXPECT_EQ( 7.5, mdata.getAxisValue(19, "axis2")); } +// y | +// -------------------------------------------- +// 1 | 1 3 5 7 9 11 13 15 17 19 | +// 0 | 0 2 4 6 8 10 12 14 16 18 | +// -------------------------------------------- +// | 0 1 2 3 4 5 6 7 8 9 | x +TEST_F(OutputDataTest, GetAxisBin) +{ + OutputData<double > data; + data.addAxis("axis1", 10, 0., 10.); + data.addAxis("axis2", 2, 0., 10.); + + EXPECT_EQ(0.5, data.getAxisBin(0, "axis1").getMidPoint()); + EXPECT_EQ(0.5, data.getAxisBin(1, "axis1").getMidPoint()); + EXPECT_EQ(9.5, data.getAxisBin(18, "axis1").getMidPoint()); + EXPECT_EQ(9.5, data.getAxisBin(19, "axis1").getMidPoint()); + EXPECT_EQ(2.5, data.getAxisBin(0, "axis2").getMidPoint()); + EXPECT_EQ(7.5, data.getAxisBin(1, "axis2").getMidPoint()); + EXPECT_EQ(2.5, data.getAxisBin(18, "axis2").getMidPoint()); + EXPECT_EQ(7.5, data.getAxisBin(19, "axis2").getMidPoint()); +} + + // y | // -------------------------------------------- diff --git a/Tests/UnitTests/TestCore/PolygonTest.h b/Tests/UnitTests/TestCore/PolygonTest.h index 8607d84bbfe26cc5b73f04db8c0dd1b04eee4c8b..72bf43fb4034a8f5d58a0595ff609e1e84618f8e 100644 --- a/Tests/UnitTests/TestCore/PolygonTest.h +++ b/Tests/UnitTests/TestCore/PolygonTest.h @@ -37,7 +37,6 @@ TEST_F(PolygonTest, SimpleRectangle) EXPECT_TRUE(polygon2.contains(-4.0, -2.0)); EXPECT_FALSE(polygon2.contains(0.0, 2.01)); EXPECT_FALSE(polygon2.contains(4.0, -2.01)); - } // ******* @@ -53,7 +52,7 @@ TEST_F(PolygonTest, SandWatchShape) std::vector<double> x = boost::assign::list_of(2.0)(-2.0)(2.0)(-2.0)(2.0); std::vector<double> y = boost::assign::list_of(2.0)(2.0)(-2.0)(-2.0)(2.0); Geometry::Polygon polygon(x, y); - std::cout << polygon << std::endl; +// std::cout << polygon << std::endl; // for some reason area calculation doesn't work for boost's polygon of such shape // EXPECT_DOUBLE_EQ(8.0, polygon.getArea()); @@ -68,6 +67,23 @@ TEST_F(PolygonTest, SandWatchShape) } +TEST_F(PolygonTest, ContainsBin) +{ + // simple closed rectangle + std::vector<double> x = boost::assign::list_of(4.0)(-4.0)(-4.0)(4.0)(4.0); + std::vector<double> y = boost::assign::list_of(2.0)(2.0)(-2.0)(-2.0)(2.0); + Geometry::Polygon polygon(x, y); + + Bin1D binx1(3.5, 4.5); + Bin1D biny1(1.5, 2.5); + EXPECT_TRUE(polygon.contains(binx1, biny1)); + + Bin1D binx2(3.5, 4.6); + Bin1D biny2(1.5, 2.6); + EXPECT_FALSE(polygon.contains(binx2, biny2)); +} + + TEST_F(PolygonTest, Clone) { std::vector<double> x = boost::assign::list_of(4.0)(-4.0)(-4.0)(4.0)(4.0); diff --git a/Tests/UnitTests/TestCore/main.cpp b/Tests/UnitTests/TestCore/main.cpp index bf4513f0e06e0cceb49b5b1089e9d7979db4dab6..98a456f7af9d2767d39211badcd47ef328a6f141 100644 --- a/Tests/UnitTests/TestCore/main.cpp +++ b/Tests/UnitTests/TestCore/main.cpp @@ -54,6 +54,7 @@ #include "Histogram1DTest.h" #include "Histogram2DTest.h" #include "PolygonTest.h" +#include "DetectorMaskTest.h"