diff --git a/slsDetectorSoftware/generator/Caller.in.h b/slsDetectorSoftware/generator/Caller.in.h index f1a3a2821..de91b2abc 100644 --- a/slsDetectorSoftware/generator/Caller.in.h +++ b/slsDetectorSoftware/generator/Caller.in.h @@ -21,6 +21,7 @@ class Caller { UdpDestination getUdpEntry(); int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand); void WrongNumberOfParameters(size_t expected); + std::vector parseRoiVector(const std::string &input); template std::string OutStringHex(const V &value) { if (value.equal()) diff --git a/slsDetectorSoftware/generator/commands.yaml b/slsDetectorSoftware/generator/commands.yaml index 3b96e48f5..1ae493055 100644 --- a/slsDetectorSoftware/generator/commands.yaml +++ b/slsDetectorSoftware/generator/commands.yaml @@ -1739,13 +1739,12 @@ readout: PUT: function: startDetectorReadout -# TODO -#rx_clearroi: -# inherit_actions: EXECUTE_SET_COMMAND_NOID -# help: "\n\tResets Region of interest in receiver. Default is all channels/pixels enabled." -# actions: -# PUT: -# function: clearRxROI +rx_clearroi: + inherit_actions: EXECUTE_SET_COMMAND_NOID + help: "\n\tResets Region of interest in receiver. Default is all channels/pixels enabled." + actions: + PUT: + function: clearRxROI ################# EXECUTE_SET_COMMAND ######################## start: @@ -2593,18 +2592,13 @@ rx_zmqip: PUT: argc: -1 -#TODO -#rx_roi: -# is_description: true -# actions: -# GET: -# argc: 0 -# PUT: -# args: -# - argc: 2 -# arg_types: [ int, int ] -# - argc: 4 -# arg_types: [ int, int, int, int ] +rx_roi: + is_description: true + actions: + GET: + argc: 0 + PUT: + argc: -1 ratecorr: is_description: true diff --git a/slsDetectorSoftware/include/sls/Detector.h b/slsDetectorSoftware/include/sls/Detector.h index fd85e427a..ae407f22b 100644 --- a/slsDetectorSoftware/include/sls/Detector.h +++ b/slsDetectorSoftware/include/sls/Detector.h @@ -988,13 +988,12 @@ class Detector { std::vector getRxROI() const; /** only at multi module level without gap pixels */ - void setRxROI(const std::vector& args); + void setRxROI(const std::vector &args); void clearRxROI(); int getNumberOfUdpPortsInRxROI() const; - ///@} /** @name File */ diff --git a/slsDetectorSoftware/src/Caller.cpp b/slsDetectorSoftware/src/Caller.cpp index 9fb08ff69..78a6f79d7 100644 --- a/slsDetectorSoftware/src/Caller.cpp +++ b/slsDetectorSoftware/src/Caller.cpp @@ -10594,7 +10594,7 @@ std::string Caller::rx_arping(int action) { return os.str(); } -/* + std::string Caller::rx_clearroi(int action) { std::ostringstream os; @@ -10637,7 +10637,7 @@ std::string Caller::rx_clearroi(int action) { return os.str(); } -*/ + std::string Caller::rx_dbitoffset(int action) { std::ostringstream os; diff --git a/slsDetectorSoftware/src/Caller.h b/slsDetectorSoftware/src/Caller.h index d1df0c0f2..5a667938f 100644 --- a/slsDetectorSoftware/src/Caller.h +++ b/slsDetectorSoftware/src/Caller.h @@ -21,6 +21,7 @@ class Caller { UdpDestination getUdpEntry(); int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand); void WrongNumberOfParameters(size_t expected); + std::vector parseRoiVector(const std::string &input); template std::string OutStringHex(const V &value) { if (value.equal()) @@ -233,7 +234,7 @@ class Caller { std::string runclk(int action); std::string runtime(int action); std::string rx_arping(int action); - //std::string rx_clearroi(int action); + std::string rx_clearroi(int action); std::string rx_dbitlist(int action); std::string rx_dbitoffset(int action); std::string rx_dbitreorder(int action); @@ -251,7 +252,7 @@ class Caller { std::string rx_padding(int action); std::string rx_printconfig(int action); std::string rx_realudpsocksize(int action); - //std::string rx_roi(int action); + std::string rx_roi(int action); std::string rx_silent(int action); std::string rx_start(int action); std::string rx_status(int action); @@ -580,7 +581,7 @@ class Caller { {"runclk", &Caller::runclk}, {"runtime", &Caller::runtime}, {"rx_arping", &Caller::rx_arping}, - //{"rx_clearroi", &Caller::rx_clearroi}, + {"rx_clearroi", &Caller::rx_clearroi}, {"rx_dbitlist", &Caller::rx_dbitlist}, {"rx_dbitoffset", &Caller::rx_dbitoffset}, {"rx_dbitreorder", &Caller::rx_dbitreorder}, @@ -598,7 +599,7 @@ class Caller { {"rx_padding", &Caller::rx_padding}, {"rx_printconfig", &Caller::rx_printconfig}, {"rx_realudpsocksize", &Caller::rx_realudpsocksize}, - //{"rx_roi", &Caller::rx_roi}, + {"rx_roi", &Caller::rx_roi}, {"rx_silent", &Caller::rx_silent}, {"rx_start", &Caller::rx_start}, {"rx_status", &Caller::rx_status}, diff --git a/slsDetectorSoftware/src/CallerSpecial.cpp b/slsDetectorSoftware/src/CallerSpecial.cpp index 394a9d5e7..033224ad8 100644 --- a/slsDetectorSoftware/src/CallerSpecial.cpp +++ b/slsDetectorSoftware/src/CallerSpecial.cpp @@ -719,50 +719,124 @@ std::string Caller::rx_zmqip(int action) { } return os.str(); } -/* TODO + std::string Caller::rx_roi(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { os << "[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in " - "receiver.\n\tOnly allowed at multi module level and without gap " + "receiver.\n\t" + << "For a list of rois, use '[' and '];' to distinguish between " + "rois and use comma inside the square brackets.\n\t" + << "For example: [0, 100, 0, 100];[200, 300, 0, 100] will set two " + "rois.\n\t" + << "Only allowed at multi module level and without gap " "pixels." << '\n'; } else if (action == defs::GET_ACTION) { if (!args.empty()) { WrongNumberOfParameters(0); } - if (det_id == -1) { - auto t = det->getRxROI(); - os << t << '\n'; + if (det_id != -1) { + throw RuntimeError("Cannot execute receiver ROI at module level"); } else { - auto t = det->getIndividualRxROIs(std::vector{det_id}); - os << t << '\n'; + auto t = det->getRxROI(); + // os << ToString(t) << '\n'; + for (const auto &r : t) { + os << r << ';'; + } + if (!t.empty()) { + os.seekp(-1, std::ios_base::end); // remove trailing ; + } + os << '\n'; } } else if (action == defs::PUT_ACTION) { - defs::ROI t; - // 2 or 4 arguments - if (args.size() != 2 && args.size() != 4) { - WrongNumberOfParameters(2); - } - if (args.size() == 2 || args.size() == 4) { + std::vector rois; + + // Support multiple args with bracketed ROIs, or single arg with + // semicolon-separated vector + bool isVectorInput = + std::all_of(args.begin(), args.end(), [](const std::string &a) { + return a.find('[') != std::string::npos && + a.find(']') != std::string::npos; + }); + + // previous format: 2 or 4 separate args + if ((args.size() == 2 || args.size() == 4) && !isVectorInput) { + defs::ROI t; t.xmin = StringTo(args[0]); t.xmax = StringTo(args[1]); + if (args.size() == 4) { + t.ymin = StringTo(args[2]); + t.ymax = StringTo(args[3]); + } + rois.emplace_back(t); + } else { + if (!isVectorInput) + WrongNumberOfParameters(2); + else { + for (const auto &arg : args) { + auto subRois = parseRoiVector(arg); + rois.insert(rois.end(), subRois.begin(), subRois.end()); + } + } } - if (args.size() == 4) { - t.ymin = StringTo(args[2]); - t.ymax = StringTo(args[3]); - } + // only multi level if (det_id != -1) { throw RuntimeError("Cannot execute receiver ROI at module level"); } - det->setRxROI(t); - os << t << '\n'; + + det->setRxROI(rois); + // os << ToString(rois) << '\n'; + for (const auto &r : rois) { + os << r << ';'; + } + if (!rois.empty()) { + os.seekp(-1, std::ios_base::end); // remove trailing ; + } + os << '\n'; } else { throw RuntimeError("Unknown action"); } return os.str(); -}*/ +} + +std::vector Caller::parseRoiVector(const std::string &input) { + std::vector rois; + std::stringstream ss(input); + std::string token; + + while (std::getline(ss, token, ';')) { + token.erase(std::remove_if(token.begin(), token.end(), ::isspace), + token.end()); + if (token.empty()) + continue; + if (token.front() != '[' || token.back() != ']') { + throw RuntimeError("Each ROI must be enclosed in square brackets: " + "[xmin,xmax,ymin,ymax]"); + } + token = token.substr(1, token.size() - 2); // remove brackets + std::vector parts; + std::stringstream inner(token); + std::string num; + while (std::getline(inner, num, ',')) { + parts.push_back(num); + } + + if (parts.size() != 4) { + throw RuntimeError("ROI must have 4 comma-separated integers"); + } + + defs::ROI roi; + roi.xmin = StringTo(parts[0]); + roi.xmax = StringTo(parts[1]); + roi.ymin = StringTo(parts[2]); + roi.ymax = StringTo(parts[3]); + rois.emplace_back(roi); + } + return rois; +} + std::string Caller::ratecorr(int action) { std::ostringstream os; if (action == defs::HELP_ACTION) { diff --git a/slsDetectorSoftware/src/Detector.cpp b/slsDetectorSoftware/src/Detector.cpp index 375faaeaa..785868e2d 100644 --- a/slsDetectorSoftware/src/Detector.cpp +++ b/slsDetectorSoftware/src/Detector.cpp @@ -1367,12 +1367,10 @@ void Detector::setRxArping(bool value, Positions pos) { pimpl->Parallel(&Module::setRxArping, pos, value); } -std::vector Detector::getRxROI() const { - return pimpl->getRxROI(); -} +std::vector Detector::getRxROI() const { return pimpl->getRxROI(); } // RxROIs can be set for all types except CTB. At multi level without gap pixels -void Detector::setRxROI(const std::vector& args) { +void Detector::setRxROI(const std::vector &args) { pimpl->setRxROI(args); } @@ -1380,7 +1378,6 @@ void Detector::clearRxROI() { pimpl->clearRxROI(); } int Detector::getNumberOfUdpPortsInRxROI() const { return pimpl->getNumberOfUdpPortsInRxROI(); - } // File diff --git a/slsDetectorSoftware/src/DetectorImpl.cpp b/slsDetectorSoftware/src/DetectorImpl.cpp index 6bd1ae8cc..34e58dc5f 100644 --- a/slsDetectorSoftware/src/DetectorImpl.cpp +++ b/slsDetectorSoftware/src/DetectorImpl.cpp @@ -31,7 +31,6 @@ namespace sls { - DetectorImpl::DetectorImpl(int detector_index, bool verify, bool update) : detectorIndex(detector_index), shm(detector_index, -1), ctb_shm(detector_index, -1, CtbConfig::shm_tag()) { @@ -536,7 +535,7 @@ void DetectorImpl::readFrameFromReceiver() { bool quadEnable = false; // to flip image bool eiger = false; - std::array rxRoi {};//TODO: get roi from json header + std::array rxRoi{}; // TODO: get roi from json header std::vector runningList(zmqSocket.size()); std::vector connectList(zmqSocket.size()); @@ -1703,44 +1702,53 @@ std::vector DetectorImpl::getRxROI() const { throw RuntimeError("No Modules added"); } - return std::vector{}; -//TODO + // return std::vector{}; + return rxRoiTemp; + // TODO } -bool DetectorImpl::roisOverlap(const defs::ROI& a, const defs::ROI& b) { - return !(a.xmax < b.xmin || a.xmin > b.xmax || - a.ymax < b.ymin || a.ymin > b.ymax); - +bool DetectorImpl::roisOverlap(const defs::ROI &a, const defs::ROI &b) { + return !(a.xmax < b.xmin || a.xmin > b.xmax || a.ymax < b.ymin || + a.ymin > b.ymax); } -void DetectorImpl::validateROIs(const std::vector& rois) { +void DetectorImpl::validateROIs(const std::vector &rois) { for (size_t i = 0; i < rois.size(); ++i) { - const auto& roi = rois[i]; + const auto &roi = rois[i]; if (roi.noRoi()) { throw RuntimeError("Invalid Roi of size 0. Roi: " + ToString(roi)); } if (roi.completeRoi()) { throw RuntimeError("Did you mean the clear roi command (API: " - "clearRxROI, cmd: rx_clearroi) Roi: " + ToString(roi) + "?"); + "clearRxROI, cmd: rx_clearroi) Roi: " + + ToString(roi) + "?"); } if (roi.xmin > roi.xmax || roi.ymin > roi.ymax) { throw RuntimeError( - "Invalid Roi. xmin/ymin exceeds xmax/ymax. Roi: " + ToString(roi)); + "Invalid Roi. xmin/ymin exceeds xmax/ymax. Roi: " + + ToString(roi)); } if (roi.xmin < 0 || roi.xmax >= shm()->numberOfChannels.x) { - throw RuntimeError("ROI x-dimension outside detector bounds. Roi: " + ToString(roi)); + throw RuntimeError( + "ROI x-dimension outside detector bounds. Roi: " + + ToString(roi)); } bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false); if (is2D) { if (roi.ymin < 0 || roi.ymax >= shm()->numberOfChannels.y) { - throw RuntimeError("ROI y-dimension outside detector bounds. Roi: " + ToString(roi)); + throw RuntimeError( + "ROI y-dimension outside detector bounds. Roi: " + + ToString(roi)); } } else { - if ((roi.ymin != -1 && roi.ymin != 0) || (roi.ymax != -1 && roi.ymax != 0)) { - throw RuntimeError("Invalid Y range for 1D detector: should be -1. Roi: " + ToString(roi)); + if ((roi.ymin != -1 && roi.ymin != 0) || + (roi.ymax != -1 && roi.ymax != 0)) { + throw RuntimeError( + "Invalid Y range for 1D detector: should be -1. Roi: " + + ToString(roi)); } } @@ -1753,7 +1761,7 @@ void DetectorImpl::validateROIs(const std::vector& rois) { } } -void DetectorImpl::setRxROI(const std::vector& args) { +void DetectorImpl::setRxROI(const std::vector &args) { if (shm()->detType == CHIPTESTBOARD || shm()->detType == defs::XILINX_CHIPTESTBOARD) { throw RuntimeError("RxRoi not implemented for this Detector"); @@ -1761,18 +1769,18 @@ void DetectorImpl::setRxROI(const std::vector& args) { if (modules.size() == 0) { throw RuntimeError("No Modules added"); } - + validateROIs(args); -//TODO + rxRoiTemp = args; + + // TODO } -void DetectorImpl::clearRxROI() { - ;// TODO: clear roi -} +void DetectorImpl::clearRxROI() { rxRoiTemp.clear(); } int DetectorImpl::getNumberOfUdpPortsInRxROI() const { - return 0;// TODO + return 0; // TODO } void DetectorImpl::getBadChannels(const std::string &fname, diff --git a/slsDetectorSoftware/src/DetectorImpl.h b/slsDetectorSoftware/src/DetectorImpl.h index c899566f2..b6a6af905 100644 --- a/slsDetectorSoftware/src/DetectorImpl.h +++ b/slsDetectorSoftware/src/DetectorImpl.h @@ -302,7 +302,7 @@ class DetectorImpl : public virtual slsDetectorDefs { verifyUniqueRxHost(const std::vector &names) const; std::vector getRxROI() const; - void setRxROI(const std::vector& args); + void setRxROI(const std::vector &args); void clearRxROI(); int getNumberOfUdpPortsInRxROI() const; @@ -427,8 +427,8 @@ class DetectorImpl : public virtual slsDetectorDefs { void verifyUniqueHost( bool isDet, std::vector> &hosts) const; - bool roisOverlap(const defs::ROI& a, const defs::ROI& b); - void validateROIs(const std::vector& rois); + bool roisOverlap(const defs::ROI &a, const defs::ROI &b); + void validateROIs(const std::vector &rois); const int detectorIndex{0}; SharedMemory shm{0, -1}; @@ -457,6 +457,8 @@ class DetectorImpl : public virtual slsDetectorDefs { void (*dataReady)(detectorData *, uint64_t, uint32_t, void *){nullptr}; void *pCallbackArg{nullptr}; + + std::vector rxRoiTemp; }; } // namespace sls \ No newline at end of file diff --git a/slsDetectorSoftware/src/Module.h b/slsDetectorSoftware/src/Module.h index a687be6c3..c84fa378b 100644 --- a/slsDetectorSoftware/src/Module.h +++ b/slsDetectorSoftware/src/Module.h @@ -301,9 +301,9 @@ class Module : public virtual slsDetectorDefs { std::array getReceiverThreadIds() const; bool getRxArping() const; void setRxArping(bool enable); - //defs::ROI getRxROI() const; - //void setRxROI(const slsDetectorDefs::ROI arg); - //void setRxROIMetadata(const slsDetectorDefs::ROI arg); + // defs::ROI getRxROI() const; + // void setRxROI(const slsDetectorDefs::ROI arg); + // void setRxROIMetadata(const slsDetectorDefs::ROI arg); /************************************************** * * diff --git a/slsDetectorSoftware/tests/CMakeLists.txt b/slsDetectorSoftware/tests/CMakeLists.txt index f70e393f2..d87f17ed0 100755 --- a/slsDetectorSoftware/tests/CMakeLists.txt +++ b/slsDetectorSoftware/tests/CMakeLists.txt @@ -5,7 +5,6 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-SharedMemory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-slsDetector.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test-Roi.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller-rx.cpp diff --git a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp index fcf0de97d..82bc1e2af 100644 --- a/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp +++ b/slsDetectorSoftware/tests/Caller/test-Caller-rx.cpp @@ -494,6 +494,42 @@ TEST_CASE("rx_roi", "[.cmdcall]") { REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT)); REQUIRE_THROWS( caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT)); + // vector of rois + { + std::ostringstream oss; + caller.call("rx_roi", {"[5, 10, -1, -1]; [25, 20, -1, -1]"}, -1, + PUT, oss); + REQUIRE(oss.str() == + "rx_roi [5, 10, -1, -1]; [25, 20, -1, -1]\n"); + } + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 20, -1, -1; 25, 30 -1, -1]"}, -1, PUT)); + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 20, -1]; [25, 30 -1, -1]"}, -1, PUT)); + // separated by space is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, -1, -1]", "[25, 28, -1, -1]"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("rx_roi", + {"[0, 10, -1, -1];[20, 30, -1, -1];[9, " + "10, -1, -1];[40, 50, -1, -1]"}, + -1, PUT)); + // overlapping rois + REQUIRE_THROWS(caller.call( + "rx_roi", {"[0, 10,-1, -1];[5, 15, -1, -1]"}, 0, PUT)); + // xmin > xmax + REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, -1, -1]"}, 0, PUT)); + // outside detector bounds + REQUIRE_THROWS( + caller.call("rx_roi", {"[95, 105, -1, -1]"}, 0, PUT)); + // module level not allowed + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 10, -1, -1]; [25, 28, -1, -1]"}, 0, PUT)); + // square brackets missing + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 20, -1, -1; 25, 30, -1, -1]"}, -1, PUT)); + // invalid roi, 4 parts expected + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 20, -1]; [25, 30, -1, -1]"}, -1, PUT)); } // 2d else { @@ -521,6 +557,39 @@ TEST_CASE("rx_roi", "[.cmdcall]") { } REQUIRE_THROWS( caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT)); + // vector of rois + { + std::ostringstream oss; + caller.call("rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, -1, + PUT, oss); + REQUIRE(oss.str() == + "rx_roi [5, 10, 20, 30];[25, 28, 14, 15]\n"); + } + // separated by space is allowed + REQUIRE_NOTHROW(caller.call( + "rx_roi", {"[5, 10, 20, 30]", "[25, 28, 14, 15]"}, -1, PUT)); + REQUIRE_NOTHROW(caller.call("rx_roi", + {"[0, 10, 0, 10];[20, 30, 0, 10];[0, " + "10, 20, 30];[40, 50, 0, 10]"}, + -1, PUT)); + // overlapping rois + REQUIRE_THROWS(caller.call( + "rx_roi", {"[0, 10, 0, 10];[5, 15, 0, 10]"}, 0, PUT)); + // xmin > xmax + REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, 0, 10]"}, 0, PUT)); + // ymin > ymax + REQUIRE_THROWS(caller.call("rx_roi", {"[0, 10, 20, 5]"}, 0, PUT)); + // outside detector bounds + REQUIRE_THROWS(caller.call("rx_roi", {"[95, 105, 0, 10]"}, 0, PUT)); + // module level not allowed + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 10, 20, 30]; [25, 28, 14, 15]"}, 0, PUT)); + // square brackets missing + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 20, 20, 30; 25, 30, 14, 15]"}, -1, PUT)); + // invalid roi, 4 parts expected + REQUIRE_THROWS(caller.call( + "rx_roi", {"[5, 20, 20]; [25, 30, 14, 15]"}, -1, PUT)); } for (int i = 0; i != det.size(); ++i) { diff --git a/slsDetectorSoftware/tests/test-Roi.cpp b/slsDetectorSoftware/tests/test-Roi.cpp deleted file mode 100644 index 9ce6c3b30..000000000 --- a/slsDetectorSoftware/tests/test-Roi.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "catch.hpp" -#include - -#include - -#include "DetectorImpl.h" -#include "sls/Detector.h" -#include "Module.h" - -#include - -namespace sls { - -TEST_CASE("ROI validation") { - DetectorImpl det(0, false, false); - det.addTestModule(slsDetectorDefs::JUNGFRAU); - std::cout << "size:"<< det.size() << std::endl; - DetectorImpl detector(0, false, false); - - SECTION("Valid non-overlapping ROIs") { - std::vector rois = { - {0, 10, 0, 10}, - {20, 30, 0, 10}, - {0, 10, 20, 30}, - {40, 50, 0, 10} - }; - REQUIRE_NOTHROW(DetectorImplTestHelper::testValidateRois(detector, rois)); - } - - SECTION("Overlapping ROIs should throw") { - std::vector rois = { - {0, 10, 0, 10}, - {5, 15, 0, 10} - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } - - SECTION("Invalid ROI (xmin > xmax)") { - std::vector rois = { - {12, 8, 0, 10} - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } - - SECTION("Invalid ROI (ymin > ymax)") { - std::vector rois = { - {0, 10, 20, 5} - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } - - SECTION("Invalid ROI (outside detector bounds)") { - // Assuming detector has 100x100 dimensions - detector.setNumberOfChannels({100, 100}); - std::vector rois = { - {95, 105, 0, 10} // xmax out of bounds - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } - - SECTION("Valid ROI for 1D detector") { - detector.setNumberOfChannels({100, 1}); - std::vector rois = { - {10, 20, -1, -1} - }; - REQUIRE_NOTHROW(DetectorImplTestHelper::testValidateRois(detector, rois)); - } - - SECTION("Invalid Y for 1D detector") { - detector.setNumberOfChannels({100, 1}); - std::vector rois = { - {10, 20, 0, 10} // Y should be -1 for 1D - }; - REQUIRE_THROWS_AS(DetectorImplTestHelper::testValidateRois(detector, rois), - sls::RuntimeError); - } -} - - -} // namespace sls diff --git a/slsSupportLib/include/sls/ToString.h b/slsSupportLib/include/sls/ToString.h index ea97a8436..55d6b628b 100644 --- a/slsSupportLib/include/sls/ToString.h +++ b/slsSupportLib/include/sls/ToString.h @@ -348,5 +348,23 @@ std::vector StringTo(const std::vector &strings) { result.push_back(StringTo(s)); return result; } +/* +template +std::string ToString(const std::vector &vec) { + std::ostringstream oss; + oss << "["; + for (size_t i = 0; i < vec.size(); ++i) { + oss << vec[i]; + if (i != vec.size() - 1) + oss << ", "; + } + oss << "]"; + return oss.str(); +}*/ + +/*template +std::ostream &operator<<(std::ostream &os, const std::vector &v) { + return os << ToString(v); +}*/ } // namespace sls