Search code examples
c++qtlayoutgraphogdf

Setting node bounding box size in OGDF


I'm attempting to layout and visualise a code flow graph in Qt using the OGDF library and the Sugiyama layout. The version I'm using is v2020.02, which should be the latest at the time of writing.

My issue: When creating nodes, I set them to various sizes, but after calling the SugiyamaLayout algorithm all node sizes are reset to 20x20 (presumably the default?). If I use another algorithm (such as PlanarizationLayout) instead, the issue disappears and node sizes keep their assigned values. I tried different configurations, such as rankings, crossMins and layouts, but the node size is not affected by those.

Minimal reproducible example:

//Create graph and attributes
graph_ = new Graph();
GA_ = new GraphAttributes(*graph_, GraphAttributes::nodeGraphics | GraphAttributes::nodeType |
 GraphAttributes::nodeLabel | GraphAttributes::nodeStyle | GraphAttributes::edgeGraphics | 
 GraphAttributes::edgeType | GraphAttributes::edgeArrow);

//Create node and set size
node n = graph_->newNode();
GA_->width(n) = 80; //Or any other dimensions
GA_->height(n) = 40;
//Other nodes and edges omitted

//Create layout
SugiyamaLayout slayout;
slayout.setRanking(new OptimalRanking());
slayout.setCrossMin(new MedianHeuristic());
OptimalHierarchyLayout* ohl = new OptimalHierarchyLayout;
ohl->layerDistance(30.0);
ohl->nodeDistance(25.0);
ohl->weightBalancing(0.8);
slayout.setLayout(ohl);
slayout.call(*GA_);

//Retrieve new node position and size
double x = GA_->x(n);
double y = GA_->y(n);
double w = GA_->width(n);  //This always retrieves w*h of 20x20,
double h = GA_->height(n); //no matter what node dimensions were initially set

//Draw graph, etc. (omitted)

Solution

  • After some more research, the OGDF Mailing List provided me with the answer.

    This behavior is indeed caused by a bug in HierarchyLayoutModule.h, where the correct bounding box sizes aren't preserved.

    The corresponding Github issue can be found here and will be fixed in the next release. In the meantime, it can be fixed by replacing the HierarchyLayoutModule::call method in \include\ogdf\layered\HierarchyLayoutModule.h with this code snippet:

    /**
     * \brief Computes a hierarchy layout of \p levels in \p GA
     * @param levels is the input hierarchy.
     * @param GA is assigned the hierarchy layout.
     */
    void call(const HierarchyLevelsBase &levels, GraphAttributes &GA) {
        GraphAttributes AGC(levels.hierarchy());
        // Copy over relevant nodeGraphics attributes that may be used by doCall or need to be preserved
        // edgeGraphics' bend points need to be cleared and aren't copied over
        if (GA.has(GraphAttributes::nodeGraphics)) {
            const GraphCopy &GC = dynamic_cast<const GraphCopy&>(AGC.constGraph());
            for (node vOrig: GA.constGraph().nodes)
            {
                node v = GC.copy(vOrig);
                if (v != nullptr) {
                    AGC.height(v) = GA.height(vOrig);
                    AGC.width(v) = GA.width(vOrig);
                    AGC.shape(v) = GA.shape(vOrig);
                }
            }
        }
        doCall(levels,AGC);
        AGC.transferToOriginal(GA);
    }