From 06aa7bdb587905749ba922893aceb6f7804863aa Mon Sep 17 00:00:00 2001 From: Manuel Date: Wed, 4 Mar 2015 23:07:34 -0800 Subject: [PATCH] UI: Overlaps resolve Fixed several issues with the overlaps resolving algorithm. Introducing the cell padding in the last graph update caused some issues that are now resolved. Coincidently the average number of algorithm iterations needed could be reduced, therefore the thing is now faster. fortune cookie message = All the answers you need are right there in front of you! --- bin/test/data/log/test_log.txt | 48 ++-- src/app/main.cpp | 4 +- src/app/qt/utility/QtGraphPostprocessor.cpp | 259 ++++++++++++------ src/app/qt/utility/QtGraphPostprocessor.h | 4 +- .../QtGraphNodeComponentMoveable.cpp | 2 +- 5 files changed, 204 insertions(+), 113 deletions(-) diff --git a/bin/test/data/log/test_log.txt b/bin/test/data/log/test_log.txt index 5ef4bcdf..6d2c61d5 100644 --- a/bin/test/data/log/test_log.txt +++ b/bin/test/data/log/test_log.txt @@ -1,27 +1,4 @@ ConfigManager.cpp ERROR: value path/to/nowhere is not present in config. -Token.cpp ERROR: Location Id was not referenced by this Token. -Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class -Edge.cpp ERROR: Nodes are not plain copies. -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined -Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined -Storage.cpp INFO: file: input.cc < 0:0 0:0> -Storage.cpp INFO: class: A -Storage.cpp INFO: method: A::A -Storage.cpp INFO: global usage: A::A -> A::count -Storage.cpp INFO: method: A::getCount -Storage.cpp INFO: global usage: A::getCount -> A::count -Storage.cpp INFO: method: A::process -Storage.cpp INFO: field: A::count -Storage.cpp INFO: class: B -Storage.cpp INFO: inheritance: B : A -Storage.cpp INFO: method: B::process -Storage.cpp INFO: override: A::process -> B::process < 0:0 0:0> -Storage.cpp INFO: type usage: B::process -> int -Storage.cpp INFO: function: main -Storage.cpp INFO: type usage: main -> B -Storage.cpp INFO: call: main -> B::B -Storage.cpp INFO: call: main -> A::getCount Storage.cpp INFO: file: input.cc < 0:0 0:0> Storage.cpp INFO: class: A Storage.cpp INFO: method: A::A @@ -56,6 +33,29 @@ SearchMatch.cpp INFO: 237 A::A ^^^^ +Storage.cpp INFO: file: input.cc < 0:0 0:0> +Storage.cpp INFO: class: A +Storage.cpp INFO: method: A::A +Storage.cpp INFO: global usage: A::A -> A::count +Storage.cpp INFO: method: A::getCount +Storage.cpp INFO: global usage: A::getCount -> A::count +Storage.cpp INFO: method: A::process +Storage.cpp INFO: field: A::count +Storage.cpp INFO: class: B +Storage.cpp INFO: inheritance: B : A +Storage.cpp INFO: method: B::process +Storage.cpp INFO: override: A::process -> B::process < 0:0 0:0> +Storage.cpp INFO: type usage: B::process -> int +Storage.cpp INFO: function: main +Storage.cpp INFO: type usage: main -> B +Storage.cpp INFO: call: main -> B::B +Storage.cpp INFO: call: main -> A::getCount +Token.cpp ERROR: Location Id was not referenced by this Token. +Node.cpp WARNING: Cannot change NodeType after it was already set from namespace to class +Edge.cpp ERROR: Nodes are not plain copies. +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined +Edge.cpp ERROR: Edge usage can't go from Node undefined to Node undefined Settings.cpp WARNING: File for Settings not found. ConfigManager.cpp ERROR: value Bool is not present in config. ConfigManager.cpp ERROR: value Int is not present in config. @@ -71,6 +71,7 @@ ConfigManager.cpp ERROR: value Int is not present in config. ConfigManager.cpp ERROR: value Float is not present in config. ConfigManager.cpp ERROR: value String is not present in config. ConfigManager.cpp ERROR: value NewBool is not present in config. +Graph.cpp ERROR: Can't remove member edge, without removing the child node. Storage.cpp INFO: typedef: type -> int Storage.cpp INFO: class: Class Storage.cpp INFO: struct: Struct @@ -135,7 +136,6 @@ Storage.cpp INFO: file: file.h < 0:0 0:0> Storage.cpp INFO: file: file.cpp < 0:0 0:0> Storage.cpp INFO: include: f.h Storage.cpp INFO: include: file.h -Graph.cpp ERROR: Can't remove member edge, without removing the child node. TextAccess.cpp WARNING: Index 'firstLine' has to be lower or equal index 'lastLine', is 3 > 2 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 TextAccess.cpp WARNING: Tried to access index 10. Maximum index is 8 diff --git a/src/app/main.cpp b/src/app/main.cpp index 43a5578c..a29c35c9 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -15,7 +15,9 @@ void init() std::shared_ptr consoleLogger = std::make_shared(); consoleLogger->setLogLevel(Logger::LOG_WARNINGS | Logger::LOG_ERRORS); LogManager::getInstance()->addLogger(consoleLogger); - LogManager::getInstance()->addLogger(std::make_shared()); + std::shared_ptr fileLogger = std::make_shared(); + fileLogger->setLogLevel(Logger::LOG_ALL); + LogManager::getInstance()->addLogger(fileLogger); utility::loadFontsFromDirectory("data/fonts", ".otf"); } diff --git a/src/app/qt/utility/QtGraphPostprocessor.cpp b/src/app/qt/utility/QtGraphPostprocessor.cpp index 6aa7a7fa..af0a01ac 100644 --- a/src/app/qt/utility/QtGraphPostprocessor.cpp +++ b/src/app/qt/utility/QtGraphPostprocessor.cpp @@ -1,5 +1,6 @@ #include "QtGraphPostprocessor.h" +// remark: maybe those two values could at some point be moved to an external config file (?) unsigned int QtGraphPostprocessor::s_cellSize = 20; unsigned int QtGraphPostprocessor::s_cellPadding = 10; @@ -9,7 +10,7 @@ void QtGraphPostprocessor::doPostprocessing(std::list>::iterator it = nodes.begin(); - for(; it != nodes.end(); it++) + for (; it != nodes.end(); it++) { - if((*it)->getSize().x < divisor) + if ((*it)->getSize().x < divisor) { divisor = (*it)->getSize().x; } - if((*it)->getSize().y < divisor) + if ((*it)->getSize().y < divisor) { divisor = (*it)->getSize().y; } - if((*it)->getSize().x > maxNodeSize) + if ((*it)->getSize().x > maxNodeSize) { maxNodeSize = (*it)->getSize().x; } - else if((*it)->getSize().y > maxNodeSize) + else if ((*it)->getSize().y > maxNodeSize) { maxNodeSize = (*it)->getSize().y; } @@ -49,14 +50,16 @@ void QtGraphPostprocessor::doPostprocessing(std::list heatMap = buildHeatMap(nodes, divisor, maxNodeSize); @@ -64,7 +67,7 @@ void QtGraphPostprocessor::doPostprocessing(std::listsetPosition(alignOnRaster(node->getPosition())); } @@ -73,18 +76,18 @@ Vec2i QtGraphPostprocessor::alignOnRaster(Vec2i position) { int rasterPosDivisor = s_cellSize + s_cellPadding; - if(position.x % rasterPosDivisor != 0) + if (position.x % rasterPosDivisor != 0) { int t = position.x / rasterPosDivisor; int r = position.x % rasterPosDivisor; - if(std::abs(r) > rasterPosDivisor/2) + if (std::abs(r) > rasterPosDivisor/2) { - if(t != 0) + if (t != 0) { t += (t / std::abs(t)); } - else if(r != 0) + else if (r != 0) { t += (r / std::abs(r)); } @@ -93,7 +96,7 @@ Vec2i QtGraphPostprocessor::alignOnRaster(Vec2i position) position.x = t * rasterPosDivisor; } - if(position.y % rasterPosDivisor != 0) + if (position.y % rasterPosDivisor != 0) { int t = position.y / rasterPosDivisor; int r = position.y % rasterPosDivisor; @@ -120,18 +123,18 @@ void QtGraphPostprocessor::resolveOutliers(std::list>::iterator it = nodes.begin(); - for(; it != nodes.end(); it++) + for (; it != nodes.end(); it++) { Vec2i pos = (*it)->getPosition(); Vec2i toCenterOfMass = centerPoint - pos; - if(toCenterOfMass.getLength() > maxDist) + if (toCenterOfMass.getLength() > maxDist) { maxDist = toCenterOfMass.getLength(); } } it = nodes.begin(); - for(; it != nodes.end(); it++) + for (; it != nodes.end(); it++) { Vec2i pos = (*it)->getPosition(); Vec2i toCenterOfMass = centerPoint - pos; @@ -145,7 +148,7 @@ void QtGraphPostprocessor::resolveOutliers(std::list QtGraphPostprocessor::buildHeatMap(const std::list>& nodes, const int atomarNodeSize, const int maxNodeSize) { - int heatMapWidth = maxNodeSize * nodes.size() / atomarNodeSize; + int heatMapWidth = (maxNodeSize * nodes.size() / atomarNodeSize) * 5; // theoretically the nodes could horizontally or vertically far from the center, therefore '*5' (it's kinda arbitrary, generally *2 should suffice, I use *5 to prevent problems in extrem cases) int heatMapHeight = heatMapWidth; MatrixDynamicBase heatMap(heatMapWidth, heatMapHeight); @@ -155,18 +158,23 @@ MatrixDynamicBase QtGraphPostprocessor::buildHeatMap(const std::li { int left = (*it)->getPosition().x / atomarNodeSize + heatMapWidth/2; int up = (*it)->getPosition().y / atomarNodeSize + heatMapHeight/2; - int width = (*it)->getSize().x / atomarNodeSize; - int height = (*it)->getSize().y / atomarNodeSize; + Vec2i size = calculateRasterNodeSize(*it); + int width = size.x; + int height = size.y; - if(left + width > heatMapWidth || left < 0) - continue; - - if(up + height > heatMapHeight || up < 0) - continue; - - for(int i = 0; i < width; i++) + if (left + width > heatMapWidth || left < 0) { - for(int j = 0; j < height; j++) + continue; + } + + if (up + height > heatMapHeight || up < 0) + { + continue; + } + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) { unsigned int x = left + i; unsigned int y = up + j; @@ -187,46 +195,48 @@ void QtGraphPostprocessor::resolveOverlap(std::list bool overlap = true; int iterationCount = 0; - int maxIterations = 10; + int maxIterations = 15; - while(overlap && iterationCount < maxIterations) + while (overlap && iterationCount < maxIterations) { + LOG_WARNING_STREAM(<< iterationCount); + overlap = false; iterationCount++; std::list>::iterator it = nodes.begin(); - for(; it != nodes.end(); it++) + for (; it != nodes.end(); it++) { - Vec2i nodePos((*it)->getPosition().x / divisor + heatMapWidth/2, - (*it)->getPosition().y / divisor + heatMapHeight/2); - Vec2i nodeSize((*it)->getSize().x / divisor, - (*it)->getSize().y / divisor); + Vec2i nodePos(0, 0); + nodePos.x = (*it)->getPosition().x / divisor + heatMapWidth/2; + nodePos.y = (*it)->getPosition().y / divisor + heatMapHeight/2; + Vec2i nodeSize = calculateRasterNodeSize(*it); - if(nodePos.x + nodeSize.x > heatMapWidth || nodePos.x < 0) + if (nodePos.x + nodeSize.x > heatMapWidth || nodePos.x < 0) + { + LOG_WARNING("Leaving heatmap area in x"); continue; + } - if(nodePos.y + nodeSize.y > heatMapHeight || nodePos.y < 0) + if (nodePos.y + nodeSize.y > heatMapHeight || nodePos.y < 0) + { + LOG_WARNING("Leaving heatmap area in y"); continue; + } Vec2f grad(0.0f, 0.0f); - if(getHeatmapGradient(grad, heatMap, nodePos, nodeSize)) + if (getHeatmapGradient(grad, heatMap, nodePos, nodeSize)) { overlap = true; } // handle overlap with no gradient // e.g. when a node lies completely on top of another - // float gradLength = grad.getLength(); - - if(grad.getLengthSquared() <= 0.000001f) + if (grad.getLengthSquared() <= 0.000001f && overlap) { - int val = heatMap.getValue(nodePos.x, nodePos.y); - if(val > 1) - { - grad = (*it)->getPosition(); - grad.normalize(); - grad *= -1.0f; - } + grad = (*it)->getPosition(); + grad.normalize(); + grad *= -1.0f; } // remove node temporarily from heat map, it will be re-added at the new position later on @@ -239,29 +249,40 @@ void QtGraphPostprocessor::resolveOverlap(std::list int maxOffset = 2*divisor; // prevent the graph from "exploding" again... - if(xOffset > maxOffset) + if (xOffset > maxOffset) + { xOffset = maxOffset; - else if(xOffset < -maxOffset) + } + else if (xOffset < -maxOffset) + { xOffset = -maxOffset; + } - if(yOffset > maxOffset) + if (yOffset > maxOffset) + { yOffset = maxOffset; - else if(yOffset < -maxOffset) + } + else if (yOffset < -maxOffset) + { yOffset = -maxOffset; + } Vec2i pos = (*it)->getPosition(); pos += Vec2i(xOffset, yOffset); - // grid allignment - // pos.x = (pos.x / divisor) * divisor; - // pos.y = (pos.y / divisor) * divisor; (*it)->setPosition(pos); - allignNodeOnRaster((*it).get()); + alignNodeOnRaster((*it).get()); // re-add node to heat map at new position nodePos.x = (*it)->getPosition().x / divisor + heatMapWidth/2; nodePos.y = (*it)->getPosition().y / divisor + heatMapHeight/2; + modifyHeatmapArea(heatMap, nodePos, nodeSize, 1); + + if(getHeatmapGradient(grad, heatMap, nodePos, nodeSize)) + { + overlap = true; + } } } } @@ -270,19 +291,19 @@ void QtGraphPostprocessor::modifyHeatmapArea(MatrixDynamicBase& he { bool wentOutOfRange = false; - for(int i = 0; i < size.x; i++) + for (int i = 0; i < size.x; i++) { - for(int j = 0; j < size.y; j++) + for (int j = 0; j < size.y; j++) { int x = leftUpperCorner.x + i; int y = leftUpperCorner.y + j; - if(x < 0 || x > static_cast(heatMap.getColumnsCount()-1)) + if (x < 0 || x > static_cast(heatMap.getColumnsCount()-1)) { wentOutOfRange = true; continue; } - if(y < 0 || y > static_cast(heatMap.getRowsCount()-1)) + if (y < 0 || y > static_cast(heatMap.getRowsCount()-1)) { wentOutOfRange = true; continue; @@ -291,7 +312,7 @@ void QtGraphPostprocessor::modifyHeatmapArea(MatrixDynamicBase& he unsigned int value = heatMap.getValue(x, y); heatMap.setValue(x, y, value+modifier); - if(wentOutOfRange == true) + if (wentOutOfRange == true) { LOG_WARNING("Left matrix range while trying to modify values."); } @@ -303,13 +324,17 @@ bool QtGraphPostprocessor::getHeatmapGradient(Vec2f& outGradient, const MatrixDy { bool overlap = false; - for(int i = 0; i < size.x; i++) + for (int i = 0; i < size.x; i++) { - for(int j = 0; j < size.y; j++) + for (int j = 0; j < size.y; j++) { int x = leftUpperCorner.x + i; int y = leftUpperCorner.y + j; + // weight factors that emphasize gradients near the nodes center + int hMagFactor = std::max(1, (int)(size.x*0.5 - std::abs(i+1 - size.x*0.5))); + int vMagFactor = std::max(1, (int)(size.y*0.5 - std::abs(j+1 - size.y*0.5))); + // if x and y lie directly at the border not all 4 neighbours can be checked if(x < 1 || x > static_cast(heatMap.getColumnsCount()-2)) continue; @@ -317,10 +342,11 @@ bool QtGraphPostprocessor::getHeatmapGradient(Vec2f& outGradient, const MatrixDy continue; float val = heatMap.getValue(x, y); - float xP1 = heatMap.getValue(x+1, y); - float xM1 = heatMap.getValue(x-1, y); - float yP1 = heatMap.getValue(x, y+1); - float yM1 = heatMap.getValue(x, y-1); + + float xP1 = heatMap.getValue(x+1, y) * hMagFactor; + float xM1 = heatMap.getValue(x-1, y) * hMagFactor; + float yP1 = heatMap.getValue(x, y+1) * vMagFactor; + float yM1 = heatMap.getValue(x, y-1) * vMagFactor; xP1 = std::sqrt(xP1); xM1 = std::sqrt(xM1); @@ -332,7 +358,7 @@ bool QtGraphPostprocessor::getHeatmapGradient(Vec2f& outGradient, const MatrixDy outGradient += Vec2f(xOffset, yOffset); - if(val > 1) + if (val > 1) { overlap = true; } @@ -342,10 +368,57 @@ bool QtGraphPostprocessor::getHeatmapGradient(Vec2f& outGradient, const MatrixDy return overlap; } +Vec2f QtGraphPostprocessor::heatMapRayCast(const MatrixDynamicBase& heatMap, const Vec2f& startPosition, const Vec2f& direction, const int minValue) +{ + float xOffset = 0.0f; + float yOffset = 0.0f; + + if(std::abs(direction.x) > 0.0000000001f) + { + xOffset = direction.x / std::abs(direction.x); + } + if(std::abs(direction.y) > 0.0000000001f) + { + yOffset = direction.y / std::abs(direction.y); + } + + if(startPosition.x < 1 || startPosition.x > static_cast(heatMap.getColumnsCount()-2)) + return Vec2f(0.0f, 0.0f); + if(startPosition.y < 1 || startPosition.y > static_cast(heatMap.getRowsCount()-2)) + return Vec2f(0.0f, 0.0f); + + Vec2f length(0.0f, 0.0f); + + bool hit = false; + + float posX = startPosition.x + xOffset; + float posY = startPosition.y + yOffset; + + do + { + if(heatMap.getValue(posX, posY) >= minValue) + { + hit = true; + length.x = length.x + xOffset; + length.y = length.y + yOffset; + + posX += xOffset; + posY += yOffset; + } + else + { + hit = false; + } + } + while(hit); + + return length; +} + void QtGraphPostprocessor::resizeNodes(std::list>& nodes) { std::list>::iterator it = nodes.begin(); - for(; it != nodes.end(); it++) + for (; it != nodes.end(); it++) { Vec2i size = (*it)->getSize(); @@ -363,22 +436,36 @@ void QtGraphPostprocessor::resizeNodes(std::list>& } size.y = newHeight; - /*if(size.x % atomarSize != 0) - { - int multiplier = size.x / atomarSize; - ++multiplier; - - size.x = atomarSize * multiplier; - } - - if(size.y % atomarSize != 0) - { - int multiplier = size.y / atomarSize; - ++multiplier; - - size.y = atomarSize * multiplier; - }*/ - (*it)->setSize(size); } } + +Vec2i QtGraphPostprocessor::calculateRasterNodeSize(const std::shared_ptr& node) +{ + Vec2i size = node->getSize(); + Vec2i rasterSize(0, 0); + + while(size.x > 0) + { + size.x = size.x - s_cellSize; + if(size.x > 0) + { + size.x = size.x - s_cellPadding; + } + + rasterSize.x = rasterSize.x + 1; + } + + while(size.y > 0) + { + size.y = size.y - s_cellSize; + if(size.y > 0) + { + size.y = size.y - s_cellPadding; + } + + rasterSize.y = rasterSize.y + 1; + } + + return rasterSize; +} diff --git a/src/app/qt/utility/QtGraphPostprocessor.h b/src/app/qt/utility/QtGraphPostprocessor.h index cc68660d..07983fed 100644 --- a/src/app/qt/utility/QtGraphPostprocessor.h +++ b/src/app/qt/utility/QtGraphPostprocessor.h @@ -13,7 +13,7 @@ class QtGraphPostprocessor public: static void doPostprocessing(std::list>& nodes); - static void allignNodeOnRaster(QtGraphNode* node); + static void alignNodeOnRaster(QtGraphNode* node); static Vec2i alignOnRaster(Vec2i position); private: @@ -25,7 +25,9 @@ private: static void resolveOverlap(std::list>& nodes, MatrixDynamicBase& heatMap, const int divisor); static void modifyHeatmapArea(MatrixDynamicBase& heatMap, const Vec2i& leftUpperCorner, const Vec2i& size, const int modifier); static bool getHeatmapGradient(Vec2f& outGradient, const MatrixDynamicBase& heatMap, const Vec2i& leftUpperCorner, const Vec2i& size); + static Vec2f heatMapRayCast(const MatrixDynamicBase& heatMap, const Vec2f& startPosition, const Vec2f& direction, const int minValue); static void resizeNodes(std::list>& nodes); + static Vec2i calculateRasterNodeSize(const std::shared_ptr& node); }; #endif // QT_GRAPH_POSTPROCESSOR_H diff --git a/src/app/qt/view/graphElements/nodeComponents/QtGraphNodeComponentMoveable.cpp b/src/app/qt/view/graphElements/nodeComponents/QtGraphNodeComponentMoveable.cpp index f3109da4..08a4f6b6 100644 --- a/src/app/qt/view/graphElements/nodeComponents/QtGraphNodeComponentMoveable.cpp +++ b/src/app/qt/view/graphElements/nodeComponents/QtGraphNodeComponentMoveable.cpp @@ -47,6 +47,6 @@ void QtGraphNodeComponentMoveable::nodeMouseReleaseEvent(QGraphicsSceneMouseEven std::shared_ptr node = m_graphNode.lock(); if (node != NULL) { - QtGraphPostprocessor::allignNodeOnRaster(node.get()); + QtGraphPostprocessor::alignNodeOnRaster(node.get()); } }