Skip to content

Commit

Permalink
Merge pull request #33 from sys-bio/replace-fix-layout-dimensions-alg…
Browse files Browse the repository at this point in the history
…orithm

Change the algorithm to keep layout canvas fixed dimensions
  • Loading branch information
adelhpour authored Dec 18, 2024
2 parents 8233169 + 94194a5 commit a2dd8f8
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,13 @@ def test_layout_size(self):
"""
sbml = te.loada(model).getSBML()
network = sbmlnetwork.SBMLNetwork(sbml)
network.setCanvasWidth(1000.0)
network.setCanvasHeight(1000.0)
self.assertEqual(network.getCanvasWidth(), 1000.0)
self.assertEqual(network.getCanvasHeight(), 1000.0)
network.setCanvasWidth(1234.0)
network.setCanvasHeight(1432.0)
self.assertEqual(network.getCanvasWidth(), 1234.0)
self.assertEqual(network.getCanvasHeight(), 1432.0)
network.autolayout()
self.assertEqual(network.getCanvasWidth(), 1000.0)
self.assertEqual(network.getCanvasHeight(), 1000.0)
self.assertEqual(network.getCanvasWidth(), 1234.0)
self.assertEqual(network.getCanvasHeight(), 1432.0)

def test_align_top(self):
model = """
Expand Down
93 changes: 8 additions & 85 deletions src/features/autolayout/libsbmlnetwork_autolayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ void autolayout_locateGlyphs(Model *model, Layout *layout) {
autolayout_updateCompartmentsExtents(model, layout);
autolayout_updateLayoutDimensions(layout);
delete autoLayoutAlgorithm;
if (!autolayout_adjustLayoutDimensions(layout))
autolayout_reiterateLocateGlyphs(model, layout);
autolayout_resetNumberOfAutoLayoutParametersResets(layout);
}

