#pragma once
#include <config.h>
#include <utils/foxtools/fxheader.h>
#include <utils/common/MsgHandler.h>
#include <utils/geom/Boundary.h>
#include <utils/gui/globjects/GUIGlObject.h>
#include <utils/gui/settings/GUIVisualizationSettings.h>
#include <utils/gui/div/GUIIOGlobals.h>
#include "RTree.h"
#define GUI_RTREE_QUAL RTree<GUIGlObject*, GUIGlObject, float, 2, GUIVisualizationSettings>
template<>
inline float GUI_RTREE_QUAL::RectSphericalVolume(Rect* a_rect) {
ASSERT(a_rect);
const float extent0 = a_rect->m_max[0] - a_rect->m_min[0];
const float extent1 = a_rect->m_max[1] - a_rect->m_min[1];
return .78539816f * (extent0 * extent0 + extent1 * extent1);
}
template<>
inline GUI_RTREE_QUAL::Rect GUI_RTREE_QUAL::CombineRect(Rect* a_rectA, Rect* a_rectB) {
ASSERT(a_rectA && a_rectB);
Rect newRect;
newRect.m_min[0] = rtree_min(a_rectA->m_min[0], a_rectB->m_min[0]);
newRect.m_max[0] = rtree_max(a_rectA->m_max[0], a_rectB->m_max[0]);
newRect.m_min[1] = rtree_min(a_rectA->m_min[1], a_rectB->m_min[1]);
newRect.m_max[1] = rtree_max(a_rectA->m_max[1], a_rectB->m_max[1]);
return newRect;
}
class SUMORTree : private GUI_RTREE_QUAL, public Boundary {
public:
SUMORTree() :
GUI_RTREE_QUAL(&GUIGlObject::drawGL),
myLock(true) {
}
virtual ~SUMORTree() {
if (myLock.locked()) {
WRITE_ERROR("Mutex of SUMORTree is locked during call of the destructor");
}
}
virtual void Insert(const float a_min[2], const float a_max[2], GUIGlObject* const & a_dataId) {
FXMutexLock locker(myLock);
GUI_RTREE_QUAL::Insert(a_min, a_max, a_dataId);
}
virtual void Remove(const float a_min[2], const float a_max[2], GUIGlObject* const & a_dataId) {
FXMutexLock locker(myLock);
GUI_RTREE_QUAL::Remove(a_min, a_max, a_dataId);
}
virtual int Search(const float a_min[2], const float a_max[2], const GUIVisualizationSettings& c) const {
FXMutexLock locker(myLock);
return GUI_RTREE_QUAL::Search(a_min, a_max, c);
}
void addAdditionalGLObject(GUIGlObject *o, const double exaggeration = 1) {
if (myLock.locked()) {
throw ProcessError("Mutex of SUMORTree is locked before object insertion");
}
FXMutexLock locker(myLock);
Boundary b = o->getCenteringBoundary();
if (exaggeration > 1) {
b.scale(exaggeration);
}
if (MsgHandler::writeDebugGLMessages()) {
if (!b.isInitialised()) {
throw ProcessError(StringUtils::format("Boundary of GUIGlObject % is not initialised (insertion)", o->getMicrosimID()));
} else if ((b.getWidth() == 0) || (b.getHeight() == 0)) {
throw ProcessError(StringUtils::format("Boundary of GUIGlObject % has an invalid size (insertion)", o->getMicrosimID()));
} else if (myTreeDebug.count(o) > 0) {
throw ProcessError("GUIGlObject was already inserted");
} else {
myTreeDebug[o] = b;
}
}
const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
Insert(cmin, cmax, o);
myTreeSize++;
}
void removeAdditionalGLObject(GUIGlObject *o, const double exaggeration = 1) {
if (myLock.locked()) {
throw ProcessError("Mutex of SUMORTree is locked before object remove");
}
FXMutexLock locker(myLock);
Boundary b = o->getCenteringBoundary();
if (exaggeration > 1) {
b.scale(exaggeration);
}
if (MsgHandler::writeDebugGLMessages()) {
if (!b.isInitialised()) {
throw ProcessError(StringUtils::format("Boundary of GUIGlObject % is not initialised (deletion)", o->getMicrosimID()));
} else if ((b.getWidth() == 0) || (b.getHeight() == 0)) {
throw ProcessError(StringUtils::format("Boundary of GUIGlObject % has an invalid size (deletion)", o->getMicrosimID()));
} else if (myTreeDebug.count(o) == 0) {
throw ProcessError("GUIGlObject wasn't inserted");
} else if (toString(b) != toString(myTreeDebug.at(o))) {
std::cout << "Tree: " << toString(myTreeDebug.at(o)) << " original: " << toString(b) << std::endl;
throw ProcessError("add boundary of GUIGlObject " + o->getMicrosimID() + " is different of removed boundary (" + toString(b) + " != " + toString(myTreeDebug.at(o)) + ")");
} else {
myTreeDebug.erase(o);
}
}
const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
Remove(cmin, cmax, o);
myTreeSize--;
}
void updateBoundaries(GUIGlObjectType type) {
std::vector<GUIGlObject*> glObjects;
glObjects.reserve(myTreeSize);
GUI_RTREE_QUAL::Iterator it;
GetFirst(it);
while (!IsNull(it)) {
const auto glType = (*it)->getType();
if ((glType == type) ||
((glType > GLO_ADDITIONALELEMENT) && (glType < GLO_SHAPE)) ||
((glType >= GLO_TAZ) && (glType < GLO_LOCKICON))) {
glObjects.push_back(*it);
}
GetNext(it);
}
for (const auto &glObject : glObjects) {
removeAdditionalGLObject(glObject);
removeObjectFromTreeDebug(glObject);
addAdditionalGLObject(glObject);
}
}
protected:
mutable FXMutex myLock;
int myTreeSize = 0;
private:
std::map<GUIGlObject*, Boundary> myTreeDebug;
bool removeObjectFromTreeDebug(const GUIGlObject* obj) {
for (auto it = myTreeDebug.begin(); it != myTreeDebug.end(); it++) {
if (it->first == obj) {
myTreeDebug.erase(it);
return true;
}
}
return false;
}
};