diff --git a/src/bindings/python/ctypes/libsbmlnetwork.py.cmake b/src/bindings/python/ctypes/libsbmlnetwork.py.cmake index b8875e2..ed8697f 100644 --- a/src/bindings/python/ctypes/libsbmlnetwork.py.cmake +++ b/src/bindings/python/ctypes/libsbmlnetwork.py.cmake @@ -25,13 +25,14 @@ class LibSBMLNetwork: A wrapper class to use libSBMLNetwork, which is an API to work with the Layout and Render packages of libSBML """ - def __init__(self, sbml): + def __init__(self, sbml, disable_auto_layout=False): """ Initializes the LibSBMLNetwork class by reading an SBML document from the given file name or the given text string :Parameters: - sbml: an SBML document in the form of either an SBML file (.xml) directory or an SBML string + - disable_auto_layout (boolean, optional): a boolean (default: False) that determines whether to disable the autolayout algorithm after loading the SBML document """ self.sbml_object = None @@ -40,7 +41,7 @@ class LibSBMLNetwork: self.display_compartments_text_label = True self.display_species_text_label = True self.display_reactions_text_label = False - self.load(sbml) + self.load(sbml, disable_auto_layout) def getVersion(self): """ @@ -65,13 +66,14 @@ class LibSBMLNetwork: lib.c_api_getLibraryCurrentDirectory.restype = ctypes.c_char_p return ctypes.c_char_p(lib.c_api_getCurrentDirectoryOfLibrary()).value.decode() - def load(self, sbml): + def load(self, sbml, disable_auto_layout=False): """ Reads an SBML document from the given file directory or the given text string :Parameters: - sbml (string): a string that determines either the name or full pathname of the SBML(.xml) file to be read or a string containing a full SBML model. + - disable_auto_layout (boolean, optional): a boolean (default: False) that determines whether to disable the autolayout algorithm after loading the SBML document :Returns: @@ -81,12 +83,13 @@ class LibSBMLNetwork: self.sbml_object = lib.c_api_readSBML(str(sbml).encode()) if not self.isSetModel(): raise Exception(f"The SBML document could not be loaded. {sbml} is neither a valid SBML file path nor a valid SBML string.") - if not self._layout_is_specified(): - self.autolayout() - self.layout_is_added = True - if not self._render_is_specified(): - self.autorender() - self.render_is_added = True + if not disable_auto_layout: + if not self._layout_is_specified(): + self.autolayout() + self.layout_is_added = True + if not self._render_is_specified(): + self.autorender() + self.render_is_added = True def save(self, file_name=""): """ @@ -175,6 +178,20 @@ class LibSBMLNetwork: """ return lib.c_api_autorender(self.sbml_object, ctypes.c_int(max_num_connected_edges)) + def updateReactionCurves(self, layout_index=0): + """ + Updates the curves of the centroid node position of the ReactionGlyphs and the curve of their SpeciesReferenceGlyphs in the Layout object with the given index in the given SBMLDocument + + :Parameters: + + - layout_index (int, optional): an integer (default: 0) that determines the index of the Layout object in the given SBMLDocument + + :Returns: + + true on success and false if the curves could not be updated + """ + return lib.c_api_updateReactionCurves(self.sbml_object, layout_index) + def align(self, nodes, alignment="center", ignore_fixed_position_nodes=False): """ Aligns the given nodes in the given alignment type form in the given SBMLDocument @@ -1317,7 +1334,7 @@ class LibSBMLNetwork: """ return lib.c_api_setSpeciesReferenceRole(self.sbml_object, str(reaction_id).encode(), str(role).encode(), reaction_glyph_index, species_reference_index, layout_index) - def getNumSpeciesReferenceAssociatedWithSpecies(self, species_id, reaction_id, reaction_glyph_index = 0): + def getNumSpeciesReferenceAssociatedWithSpecies(self, species_id, reaction_id, reaction_glyph_index = 0, layout_index = 0): """ Returns the number of SpeciesReferences associated with the given species_id in the given SBMLDocument @@ -1331,7 +1348,7 @@ class LibSBMLNetwork: an integer that determines the number of SpeciesReferences associated with the given species_id in the given SBMLDocument """ - return lib.c_api_getNumSpeciesReferenceAssociatedWithSpecies(self.sbml_object, str(species_id).encode(), str(reaction_id).encode(), reaction_glyph_index) + return lib.c_api_getNumSpeciesReferenceAssociatedWithSpecies(self.sbml_object, str(species_id).encode(), str(reaction_id).encode(), reaction_glyph_index, layout_index) def getSpeciesReferenceIndexAssociatedWithSpecies(self, species_id, reaction_id, reaction_glyph_index = 0, n = 0, layout_index = 0): """ @@ -13028,6 +13045,28 @@ class LibSBMLNetwork: return list_of_geometric_shapes + def getStoichiometricSpeciesReference(self): + """ + Returns the flag to create a species reference for each stoichiometry in the autolayout algorithm + + :Returns: + + a boolean that determines whether the autolayout must create a species reference for each stoichiometry or not + + """ + return lib.c_api_getStoichiometricSpeciesReference(self.sbml_object) + + def setStoichiometricSpeciesReference(self, stoichiometric_species_reference): + """ + Set the flag to create a species reference for each stoichiometry in the autolayout algorithm + + :Parameters: + + - stoichiometric_species_reference (bool): a boolean that determines whether the autolayout must create a species reference for each stoichiometry or not + + """ + return lib.c_api_setStoichiometricSpeciesReference(self.sbml_object, stoichiometric_species_reference) + def getUseNameAsTextLabel(self, layout_index=0): """ Returns the flag to use the name of the model entity as the text label of the GraphicalObject associated with the model entity in the layout with the given layout_index diff --git a/src/bindings/python/ctypes/sbmlnetwork/src/sbmlnetwork/sbmlnetwork.py b/src/bindings/python/ctypes/sbmlnetwork/src/sbmlnetwork/sbmlnetwork.py index f1712e8..e613075 100644 --- a/src/bindings/python/ctypes/sbmlnetwork/src/sbmlnetwork/sbmlnetwork.py +++ b/src/bindings/python/ctypes/sbmlnetwork/src/sbmlnetwork/sbmlnetwork.py @@ -5,8 +5,13 @@ class SBMLNetwork(libsbmlnetwork.LibSBMLNetwork): - def __init__(self, sbml=""): - super().__init__(sbml) + def __init__(self, sbml="", disable_autolayout=False): + """ + Initializes the SBMLNetwork object. + :param sbml: + :param disable_autolayout: + """ + super().__init__(sbml, disable_autolayout) def draw(self, file_name=""): """ @@ -27,14 +32,15 @@ def draw(self, file_name=""): self.display_reactions_text_label)) -def load(sbml): +def load(sbml, disable_autolayout=False): """ Loads the SBML model. :param sbml: The SBML model. + :param disable_autolayout: If True, the autolayout will not be applied. :return: SBMLNetwork """ - return SBMLNetwork(sbml) + return SBMLNetwork(sbml, disable_autolayout) diff --git a/src/bindings/python/ctypes/sbmlnetwork/tests/test_with_specific_models.py b/src/bindings/python/ctypes/sbmlnetwork/tests/test_with_specific_models.py index ffdcf06..1ffcf12 100644 --- a/src/bindings/python/ctypes/sbmlnetwork/tests/test_with_specific_models.py +++ b/src/bindings/python/ctypes/sbmlnetwork/tests/test_with_specific_models.py @@ -75,7 +75,7 @@ def test_use_name_as_text_label(self): """ sbml = te.loada(model).getSBML() network = sbmlnetwork.SBMLNetwork(sbml) - # default use name as text label is False + # default use name as text label self.assertEqual(network.getText("S1"), "Species 1") # set use name as text label to False network.setUseNameAsTextLabel(False) @@ -119,10 +119,13 @@ def test_layout_size(self): """ sbml = te.loada(model).getSBML() network = sbmlnetwork.SBMLNetwork(sbml) - network.setCanvasWidth(1234.0) - network.setCanvasHeight(1432.0) - self.assertEqual(network.getCanvasWidth(), 1234.0) - self.assertEqual(network.getCanvasHeight(), 1432.0) + network.setCanvasWidth(1000.0) + network.setCanvasHeight(1000.0) + self.assertEqual(network.getCanvasWidth(), 1000.0) + self.assertEqual(network.getCanvasHeight(), 1000.0) + network.autolayout() + self.assertEqual(network.getCanvasWidth(), 1000.0) + self.assertEqual(network.getCanvasHeight(), 1000.0) def test_align_top(self): model = """ @@ -793,6 +796,65 @@ def test_swap_species_glyph_in_reaction(self): network.setSpeciesGlyphIndexInReactionGlyph("S1", "J2", 2) self.assertEqual(network.getSpeciesGlyphIndex("S1", "J1"), 2) + def test_species_reference_index_associated_with_species(self): + model = ''' + J0: S1 -> S2; + ''' + sbml = te.loada(model).getSBML() + network = sbmlnetwork.SBMLNetwork(sbml) + self.assertEqual(network.getSpeciesReferenceIndexAssociatedWithSpecies("S1", "J0"), 0) + self.assertEqual(network.getSpeciesReferenceIndexAssociatedWithSpecies("S2", "J0"), 1) + + def test_set_stoichiometric_species_reference(self): + model = ''' + J0: 100000 S1 -> 200000 S2; + ''' + sbml = te.loada(model).getSBML() + network = sbmlnetwork.SBMLNetwork(sbml, disable_autolayout=True) + # set stoichiometric species reference + network.setStoichiometricSpeciesReference(False) + network.autolayout() + self.assertEqual(network.getNumSpeciesReferenceAssociatedWithSpecies("S1", "J0"), 1) + + def test_disable_autolayout_at_load(self): + model = ''' + S1 -> S2; + ''' + sbml = te.loada(model).getSBML() + network = sbmlnetwork.SBMLNetwork(sbml, disable_autolayout=True) + self.assertEqual(network.getNumLayouts(), 0) + self.assertEqual(network.getNumGlobalRenderInformation(), 0) + self.assertEqual(network.getNumLocalRenderInformation(), 0) + network.autolayout() + self.assertEqual(network.getNumLayouts(), 1) + self.assertEqual(network.getNumGlobalRenderInformation(), 1) + self.assertEqual(network.getNumLocalRenderInformation(), 1) + + def test_set_colors_of_a_group_of_graphical_objects(self): + model = ''' + S1 -> S2; + ''' + sbml = te.loada(model).getSBML() + network = sbmlnetwork.SBMLNetwork(sbml) + network.setCompartmentsBorderColor("#FF0000") + network.setCompartmentsFontColor("#A52A2A") + network.setSpeciesBorderColor("#00FF00") + network.setSpeciesFontColor("#800080") + network.setReactionsLineColor("#0000FF") + network.setReactionsFontColor("#FFC0CB") + network.setCompartmentsFillColor("#FFFF00") + network.setSpeciesFillColor("#FFA500") + network.setReactionsFillColor("#FF00FF") + self.assertEqual(network.getCompartmentsBorderColor(), "red") + self.assertEqual(network.getCompartmentsFontColor(), "brown") + self.assertEqual(network.getSpeciesBorderColor(), "lime") + self.assertEqual(network.getSpeciesFontColor(), "purple") + self.assertEqual(network.getReactionsLineColor(), "blue") + self.assertEqual(network.getReactionsFontColor(), "pink") + self.assertEqual(network.getCompartmentsFillColor(), "yellow") + self.assertEqual(network.getSpeciesFillColor(), "orange") + self.assertEqual(network.getReactionsFillColor(), "fuchsia") + @staticmethod def _get_max_position_y(network, species_list): max_position_y = -math.inf diff --git a/src/c_api/libsbmlnetwork_c_api.cpp b/src/c_api/libsbmlnetwork_c_api.cpp index f70437e..743f194 100644 --- a/src/c_api/libsbmlnetwork_c_api.cpp +++ b/src/c_api/libsbmlnetwork_c_api.cpp @@ -73,6 +73,10 @@ namespace LIBSBMLNETWORK_CPP_NAMESPACE { return autorender(document, maxNumConnectedEdges); } + int c_api_updateReactionCurves(SBMLDocument* document, const int layoutIndex) { + return updateLayoutCurves(document, getLayout(document, layoutIndex)); + } + int c_api_align(SBMLDocument* document, const char ***nodes, const int nodesSize, const char* alignment, bool ignorefixedPositionNodes) { std::set > nodesSet = std::set >(); if (nodes) { @@ -185,6 +189,14 @@ namespace LIBSBMLNETWORK_CPP_NAMESPACE { return createDefaultLayoutLocations(document, maxNumConnectedEdges, resetFixedPositionElements, fixedPositionNodesSet); } + bool c_api_getStoichiometricSpeciesReference(SBMLDocument* document) { + return getStoichiometricSpeciesReference(document); + } + + int c_api_setStoichiometricSpeciesReference(SBMLDocument* document, bool stoichiometricSpeciesReference) { + return setStoichiometricSpeciesReference(document, stoichiometricSpeciesReference); + } + bool c_api_getUseNameAsTextLabel(SBMLDocument* document, int layoutIndex) { return getUseNameAsTextLabel(document, layoutIndex); } diff --git a/src/c_api/libsbmlnetwork_c_api.h b/src/c_api/libsbmlnetwork_c_api.h index 2f1cfb1..98eb265 100644 --- a/src/c_api/libsbmlnetwork_c_api.h +++ b/src/c_api/libsbmlnetwork_c_api.h @@ -87,6 +87,12 @@ namespace LIBSBMLNETWORK_CPP_NAMESPACE { /// @return integer value indicating success/failure of the function. LIBSBMLNETWORK_EXTERN int c_api_autorender(SBMLDocument *document, const int maxNumConnectedEdges = 3); + /// @brief Updates the curves of the centroid node position of the ReactionGlyphs and the curve of their SpeciesReferenceGlyphs in the Layout object with the given index in the given SBMLDocument. + /// @param document a pointer to the SBMLDocument object. + /// @param layoutIndex the index number of the Layout to return. + /// @return integer value indicating success/failure of the function. + LIBSBMLNETWORK_EXTERN int c_api_updateReactionCurves(SBMLDocument* document, const int layoutIndex = 0); + /// @brief Align the nodes position in the SBML document in the given alignment type. /// @param document a pointer to the SBMLDocument object. /// @param nodes an array of strings containing the ids of the nodes and their associated graphical objects that should be aligned. @@ -231,7 +237,29 @@ namespace LIBSBMLNETWORK_CPP_NAMESPACE { LIBSBMLNETWORK_EXTERN int c_api_createDefaultLayoutLocations(SBMLDocument* document, const int maxNumConnectedEdges = 3, bool resetFixedPositionElements = false, const char*** fixedPositionNodeIds = NULL, const int fixedPositionNodesSize = 0); - LIBSBMLNETWORK_EXTERN int c_api_setUseNameAsTextLabel(SBMLDocument* document, bool useNameAsTextLabel, int layoutIndex); + /// @brief Returns the value of the option to generate stoichiometric species reference in the autolayout algorithm. + /// @param document a pointer to the SBMLDocument object. + /// @return the value of the option to generate stoichiometric species reference in the autolayout algorithm. + LIBSBMLNETWORK_EXTERN bool c_api_getStoichiometricSpeciesReference(SBMLDocument* document); + + /// @brief Sets the value of the option to generate stoichiometric species reference in the autolayout algorithm. + /// @param document a pointer to the SBMLDocument object. + /// @param stoichiometricSpeciesReference the value of the option to generate stoichiometric species reference in the autolayout algorithm. + /// @return integer value indicating success/failure of the function. + LIBSBMLNETWORK_EXTERN int c_api_setStoichiometricSpeciesReference(SBMLDocument* document, bool stoichiometricSpeciesReference); + + /// @brief Returns the option to use the name of the model entity as the text label of the GraphicalObject associated with the model entities in the Layout object with the given index in the ListOfLayouts of the SBMLDocument. + /// @param document a pointer to the SBMLDocument object. + /// @param layoutIndex the index number of the Layout to return. + /// @return the option to use the name of the model entity as the text label of the GraphicalObject associated with the model entities. + LIBSBMLNETWORK_EXTERN bool c_api_getUseNameAsTextLabel(SBMLDocument* document, int layoutIndex = 0); + + /// @brief Sets the option to use the name of the model entity as the text label of the GraphicalObject associated with the model entities in the Layout object with the given index in the ListOfLayouts of the SBMLDocument. + /// @param document a pointer to the SBMLDocument object. + /// @param useNameAsTextLabel the option to use the name of the model entity as the text label of the GraphicalObject associated with the model entities. + /// @param layoutIndex the index number of the Layout to return. + /// @return integer value indicating success/failure of the function. + LIBSBMLNETWORK_EXTERN int c_api_setUseNameAsTextLabel(SBMLDocument* document, bool useNameAsTextLabel, int layoutIndex = 0); /// @brief Create an alias SpeciesGlyph object for Species with the given id and connect all the SpeciesReferences in the ReactionGlyph object with the given id and index that contain Species as a participant to the alias SpeciesGlyph in the Layout object with the given index in the ListOfLayouts of the SBMLDocument. /// @param document a pointer to the SBMLDocument object. diff --git a/src/features/alias_elements/libsbmlnetwork_alias_reaction.cpp b/src/features/alias_elements/libsbmlnetwork_alias_reaction.cpp index 5100683..ec34433 100644 --- a/src/features/alias_elements/libsbmlnetwork_alias_reaction.cpp +++ b/src/features/alias_elements/libsbmlnetwork_alias_reaction.cpp @@ -51,7 +51,7 @@ namespace LIBSBMLNETWORK_CPP_NAMESPACE { speciesGlyphAliasSpeciesGlyphIds[speciesGlyph->getId()]); if (connectedSpeciesGlyph) { speciesGlyphAliasSpeciesGlyphIds[speciesGlyph->getId()] = connectedSpeciesGlyph->getId(); - int stoichiometry = getStoichiometryAsInteger( + int stoichiometry = getStoichiometryAsInteger(layout, findSpeciesReference(document->getModel(), layout, referenceReactionGlyph, speciesGlyph)); for (unsigned int stoichiometryIndex = 0; stoichiometryIndex < stoichiometry; stoichiometryIndex++) alias_element_createAliasSpeciesReferenceGlyph(reactionGlyph, speciesReferenceGlyph, diff --git a/src/features/autolayout/libsbmlnetwork_autolayout.cpp b/src/features/autolayout/libsbmlnetwork_autolayout.cpp index b17f9d7..e230702 100755 --- a/src/features/autolayout/libsbmlnetwork_autolayout.cpp +++ b/src/features/autolayout/libsbmlnetwork_autolayout.cpp @@ -33,15 +33,9 @@ void autolayout_locateGlyphs(Model *model, Layout *layout) { autolayout_updateCompartmentsExtents(model, layout); autolayout_updateLayoutDimensions(layout); delete autoLayoutAlgorithm; - if (!autolayout_adjustLayoutDimensions(layout)) { - if (autolayout_autolayoutMayStillConverge(layout)) { - autolayout_updateGravity(layout); - autolayout_updateStiffness(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."); - } + if (!autolayout_adjustLayoutDimensions(layout)) + autolayout_reiterateLocateGlyphs(model, layout); + autolayout_resetNumberOfAutoLayoutParametersResets(layout); } void autolayout_locateReactions(Model *model, Layout *layout) { @@ -64,11 +58,29 @@ 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()) { - autolayout_setStiffness(layout, 10.0); - return 10.0; + stiffness = "10.0"; + autolayout_setStiffness(layout, stod(stiffness)); } return std::stod(stiffness); @@ -89,8 +101,8 @@ double autolayout_getStiffnessAdjustmentFactor(Layout *layout) { const double autolayout_getGravity(Layout *layout) { std::string gravity = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout, "gravity"); if (gravity.empty()) { - autolayout_setGravity(layout, 15.0); - return 15.0; + gravity = "15.0"; + autolayout_setGravity(layout, std::stod(gravity)); } return std::stod(gravity); @@ -110,36 +122,32 @@ double autolayout_getGravityAdjustmentFactor(Layout *layout) { double autolayout_getCurrentDimensionToDesiredDimensionRatio(Layout *layout) { double desiredWidth = autolayout_getLayoutDimensionsDesiredWidth(layout); + double widthRatio = layout->getDimensions()->width() / desiredWidth; double desiredHeight = autolayout_getLayoutDimensionsDesiredHeight(layout); - if (layout->getDimensions()->width() < desiredWidth || layout->getDimensions()->height() < desiredHeight) { - double widthRatio = layout->getDimensions()->width() / desiredWidth; - double heightRatio = layout->getDimensions()->height() / desiredHeight; - return std::sqrt(widthRatio * widthRatio + heightRatio * heightRatio); - } - else if (layout->getDimensions()->width() > desiredWidth || layout->getDimensions()->height() > desiredHeight) { - double widthRatio = layout->getDimensions()->width() / desiredWidth; - double heightRatio = layout->getDimensions()->height() / desiredHeight; - return std::sqrt(widthRatio * widthRatio + heightRatio * heightRatio); - } - - return 1.0; + 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); - if (layout->getDimensions()->width() < desiredWidth || layout->getDimensions()->height() < desiredHeight) { - double widthRatio = desiredWidth / layout->getDimensions()->width(); - double heightRatio = desiredHeight / layout->getDimensions()->height(); - return std::sqrt(widthRatio * widthRatio + heightRatio * heightRatio); - } - else if (layout->getDimensions()->width() > desiredWidth || layout->getDimensions()->height() > desiredHeight) { - double widthRatio = desiredWidth / layout->getDimensions()->width(); - double heightRatio = desiredHeight / layout->getDimensions()->height(); - return std::sqrt(widthRatio * widthRatio + heightRatio * heightRatio); - } + double heightRatio = desiredHeight / layout->getDimensions()->height(); + return std::sqrt(0.5 * (widthRatio * widthRatio + heightRatio * heightRatio)); +} - return 1.0; +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) { @@ -336,9 +344,9 @@ const bool autolayout_adjustLayoutDimensions(Layout *layout) { double widthGap = desiredWidth - layout->getDimensions()->width(); double desiredHeight = autolayout_getLayoutDimensionsDesiredHeight(layout); double heightGap = desiredHeight - layout->getDimensions()->height(); - if (widthGap <= 0.1 * desiredWidth && heightGap <= 0.1 * desiredHeight) { - autolayout_setLayoutDimensionsDesiredWidth(layout, layout->getDimensions()->width()); - autolayout_setLayoutDimensionsDesiredHeight(layout, 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; } @@ -353,11 +361,6 @@ const double autolayout_getLayoutDimensionsDesiredWidth(Layout *layout) {; return layout->getDimensions()->width(); } -void autolayout_setLayoutDimensionsDesiredWidth(Layout *layout, const double &width) { - if (!LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout->getDimensions(), "width").empty()) - LIBSBMLNETWORK_CPP_NAMESPACE::user_data_setUserData(layout->getDimensions(), "width", std::to_string(width)); -} - const double autolayout_getLayoutDimensionsDesiredHeight(Layout *layout) { std::string presetHeight = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout->getDimensions(), "height"); if (!presetHeight.empty()) @@ -366,13 +369,8 @@ const double autolayout_getLayoutDimensionsDesiredHeight(Layout *layout) { return layout->getDimensions()->height(); } -void autolayout_setLayoutDimensionsDesiredHeight(Layout *layout, const double &height) { - if (!LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout->getDimensions(), "height").empty()) - LIBSBMLNETWORK_CPP_NAMESPACE::user_data_setUserData(layout->getDimensions(), "height", std::to_string(height)); -} - -const bool autolayout_autolayoutMayStillConverge(Layout *layout) { - if (autolayout_getGravity(layout) > 1.0) +const bool autolayout_isGravityValueAcceptable(Layout *layout) { + if (autolayout_getGravity(layout) > 0.1 && autolayout_getGravity(layout) < 1000.0) return true; return false; diff --git a/src/features/autolayout/libsbmlnetwork_autolayout.h b/src/features/autolayout/libsbmlnetwork_autolayout.h index e7c0267..806f9ca 100755 --- a/src/features/autolayout/libsbmlnetwork_autolayout.h +++ b/src/features/autolayout/libsbmlnetwork_autolayout.h @@ -14,6 +14,10 @@ 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); @@ -34,6 +38,10 @@ 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); void autolayout_randomizeSpeciesGlyphsLocations(Model* model, Layout* layout, const double& canvasWidth, const double& canvasHeight); @@ -66,13 +74,9 @@ const bool autolayout_adjustLayoutDimensions(Layout *layout); const double autolayout_getLayoutDimensionsDesiredWidth(Layout *layout); -void autolayout_setLayoutDimensionsDesiredWidth(Layout *layout, const double& width); - const double autolayout_getLayoutDimensionsDesiredHeight(Layout *layout); -void autolayout_setLayoutDimensionsDesiredHeight(Layout *layout, const double& height); - -const bool autolayout_autolayoutMayStillConverge(Layout *layout); +const bool autolayout_isGravityValueAcceptable(Layout *layout); void autolayout_extractExtents(Layout* layout, double &maxX, double &maxY); diff --git a/src/features/autolayout/libsbmlnetwork_autolayout_node.cpp b/src/features/autolayout/libsbmlnetwork_autolayout_node.cpp index 353d408..56fe402 100644 --- a/src/features/autolayout/libsbmlnetwork_autolayout_node.cpp +++ b/src/features/autolayout/libsbmlnetwork_autolayout_node.cpp @@ -8,7 +8,10 @@ AutoLayoutNodeBase::AutoLayoutNodeBase(Model* model, Layout* layout, GraphicalObject* graphicalObject, const bool& positionFixed) : AutoLayoutObjectBase(model, layout) { _degree = 0; - _useNameAsTextLabel = LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout, "use_name_as_text_label") != "false"; + if (LIBSBMLNETWORK_CPP_NAMESPACE::user_data_getUserData(layout, "use_name_as_text_label") == "false") + _useNameAsTextLabel = false; + else + _useNameAsTextLabel = true; _graphicalObject = graphicalObject; setPositionFixed(positionFixed); } diff --git a/src/features/set_layout_features/libsbmlnetwork_set_layout_features.cpp b/src/features/set_layout_features/libsbmlnetwork_set_layout_features.cpp index 69913d0..98d1391 100644 --- a/src/features/set_layout_features/libsbmlnetwork_set_layout_features.cpp +++ b/src/features/set_layout_features/libsbmlnetwork_set_layout_features.cpp @@ -10,6 +10,7 @@ namespace LIBSBMLNETWORK_CPP_NAMESPACE { int set_layout_features_setDefaultLayoutFeatures(SBMLDocument* document, Layout* layout, const int maxNumConnectedEdges) { if (document && layout) { + user_data_passUserData(document, layout); defaults_setDefaultLayoutId(layout); defaults_setDefaultLayoutDimensions(layout); Model* model = document->getModel(); @@ -29,6 +30,7 @@ int set_layout_features_setDefaultLayoutFeatures(SBMLDocument* document, Layout* int set_layout_features_setDefaultLayoutLocations(SBMLDocument* document, Layout* layout, const int maxNumConnectedEdges, bool resetFixedPositionElements, const std::set > fixedPositionNodesSet) { if (document && layout) { + user_data_passUserData(document, layout); defaults_setDefaultLayoutId(layout); defaults_setDefaultLayoutDimensions(layout); Model* model = document->getModel(); @@ -133,7 +135,7 @@ void set_layout_features_setReactionGlyphs(Model* model, Layout* layout, const i void set_layout_features_setReactantGlyphs(Layout* layout, Reaction* reaction, ReactionGlyph* reactionGlyph, const int maxNumConnectedEdges, const std::vector>& userData) { for (unsigned int i = 0; i < reaction->getNumReactants(); i++) { SimpleSpeciesReference* speciesReference = reaction->getReactant(i); - int stoichiometry = getStoichiometryAsInteger(speciesReference); + int stoichiometry = getStoichiometryAsInteger(layout, speciesReference); for (unsigned int stoichiometryIndex = 0; stoichiometryIndex < stoichiometry; stoichiometryIndex++) { SpeciesReferenceGlyph *speciesReferenceGlyph = set_layout_features_createSpeciesReferenceGlyph(layout, reactionGlyph, speciesReference->getSpecies(), stoichiometryIndex, maxNumConnectedEdges, userData); speciesReferenceGlyph->setRole(SPECIES_ROLE_SUBSTRATE); @@ -144,7 +146,7 @@ void set_layout_features_setReactantGlyphs(Layout* layout, Reaction* reaction, R void set_layout_features_setProductGlyphs(Layout* layout, Reaction* reaction, ReactionGlyph* reactionGlyph, const int maxNumConnectedEdges, const std::vector>& userData) { for (unsigned int i = 0; i < reaction->getNumProducts(); i++) { SimpleSpeciesReference* speciesReference = reaction->getProduct(i); - int stoichiometry = getStoichiometryAsInteger(speciesReference); + int stoichiometry = getStoichiometryAsInteger(layout, speciesReference); for (unsigned int stoichiometryIndex = 0; stoichiometryIndex < stoichiometry; stoichiometryIndex++) { SpeciesReferenceGlyph* speciesReferenceGlyph = set_layout_features_createSpeciesReferenceGlyph(layout, reactionGlyph, speciesReference->getSpecies(), stoichiometryIndex, maxNumConnectedEdges, userData); speciesReferenceGlyph->setRole(SPECIES_ROLE_PRODUCT); diff --git a/src/features/update_curves/libsbmlnetwork_update_curves.cpp b/src/features/update_curves/libsbmlnetwork_update_curves.cpp index 3c9251f..639225e 100644 --- a/src/features/update_curves/libsbmlnetwork_update_curves.cpp +++ b/src/features/update_curves/libsbmlnetwork_update_curves.cpp @@ -1,11 +1,13 @@ #include "libsbmlnetwork_update_curves.h" #include "../../features/set_layout_features/libsbmlnetwork_set_layout_features.h" #include "../../features/autolayout/libsbmlnetwork_autolayout.h" +#include "../../features/user_data/libsbmlnetwork_user_data.h" namespace LIBSBMLNETWORK_CPP_NAMESPACE { int update_curves_updateLayoutCurves(SBMLDocument* document, Layout* layout) { if (document && layout) { + user_data_passUserData(document, layout); Model* model = document->getModel(); if (model) { set_layout_features_clearReactionTextGlyphs(layout); diff --git a/src/features/user_data/libsbmlnetwork_user_data.cpp b/src/features/user_data/libsbmlnetwork_user_data.cpp index 5bc3805..d0223f8 100644 --- a/src/features/user_data/libsbmlnetwork_user_data.cpp +++ b/src/features/user_data/libsbmlnetwork_user_data.cpp @@ -269,5 +269,20 @@ int user_data_freeUserData(SBase* sBase) { return -1; } + +int user_data_passUserData(SBase* sBase1, SBase* sBase2) { + if (sBase1 && sBase2) { + if (sBase1->isSetUserData()) { + auto userData = (std::map*)sBase1->getUserData(); + for (auto it = userData->begin(); it != userData->end(); it++) { + user_data_setUserData(sBase2, it->first, it->second); + } + } + + return 0; + } + + return -1; +} } diff --git a/src/features/user_data/libsbmlnetwork_user_data.h b/src/features/user_data/libsbmlnetwork_user_data.h index 36405e8..8a1820b 100644 --- a/src/features/user_data/libsbmlnetwork_user_data.h +++ b/src/features/user_data/libsbmlnetwork_user_data.h @@ -41,6 +41,8 @@ int user_data_freeUserData(SBMLDocument* document); int user_data_freeUserData(SBase* sBase); +int user_data_passUserData(SBase* sBase1, SBase* sBase2); + } #endif diff --git a/src/libsbmlnetwork_layout_helpers.cpp b/src/libsbmlnetwork_layout_helpers.cpp index c3c33fd..aefccce 100755 --- a/src/libsbmlnetwork_layout_helpers.cpp +++ b/src/libsbmlnetwork_layout_helpers.cpp @@ -527,9 +527,11 @@ const bool isUniUniReaction(Reaction* reaction) { return reaction && reaction->getNumReactants() == 1 && reaction->getNumProducts() == 1; } -const int getStoichiometryAsInteger(SimpleSpeciesReference* speciesReference) { - if (speciesReference && dynamic_cast(speciesReference) && ((SpeciesReference*)speciesReference)->isSetStoichiometry()) - return int(((SpeciesReference*)speciesReference)->getStoichiometry()); +const int getStoichiometryAsInteger(Layout* layout, SimpleSpeciesReference* speciesReference) { + if (user_data_getUserData(layout, "stoichiometric_species_reference") != "false") { + if (speciesReference && dynamic_cast(speciesReference) && ((SpeciesReference*)speciesReference)->isSetStoichiometry()) + return int(((SpeciesReference*)speciesReference)->getStoichiometry()); + } return 1; } diff --git a/src/libsbmlnetwork_layout_helpers.h b/src/libsbmlnetwork_layout_helpers.h index e18bb67..c65f28c 100755 --- a/src/libsbmlnetwork_layout_helpers.h +++ b/src/libsbmlnetwork_layout_helpers.h @@ -114,7 +114,7 @@ const bool isUniUniReaction(Model* model, ReactionGlyph* reactionGlyph); const bool isUniUniReaction(Reaction* reaction); -const int getStoichiometryAsInteger(SimpleSpeciesReference* speciesReference); +const int getStoichiometryAsInteger(Layout* layout, SimpleSpeciesReference* speciesReference); void updateAssociatedTextGlyphsPositionX(Layout* layout, GraphicalObject* graphicalObject, const double& movedDistanceX); diff --git a/src/libsbmlnetwork_render.cpp b/src/libsbmlnetwork_render.cpp index 44fae05..be59072 100755 --- a/src/libsbmlnetwork_render.cpp +++ b/src/libsbmlnetwork_render.cpp @@ -1189,7 +1189,7 @@ int setCompartmentStrokeColor(GlobalRenderInformation* globalRenderInformation, Style* style = getStyleByType(globalRenderInformation, getCompartmentGlyphStyleType()); if (style) { std::string colorId = addColor(globalRenderInformation, strokeColor); - return setStrokeColor(style, colorId, getValue(globalRenderInformation, strokeColor)); + return setStrokeColor(style, colorId, getValue(globalRenderInformation, colorId)); } return -1; @@ -1203,7 +1203,7 @@ int setSpeciesStrokeColor(GlobalRenderInformation* globalRenderInformation, cons Style* style = getStyleByType(globalRenderInformation, getSpeciesGlyphStyleType()); if (style) { std::string colorId = addColor(globalRenderInformation, strokeColor); - return setStrokeColor(style, colorId, getValue(globalRenderInformation, strokeColor)); + return setStrokeColor(style, colorId, getValue(globalRenderInformation, colorId)); } return -1; @@ -1217,7 +1217,7 @@ int setReactionStrokeColor(GlobalRenderInformation* globalRenderInformation, con Style* style = getStyleByType(globalRenderInformation, getReactionGlyphStyleType()); if (style) { std::string colorId = addColor(globalRenderInformation, strokeColor); - return setStrokeColor(style, colorId, getValue(globalRenderInformation, strokeColor)); + return setStrokeColor(style, colorId, getValue(globalRenderInformation, colorId)); } return -1; @@ -1228,14 +1228,14 @@ int setSpeciesReferenceStrokeColor(GlobalRenderInformation* globalRenderInformat std::string colorId = addColor(globalRenderInformation, strokeColor); Style* style = getStyleByType(globalRenderInformation, getSpeciesReferenceGlyphStyleType()); if (style) { - if (!setStrokeColor(style, colorId, getValue(globalRenderInformation, strokeColor))) + if (!setStrokeColor(style, colorId, getValue(globalRenderInformation, colorId))) stokeColorIsSet = true; } std::vector> styleRoles = getStyleRoles(); for (unsigned int i = 0; i < styleRoles.size(); i++) { Style* style = getStyleByRole(globalRenderInformation, styleRoles[i].second); if (style) { - if (!setStrokeColor(style, colorId, getValue(globalRenderInformation, strokeColor))) + if (!setStrokeColor(style, colorId, getValue(globalRenderInformation, colorId))) stokeColorIsSet = true; } } @@ -2853,7 +2853,7 @@ int setCompartmentFillColor(GlobalRenderInformation* globalRenderInformation, co Style* style = getStyleByType(globalRenderInformation, getCompartmentGlyphStyleType()); if (style) { std::string colorId = addColor(globalRenderInformation, fillColor); - return setFillColor(style, colorId, getValue(globalRenderInformation, fillColor)); + return setFillColor(style, colorId, getValue(globalRenderInformation, colorId)); } return -1; @@ -2878,7 +2878,7 @@ int setSpeciesFillColor(GlobalRenderInformation* globalRenderInformation, const Style* style = getStyleByType(globalRenderInformation, getSpeciesGlyphStyleType()); if (style) { std::string colorId = addColor(globalRenderInformation, fillColor); - return setFillColor(style, colorId, getValue(globalRenderInformation, fillColor)); + return setFillColor(style, colorId, getValue(globalRenderInformation, colorId)); } return -1; @@ -2903,7 +2903,7 @@ int setReactionFillColor(GlobalRenderInformation* globalRenderInformation, const Style* style = getStyleByType(globalRenderInformation, getReactionGlyphStyleType()); if (style) { std::string colorId = addColor(globalRenderInformation, fillColor); - return setFillColor(style, colorId, getValue(globalRenderInformation, fillColor)); + return setFillColor(style, colorId, getValue(globalRenderInformation, colorId)); } return -1; diff --git a/src/libsbmlnetwork_sbmldocument.cpp b/src/libsbmlnetwork_sbmldocument.cpp index 7c1140c..bf7a338 100644 --- a/src/libsbmlnetwork_sbmldocument.cpp +++ b/src/libsbmlnetwork_sbmldocument.cpp @@ -310,4 +310,16 @@ namespace LIBSBMLNETWORK_CPP_NAMESPACE { return NULL; } + + bool getStoichiometricSpeciesReference(SBMLDocument* document) { + std::string stoichiometricSpeciesReference = user_data_getUserData(document, "stoichiometric_species_reference"); + if (stoichiometricSpeciesReference == "false") + return false; + + return true; + } + + int setStoichiometricSpeciesReference(SBMLDocument* document, bool stoichiometricSpeciesReference) { + return user_data_setUserData(document, "stoichiometric_species_reference", stoichiometricSpeciesReference ? "true" : "false"); + } } \ No newline at end of file diff --git a/src/libsbmlnetwork_sbmldocument.h b/src/libsbmlnetwork_sbmldocument.h index 77132bd..501e93b 100644 --- a/src/libsbmlnetwork_sbmldocument.h +++ b/src/libsbmlnetwork_sbmldocument.h @@ -223,6 +223,17 @@ LIBSBMLNETWORK_EXTERN SpeciesReference* getSpeciesReference(SBMLDocument* docume /// @return a pointer to the ModifierSpeciesReference object, or @c NULL if the object does not exists or is not of type modifier. LIBSBMLNETWORK_EXTERN ModifierSpeciesReference* getModifierSpeciesReference(SBMLDocument* document, const std::string& reactionId, const std::string& speciesId); +/// @brief Returns the value of the option to generate stoichiometric species reference in the autolayout algorithm. +/// @param document a pointer to the SBMLDocument object. +/// @return the value of the option to generate stoichiometric species reference in the autolayout algorithm. +LIBSBMLNETWORK_EXTERN bool getStoichiometricSpeciesReference(SBMLDocument* document); + +/// @brief Sets the value of the option to generate stoichiometric species reference in the autolayout algorithm. +/// @param document a pointer to the SBMLDocument object.q +/// @param stoichiometricSpeciesReference the value of the option to generate stoichiometric species reference in the autolayout algorithm. +/// @return integer value indicating success/failure of the function. +LIBSBMLNETWORK_EXTERN int setStoichiometricSpeciesReference(SBMLDocument* document, bool stoichiometricSpeciesReference); + } #endif \ No newline at end of file diff --git a/src/libsbmlnetwork_sbmldocument_layout.cpp b/src/libsbmlnetwork_sbmldocument_layout.cpp index a200ca2..a295eda 100644 --- a/src/libsbmlnetwork_sbmldocument_layout.cpp +++ b/src/libsbmlnetwork_sbmldocument_layout.cpp @@ -77,7 +77,11 @@ int updateLayoutCurves(SBMLDocument* document, Layout* layout) { } bool getUseNameAsTextLabel(SBMLDocument* document, unsigned int layoutIndex) { - return user_data_getUserData(getLayout(document, layoutIndex), "use_name_as_text_label") != "false"; + std::string useNameAsTextLabel = user_data_getUserData(getLayout(document, layoutIndex), "use_name_as_text_label"); + if (useNameAsTextLabel == "false") + return false; + + return true; } int setUseNameAsTextLabel(SBMLDocument* document, unsigned int layoutIndex, bool useNameAsTextLabel) { @@ -775,18 +779,19 @@ bool isSetText(SBMLDocument* document, unsigned int layoutIndex, const std::stri return isSetText(getLayout(document, layoutIndex), id); } -const std::string getText(const SBMLDocument* document, const std::string& id, unsigned int graphicalObjectIndex, unsigned int textGlyphIndex) { +const std::string getText(SBMLDocument* document, const std::string& id, unsigned int graphicalObjectIndex, unsigned int textGlyphIndex) { return getText(document, 0, id, graphicalObjectIndex, textGlyphIndex); } -const std::string getText(const SBMLDocument* document, unsigned int layoutIndex, const std::string& id, unsigned int graphicalObjectIndex, unsigned int textGlyphIndex) { +const std::string getText(SBMLDocument* document, unsigned int layoutIndex, const std::string& id, unsigned int graphicalObjectIndex, unsigned int textGlyphIndex) { std::string text = getText(getLayout(const_cast(document), layoutIndex), id, graphicalObjectIndex, textGlyphIndex); if (!text.empty()) { return text; } SBase* sBase = getSBMLObject(const_cast(document), getOriginOfTextId(document, layoutIndex, id, graphicalObjectIndex, textGlyphIndex)); if (sBase) { - if (user_data_getUserData(getLayout(const_cast(document), layoutIndex), "use_name_as_text_label") != "false") { + std::string useNameAsTextLabel = user_data_getUserData(getLayout(document, layoutIndex), "use_name_as_text_label"); + if (useNameAsTextLabel != "false") { text = sBase->getName(); if (!text.empty()) return text; diff --git a/src/libsbmlnetwork_sbmldocument_layout.h b/src/libsbmlnetwork_sbmldocument_layout.h index 0d316ad..92a81ea 100644 --- a/src/libsbmlnetwork_sbmldocument_layout.h +++ b/src/libsbmlnetwork_sbmldocument_layout.h @@ -1540,7 +1540,7 @@ LIBSBMLNETWORK_EXTERN bool isSetText(SBMLDocument* document, unsigned int layout /// @param textGlyphIndex the index of the TextGlyph to return. /// @return the "text" attribute of this TextGlyph object or @c empty string if either the "text" attribute is not set /// , TextGlyph does not exits or the object is @c NULL. -LIBSBMLNETWORK_EXTERN const std::string getText(const SBMLDocument* document, const std::string& id, unsigned int graphicalObjectIndex = 0, unsigned int textGlyphIndex = 0); +LIBSBMLNETWORK_EXTERN const std::string getText(SBMLDocument* document, const std::string& id, unsigned int graphicalObjectIndex = 0, unsigned int textGlyphIndex = 0); /// @brief Returns the "text" attribute of the TextGlyph object with the given index associated with the given id in /// the Layout object with the given index of the SBML document. @@ -1551,7 +1551,7 @@ LIBSBMLNETWORK_EXTERN const std::string getText(const SBMLDocument* document, co /// @param textGlyphIndex the index of the TextGlyph to return. /// @return the "text" attribute of this TextGlyph object or @c empty string if either the "text" attribute is not set /// , TextGlyph does not exits or the object is @c NULL. -LIBSBMLNETWORK_EXTERN const std::string getText(const SBMLDocument* document, unsigned int layoutIndex, const std::string& id, unsigned int graphicalObjectIndex = 0, unsigned int textGlyphIndex = 0); +LIBSBMLNETWORK_EXTERN const std::string getText(SBMLDocument* document, unsigned int layoutIndex, const std::string& id, unsigned int graphicalObjectIndex = 0, unsigned int textGlyphIndex = 0); /// @brief Sets the value of the "text" attribute of the first TextGlyph object associated with the given id in /// the first Layout object of the SBML document.