void autolayout_locateReactions(Model *model, Layout *layout) {
Expand All @@ -58,24 +55,6 @@ void autolayout_locateReactions(Model *model, Layout *layout) {
delete autoLayoutAlgorithm;
}

void autolayout_reiterateLocateGlyphs(Model *model, Layout *layout) {
if (autolayout_isGravityValueAcceptable(layout)) {
autolayout_updateGravity(layout);
autolayout_updateStiffness(layout);
autolayout_locateGlyphs(model, layout);
}
else if (autolayout_getNumberOfAutoLayoutParametersResets(layout) < 5) {
autolayout_resetAutoLayoutParameters(layout);
autolayout_locateGlyphs(model, layout);
}
else
error_log_addErrorToLog(layout, "Auto-layout fails to converge with the given layout dimensions. Please adjust layout width and height and try again.");
}

void autolayout_resetNumberOfAutoLayoutParametersResets(Layout *layout) {
LIBSBMLNETWORK_CPP_NAMESPACE::user_data_setUserData(layout, "number_of_auto_layout_parameters_resets", "0");
}

const double autolayout_getStiffness(Layout *layout) {
std::string stiffness = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout, "stiffness");
if (stiffness.empty()) {
Expand All @@ -90,14 +69,6 @@ void autolayout_setStiffness(Layout *layout, const double &stiffness) {
LIBSBMLNETWORK_CPP_NAMESPACE::user_data_setUserData(layout, "stiffness", std::to_string(stiffness));
}

void autolayout_updateStiffness(Layout *layout) {
autolayout_setStiffness(layout, autolayout_getStiffnessAdjustmentFactor(layout) * autolayout_getStiffness(layout));
}

double autolayout_getStiffnessAdjustmentFactor(Layout *layout) {
return std::max(std::min(autolayout_getDesiredDimensionToCurrentDimensionRatio(layout), 1.1), 0.9);
}

const double autolayout_getGravity(Layout *layout) {
std::string gravity = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout, "gravity");
if (gravity.empty()) {
Expand All @@ -112,44 +83,6 @@ void autolayout_setGravity(Layout *layout, const double &gravity) {
LIBSBMLNETWORK_CPP_NAMESPACE::user_data_setUserData(layout, "gravity", std::to_string(gravity));
}

void autolayout_updateGravity(Layout *layout) {
autolayout_setGravity(layout, autolayout_getGravityAdjustmentFactor(layout) * autolayout_getGravity(layout));
}

double autolayout_getGravityAdjustmentFactor(Layout *layout) {
return std::max(std::min(autolayout_getCurrentDimensionToDesiredDimensionRatio(layout), 1.05), 0.95);
}

double autolayout_getCurrentDimensionToDesiredDimensionRatio(Layout *layout) {
double desiredWidth = autolayout_getLayoutDimensionsDesiredWidth(layout);
double widthRatio = layout->getDimensions()->width() / desiredWidth;
double desiredHeight = autolayout_getLayoutDimensionsDesiredHeight(layout);
double heightRatio = layout->getDimensions()->height() / desiredHeight;
return std::sqrt(0.5 * (widthRatio * widthRatio + heightRatio * heightRatio));
}

double autolayout_getDesiredDimensionToCurrentDimensionRatio(Layout *layout) {
double desiredWidth = autolayout_getLayoutDimensionsDesiredWidth(layout);
double widthRatio = desiredWidth / layout->getDimensions()->width();
double desiredHeight = autolayout_getLayoutDimensionsDesiredHeight(layout);
double heightRatio = desiredHeight / layout->getDimensions()->height();
return std::sqrt(0.5 * (widthRatio * widthRatio + heightRatio * heightRatio));
}

void autolayout_resetAutoLayoutParameters(Layout *layout) {
autolayout_setStiffness(layout, 10.0);
autolayout_setGravity(layout, 15.0);
LIBSBMLNETWORK_CPP_NAMESPACE::user_data_setUserData(layout, "number_of_auto_layout_parameters_resets", std::to_string(autolayout_getNumberOfAutoLayoutParametersResets(layout) + 1));
}

const int autolayout_getNumberOfAutoLayoutParametersResets(Layout *layout) {
std::string numberOfResets = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout, "number_of_auto_layout_parameters_resets");
if (!numberOfResets.empty())
return std::stoi(numberOfResets);

return 0;
}

void autolayout_randomizeGlyphsLocations(Model *model, Layout *layout) {
double canvasWidth = layout->getDimensions()->width();
double canvasHeight = layout->getDimensions()->height();
Expand Down Expand Up @@ -329,30 +262,20 @@ void autolayout_updateLayoutDimensions(Layout *layout) {
if (!layoutContainsGlyphs(layout)) {
layout->getDimensions()->setWidth(0);
layout->getDimensions()->setHeight(0);
return;
} else {
}
else {
double maxX;
double maxY;
autolayout_extractExtents(layout, maxX, maxY);
layout->getDimensions()->setWidth(maxX);
layout->getDimensions()->setHeight(maxY);
std::string presetWidth = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout->getDimensions(), "width");
if (presetWidth.empty())
layout->getDimensions()->setWidth(maxX);
std::string presetHeight = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout->getDimensions(), "height");
if (presetHeight.empty())
layout->getDimensions()->setHeight(maxY);
}
}

const bool autolayout_adjustLayoutDimensions(Layout *layout) {
double desiredWidth = autolayout_getLayoutDimensionsDesiredWidth(layout);
double widthGap = desiredWidth - layout->getDimensions()->width();
double desiredHeight = autolayout_getLayoutDimensionsDesiredHeight(layout);
double heightGap = desiredHeight - layout->getDimensions()->height();
if (widthGap >= 0.0 && widthGap <= 0.1 * desiredWidth && heightGap >= 0.0 && heightGap <= 0.1 * desiredHeight) {
layout->getDimensions()->setWidth(desiredWidth);
layout->getDimensions()->setHeight(desiredHeight);
return true;
}

return false;
}

const double autolayout_getLayoutDimensionsDesiredWidth(Layout *layout) {;
std::string presetWidth = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout->getDimensions(), "width");
if (!presetWidth.empty())
Expand Down
26 changes: 0 additions & 26 deletions src/features/autolayout/libsbmlnetwork_autolayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,14 @@ void autolayout_locateGlyphs(Model* model, Layout* layout);

void autolayout_locateReactions(Model *model, Layout *layout);

void autolayout_reiterateLocateGlyphs(Model *model, Layout *layout);

void autolayout_resetNumberOfAutoLayoutParametersResets(Layout *layout);

const double autolayout_getStiffness(Layout *layout);

void autolayout_setStiffness(Layout *layout, const double& stiffness);

void autolayout_updateStiffness(Layout *layout);

double autolayout_getStiffnessAdjustmentFactor(Layout *layout);

const double autolayout_getGravity(Layout *layout);

void autolayout_setGravity(Layout *layout, const double& gravity);

void autolayout_updateGravity(Layout *layout);

double autolayout_getGravityAdjustmentFactor(Layout *layout);

double autolayout_getCurrentDimensionToDesiredDimensionRatio(Layout *layout);

double autolayout_getDesiredDimensionToCurrentDimensionRatio(Layout *layout);

void autolayout_resetAutoLayoutParameters(Layout *layout);

const int autolayout_getNumberOfAutoLayoutParametersResets(Layout *layout);

void autolayout_randomizeGlyphsLocations(Model* model, Layout* layout);
Expand Down Expand Up @@ -70,14 +52,6 @@ void autolayout_updateCompartmentsExtentsUsingTheirPresetAttributes(Layout *layo

void autolayout_updateLayoutDimensions(Layout* layout);

const bool autolayout_adjustLayoutDimensions(Layout *layout);

const double autolayout_getLayoutDimensionsDesiredWidth(Layout *layout);

const double autolayout_getLayoutDimensionsDesiredHeight(Layout *layout);

const bool autolayout_isGravityValueAcceptable(Layout *layout);

void autolayout_extractExtents(Layout* layout, double &maxX, double &maxY);

void autolayout_extractExtents(BoundingBox* boundingBox, double &minX, double &minY, double &maxX, double &maxY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../defaults/libsbmlnetwork_defaults_layout.h"
#include <cstdlib>
#include <cmath>
#include <climits>

#ifndef M_PI
#define M_PI 3.14159265358979323846
Expand Down Expand Up @@ -69,17 +70,17 @@ void FruchtermanReingoldAlgorithmBase::setNodesDegrees() {
void FruchtermanReingoldAlgorithmBase::setWidth(Layout* layout) {
std::string width = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout->getDimensions(), "width");
if (!width.empty() && std::stod(width) > 0.0) {
_width = std::max(0.0, std::stod(width) - 6 * defaults_getDefaultAutoLayoutPadding());
_width = std::max(0.0, std::stod(width) - 2 * defaults_getDefaultAutoLayoutPadding());
_useHorizontalBoundary = true;
}
else
_width = _nodes.size() * _nodes.size() * _stiffness * 5;
_width = _nodes.size() * 10 * _stiffness;
}

void FruchtermanReingoldAlgorithmBase::setHeight(Layout* layout) {
std::string height = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout->getDimensions(), "height");
if (!height.empty() && std::stod(height) > 0.0) {
_height = std::max(0.0, std::stod(height) - 6 * defaults_getDefaultAutoLayoutPadding());
_height = std::max(0.0, std::stod(height) - 2 * defaults_getDefaultAutoLayoutPadding());
_useVerticalBoundary = true;
}
else
Expand Down Expand Up @@ -116,6 +117,7 @@ void FruchtermanReingoldAlgorithmBase::apply() {
initialize();
iterate();
updateNodesDimensions();
scaleCoordinates();
adjustCoordinateOrigin();
updateConnectionsControlPoints();
}
Expand Down Expand Up @@ -316,20 +318,47 @@ void FruchtermanReingoldAlgorithmBase::updateNodesDimensions() {
}
}

void FruchtermanReingoldAlgorithmBase::scaleCoordinates() {
double minX = INT_MAX;
double minY = INT_MAX;
double maxX = INT_MIN;
double maxY = INT_MIN;
for (int nodeIndex = 0; nodeIndex < _nodes.size(); nodeIndex++) {
if (((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX() < minX)
minX = ((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX();
if (((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY() < minY)
minY = ((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY();
if (((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX() + ((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getWidth() > maxX)
maxX = ((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX() + ((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getWidth();
if (((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY() + ((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getHeight() > maxY)
maxY = ((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY() + ((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getHeight();
}
double width = maxX - minX;
double height = maxY - minY;
double horizontalScale = _width / width;
double verticalScale = _height / height;
for (int nodeIndex = 0; nodeIndex < _nodes.size(); nodeIndex++) {
if (!((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->isPositionFixed()) {
((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->setX(((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX() * horizontalScale);
((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->setY(((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY() * verticalScale);
}
}
}

void FruchtermanReingoldAlgorithmBase::adjustCoordinateOrigin() {
AutoLayoutPoint _origin = AutoLayoutPoint(0.0, 0.0);
AutoLayoutPoint origin = AutoLayoutPoint(0.0, 0.0);
for (int nodeIndex = 0; nodeIndex < _nodes.size(); nodeIndex++) {
if (((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX() < _origin.getX())
_origin.setX(((AutoLayoutNodeBase *) _nodes.at(nodeIndex))->getX());
if (((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY() < _origin.getY())
_origin.setY(((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY());
if (((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX() < origin.getX())
origin.setX(((AutoLayoutNodeBase *) _nodes.at(nodeIndex))->getX());
if (((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY() < origin.getY())
origin.setY(((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY());
}
_origin.setX(_origin.getX() - defaults_getDefaultAutoLayoutPadding());
_origin.setY(_origin.getY() - defaults_getDefaultAutoLayoutPadding());
origin.setX(origin.getX() - defaults_getDefaultAutoLayoutPadding());
origin.setY(origin.getY() - defaults_getDefaultAutoLayoutPadding());
for (int nodeIndex = 0; nodeIndex < _nodes.size(); nodeIndex++) {
if (!((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->isPositionFixed()) {
((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->setX(((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX() - _origin.getX());
((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->setY(((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY() - _origin.getY());
((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->setX(((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getX() - origin.getX());
((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->setY(((AutoLayoutNodeBase*)_nodes.at(nodeIndex))->getY() - origin.getY());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class FruchtermanReingoldAlgorithmBase {

void applyGravity();

void scaleCoordinates();

void adjustCoordinates();

void adjustNodeCoordinates(AutoLayoutObjectBase* node);
Expand Down

0 comments on commit a2dd8f8

Please sign in to comment.