/*! * \file CyclopsGrid.h * \date 2019/12/03 * * \author Lin, Chi * Contact: lin.chi@hzleaper.com * * * \note */ #ifndef __CyclopsGrid_h_ #define __CyclopsGrid_h_ #include #include #include #include "CVUtils.h" #include "CyclopsParam.h" struct CyclopsGrid { virtual void serialize(FileStorage& fs) const = 0; virtual void deserialize(const FileNode& node) = 0; virtual bool genNextValue() = 0; virtual void resetGrid() = 0; virtual size_t getType() const = 0; virtual CyclopsGrid* copy() const = 0; virtual int getParamIdx() const = 0; virtual void assign(CyclopsParam* param) const = 0; virtual int size() const = 0; virtual void print(std::stringstream& ss) const = 0; }; class CyclopsGrids; template struct CyclopsGridX : public CyclopsGrid { int paramIdx; T val; T minVal; T maxVal; T stepVal; bool logStep; CyclopsGridX(int idx, const T& minV, const T& maxV, const T& stepV, bool isLogSep) : paramIdx(idx), minVal(minV), maxVal(maxV), stepVal(stepV), logStep(isLogSep) { resetGrid(); } virtual ~CyclopsGridX() {} virtual void serialize(FileStorage& fs) const { fs << "paramIdx" << paramIdx; fs << "val" << val; fs << "min" << minVal; fs << "max" << maxVal; fs << "step" << stepVal; fs << "log" << logStep; } virtual void deserialize(const FileNode& node) { node["paramIdx"] >> paramIdx; node["val"] >> val; node["min"] >> minVal; node["max"] >> maxVal; node["step"] >> stepVal; node["log"] >> logStep; } virtual bool genNextValue() { T v = logStep ? val * stepVal : val + stepVal; if (v <= maxVal) { val = v; return true; } else { return false; } } virtual void resetGrid() { val = minVal; } virtual size_t getType() const { return typeid(T).hash_code(); } virtual CyclopsGrid* copy() const { CyclopsGridX* p = new CyclopsGridX(paramIdx, minVal, maxVal, stepVal, logStep); p->val = val; return p; } virtual int getParamIdx() const { return paramIdx; } virtual void assign(CyclopsParam* param) const { if (param->getType() != getType()) return; // different type; CyclopsParamX* realParam = dynamic_cast*>(param); if (!realParam) return; // type case failed realParam->setValue(val); } virtual int size() const { if (logStep) return (floor(std::log(maxVal / minVal) / std::log(stepVal)) + 1); else return (maxVal - minVal) / stepVal + 1; } virtual void print(std::stringstream& ss) const { ss << val; } protected: friend class CyclopsGrids; CyclopsGridX() {}; }; typedef CyclopsGridX CyclopsGridInt; typedef CyclopsGridX CyclopsGridDouble; typedef CyclopsGridX CyclopsGridBool; // spacial instantiation for bool param int CyclopsGridBool::size() const { return 2; // true and false } bool CyclopsGridBool::genNextValue() { val = !val; return !val; } void CyclopsGridBool::resetGrid() { val = false; } typedef CyclopsGridX CyclopsGridSize; // special instantiation for size param bool CyclopsGridSize::genNextValue() { Size v = val; v.width = (logStep ? (v.width * stepVal.width) : (v.width + stepVal.width)); if (v.width > maxVal.width) { // try height v.width = minVal.width; v.height = (logStep ? (v.height * stepVal.height) : (v.height + stepVal.height)); if (v.height > maxVal.height) { return false; } } val = v; return true; } void CyclopsGridSize::resetGrid() { val.width = minVal.width; val.height = minVal.height; } int CyclopsGridSize::size() const { if (logStep) { int wsize = floor(std::log(maxVal.width / minVal.width) / std::log(stepVal.width)) + 1; int hsize = floor(std::log(maxVal.height / minVal.height) / std::log(stepVal.height)) + 1; return wsize * hsize; } else { return (((maxVal.width - minVal.width) / stepVal.width) + 1) * (((maxVal.height - minVal.height) / stepVal.height) + 1); } } void CyclopsGridSize::print(std::stringstream& ss) const { ss << val.width << " x " << val.height; } // add more CyclopsParamX for other data types // special enum grid struct CyclopsGridEnum : public CyclopsGridInt { int curIdx; std::vector validVals; CyclopsGridEnum(int idx, const std::vector& validV) : validVals(validV) { paramIdx = idx; resetGrid(); } virtual ~CyclopsGridEnum() {} virtual void serialize(FileStorage& fs) const { fs << "paramIdx" << paramIdx; fs << "val" << val; fs << "curIdx" << curIdx; fs << "validVals" << validVals; } virtual void deserialize(const FileNode& node) { node["paramIdx"] >> paramIdx; node["val"] >> val; node["curIdx"] >> curIdx; node["validVals"] >> validVals; } virtual bool genNextValue() { int idx = curIdx + 1; if (idx >= 0 && idx < validVals.size()) { val = validVals[idx]; curIdx = idx; return true; } else { return false; } } virtual void resetGrid() { curIdx = 0; val = validVals[0]; } virtual CyclopsGrid* copy() const { CyclopsGridEnum* p = new CyclopsGridEnum(paramIdx, validVals); p->val = val; p->curIdx = curIdx; return p; } virtual int size() const { return validVals.size(); } protected: friend class CyclopsGrids; CyclopsGridEnum() {}; }; struct CyclopsGrids { public: CyclopsGrids() {} CyclopsGrids(const std::string& name) : targetName(name) {} ~CyclopsGrids() { for (CyclopsGrid* g : grids) delete g; grids.clear(); } CyclopsGrids(const CyclopsGrids& other) { targetName = other.targetName; for (const CyclopsGrid* g : other.grids) { grids.push_back(g->copy()); } } void operator= (const CyclopsParams& other) = delete; const std::string& getTargetName() const { return targetName; } void setTargetName(const std::string& n) { targetName = n; } template bool addGrid(int paramIdx, const T& minV, const T& maxV, const T& stepV, bool logStep = false) { if (minV > maxV) return false; if (!logStep && minV + stepV <= minV) return false; if (logStep && minV * stepV <= minV) return false; grids.push_back(new CyclopsGridX(paramIdx, minV, maxV, stepV, logStep)); return true; } template<> bool addGrid(int paramIdx, const Size& minV, const Size& maxV, const Size& stepV, bool logStep) { if (minV > maxV) return false; if (!logStep && (stepV.width <= 0 || stepV.height <= 0)) return false; if (logStep && (stepV.width <= 1 || stepV.height <= 1)) return false; grids.push_back(new CyclopsGridX(paramIdx, minV, maxV, stepV, logStep)); return true; } template<> bool addGrid(int paramIdx, const bool& minV, const bool& maxV, const bool& stepV, bool logStep) = delete; bool addBool(int paramIdx) { grids.push_back(new CyclopsGridBool(paramIdx, false, true, true, false)); // meaningless settings return true; } bool addEnum(int paramIdx, const std::vector& validVals) { if (validVals.empty()) return false; grids.push_back(new CyclopsGridEnum(paramIdx, validVals)); return true; } bool removeGrid(int paramIdx) { for (int i = 0; i < grids.size(); ++i) { const CyclopsGrid* g = grids[i]; if (g->getParamIdx() == paramIdx) { delete g; grids.erase(grids.begin() + i); return true; } } return true; } int count() const { return grids.size(); } void serialize(FileStorage& fs) const { fs << "targetName" << targetName; fs << "grids" << "["; for (const CyclopsGrid* g : grids) { fs << "{:"; fs << "type" << std::to_string(g->getType()); g->serialize(fs); fs << "}"; } fs << "]"; } void deserialize(const FileNode& node) { node["targetName"] >> targetName; FileNode gNode = node["grids"]; if (gNode.isNone()) return; if (!grids.empty()) return; for (auto it = gNode.begin(); it != gNode.end(); ++it) { std::string typecode; (*it)["type"] >> typecode; size_t typeId = std::stoull(typecode); CyclopsGrid* g = nullptr; if (typeId == typeid(int).hash_code()) { if ((*it)["validVals"].isNone()) g = new CyclopsGridInt(); else g = new CyclopsGridEnum(); } else if (typeId == typeid(double).hash_code()) { g = new CyclopsGridDouble(); } else if (typeId == typeid(bool).hash_code()) { g = new CyclopsGridBool(); } else if (typeId == typeid(Size).hash_code()) { g = new CyclopsGridSize(); } else { // invalid type code continue; } g->deserialize(*it); grids.push_back(g); } } bool genNextGrid() { int c = grids.size(); for (int i = 0; i < c; ++i) { CyclopsGrid* g = grids[i]; if (!g) continue; if (g->genNextValue()) { // reset all previous to first value for (int j = 0; j < i; ++j) { CyclopsGrid* p = grids[j]; p->resetGrid(); } return true; } } return false; } const CyclopsGrid* getGrid(int paramIdx) const { for (int i = 0; i < grids.size(); ++i) { const CyclopsGrid* g = grids[i]; if (g->getParamIdx() == paramIdx) { return g; } } return nullptr; } const CyclopsGrid* itemGrid(int index) const { if (index < 0 || index >= grids.size()) return nullptr; return grids[index]; } template T getValue(int paramIdx, bool* ok) const { const CyclopsGrid* g = getGrid(paramIdx); if (g) { const CyclopsGridX* gt = dynamic_cast*>(g); if (ok) *ok = true; return gt->val; } if (ok) *ok = false; return T(); } void reset() { for (CyclopsGrid* g : grids) { g->resetGrid(); } } template void getSetting(int paramIdx, T* pMinVal = nullptr, T* pMaxVal = nullptr, T* pStepVal = nullptr) const { for (int i = 0; i < grids.size(); ++i) { const CyclopsGrid* g = grids[i]; if (g->getParamIdx() == paramIdx) { const CyclopsGridX* gt = dynamic_cast*>(g); if (gt) { if (pMinVal) *pMinVal = gt->minVal; if (pMaxVal) *pMaxVal = gt->maxVal; if (pStepVal) *pStepVal = gt->stepVal; } } } } void getEnumSetting(int paramIdx, std::vector& validVals) const { for (int i = 0; i < grids.size(); ++i) { const CyclopsGrid* g = grids[i]; if (g->getParamIdx() == paramIdx) { const CyclopsGridEnum* gt = dynamic_cast(g); if (gt) { validVals = gt->validVals; } } } } template bool checkParamType(int idx) const { if (idx < 0 || idx > grids.size()) return false; return grids[idx]->getType() == typeid(T).hash_code(); } void assign(CyclopsParams* params) { for (int i = 0; i < params->count(); ++i) { const CyclopsGrid* g = getGrid(i); if (!g) continue; g->assign(params->get(i)); } params->setDirtyBit(true); } int size() const { int ret = 1; for (CyclopsGrid* g : grids) { ret *= g->size(); } return ret; } std::string print() { std::stringstream ss; for (int i = 0; i < grids.size(); ++i) { const CyclopsGrid* g = grids[i]; g->print(ss); ss << ","; } return ss.str(); } std::string print(const CyclopsParams* params) { std::stringstream ss; for (int i = 0; i < grids.size(); ++i) { const CyclopsGrid* g = grids[i]; const CyclopsParam* p = params->get(g->getParamIdx()); p->print(ss); ss << ","; } return ss.str(); } private: std::string targetName; std::vector grids; }; #endif // CyclopsGrid_h_