double CCopasiSpringLayout::potSpeciesReaction(const CLMetabGlyph & a, const CLReactionGlyph & b) const { double tmp = bound_distance(a.getX() + a.getWidth() / 2, a.getY() + a.getHeight() / 2, b.getX() + b.getWidth() / 2, b.getY() + b.getHeight() / 2, 200); if (tmp < 1) tmp = 1; return /*a.charge*b.charge*/ 1 / tmp; //TODO: reintroduce the charge }
/* return ret; } */ double CCopasiSpringLayout::potSpeciesCompartment(const CLMetabGlyph & s, const CLCompartmentGlyph & c) const { double tmp = 0; double dist = fabs((s.getX() + 0.5 * s.getWidth()) - (c.getX() + 0.5 * c.getWidth())); if (dist > (0.5 * c.getWidth() - 50)) tmp += pow(dist - 0.5 * c.getWidth() + 50, 2); dist = fabs((s.getY() + 0.5 * s.getHeight()) - (c.getY() + 0.5 * c.getHeight())); if (dist > (0.5 * c.getHeight() - 50)) tmp += pow(dist - 0.5 * c.getHeight() + 50, 2); return tmp /**s.charge*/; //TODO reintroduce charge }
double CCopasiSpringLayout::potSpeciesSpecies(const CLMetabGlyph & a, const CLMetabGlyph & b) const { double tmp; tmp = bound_distance(a.getX() + a.getWidth() / 2, a.getY() + a.getHeight() / 2, b.getX() + b.getWidth() / 2, b.getY() + b.getHeight() / 2, 200); if (tmp < 1) tmp = 1; return /*a.charge*b.charge*/ 1 / tmp; //TODO: reintroduce the charge //if (tmp<30) // return 0.001*(30-tmp)*a.charge*b.charge; //else // return 0; }
void CLayout::exportToSBML(Layout * layout, const std::map<CCopasiObject*, SBase*> & copasimodelmap, std::map<std::string, const SBase*>& sbmlIDs) const { if (!layout) return; //Name and ID std::string id = CSBMLExporter::createUniqueId(sbmlIDs, "layout_"); layout->setId(id); sbmlIDs.insert(std::pair<const std::string, const SBase*>(id, layout)); //we do not check if the layout is already present in the libsbml data //structures. This is no big deal since at the moment no software //relies on persistent IDs for layout elements. //Dimensions Dimensions tmpDim = mDimensions.getSBMLDimensions(); layout->setDimensions(&tmpDim); //some of the following code is not used at the moment: the COPASI model map //does not contain glyphs. Since this may change in the future I leave the code //below. // create a map from COPASI layout object to SBML objects. We do not put //the layout objects into the global map (copasimodelmap) but we need to have //access to all objects in the current layout since speciesReferenceGlyph and //textGlyph need to reference other graphical objects. std::map<const CLBase*, const SBase*> layoutmap; //Compartment glyphs unsigned C_INT32 i, imax = mvCompartments.size(); for (i = 0; i < imax; ++i) { CLCompartmentGlyph * tmp = mvCompartments[i]; //check if the compartment glyph exists in the libsbml data std::map<CCopasiObject*, SBase*>::const_iterator it; it = copasimodelmap.find(tmp); CompartmentGlyph * pCG; if (it == copasimodelmap.end()) //not found { pCG = new CompartmentGlyph; layout->getListOfCompartmentGlyphs()->appendAndOwn(pCG); } else { pCG = dynamic_cast<CompartmentGlyph*>(it->second); } layoutmap.insert(std::pair<const CLBase*, const SBase*>(tmp, pCG)); tmp->exportToSBML(pCG, copasimodelmap, sbmlIDs); } //Species glyphs imax = mvMetabs.size(); for (i = 0; i < imax; ++i) { CLMetabGlyph * tmp = mvMetabs[i]; //check if the glyph exists in the libsbml data std::map<CCopasiObject*, SBase*>::const_iterator it; it = copasimodelmap.find(tmp); SpeciesGlyph * pG; if (it == copasimodelmap.end()) //not found { pG = new SpeciesGlyph; layout->getListOfSpeciesGlyphs()->appendAndOwn(pG); } else { pG = dynamic_cast<SpeciesGlyph*>(it->second); } layoutmap.insert(std::pair<const CLBase*, const SBase*>(tmp, pG)); tmp->exportToSBML(pG, copasimodelmap, sbmlIDs); } //Reaction glyphs imax = mvReactions.size(); for (i = 0; i < imax; ++i) { CLReactionGlyph * tmp = mvReactions[i]; //check if the glyph exists in the libsbml data std::map<CCopasiObject*, SBase*>::const_iterator it; it = copasimodelmap.find(tmp); ReactionGlyph * pG; if (it == copasimodelmap.end()) //not found { pG = new ReactionGlyph; layout->getListOfReactionGlyphs()->appendAndOwn(pG); } else { pG = dynamic_cast<ReactionGlyph*>(it->second); } layoutmap.insert(std::pair<const CLBase*, const SBase*>(tmp, pG)); //we need to pass the layoutmap here for 2 reasons: //1. the metabreferenceglyphs need to be added //2. the metabreferenceglyphs need to resolve the reference to the metabglyph tmp->exportToSBML(pG, copasimodelmap, sbmlIDs, layoutmap); } //Text glyphs imax = mvLabels.size(); for (i = 0; i < imax; ++i) { CLTextGlyph * tmp = mvLabels[i]; //check if the glyph exists in the libsbml data std::map<CCopasiObject*, SBase*>::const_iterator it; it = copasimodelmap.find(tmp); TextGlyph * pG; if (it == copasimodelmap.end()) //not found { pG = new TextGlyph; layout->getListOfTextGlyphs()->appendAndOwn(pG); } else { pG = dynamic_cast<TextGlyph*>(it->second); } layoutmap.insert(std::pair<const CLBase*, const SBase*>(tmp, pG)); tmp->exportToSBML(pG, copasimodelmap, sbmlIDs); } //generic glyphs imax = mvGraphicalObjects.size(); for (i = 0; i < imax; ++i) { CLGraphicalObject * tmp = mvGraphicalObjects[i]; //check if the glyph exists in the libsbml data std::map<CCopasiObject*, SBase*>::const_iterator it; it = copasimodelmap.find(tmp); GraphicalObject * pG; if (it == copasimodelmap.end()) //not found { pG = new GraphicalObject; layout->getListOfAdditionalGraphicalObjects()->appendAndOwn(pG); } else { pG = dynamic_cast<GraphicalObject*>(it->second); } layoutmap.insert(std::pair<const CLBase*, const SBase*>(tmp, pG)); tmp->exportToSBML(pG, copasimodelmap, sbmlIDs); } //now that we have all graphical objects in the layoutmap we can resolve the references //in the text glyphs imax = mvLabels.size(); for (i = 0; i < imax; ++i) { const CLTextGlyph * tmp = mvLabels[i]; //find the corresponding SBML object std::map<const CLBase*, const SBase*>::const_iterator it = layoutmap.find(tmp); if (it != layoutmap.end() && it->second && dynamic_cast<const TextGlyph*>(it->second)) { tmp->exportReferenceToSBML(const_cast<TextGlyph*>(dynamic_cast<const TextGlyph*>(it->second)), layoutmap); } } }
void CLGeneralGlyph::exportToSBML(GraphicalObject * g, //TODO const std::map<const CCopasiObject*, SBase*> & copasimodelmap, std::map<std::string, const SBase*>& sbmlIDs, std::map<const CLBase*, const SBase*> & layoutmap) const { if (!g) return; //call the coresponding method of the base class CLGraphicalObject::exportToSBML(g, copasimodelmap, sbmlIDs); #if LIBSBML_VERSION >= 50800 GeneralGlyph *general = dynamic_cast<GeneralGlyph *>(g); if (!general) return; //reference to model objects CCopasiObject* tmp = getModelObject(); if (tmp) { std::map<const CCopasiObject*, SBase*>::const_iterator it = copasimodelmap.find(tmp); if (it != copasimodelmap.end()) { if (it->second) general->setReferenceId(it->second->getId()); } const CLBase* base = dynamic_cast<const CLBase*>(tmp); if (base) { std::map<const CLBase*, const SBase*>::const_iterator it2 = layoutmap.find(base); if (it2 != layoutmap.end()) { if (it2->second) general->setReferenceId(it2->second->getId()); } } } //curve mCurve.exportToSBML(general->getCurve(), copasimodelmap); //reference glyphs size_t i, imax = mvReferences.size(); for (i = 0; i < imax; ++i) { CLReferenceGlyph * tmp = mvReferences[i]; //check if the glyph exists in the libsbml data std::map<const CCopasiObject*, SBase*>::const_iterator it; it = copasimodelmap.find(tmp); ReferenceGlyph * pG; if (it == copasimodelmap.end()) //not found { pG = general->createReferenceGlyph(); } else { pG = dynamic_cast<ReferenceGlyph*>(it->second); } layoutmap.insert(std::pair<const CLBase*, const SBase*>(tmp, pG)); tmp->exportToSBML(pG, copasimodelmap, sbmlIDs, layoutmap); } imax = mvSubglyphs.size(); for (i = 0; i < imax; ++i) { CLGraphicalObject * tmp = mvSubglyphs[i]; CLMetabGlyph * metab = dynamic_cast<CLMetabGlyph*>(tmp); CLCompartmentGlyph* comp = dynamic_cast<CLCompartmentGlyph*>(tmp); CLGeneralGlyph* gg = dynamic_cast<CLGeneralGlyph*>(tmp); CLTextGlyph* text = dynamic_cast<CLTextGlyph*>(tmp); //check if the glyph exists in the libsbml data std::map<const CCopasiObject*, SBase*>::const_iterator it; it = copasimodelmap.find(tmp); GraphicalObject * pG; if (it == copasimodelmap.end()) //not found { if (metab) pG = ((Layout*)g->getParentSBMLObject()->getParentSBMLObject())->createSpeciesGlyph(); else if (comp) pG = ((Layout*)g->getParentSBMLObject()->getParentSBMLObject())->createCompartmentGlyph(); else if (gg) pG = ((Layout*)g->getParentSBMLObject()->getParentSBMLObject())->createGeneralGlyph(); else if (text) pG = ((Layout*)g->getParentSBMLObject()->getParentSBMLObject())->createTextGlyph(); else pG = ((Layout*)g->getParentSBMLObject()->getParentSBMLObject())->createAdditionalGraphicalObject(); } else { pG = dynamic_cast<GraphicalObject*>(it->second); } layoutmap.insert(std::pair<const CLBase*, const SBase*>(tmp, pG)); if (metab) metab->exportToSBML(static_cast<SpeciesGlyph*>(pG), copasimodelmap, sbmlIDs); else if (comp) comp->exportToSBML(static_cast<CompartmentGlyph*>(pG), copasimodelmap, sbmlIDs); else if (text) text->exportToSBML(static_cast<TextGlyph*>(pG), copasimodelmap, sbmlIDs); else if (gg) gg->exportToSBML(pG, copasimodelmap, sbmlIDs, layoutmap); else tmp->exportToSBML(pG, copasimodelmap, sbmlIDs); } #endif // LIBSBML_VERSION >= 50800 }
/** * This function produces a random layout. It first shufles around * metab glyphs and reaction centers, and finally corrects all ars */ void CCopasiSpringLayout::randomize() { CRandom* pRandom = CRandom::createGenerator(CRandom::mt19937, CRandom::getSystemSeed()); size_t i; //compartment glyphs //metab glyphs for (i = 0; i < mpLayout->getListOfMetaboliteGlyphs().size(); ++i) { CLMetabGlyph* pMetabGlyph = &mpLayout->getListOfMetaboliteGlyphs()[i]; const CMetab* pMetab = dynamic_cast<const CMetab*>(pMetabGlyph->getModelObject()); if (!pMetab) continue; //find the compartment glyph const CCompartment* pComp = pMetab->getCompartment(); if (!pComp) continue; const CLCompartmentGlyph* pCompGlyph = NULL; size_t j; for (j = 0; j < mpLayout->getListOfCompartmentGlyphs().size(); ++j) if (mpLayout->getListOfCompartmentGlyphs()[j].getModelObjectKey() == pComp->getKey()) { pCompGlyph = &mpLayout->getListOfCompartmentGlyphs()[j]; break; } if (pCompGlyph) randomlyPlaceGlyphInCompartmentGlyph(pMetabGlyph, pCompGlyph, pRandom); else randomlyPlaceGlyphInDimensions(pMetabGlyph, &mpLayout->getDimensions(), pRandom); } //reaction glyphs for (i = 0; i < mpLayout->getListOfReactionGlyphs().size(); ++i) { CLReactionGlyph* pReactionGlyph = &mpLayout->getListOfReactionGlyphs()[i]; CLPoint center(0, 0); size_t count; for (count = 0; count < pReactionGlyph->getListOfMetabReferenceGlyphs().size(); ++count) { CLMetabGlyph* metabGlyph = pReactionGlyph->getListOfMetabReferenceGlyphs()[count].getMetabGlyph(); if (metabGlyph == NULL) continue; center = center + metabGlyph->getBoundingBox().getCenter(); } center = center * (1.0 / pReactionGlyph->getListOfMetabReferenceGlyphs().size()); center = center + CLPoint(pRandom->getRandomCC() * 20 - 10, pRandom->getRandomCC() * 20 - 10); pReactionGlyph->setPosition(center); /*if (pCompGlyph) randomlyPlaceGlyphInCompartmentGlyph(pMetabGlyph, pCompGlyph); else randomlyPlaceGlyphInDimensions(pMetabGlyph, &mpCurrentLayout->getDimensions());*/ } placeTextGlyphs(mpLayout); delete pRandom; finalizeState(); }
void CCopasiSpringLayout::finalizeState() { unsigned int i; //update the positions of the dependent glyphs //this can be done here since we assume that those glyphs //do not affect the layout. updateFixedRelations(); //for now, only create curves for the reaction glyphs for (i = 0; i < mpLayout->getListOfReactionGlyphs().size() ; ++i) { CLReactionGlyph* pRG = &mpLayout->getListOfReactionGlyphs()[i]; //Determine the average position of substrates and products, giving less weight to side reactants CLPoint s, p; double s_c = 0; double p_c = 0; unsigned int j, jmax = pRG->getListOfMetabReferenceGlyphs().size(); for (j = 0; j < jmax; ++j) { if (pRG->getListOfMetabReferenceGlyphs()[j].getFunctionalRole() == CLMetabReferenceGlyph::SUBSTRATE) { CLMetabGlyph* metabGlyph = pRG->getListOfMetabReferenceGlyphs()[j].getMetabGlyph(); if (metabGlyph != NULL) { s_c += 1.0; s = s + metabGlyph->getBoundingBox().getCenter(); } } if (pRG->getListOfMetabReferenceGlyphs()[j].getFunctionalRole() == CLMetabReferenceGlyph::SIDESUBSTRATE) { CLMetabGlyph* metabGlyph = pRG->getListOfMetabReferenceGlyphs()[j].getMetabGlyph(); if (metabGlyph != NULL) { s_c += 0.1; s = s + metabGlyph->getBoundingBox().getCenter() * 0.1; } } if (pRG->getListOfMetabReferenceGlyphs()[j].getFunctionalRole() == CLMetabReferenceGlyph::PRODUCT) { CLMetabGlyph* metabGlyph = pRG->getListOfMetabReferenceGlyphs()[j].getMetabGlyph(); if (metabGlyph != NULL) { p_c += 1.0; p = p + metabGlyph->getBoundingBox().getCenter(); } } if (pRG->getListOfMetabReferenceGlyphs()[j].getFunctionalRole() == CLMetabReferenceGlyph::SIDEPRODUCT) { CLMetabGlyph* metabGlyph = pRG->getListOfMetabReferenceGlyphs()[j].getMetabGlyph(); if (metabGlyph != NULL) { p_c += 0.1; p = p + metabGlyph->getBoundingBox().getCenter() * 0.1; } } } CLPoint position = pRG->getPosition(); if (position.getX() == 0 && position.getY() == 0 && pRG->getDimensions().getWidth() == 0 && pRG->getDimensions().getHeight() == 0 && pRG->getCurve().getNumCurveSegments() > 0) { position = pRG->getCurve().getCurveSegments()[0].getStart(); pRG->setPosition(position); } if (s_c > 0) s = s * (1 / s_c); else { s = position; } if (p_c > 0) p = p * (1 / p_c); else p = position; CLPoint dir = p - s; //overall direction of reaction if (dir.getX() == 0 && dir.getY() == 0) dir = CLPoint(1, 0); CLPoint ortho_dir = CLPoint(dir.getY(), -dir.getX()); ortho_dir.scale(1 / sqrt(pow(ortho_dir.getX(), 2) + pow(ortho_dir.getY(), 2))); CLPoint reaction_s = position - (dir * 0.05); CLPoint reaction_p = position + (dir * 0.05); CLPoint reaction_m1 = position + ortho_dir * 10; CLPoint reaction_m2 = position - ortho_dir * 10; pRG->getCurve().clear(); pRG->getCurve().addCurveSegment(CLLineSegment(reaction_s, reaction_p)); for (j = 0; j < jmax; ++j) { //here we need to generate the curves for the MetabReferenceGlyphs. //we will need to consider the size of the glyphs, role of the metab in the reaction, etc. //For now, only a primitive implementation: TODO: improve CLMetabReferenceGlyph* pMRG = &pRG->getListOfMetabReferenceGlyphs()[j]; double direction; //double modifierLength = -0.2; switch (pMRG->getFunctionalRole()) { case CLMetabReferenceGlyph::SUBSTRATE : case CLMetabReferenceGlyph::SIDESUBSTRATE : { direction = -0.1; CLPoint metabPoint = borderProjection(pMRG->getMetabGlyph(), reaction_s + dir * direction /*(modifierLength * 1.5)*/, 5); pMRG->getCurve().clear(); pMRG->getCurve().addCurveSegment(CLLineSegment(reaction_s, metabPoint, reaction_s + dir * direction, (reaction_s + dir * (direction * 1.5) + metabPoint) * 0.5)); } break; case CLMetabReferenceGlyph::PRODUCT : case CLMetabReferenceGlyph::SIDEPRODUCT : { direction = 0.1; CLPoint metabPoint = borderProjection(pMRG->getMetabGlyph(), reaction_p + dir * direction /*(modifierLength * 1.5)*/, 5); pMRG->getCurve().clear(); pMRG->getCurve().addCurveSegment(CLLineSegment(reaction_p, metabPoint, reaction_p + dir * direction, (reaction_p + dir * (direction * 1.5) + metabPoint) * 0.5)); } break; default: { CLPoint reactionPoint; if (pMRG->getMetabGlyph() && ortho_dir.dot(pRG->getPosition() - pMRG->getMetabGlyph()->getPosition()) < 0) { direction = +10.0; reactionPoint = reaction_m1; } else { direction = -10.0; reactionPoint = reaction_m2; } CLPoint metabPoint = borderProjection(pMRG->getMetabGlyph(), reactionPoint + dir * 0 * direction /*(modifierLength * 1.5)*/, 5); pMRG->getCurve().clear(); pMRG->getCurve().addCurveSegment(CLLineSegment(metabPoint, reactionPoint, (reactionPoint + dir * (0 * direction * 1.5) + metabPoint) * 0.5, reactionPoint + ortho_dir * direction)); } } } } //update the curves in the general glyph for (i = 0; i < mpLayout->getListOfGeneralGlyphs().size() ; ++i) { CLGeneralGlyph* pGG = &mpLayout->getListOfGeneralGlyphs()[i]; size_t j; for (j = 0; j < pGG->getListOfReferenceGlyphs().size(); ++j) { CLReferenceGlyph* pRG = &pGG->getListOfReferenceGlyphs()[j]; if (pRG->getCurve().getNumCurveSegments() == 0) continue; CLPoint refPoint = borderProjection(pRG->getTargetGlyph(), pRG->getBoundingBox().getCenter(), 5); pRG->getCurve().clear(); pRG->getCurve().addCurveSegment(CLLineSegment(refPoint, pRG->getBoundingBox().getCenter())); } } //calculate bounding box for the layout, or recenter the layout mpLayout->calculateAndAssignBounds(); }
CLayout* CCopasiSpringLayout::createLayout( CDataContainer *parent, const std::set<const CCompartment*>& compartments, const std::set<const CReaction*>& reactions, const std::set<const CMetab*>& metabs, const std::set<const CMetab*>& sideMetabs, Parameters* mParams ) { CLayout *pResult = new CLayout("Layout", parent); double fontSize = 16.0; double fontHeight = fontSize * 1.5; // create a species glyph for each species in metabs std::map<const CCompartment*, CompartmentInfo> compInfo; std::map<const CMetab*, CLMetabGlyph*> metabMap; std::set<const CMetab*>::const_iterator metabIt; for (metabIt = metabs.begin(); metabIt != metabs.end(); ++metabIt) { if (sideMetabs.find(*metabIt) != sideMetabs.end()) continue; //estimate the size of the glyph double width = (double)((*metabIt)->getObjectName().length() * fontSize); double height = (double)fontHeight; if (width < height) { width = height; } //create the glyph CLMetabGlyph* pMetabGlyph = new CLMetabGlyph; pMetabGlyph->setDimensions(CLDimensions(width + 4, height + 4)); pMetabGlyph->setModelObjectKey((*metabIt)->getKey()); pResult->addMetaboliteGlyph(pMetabGlyph); metabMap[*metabIt] = pMetabGlyph; //create the text glyph for the label CLTextGlyph* pTextGlyph = new CLTextGlyph; pTextGlyph->setDimensions(CLDimensions(width, height)); pTextGlyph->setGraphicalObjectKey(pMetabGlyph->getKey()); pTextGlyph->setModelObjectKey((*metabIt)->getKey()); pResult->addTextGlyph(pTextGlyph); //add up the sizes for the compartment const CCompartment* pComp = NULL; if (compartments.find((*metabIt)->getCompartment()) != compartments.end()) pComp = (*metabIt)->getCompartment(); compInfo[pComp].add((width + 4) * (height + 4)); } //now the reaction glyphs std::set<const CReaction*>::const_iterator reactIt; for (reactIt = reactions.begin(); reactIt != reactions.end(); ++reactIt) { CLReactionGlyph* pReactionGlyph = new CLReactionGlyph; //pResult->setDimensions(CLDimensions(width, height)); pReactionGlyph->setModelObjectKey((*reactIt)->getKey()); //pReactionGlyph->getCurve().addCurveSegment(CLLineSegment(CLPoint(x, y), // CLPoint(x + length, y))); bool isReversible = (*reactIt)->isReversible(); pResult->addReactionGlyph(pReactionGlyph); //now add the species reference glyphs. //substrates const CDataVector < CChemEqElement >& substrates = (*reactIt)->getChemEq().getSubstrates(); bool substrateExists = false; CDataVector<CChemEqElement>::const_iterator elIt; for (elIt = substrates.begin(); elIt != substrates.end(); ++elIt) { const CMetab* pMetab = elIt->getMetabolite(); if (!pMetab) continue; CLMetabGlyph* pMetabGlyph = NULL; CLMetabReferenceGlyph::Role role; // = CLMetabReferenceGlyph::SUBSTRATE; CLMetabReferenceGlyph::Role functionalRole; //is it a side reactant? If yes, create a new metab glyph if (sideMetabs.find(pMetab) != sideMetabs.end()) { //estimate the size of the glyph double width = (double)((pMetab)->getObjectName().length() * fontSize); double height = (double)fontHeight; if (width < height) { width = height; } //create the glyph pMetabGlyph = new CLMetabGlyph; pMetabGlyph->setDimensions(CLDimensions(width + 4, height + 4)); pMetabGlyph->setModelObjectKey(pMetab->getKey()); //TODO: mark as duplicate pResult->addMetaboliteGlyph(pMetabGlyph); //create the text glyph for the label CLTextGlyph* pTextGlyph = new CLTextGlyph; pTextGlyph->setDimensions(CLDimensions(width, height)); pTextGlyph->setGraphicalObjectKey(pMetabGlyph->getKey()); pTextGlyph->setModelObjectKey(pMetab->getKey()); pResult->addTextGlyph(pTextGlyph); //add up the sizes for the compartment const CCompartment* pComp = NULL; if (compartments.find(pMetab->getCompartment()) != compartments.end()) pComp = pMetab->getCompartment(); compInfo[pComp].add((width + 4) * (height + 4)); role = isReversible ? CLMetabReferenceGlyph::SIDEPRODUCT : CLMetabReferenceGlyph::SIDESUBSTRATE; functionalRole = CLMetabReferenceGlyph::SIDESUBSTRATE; } else { //find the existing metab glyph std::map<const CMetab*, CLMetabGlyph*>::const_iterator mmIt; mmIt = metabMap.find(pMetab); if (mmIt != metabMap.end()) pMetabGlyph = mmIt->second; role = isReversible ? CLMetabReferenceGlyph::PRODUCT : CLMetabReferenceGlyph::SUBSTRATE; functionalRole = CLMetabReferenceGlyph::SUBSTRATE; } if (!pMetabGlyph) continue; CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph; //pResult->setModelObjectKey(modelobjectkey); pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey()); pRefGlyph->setRole(role); pRefGlyph->setFunctionalRole(functionalRole); pReactionGlyph->addMetabReferenceGlyph(pRefGlyph); substrateExists = true; } //substrates // if we have no substrates, add a dummy / invisible node for now if (!substrateExists) { CLMetabGlyph* pMetabGlyph = new CLMetabGlyph; pMetabGlyph->setDimensions(CLDimensions(1, 1)); pMetabGlyph->setObjectRole("invisible"); pResult->addMetaboliteGlyph(pMetabGlyph); CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph; //pResult->setModelObjectKey(modelobjectkey); pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey()); pRefGlyph->setRole(CLMetabReferenceGlyph::SUBSTRATE); //TODO side substr? pRefGlyph->setFunctionalRole(CLMetabReferenceGlyph::SUBSTRATE); pReactionGlyph->addMetabReferenceGlyph(pRefGlyph); } //products const CDataVector < CChemEqElement >& products = (*reactIt)->getChemEq().getProducts(); bool productExists = false; for (elIt = products.begin(); elIt != products.end(); ++elIt) { const CMetab* pMetab = elIt->getMetabolite(); if (!pMetab) continue; CLMetabGlyph* pMetabGlyph = NULL; CLMetabReferenceGlyph::Role role; // = CLMetabReferenceGlyph::SUBSTRATE; CLMetabReferenceGlyph::Role functionalRole; //is it a side reactant? If yes, create a new metab glyph if (sideMetabs.find(pMetab) != sideMetabs.end()) { //estimate the size of the glyph double width = (double)((pMetab)->getObjectName().length() * fontSize); double height = (double)fontHeight; if (width < height) { width = height; } //create the glyph pMetabGlyph = new CLMetabGlyph; pMetabGlyph->setDimensions(CLDimensions(width + 4, height + 4)); pMetabGlyph->setModelObjectKey(pMetab->getKey()); //TODO: mark as duplicate pResult->addMetaboliteGlyph(pMetabGlyph); //create the text glyph for the label CLTextGlyph* pTextGlyph = new CLTextGlyph; pTextGlyph->setDimensions(CLDimensions(width, height)); pTextGlyph->setGraphicalObjectKey(pMetabGlyph->getKey()); pTextGlyph->setModelObjectKey(pMetab->getKey()); pResult->addTextGlyph(pTextGlyph); //add up the sizes for the compartment const CCompartment* pComp = NULL; if (compartments.find(pMetab->getCompartment()) != compartments.end()) pComp = pMetab->getCompartment(); compInfo[pComp].add((width + 4) * (height + 4)); role = CLMetabReferenceGlyph::SIDEPRODUCT; functionalRole = CLMetabReferenceGlyph::SIDEPRODUCT; } else { //find the existing metab glyph std::map<const CMetab*, CLMetabGlyph*>::const_iterator mmIt; mmIt = metabMap.find(pMetab); if (mmIt != metabMap.end()) pMetabGlyph = mmIt->second; role = CLMetabReferenceGlyph::PRODUCT; functionalRole = CLMetabReferenceGlyph::PRODUCT; } if (!pMetabGlyph) continue; CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph; //pResult->setModelObjectKey(modelobjectkey); pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey()); pRefGlyph->setRole(role); pRefGlyph->setFunctionalRole(functionalRole); pReactionGlyph->addMetabReferenceGlyph(pRefGlyph); productExists = true; } //products // if we have no substrates, add a dummy / invisible node for now if (!productExists) { CLMetabGlyph* pMetabGlyph = new CLMetabGlyph; pMetabGlyph->setDimensions(CLDimensions(1, 1)); pMetabGlyph->setObjectRole("invisible"); pResult->addMetaboliteGlyph(pMetabGlyph); CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph; //pResult->setModelObjectKey(modelobjectkey); pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey()); pRefGlyph->setRole(CLMetabReferenceGlyph::PRODUCT); //TODO side substr? pReactionGlyph->addMetabReferenceGlyph(pRefGlyph); } //modifiers const CDataVector < CChemEqElement >& modifiers = (*reactIt)->getChemEq().getModifiers(); for (elIt = modifiers.begin(); elIt != modifiers.end(); ++elIt) { const CMetab* pMetab = elIt->getMetabolite(); if (!pMetab) continue; CLMetabGlyph* pMetabGlyph = NULL; CLMetabReferenceGlyph::Role role; // = CLMetabReferenceGlyph::SUBSTRATE; //is it a side reactant? If yes, create a new metab glyph if (sideMetabs.find(pMetab) != sideMetabs.end()) { //estimate the size of the glyph double width = (double)((pMetab)->getObjectName().length() * fontSize); double height = (double)fontHeight; if (width < height) { width = height; } //create the glyph pMetabGlyph = new CLMetabGlyph; pMetabGlyph->setDimensions(CLDimensions(width + 4, height + 4)); pMetabGlyph->setModelObjectKey(pMetab->getKey()); //TODO: mark as duplicate pResult->addMetaboliteGlyph(pMetabGlyph); //create the text glyph for the label CLTextGlyph* pTextGlyph = new CLTextGlyph; pTextGlyph->setDimensions(CLDimensions(width, height)); pTextGlyph->setGraphicalObjectKey(pMetabGlyph->getKey()); pTextGlyph->setModelObjectKey(pMetab->getKey()); pResult->addTextGlyph(pTextGlyph); //add up the sizes for the compartment const CCompartment* pComp = NULL; if (compartments.find(pMetab->getCompartment()) != compartments.end()) pComp = pMetab->getCompartment(); compInfo[pComp].add((width + 4) * (height + 4)); role = CLMetabReferenceGlyph::MODIFIER; //TODO SIDEMODIFIER??? } else { //find the existing metab glyph std::map<const CMetab*, CLMetabGlyph*>::const_iterator mmIt; mmIt = metabMap.find(pMetab); if (mmIt != metabMap.end()) pMetabGlyph = mmIt->second; role = CLMetabReferenceGlyph::MODIFIER; } if (!pMetabGlyph) continue; CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph; //pResult->setModelObjectKey(modelobjectkey); pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey()); pRefGlyph->setRole(role); pReactionGlyph->addMetabReferenceGlyph(pRefGlyph); } //modifiers } //reactions //rules size_t i; for (i = 0; i < pResult->getListOfMetaboliteGlyphs().size(); ++i) { const CLMetabGlyph* pMetabGlyph = &pResult->getListOfMetaboliteGlyphs()[i]; const CMetab* pMetab = dynamic_cast<const CMetab*>(pMetabGlyph->getModelObject()); if (!pMetab) continue; if (pMetab->getStatus() == CModelEntity::Status::ODE || pMetab->getStatus() == CModelEntity::Status::ASSIGNMENT) { CLGeneralGlyph* pGG = new CLGeneralGlyph; pGG->setDimensions(CLDimensions(10, 10)); pGG->setObjectRole("rule"); pResult->addGeneralGlyph(pGG); CLReferenceGlyph* pRefGlyph = new CLReferenceGlyph; pRefGlyph->setDimensions(CLDimensions(10, 10)); pRefGlyph->setTargetGlyphKey(pMetabGlyph->getKey()); pRefGlyph->setRole("rule connection"); pGG->addReferenceGlyph(pRefGlyph); } } //after all other glyphs are created, create the compartment glyphs double xxx = 0; std::set<const CCompartment*>::const_iterator compIt; for (compIt = compartments.begin(); compIt != compartments.end(); ++compIt) { double compSize = 10000; std::map<const CCompartment*, CompartmentInfo>::const_iterator ccIt; ccIt = compInfo.find(*compIt); if (ccIt != compInfo.end()) { //some glyphs are placed inside this compartment glyph compSize = ccIt->second.mAreaSum * 40; } //create the glyph CLCompartmentGlyph* pCompGlyph = new CLCompartmentGlyph; pCompGlyph->setModelObjectKey((*compIt)->getKey()); pCompGlyph->setDimensions(CLDimensions(CLDimensions(sqrt(compSize), sqrt(compSize)))); pCompGlyph->setPosition(CLPoint(xxx, 5)); xxx += sqrt(compSize) + 10; pResult->addCompartmentGlyph(pCompGlyph); } // // double sss = sqrt(compInfo[NULL].mAreaSum * 40); // // // determine and set the layout dimensions // CLBoundingBox box = pResult->calculateBoundingBox(); // if (box.getDimensions().getWidth() < sss) // box.getDimensions().setWidth(sss); // // if (box.getDimensions().getHeight() < sss) // box.getDimensions().setHeight(sss); // // pResult->setDimensions(CLDimensions(box.getDimensions().getWidth() + 30.0, box.getDimensions().getHeight() + 30.0)); // randomize CCopasiSpringLayout l(pResult, mParams); l.randomize(); // determine and set the layout dimensions CLBoundingBox box = pResult->calculateBoundingBox(); pResult->setDimensions(CLDimensions(box.getDimensions().getWidth() + 30.0, box.getDimensions().getHeight() + 30.0)); return pResult; }