diff --git a/src/app/qt/graphics/QtAngledLineItem.cpp b/src/app/qt/graphics/QtAngledLineItem.cpp index aeddfd1e..e1ca0735 100644 --- a/src/app/qt/graphics/QtAngledLineItem.cpp +++ b/src/app/qt/graphics/QtAngledLineItem.cpp @@ -8,6 +8,8 @@ QtAngledLineItem::QtAngledLineItem(QGraphicsItem* parent) : QGraphicsLineItem(parent) + , m_onBack(false) + , m_horizontalIn(false) { this->setAcceptHoverEvents(true); } @@ -38,6 +40,16 @@ void QtAngledLineItem::updateLine( this->setPen(QPen(QBrush(style.color.c_str()), style.width, Qt::SolidLine, Qt::RoundCap)); } +void QtAngledLineItem::setOnBack(bool back) +{ + m_onBack = back; +} + +void QtAngledLineItem::setHorizontalIn(bool horizontal) +{ + m_horizontalIn = horizontal; +} + QPainterPath QtAngledLineItem::shape() const { int w = m_style.arrowWidth / 2 + 1; @@ -185,23 +197,31 @@ QPolygon QtAngledLineItem::getPath() const const Vec4i& oR = m_ownerRect; const Vec4i& tR = m_targetRect; - Vec2f o[2] = { Vec2f(m_ownerParentRect.x, (oR.y + 2 * oR.w) / 3), Vec2f(m_ownerParentRect.z, (oR.y + 2 * oR.w) / 3) }; - Vec2f t[2] = { Vec2f(m_targetParentRect.x, (2 * tR.y + tR.w) / 3), Vec2f(m_targetParentRect.z, (2 * tR.y + tR.w) / 3) }; + Vec2f o[2] = { Vec2f(m_ownerParentRect.x, (2 * oR.y + oR.w) / 3), Vec2f(m_ownerParentRect.z, (2 * oR.y + oR.w) / 3) }; + Vec2f t[2] = { Vec2f(m_targetParentRect.x, (tR.y + 2 * tR.w) / 3), Vec2f(m_targetParentRect.z, (tR.y + 2 * tR.w) / 3) }; int io = -1; int it = -1; float dist = -1; - for (int i = 0; i < 2; i++) + if (m_onBack) { - for (int j = 0; j < 2; j++) + io = 1; + it = 1; + } + else + { + for (int i = 0; i < 2; i++) { - Vec2f diff = o[i] - t[j]; - if (dist < 0 || diff.getLength() < dist) + for (int j = 0; j < 2; j++) { - dist = diff.getLength(); - io = i; - it = j; + Vec2f diff = o[i] - t[j]; + if (dist < 0 || diff.getLength() < dist) + { + dist = diff.getLength(); + io = i; + it = j; + } } } } @@ -233,7 +253,11 @@ QPolygon QtAngledLineItem::getPath() const } } - if (it == io && ((it && tp.x() < op.x()) || (!it && tp.x() > op.x())) ) + if (it == io && ((it && tp.x() < op.x()) || (!it && tp.x() > op.x()))) + { + tp.setX(op.x()); + } + else if (it != io && m_horizontalIn) { tp.setX(op.x()); } @@ -242,10 +266,10 @@ QPolygon QtAngledLineItem::getPath() const op.setX(tp.x()); } - o[0] = Vec2f(oR.x, (oR.y + 2 * oR.w) / 3); - o[1] = Vec2f(oR.z, (oR.y + 2 * oR.w) / 3); - t[0] = Vec2f(tR.x, (2 * tR.y + tR.w) / 3); - t[1] = Vec2f(tR.z, (2 * tR.y + tR.w) / 3); + o[0] = Vec2f(oR.x, (2 * oR.y + oR.w) / 3); + o[1] = Vec2f(oR.z, (2 * oR.y + oR.w) / 3); + t[0] = Vec2f(tR.x, (tR.y + 2 * tR.w) / 3); + t[1] = Vec2f(tR.z, (tR.y + 2 * tR.w) / 3); if (o[io].y < t[it].y) { diff --git a/src/app/qt/graphics/QtAngledLineItem.h b/src/app/qt/graphics/QtAngledLineItem.h index 46ab6ddd..d98ff0bb 100644 --- a/src/app/qt/graphics/QtAngledLineItem.h +++ b/src/app/qt/graphics/QtAngledLineItem.h @@ -19,6 +19,9 @@ public: Vec4i ownerParentRect, Vec4i targetParentRect, GraphViewStyle::EdgeStyle style); + void setOnBack(bool back); + void setHorizontalIn(bool horizontal); + virtual QPainterPath shape() const; virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget); @@ -33,6 +36,9 @@ private: Vec4i m_targetParentRect; GraphViewStyle::EdgeStyle m_style; + + bool m_onBack; + bool m_horizontalIn; }; #endif // QT_ANGLED_LINE_ITEM_H diff --git a/src/app/qt/view/graphElements/QtGraphEdge.cpp b/src/app/qt/view/graphElements/QtGraphEdge.cpp index 64d5581b..4909fc1e 100644 --- a/src/app/qt/view/graphElements/QtGraphEdge.cpp +++ b/src/app/qt/view/graphElements/QtGraphEdge.cpp @@ -22,11 +22,16 @@ QtGraphEdge::QtGraphEdge( , m_target(target) , m_child(nullptr) , m_isActive(false) + , m_fromActive(false) + , m_toActive(false) , m_weight(weight) , m_direction(TokenComponentAggregation::DIRECTION_NONE) , m_mousePos(0.0f, 0.0f) , m_mouseMoved(false) { + m_fromActive = m_owner.lock()->getIsActive(); + m_toActive = m_target.lock()->getIsActive(); + this->updateLine(); } @@ -100,6 +105,16 @@ void QtGraphEdge::updateLine() owner->getBoundingRect(), target->getBoundingRect(), owner->getParentBoundingRect(), target->getParentBoundingRect(), style); + + if (m_fromActive && owner->getLastParent() == target->getLastParent()) + { + dynamic_cast(m_child)->setOnBack(true); + } + + if (m_toActive) + { + dynamic_cast(m_child)->setHorizontalIn(true); + } } this->setZValue(style.zValue); // Used to draw edges always on top of nodes. @@ -112,9 +127,11 @@ bool QtGraphEdge::getIsActive() const void QtGraphEdge::setIsActive(bool isActive) { - m_isActive = isActive; - - updateLine(); + if (m_isActive != isActive) + { + m_isActive = isActive; + updateLine(); + } } void QtGraphEdge::onClick() @@ -138,7 +155,7 @@ void QtGraphEdge::focusIn() void QtGraphEdge::focusOut() { - this->setIsActive(m_isActive); + updateLine(); } void QtGraphEdge::mousePressEvent(QGraphicsSceneMouseEvent* event) diff --git a/src/app/qt/view/graphElements/QtGraphEdge.h b/src/app/qt/view/graphElements/QtGraphEdge.h index 855bb5da..13282936 100644 --- a/src/app/qt/view/graphElements/QtGraphEdge.h +++ b/src/app/qt/view/graphElements/QtGraphEdge.h @@ -32,6 +32,7 @@ public: bool getIsActive() const; void setIsActive(bool isActive); + void setFromAndToActive(bool fromActive, bool toActive); void onClick(); @@ -57,6 +58,8 @@ private: QGraphicsLineItem* m_child; bool m_isActive; + bool m_fromActive; + bool m_toActive; size_t m_weight; TokenComponentAggregation::Direction m_direction; diff --git a/src/app/qt/view/graphElements/QtGraphNode.cpp b/src/app/qt/view/graphElements/QtGraphNode.cpp index 50bfce87..94229477 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.cpp +++ b/src/app/qt/view/graphElements/QtGraphNode.cpp @@ -61,6 +61,21 @@ QtGraphNode* QtGraphNode::getParent() const return m_parentNode.lock().get(); } +QtGraphNode* QtGraphNode::getLastParent() const +{ + QtGraphNode* node = const_cast(this); + while (true) + { + QtGraphNode* parent = dynamic_cast(node->parentItem()); + if (!parent) + { + break; + } + node = parent; + } + return node; +} + void QtGraphNode::setParent(std::weak_ptr parentNode) { m_parentNode = parentNode; @@ -134,18 +149,7 @@ Vec4i QtGraphNode::getBoundingRect() const Vec4i QtGraphNode::getParentBoundingRect() const { - const QtGraphNode* node = this; - while (true) - { - const QtGraphNode* parent = dynamic_cast(node->parentItem()); - if (!parent) - { - break; - } - node = parent; - - } - return node->getBoundingRect(); + return getLastParent()->getBoundingRect(); } void QtGraphNode::addOutEdge(const std::shared_ptr& edge) diff --git a/src/app/qt/view/graphElements/QtGraphNode.h b/src/app/qt/view/graphElements/QtGraphNode.h index 46feac21..b6e14a9e 100644 --- a/src/app/qt/view/graphElements/QtGraphNode.h +++ b/src/app/qt/view/graphElements/QtGraphNode.h @@ -3,6 +3,8 @@ #include +#include "utility/math/Vector4.h" + #include "component/view/GraphViewStyle.h" class QFont; @@ -33,6 +35,7 @@ public: virtual ~QtGraphNode(); QtGraphNode* getParent() const; + QtGraphNode* getLastParent() const; void setParent(std::weak_ptr parentNode); std::list> getSubNodes() const; diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 5707b0c8..11a45b7b 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -35,8 +35,12 @@ add_files( add_files( LIB_FILES + component/controller/helper/BucketGrid.cpp + component/controller/helper/BucketGrid.h component/controller/helper/DummyEdge.h component/controller/helper/DummyNode.h + component/controller/helper/GraphLayouter.cpp + component/controller/helper/GraphLayouter.h component/controller/helper/GraphPostprocessor.cpp component/controller/helper/GraphPostprocessor.h component/controller/helper/SnippetMerger.cpp @@ -50,8 +54,6 @@ add_files( component/controller/FeatureController.h component/controller/GraphController.cpp component/controller/GraphController.h - component/controller/GraphLayouter.cpp - component/controller/GraphLayouter.h component/controller/RefreshController.cpp component/controller/RefreshController.h component/controller/SearchController.cpp diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index 26dd2728..c1159d70 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -7,6 +7,7 @@ #include "component/controller/helper/DummyEdge.h" #include "component/controller/helper/DummyNode.h" +#include "component/controller/helper/GraphLayouter.h" #include "component/controller/helper/GraphPostprocessor.h" #include "component/view/GraphView.h" #include "component/view/GraphViewStyle.h" @@ -88,8 +89,7 @@ void GraphController::handleMessage(MessageGraphNodeBundleSplit* message) setActiveAndVisibility(utility::concat(m_activeNodeIds, m_activeEdgeIds)); layoutNesting(); - GraphLayouter::layoutSpectralPrototype(m_dummyNodes, m_dummyEdges); - GraphPostprocessor::doPostprocessing(m_dummyNodes); + layoutGraph(); buildGraph(message); } @@ -102,9 +102,9 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message) node->expanded = message->expand; setActiveAndVisibility(utility::concat(m_activeNodeIds, m_activeEdgeIds)); - layoutNesting(); - GraphPostprocessor::doPostprocessing(m_dummyNodes); + layoutNesting(); + layoutGraph(); buildGraph(message); } @@ -179,8 +179,7 @@ void GraphController::createDummyGraphForTokenIds(const std::vector& tokenId bundleNodes(); layoutNesting(); - GraphLayouter::layoutSpectralPrototype(m_dummyNodes, m_dummyEdges); - GraphPostprocessor::doPostprocessing(m_dummyNodes); + layoutGraph(); m_graph = graph; } @@ -867,6 +866,14 @@ void GraphController::layoutToGrid(DummyNode& node) const } } +void GraphController::layoutGraph() +{ + // GraphLayouter::layoutSpectralPrototype(m_dummyNodes, m_dummyEdges); + // GraphPostprocessor::doPostprocessing(m_dummyNodes); + + GraphLayouter::layoutBucket(m_dummyNodes, m_dummyEdges, getView()->getViewSize()); +} + DummyNode* GraphController::findDummyNodeRecursive(std::vector& nodes, Id tokenId) const { for (DummyNode& node : nodes) diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index 7c9f5a66..49062ea4 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -13,7 +13,6 @@ #include "utility/messaging/type/MessageGraphNodeMove.h" #include "component/controller/Controller.h" -#include "component/controller/GraphLayouter.h" #include "component/view/GraphView.h" #include "data/graph/token_component/TokenComponentAccess.h" #include "data/graph/token_component/TokenComponentAggregation.h" @@ -72,6 +71,8 @@ private: void addExpandToggleNode(DummyNode& node) const; void layoutToGrid(DummyNode& node) const; + void layoutGraph(); + DummyNode* findDummyNodeRecursive(std::vector& nodes, Id tokenId) const; DummyNode* findTopLevelDummyNodeRecursive(std::vector& nodes, Id tokenId) const; DummyNode* findDummyNodeAccessRecursive(std::vector& nodes, Id parentId, TokenComponentAccess::AccessType type) const; diff --git a/src/lib/component/controller/helper/BucketGrid.cpp b/src/lib/component/controller/helper/BucketGrid.cpp new file mode 100644 index 00000000..16e389b6 --- /dev/null +++ b/src/lib/component/controller/helper/BucketGrid.cpp @@ -0,0 +1,352 @@ +#include "component/controller/helper/BucketGrid.h" + +#include "component/controller/helper/DummyEdge.h" +#include "component/controller/helper/DummyNode.h" +#include "component/view/GraphViewStyle.h" + +Bucket::Bucket() + : i(0) + , j(0) + , m_width(0) + , m_height(0) +{ +} + +Bucket::Bucket(int i, int j) + : i(i) + , j(j) + , m_width(0) + , m_height(0) +{ +} + +int Bucket::getWidth() const +{ + return m_width; +} + +int Bucket::getHeight() const +{ + return m_height; +} + +bool Bucket::hasNode(DummyNode* node) const +{ + for (DummyNode* n : m_nodes) + { + if (node == n) + { + return true; + } + } + + return false; +} + +void Bucket::addNode(DummyNode* node) +{ + m_nodes.push_back(node); + + m_width = (node->size.x > m_width ? node->size.x : m_width); + m_height += node->size.y + GraphViewStyle::toGridGap(10); +} + +void Bucket::preLayout(Vec2i viewSize) +{ + int cols = m_height / viewSize.y + 1; + + int x = 0; + int y = 0; + int height = m_height / cols; + int width = 0; + + m_height = 0; + + for (DummyNode* node : m_nodes) + { + node->position.x = x; + node->position.y = y; + + y += node->size.y + GraphViewStyle::toGridGap(10); + + width = (node->size.x > width ? node->size.x : width); + m_height = (y > m_height ? y : m_height); + + if (y > height) + { + y = 0; + + x += width + GraphViewStyle::toGridGap(25); + width = 0; + } + } + + m_width = x + width; +} + +void Bucket::layout(int x, int y, int width, int height) +{ + int cx = GraphViewStyle::toGridOffset(x + (width - m_width) / 2); + int cy = GraphViewStyle::toGridOffset(y + (height - m_height) / 2); + + for (DummyNode* node : m_nodes) + { + node->position.x = node->position.x + cx; + node->position.y = node->position.y + cy; + } +} + + +void BucketGrid::layout(std::vector& nodes, const std::vector& edges, Vec2i viewSize) +{ + BucketGrid grid(viewSize); + grid.createBuckets(nodes, edges); + grid.layoutBuckets(); +} + +BucketGrid::BucketGrid(Vec2i viewSize) + : m_viewSize(viewSize) + , m_i1(0) + , m_j1(0) + , m_i2(0) + , m_j2(0) +{ + m_buckets[0][0] = Bucket(0, 0); +} + +void BucketGrid::createBuckets(std::vector& nodes, const std::vector& edges) +{ + if (!nodes.size()) + { + return; + } + + bool activeNodeAdded = false; + for (DummyNode& node : nodes) + { + if (node.hasActiveSubNode()) + { + addNode(&node); + activeNodeAdded = true; + } + } + + if (!activeNodeAdded) + { + addNode(&nodes[0]); + } + + std::vector remainingEdges; + for (const DummyEdge& edge : edges) + { + remainingEdges.push_back(&edge); + } + + size_t i = 0; + while (remainingEdges.size()) + { + const DummyEdge* edge = remainingEdges[i]; + + DummyNode* owner = findTopMostDummyNodeRecursive(nodes, edge->ownerId); + DummyNode* target = findTopMostDummyNodeRecursive(nodes, edge->targetId); + + bool removeEdge = false; + if (!owner || !target) + { + removeEdge = true; + } + else + { + bool horizontal = edge->data ? !edge->data->isType(Edge::EDGE_INHERITANCE) : true; + removeEdge = addNode(owner, target, horizontal); + } + + if (removeEdge) + { + remainingEdges.erase(remainingEdges.begin() + i); + } + else + { + i++; + } + + if (i == remainingEdges.size()) + { + i = 0; + } + } +} + +void BucketGrid::layoutBuckets() +{ + std::map widths; + std::map heights; + + for (int j = m_j1; j <= m_j2; j++) + { + for (int i = m_i1; i <= m_i2; i++) + { + Bucket* bucket = &m_buckets[j][i]; + + bucket->preLayout(m_viewSize); + + std::map::iterator wt = widths.find(i); + if (wt == widths.end() || wt->second < bucket->getWidth()) + { + widths[i] = bucket->getWidth(); + } + + std::map::iterator ht = heights.find(j); + if (ht == heights.end() || ht->second < bucket->getHeight()) + { + heights[j] = bucket->getHeight(); + } + } + } + + int y = 0; + for (int j = m_j1; j <= m_j2; j++) + { + int x = 0; + for (int i = m_i1; i <= m_i2; i++) + { + Bucket* bucket = &m_buckets[j][i]; + + bucket->layout(x, y, widths[i], heights[j]); + + x += widths[i] + GraphViewStyle::toGridGap(85); + } + + y += heights[j] + GraphViewStyle::toGridGap(45); + } +} + +DummyNode* BucketGrid::findTopMostDummyNodeRecursive(std::vector& nodes, Id tokenId, DummyNode* top) +{ + for (DummyNode& node : nodes) + { + DummyNode* t = (top ? top : &node); + + if (node.visible && node.tokenId == tokenId) + { + return t; + } + + DummyNode* result = findTopMostDummyNodeRecursive(node.subNodes, tokenId, t); + if (result != nullptr) + { + return result; + } + } + + return nullptr; +} + +void BucketGrid::addNode(DummyNode* node) +{ + Bucket* bucket = getBucket(0, 0); + bucket->addNode(node); +} + +bool BucketGrid::addNode(DummyNode* owner, DummyNode* target, bool horizontal) +{ + Bucket* ownerBucket = getBucket(owner); + Bucket* targetBucket = getBucket(target); + + if (!ownerBucket && !targetBucket) + { + return false; + } + else if (ownerBucket && targetBucket) + { + return true; + } + + if (ownerBucket) + { + int i = horizontal ? ownerBucket->i + 1 : ownerBucket->i; + int j = horizontal ? ownerBucket->j : ownerBucket->j - 1; + + Bucket* bucket = getBucket(i, j); + bucket->addNode(target); + } + else + { + int i = horizontal ? targetBucket->i - 1 : targetBucket->i; + int j = horizontal ? targetBucket->j : targetBucket->j + 1; + + Bucket* bucket = getBucket(i, j); + bucket->addNode(owner); + } + + return true; +} + +Bucket* BucketGrid::getBucket(int i, int j) +{ + bool newColumn = false; + bool newRow = false; + + if (i == m_i1 - 1) + { + m_i1 = i; + newColumn = true; + } + else if (i == m_i2 + 1) + { + m_i2 = i; + newColumn = true; + } + + if (newColumn) + { + for (int cj = m_j1; cj <= m_j2; cj++) + { + m_buckets[cj][i] = Bucket(i, cj); + } + } + + if (j == m_j1 - 1) + { + m_j1 = j; + newRow = true; + } + else if (j == m_j2 + 1) + { + m_j2 = j; + newRow = true; + } + + if (newRow) + { + for (int ci = m_i1; ci <= m_i2; ci++) + { + m_buckets[j][ci] = Bucket(ci, j); + } + } + + if (i >= m_i1 && i <= m_i2 && j >= m_j1 && j <= m_j2) + { + return &m_buckets[j][i]; + } + + return nullptr; +} + +Bucket* BucketGrid::getBucket(DummyNode* node) +{ + for (int j = m_j1; j <= m_j2; j++) + { + for (int i = m_i1; i <= m_i2; i++) + { + Bucket* bucket = &m_buckets[j][i]; + + if (bucket->hasNode(node)) + { + return bucket; + } + } + } + + return nullptr; +} diff --git a/src/lib/component/controller/helper/BucketGrid.h b/src/lib/component/controller/helper/BucketGrid.h new file mode 100644 index 00000000..b0e706df --- /dev/null +++ b/src/lib/component/controller/helper/BucketGrid.h @@ -0,0 +1,66 @@ +#ifndef BUCKET_GRID_H +#define BUCKET_GRID_H + +#include + +#include "utility/math/Vector2.h" +#include "utility/types.h" + +struct DummyEdge; +struct DummyNode; + +class Bucket +{ +public: + Bucket(); + Bucket(int i, int j); + + int getWidth() const; + int getHeight() const; + + bool hasNode(DummyNode* node) const; + void addNode(DummyNode* node); + + void preLayout(Vec2i viewSize); + void layout(int x, int y, int width, int height); + + int i; + int j; + +private: + int m_width; + int m_height; + + std::vector m_nodes; +}; + + +class BucketGrid +{ +public: + static void layout(std::vector& nodes, const std::vector& edges, Vec2i viewSize); + +private: + BucketGrid(Vec2i viewSize); + + void createBuckets(std::vector& nodes, const std::vector& edges); + void layoutBuckets(); + + DummyNode* findTopMostDummyNodeRecursive(std::vector& nodes, Id tokenId, DummyNode* top = nullptr); + + void addNode(DummyNode* node); + bool addNode(DummyNode* owner, DummyNode* target, bool horizontal); + + Bucket* getBucket(int i, int j); + Bucket* getBucket(DummyNode* node); + + Vec2i m_viewSize; + std::map> m_buckets; + + int m_i1; + int m_j1; + int m_i2; + int m_j2; +}; + +#endif // BUCKET_GRID_H diff --git a/src/lib/component/controller/GraphLayouter.cpp b/src/lib/component/controller/helper/GraphLayouter.cpp similarity index 93% rename from src/lib/component/controller/GraphLayouter.cpp rename to src/lib/component/controller/helper/GraphLayouter.cpp index a15926b7..be9ba675 100644 --- a/src/lib/component/controller/GraphLayouter.cpp +++ b/src/lib/component/controller/helper/GraphLayouter.cpp @@ -1,13 +1,13 @@ -#include "component/controller/GraphLayouter.h" +#include "component/controller/helper/GraphLayouter.h" #include #include #include -#include "utility/math/MatrixDynamicBase.h" - +#include "component/controller/helper/BucketGrid.h" #include "component/controller/helper/DummyEdge.h" #include "component/controller/helper/DummyNode.h" +#include "data/graph/Node.h" // for prototyping, remove when done #include "Eigen/Dense" @@ -64,6 +64,11 @@ void GraphLayouter::layoutSimpleRing(std::vector& nodes) } } +void GraphLayouter::layoutBucket(std::vector& nodes, const std::vector& edges, Vec2i viewSize) +{ + BucketGrid::layout(nodes, edges, viewSize); +} + void GraphLayouter::layoutSpectralPrototype(std::vector& nodes, const std::vector& edges) { if (nodes.size() < 2) @@ -153,7 +158,8 @@ void GraphLayouter::layoutSpectralPrototype(std::vector& nodes, const } } -MatrixDynamicBase GraphLayouter::buildLaplacianMatrix(const std::vector& nodes, const std::vector& edges) +MatrixDynamicBase GraphLayouter::buildLaplacianMatrix( + const std::vector& nodes, const std::vector& edges) { MatrixDynamicBase matrix(nodes.size(), nodes.size()); diff --git a/src/lib/component/controller/GraphLayouter.h b/src/lib/component/controller/helper/GraphLayouter.h similarity index 54% rename from src/lib/component/controller/GraphLayouter.h rename to src/lib/component/controller/helper/GraphLayouter.h index 2e3deeb9..45bb0cea 100644 --- a/src/lib/component/controller/GraphLayouter.h +++ b/src/lib/component/controller/helper/GraphLayouter.h @@ -3,8 +3,9 @@ #include -template -class MatrixDynamicBase; +#include "utility/math/MatrixDynamicBase.h" +#include "utility/math/Vector2.h" +#include "utility/types.h" struct DummyEdge; struct DummyNode; @@ -12,15 +13,16 @@ struct DummyNode; class GraphLayouter { public: - typedef void (*LayoutFunction)(std::vector&); - static void layoutSimpleRaster(std::vector& nodes); static void layoutSimpleRing(std::vector& nodes); + static void layoutBucket(std::vector& nodes, const std::vector& edges, Vec2i viewSize); + static void layoutSpectralPrototype(std::vector& nodes, const std::vector& edges); private: - static MatrixDynamicBase buildLaplacianMatrix(const std::vector& nodes, const std::vector& edges); + static MatrixDynamicBase buildLaplacianMatrix( + const std::vector& nodes, const std::vector& edges); }; #endif // GRAPH_LAYOUTER_H diff --git a/src/lib/component/view/GraphViewStyle.cpp b/src/lib/component/view/GraphViewStyle.cpp index 54c3f11e..91e59768 100644 --- a/src/lib/component/view/GraphViewStyle.cpp +++ b/src/lib/component/view/GraphViewStyle.cpp @@ -484,9 +484,14 @@ GraphViewStyle::EdgeStyle GraphViewStyle::getStyleForEdgeType(Edge::EdgeType typ return style; } -size_t GraphViewStyle::toGridSize(size_t x) +int GraphViewStyle::toGridOffset(int x) { - size_t r = s_gridCellSize; + if (x < 1) + { + return 0; + } + + int r = 0; while (r < x - 1) { @@ -496,8 +501,28 @@ size_t GraphViewStyle::toGridSize(size_t x) return r; } -size_t GraphViewStyle::s_gridCellSize = 5; -size_t GraphViewStyle::s_gridCellPadding = 10; +int GraphViewStyle::toGridSize(int x) +{ + if (x < 1) + { + return 0; + } + + return s_gridCellSize + toGridOffset(x - s_gridCellSize); +} + +int GraphViewStyle::toGridGap(int x) +{ + if (x < 1) + { + return 0; + } + + return s_gridCellPadding + toGridOffset(x - s_gridCellPadding); +} + +int GraphViewStyle::s_gridCellSize = 5; +int GraphViewStyle::s_gridCellPadding = 10; std::map GraphViewStyle::s_charWidths; std::map GraphViewStyle::s_charHeights; diff --git a/src/lib/component/view/GraphViewStyle.h b/src/lib/component/view/GraphViewStyle.h index bc221f92..02e0f0d7 100644 --- a/src/lib/component/view/GraphViewStyle.h +++ b/src/lib/component/view/GraphViewStyle.h @@ -5,7 +5,6 @@ #include #include "utility/math/Vector2.h" -#include "utility/math/Vector4.h" #include "data/graph/Node.h" #include "data/graph/token_component/TokenComponentAccess.h" @@ -116,10 +115,12 @@ public: static EdgeStyle getStyleForEdgeType(Edge::EdgeType type, bool isActive, bool isFocused); - static size_t toGridSize(size_t x); + static int toGridOffset(int x); + static int toGridSize(int x); + static int toGridGap(int x); - static size_t s_gridCellSize; - static size_t s_gridCellPadding; + static int s_gridCellSize; + static int s_gridCellPadding; private: static std::map s_charWidths;