diff --git a/CHANGELOG b/CHANGELOG index 64ccace37428560e78ff59b6c9d27a1b74172ebd..4c2cfd9bd370302675b61362a25b0b36dd5365d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +minerva (15.0.0~alpha.0) stable; urgency=medium + * Bug fix: position of structural state is preserved on upload CellDesigner + file (#671) + minerva (14.0.3) stable; urgency=medium * Bug fix: default zoom level on main map works even when x or y are undefined (#993) diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerElementCollection.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerElementCollection.java index bfdabc42923e68d275393f892641752655325ba3..259a5e75bef4e2532aa82d9ec9c9433bd291a557 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerElementCollection.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerElementCollection.java @@ -107,14 +107,18 @@ public class CellDesignerElementCollection { regions.addAll(asGene.getModificationResidues()); } else if (modelElement instanceof Protein) { Protein asProtein = ((Protein) modelElement); - modifications = asProtein.getStructuralState(); + if (asProtein.getStructuralState() != null) { + modifications = asProtein.getStructuralState().getValue(); + } regions.addAll(asProtein.getModificationResidues()); } else if (modelElement instanceof Rna) { Rna asRna = ((Rna) modelElement); regions.addAll(asRna.getRegions()); } else if (modelElement instanceof Complex) { Complex asComplex = ((Complex) modelElement); - modifications = asComplex.getStructuralState(); + if (asComplex.getStructuralState() != null) { + modifications = asComplex.getStructuralState().getValue(); + } } for (ModificationResidue region : regions) { if (region instanceof AbstractSiteModification) { diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/AbstractAliasXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/AbstractAliasXmlParser.java index c70a43f7a53a0f5aaef4f122e70ec156619df22f..db1a38bcbada679280da60e109b0626ee2eacc61 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/AbstractAliasXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/AbstractAliasXmlParser.java @@ -7,7 +7,10 @@ import org.w3c.dom.*; import lcsb.mapviewer.common.XmlParser; import lcsb.mapviewer.common.exception.InvalidXmlSchemaException; import lcsb.mapviewer.converter.model.celldesigner.CommonXmlParser; +import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter; +import lcsb.mapviewer.model.map.species.*; import lcsb.mapviewer.model.map.species.Element; +import lcsb.mapviewer.model.map.species.field.StructuralState; /** * Generic abstract interface for parsing CellDesigner xml nodes with species @@ -87,4 +90,20 @@ public abstract class AbstractAliasXmlParser<T extends Element> { return "<celldesigner:font size=\"" + alias.getFontSize().intValue() + "\"/>"; } + protected String createStructuralStateTag(Species species) { + StructuralState structuralState = null; + if (species instanceof Protein) { + structuralState = ((Protein) species).getStructuralState(); + } + if (species instanceof Complex) { + structuralState = ((Complex) species).getStructuralState(); + } + if (structuralState != null) { + CellDesignerAliasConverter converter = new CellDesignerAliasConverter(species, false); + double angle = converter.getAngleForPoint(species, structuralState.getCenter()); + return "<celldesigner:structuralState angle=\"" + angle + "\"/>"; + } + return ""; + } + } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/ComplexAliasXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/ComplexAliasXmlParser.java index ee84daedd66d96f37b405104bee40903f6f71d54..8c11c5182f25088c1d613d3c67fc520451d741be 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/ComplexAliasXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/ComplexAliasXmlParser.java @@ -120,8 +120,7 @@ public class ComplexAliasXmlParser extends AbstractAliasXmlParser<Complex> { // not handled continue; } else if (node.getNodeName().equalsIgnoreCase("celldesigner:structuralState")) { - // not handled - continue; + species.setStructuralStateAngle(Double.parseDouble(XmlParser.getNodeAttr("angle", node))); } else { throw new InvalidXmlSchemaException("Unknown element of celldesigner:speciesAlias: " + node.getNodeName()); } @@ -163,21 +162,22 @@ public class ComplexAliasXmlParser extends AbstractAliasXmlParser<Complex> { parents.put(result.getElementId(), complexSpeciesAliasId); } complexAliasesMapById.put(result.getElementId(), result); + species.updateModelElementAfterLayoutAdded(result); return result; } @Override - public String toXml(Complex alias) { + public String toXml(Complex complex) { Compartment ca = null; - // we have to exclude artifitial compartment aliases, becuase they aren't + // we have to exclude artificial compartment aliases, because they aren't // exported to CellDesigner file - if (alias.getCompartment() != null && !(alias.getCompartment() instanceof PathwayCompartment)) { - ca = alias.getCompartment(); - } else if (alias.getComplex() == null) { - ModelData modelData = alias.getModelData(); + if (complex.getCompartment() != null && !(complex.getCompartment() instanceof PathwayCompartment)) { + ca = complex.getCompartment(); + } else if (complex.getComplex() == null) { + ModelData modelData = complex.getModelData(); if (modelData != null) { for (Compartment cAlias : modelData.getModel().getCompartments()) { - if (!(cAlias instanceof PathwayCompartment) && cAlias.cross(alias)) { + if (!(cAlias instanceof PathwayCompartment) && cAlias.cross(complex)) { if (ca == null) { ca = cAlias; } else if (ca.getSize() > cAlias.getSize()) { @@ -188,7 +188,7 @@ public class ComplexAliasXmlParser extends AbstractAliasXmlParser<Complex> { } } - Complex complexAlias = alias.getComplex(); + Complex complexAlias = complex.getComplex(); String compartmentAliasId = null; if (ca != null) { @@ -196,8 +196,8 @@ public class ComplexAliasXmlParser extends AbstractAliasXmlParser<Complex> { } StringBuilder sb = new StringBuilder(""); sb.append("<celldesigner:complexSpeciesAlias "); - sb.append("id=\"" + alias.getElementId() + "\" "); - sb.append("species=\"" + elements.getElementId(alias) + "\" "); + sb.append("id=\"" + complex.getElementId() + "\" "); + sb.append("species=\"" + elements.getElementId(complex) + "\" "); if (compartmentAliasId != null) { sb.append("compartmentAlias=\"" + compartmentAliasId + "\" "); } @@ -206,8 +206,8 @@ public class ComplexAliasXmlParser extends AbstractAliasXmlParser<Complex> { } sb.append(">\n"); - if (alias.getActivity() != null) { - if (alias.getActivity()) { + if (complex.getActivity() != null) { + if (complex.getActivity()) { sb.append("<celldesigner:activity>active</celldesigner:activity>\n"); } else { sb.append("<celldesigner:activity>inactive</celldesigner:activity>\n"); @@ -215,28 +215,29 @@ public class ComplexAliasXmlParser extends AbstractAliasXmlParser<Complex> { } sb.append("<celldesigner:bounds "); - sb.append("x=\"" + alias.getX() + "\" "); - sb.append("y=\"" + alias.getY() + "\" "); - sb.append("w=\"" + alias.getWidth() + "\" "); - sb.append("h=\"" + alias.getHeight() + "\" "); + sb.append("x=\"" + complex.getX() + "\" "); + sb.append("y=\"" + complex.getY() + "\" "); + sb.append("w=\"" + complex.getWidth() + "\" "); + sb.append("h=\"" + complex.getHeight() + "\" "); sb.append("/>\n"); - sb.append(createFontTag(alias)); + sb.append(createFontTag(complex)); sb.append("<celldesigner:view state=\"usual\"/>\n"); sb.append("<celldesigner:usualView>"); - sb.append("<celldesigner:innerPosition x=\"" + alias.getX() + "\" y=\"" + alias.getY() + "\"/>"); - sb.append("<celldesigner:boxSize width=\"" + alias.getWidth() + "\" height=\"" + alias.getHeight() + "\"/>"); - sb.append("<celldesigner:singleLine width=\"" + alias.getLineWidth() + "\"/>"); - sb.append("<celldesigner:paint color=\"" + XmlParser.colorToString(alias.getColor()) + "\" scheme=\"Color\"/>"); + sb.append("<celldesigner:innerPosition x=\"" + complex.getX() + "\" y=\"" + complex.getY() + "\"/>"); + sb.append("<celldesigner:boxSize width=\"" + complex.getWidth() + "\" height=\"" + complex.getHeight() + "\"/>"); + sb.append("<celldesigner:singleLine width=\"" + complex.getLineWidth() + "\"/>"); + sb.append("<celldesigner:paint color=\"" + XmlParser.colorToString(complex.getColor()) + "\" scheme=\"Color\"/>"); sb.append("</celldesigner:usualView>\n"); sb.append("<celldesigner:briefView>"); - sb.append("<celldesigner:innerPosition x=\"" + alias.getX() + "\" y=\"" + alias.getY() + "\"/>"); - sb.append("<celldesigner:boxSize width=\"" + alias.getWidth() + "\" height=\"" + alias.getHeight() + "\"/>"); - sb.append("<celldesigner:singleLine width=\"" + alias.getWidth() + "\"/>"); - sb.append("<celldesigner:paint color=\"" + XmlParser.colorToString(alias.getColor()) + "\" scheme=\"Color\"/>"); + sb.append("<celldesigner:innerPosition x=\"" + complex.getX() + "\" y=\"" + complex.getY() + "\"/>"); + sb.append("<celldesigner:boxSize width=\"" + complex.getWidth() + "\" height=\"" + complex.getHeight() + "\"/>"); + sb.append("<celldesigner:singleLine width=\"" + complex.getWidth() + "\"/>"); + sb.append("<celldesigner:paint color=\"" + XmlParser.colorToString(complex.getColor()) + "\" scheme=\"Color\"/>"); sb.append("</celldesigner:briefView>\n"); + sb.append(createStructuralStateTag(complex)); sb.append("</celldesigner:complexSpeciesAlias>\n"); return sb.toString(); } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/SpeciesAliasXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/SpeciesAliasXmlParser.java index 88744fd1d07afa4b4dc02ec1d7fea103a9833e41..eb6732861b5a0a78a43082cad9f4a29d035775a3 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/SpeciesAliasXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/SpeciesAliasXmlParser.java @@ -14,8 +14,7 @@ import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.compartment.PathwayCompartment; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelData; -import lcsb.mapviewer.model.map.species.Complex; -import lcsb.mapviewer.model.map.species.Species; +import lcsb.mapviewer.model.map.species.*; /** * Parser of CellDesigner xml used for parsing SpeciesAlias. @@ -98,8 +97,10 @@ public class SpeciesAliasXmlParser extends AbstractAliasXmlParser<Species> { } else if (node.getNodeName().equalsIgnoreCase("celldesigner:info")) { processAliasState(node, result); } else if (node.getNodeName().equalsIgnoreCase("celldesigner:structuralState")) { - // not handled - continue; + if (species instanceof CellDesignerProtein) { + ((CellDesignerProtein<?>) species) + .setStructuralStateAngle(Double.parseDouble(XmlParser.getNodeAttr("angle", node))); + } } else { throw new InvalidXmlSchemaException( errorPrefix + "Unknown element of celldesigner:speciesAlias: " + node.getNodeName()); @@ -231,6 +232,7 @@ public class SpeciesAliasXmlParser extends AbstractAliasXmlParser<Species> { sb.append("<celldesigner:info state=\"open\" prefix=\"" + species.getStatePrefix() + "\" label=\"" + species.getStateLabel() + "\"/>\n"); } + sb.append(createStructuralStateTag(species)); sb.append("</celldesigner:speciesAlias>\n"); return sb.toString(); } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerComplexSpecies.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerComplexSpecies.java index 2a815be82acd526c74db1b11a6ce801ae50ac20b..b3e924533aaf224d55dd56e7b3afd1394d129a2c 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerComplexSpecies.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerComplexSpecies.java @@ -9,6 +9,7 @@ import org.apache.logging.log4j.Logger; import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.NotImplementedException; import lcsb.mapviewer.model.map.species.Complex; +import lcsb.mapviewer.model.map.species.Species; /** * Class representing CellDesigner {@link Complex}. @@ -38,6 +39,8 @@ public class CellDesignerComplexSpecies extends CellDesignerSpecies<Complex> { */ private String structuralState = null; + private Double structuralStateAngle = null; + /** * Default constructor. */ @@ -46,8 +49,8 @@ public class CellDesignerComplexSpecies extends CellDesignerSpecies<Complex> { } /** - * Constructor that initiale the complex with the data from the object passed as - * an argument. + * Constructor that initialize the complex with the data from the object passed + * as an argument. * * @param original * object used for initializing data @@ -90,11 +93,15 @@ public class CellDesignerComplexSpecies extends CellDesignerSpecies<Complex> { if (elements.size() > 0) { throw new NotImplementedException(); } - result.setStructuralState(structuralState); return result; } + @Override + public void updateModelElementAfterLayoutAdded(Species element) { + ((Complex) element).setStructuralState(createStructuralState(element, structuralState, structuralStateAngle)); + } + /** * Adds element to the complex. * @@ -169,4 +176,12 @@ public class CellDesignerComplexSpecies extends CellDesignerSpecies<Complex> { this.elements = elements; } + public Double getStructuralStateAngle() { + return structuralStateAngle; + } + + public void setStructuralStateAngle(Double structuralStateAngle) { + this.structuralStateAngle = structuralStateAngle; + } + } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerProtein.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerProtein.java index 70e447b3712aa2140a4240da0f586efaff38cf2b..f970c873ae21b0b44e0629e25193448f6ff67d77 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerProtein.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerProtein.java @@ -37,6 +37,8 @@ public class CellDesignerProtein<T extends Protein> extends CellDesignerSpecies< */ private String structuralState = null; + private Double structuralStateAngle = null; + /** * List of modifications for the Protein. */ @@ -94,7 +96,6 @@ public class CellDesignerProtein<T extends Protein> extends CellDesignerSpecies< @Override protected void setModelObjectFields(T result) { super.setModelObjectFields(result); - result.setStructuralState(structuralState); } @Override @@ -110,6 +111,7 @@ public class CellDesignerProtein<T extends Protein> extends CellDesignerSpecies< throw new InvalidArgumentException("Cannot add modification residue to element: " + mr.getClass()); } } + protein.setStructuralState(createStructuralState(species, structuralState, structuralStateAngle)); } /** @@ -167,4 +169,12 @@ public class CellDesignerProtein<T extends Protein> extends CellDesignerSpecies< this.modificationResidues = modificationResidues; } + public Double getStructuralStateAngle() { + return structuralStateAngle; + } + + public void setStructuralStateAngle(Double structuralStateAngle) { + this.structuralStateAngle = structuralStateAngle; + } + } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java index 35f6b92423cf3873fcc70fad6025929cd29a17e5..6bb922034175ea7aee9cb0ae621c66f5c473e2b4 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java @@ -1,15 +1,20 @@ package lcsb.mapviewer.converter.model.celldesigner.structure; +import java.awt.*; +import java.awt.geom.Point2D; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.NotImplementedException; +import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter; import lcsb.mapviewer.model.map.MiriamData; import lcsb.mapviewer.model.map.kinetics.SbmlUnit; import lcsb.mapviewer.model.map.kinetics.SbmlUnitType; import lcsb.mapviewer.model.map.species.Species; import lcsb.mapviewer.model.map.species.field.PositionToCompartment; +import lcsb.mapviewer.model.map.species.field.StructuralState; /** * Generic CellDesigner element. @@ -26,6 +31,14 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement< */ private static final long serialVersionUID = 1L; + private static final int STRUCTURAL_STATE_FONT_SIZE = 10; + + private static final double MIN_STRUCTURAL_STATE_WIDTH = 60; + + private static final int TEXT_MARGIN_FOR_STRUCTURAL_STATE_DESC = 40; + + private static final int MIN_STRUCTURAL_STATE_HEIGHT = 20; + /** * Default class logger. */ @@ -582,4 +595,40 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement< public void updateModelElementAfterLayoutAdded(Species element) { } + protected StructuralState createStructuralState(Species species, String structuralState, Double angle) { + if (structuralState == null) { + return null; + } + + CellDesignerAliasConverter converter = new CellDesignerAliasConverter(species, false); + + Font font = new Font(Font.SANS_SERIF, 0, STRUCTURAL_STATE_FONT_SIZE); + Canvas c = new Canvas(); + FontMetrics fm = c.getFontMetrics(font); + + double width = MIN_STRUCTURAL_STATE_WIDTH; + double height = MIN_STRUCTURAL_STATE_HEIGHT; + if (!structuralState.trim().equals("")) { + width = Math.max(MIN_STRUCTURAL_STATE_WIDTH, + fm.stringWidth(structuralState) + TEXT_MARGIN_FOR_STRUCTURAL_STATE_DESC); + } + width = Math.min(width, species.getWidth()); + + StructuralState result = new StructuralState(); + result.setFontSize(STRUCTURAL_STATE_FONT_SIZE); + result.setHeight(height); + result.setWidth(width); + result.setValue(structuralState); + + if (angle == null) { + logger.warn("Angle is not defined using 0 as default"); + angle = 0.0; + } + Point2D position = converter.getResidueCoordinates(species, angle); + position.setLocation(position.getX() - width / 2, position.getY() - height / 2); + result.setPosition(position); + + return result; + } + } diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/SpeciesState.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/SpeciesState.java index dbd505bdc0146d6447c04b8d75817e723be33c0b..c428669472af041edab0c569c121f327ea28a332 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/SpeciesState.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/SpeciesState.java @@ -54,14 +54,18 @@ public class SpeciesState { public SpeciesState(Species species) { if (species instanceof Protein) { Protein protein = (Protein) species; - setStructuralState(protein.getStructuralState()); + if (protein.getStructuralState() != null) { + setStructuralState(protein.getStructuralState().getValue()); + } for (ModificationResidue mr : protein.getModificationResidues()) { addModificationResidue(new CellDesignerModificationResidue(mr)); } } else if (species instanceof Complex) { Complex complex = (Complex) species; - setStructuralState(complex.getStructuralState()); + if (complex.getStructuralState() != null) { + setStructuralState(complex.getStructuralState().getValue()); + } } else if (species instanceof Rna) { Rna rna = (Rna) species; for (ModificationResidue region : rna.getRegions()) { diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ProteinConverterTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ProteinConverterTest.java index c8774ca65fac033130cafe9f8f74fe04de88145d..ea4ede726074ee477abb7bfd28ce1e56f3ea3697 100644 --- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ProteinConverterTest.java +++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ProteinConverterTest.java @@ -11,8 +11,7 @@ import org.junit.*; import lcsb.mapviewer.common.Configuration; import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions; import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor; -import lcsb.mapviewer.model.map.species.GenericProtein; -import lcsb.mapviewer.model.map.species.Protein; +import lcsb.mapviewer.model.map.species.*; public class ProteinConverterTest extends CellDesignerTestFunctions { static Logger logger = LogManager.getLogger(ProteinConverterTest.class); @@ -59,6 +58,23 @@ public class ProteinConverterTest extends CellDesignerTestFunctions { } } + @Test + public void testAngleConversionForReceptor() { + Protein protein = new ReceptorProtein("id"); + protein.setWidth(10); + protein.setHeight(60); + protein.setX(200); + protein.setY(500); + + CellDesignerAliasConverter converter = new CellDesignerAliasConverter(protein, false); + + for (double angle = 0.0; angle < Math.PI * 2; angle += 0.1) { + Point2D point = converter.getResidueCoordinates(protein, angle); + double angle2 = converter.getAngleForPoint(protein, point); + assertEquals(angle, angle2, Configuration.EPSILON); + } + } + @Test public void testGetResidueCoords() throws Exception { GenericProtein protein = new GenericProtein("id"); diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/ComplexParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/ComplexParserTest.java index 336f829172c1f94d90da9a2e1763061d5779ea35..287682346d12324fb01fa4c4346606a39055cdca 100644 --- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/ComplexParserTest.java +++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/ComplexParserTest.java @@ -44,8 +44,17 @@ public class ComplexParserTest extends CellDesignerTestFunctions { @Test public void testComplexState() throws Exception { Model model = getModelForFile("testFiles/problematic/complex_with_state.xml"); - Complex complex = (Complex) model.getElementByElementId("csa1"); - assertEquals("test state", complex.getStructuralState()); + Complex complex = model.getElementByElementId("csa1"); + assertNotNull(complex.getStructuralState()); + assertEquals("test state", complex.getStructuralState().getValue()); + + assertEquals(0, getWarnings().size()); + } + + @Test + public void testMovedState() throws Exception { + Model model = getModelForFile("testFiles/protein_with_moved_state.xml"); + testXmlSerialization(model); } @Test(expected = InvalidXmlSchemaException.class) diff --git a/converter-CellDesigner/testFiles/protein_with_moved_state.xml b/converter-CellDesigner/testFiles/protein_with_moved_state.xml new file mode 100644 index 0000000000000000000000000000000000000000..4bb1c80897c345b03769cd147f3768e1610f1525 --- /dev/null +++ b/converter-CellDesigner/testFiles/protein_with_moved_state.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4"> +<model metaid="untitled" id="untitled"> +<annotation> +<celldesigner:extension> +<celldesigner:modelVersion>4.0</celldesigner:modelVersion> +<celldesigner:modelDisplay sizeX="600" sizeY="400"/> +<celldesigner:listOfCompartmentAliases/> +<celldesigner:listOfComplexSpeciesAliases/> +<celldesigner:listOfSpeciesAliases> +<celldesigner:speciesAlias id="sa1" species="s1"> +<celldesigner:activity>inactive</celldesigner:activity> +<celldesigner:bounds x="192.0" y="176.0" w="80.0" h="50.0"/> +<celldesigner:font size="12"/> +<celldesigner:view state="usual"/> +<celldesigner:structuralState angle="5.338676308955931"/> +<celldesigner:usualView> +<celldesigner:innerPosition x="0.0" y="0.0"/> +<celldesigner:boxSize width="80.0" height="50.0"/> +<celldesigner:singleLine width="1.0"/> +<celldesigner:paint color="ffffffcc" scheme="Color"/> +</celldesigner:usualView> +<celldesigner:briefView> +<celldesigner:innerPosition x="0.0" y="0.0"/> +<celldesigner:boxSize width="80.0" height="60.0"/> +<celldesigner:singleLine width="0.0"/> +<celldesigner:paint color="3fff0000" scheme="Color"/> +</celldesigner:briefView> +<celldesigner:info state="empty" angle="-1.5707963267948966"/> +</celldesigner:speciesAlias> +</celldesigner:listOfSpeciesAliases> +<celldesigner:listOfGroups/> +<celldesigner:listOfProteins> +<celldesigner:protein id="pr1" name="s1" type="RECEPTOR"/> +</celldesigner:listOfProteins> +<celldesigner:listOfGenes/> +<celldesigner:listOfRNAs/> +<celldesigner:listOfAntisenseRNAs/> +<celldesigner:listOfLayers/> +<celldesigner:listOfBlockDiagrams/> +</celldesigner:extension> +</annotation> +<listOfUnitDefinitions> +<unitDefinition metaid="substance" id="substance" name="substance"> +<listOfUnits> +<unit metaid="CDMT00001" kind="mole"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="volume" id="volume" name="volume"> +<listOfUnits> +<unit metaid="CDMT00002" kind="litre"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="area" id="area" name="area"> +<listOfUnits> +<unit metaid="CDMT00003" kind="metre" exponent="2"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="length" id="length" name="length"> +<listOfUnits> +<unit metaid="CDMT00004" kind="metre"/> +</listOfUnits> +</unitDefinition> +<unitDefinition metaid="time" id="time" name="time"> +<listOfUnits> +<unit metaid="CDMT00005" kind="second"/> +</listOfUnits> +</unitDefinition> +</listOfUnitDefinitions> +<listOfCompartments> +<compartment metaid="default" id="default" size="1" units="volume"/> +</listOfCompartments> +<listOfSpecies> +<species metaid="s1" id="s1" name="s1" compartment="default" initialAmount="0"> +<annotation> +<celldesigner:extension> +<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment> +<celldesigner:speciesIdentity> +<celldesigner:class>PROTEIN</celldesigner:class> +<celldesigner:proteinReference>pr1</celldesigner:proteinReference> +<celldesigner:state> +<celldesigner:listOfStructuralStates> +<celldesigner:structuralState structuralState="open"/> +</celldesigner:listOfStructuralStates> +</celldesigner:state> +</celldesigner:speciesIdentity> +</celldesigner:extension> +</annotation> +</species> +</listOfSpecies> +</model> +</sbml> diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java index c3cc9949f4e74f5f32037df7a5c1afbafb24bf4e..eb61780079473b5aee3f2b50461db7d2dc0943f7 100644 --- a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java +++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java @@ -10,8 +10,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.sbgn.*; import org.sbgn.bindings.*; -import org.sbgn.bindings.Map; import org.sbgn.bindings.Arc.*; +import org.sbgn.bindings.Map; import lcsb.mapviewer.common.comparator.DoubleComparator; import lcsb.mapviewer.common.exception.InvalidArgumentException; @@ -24,8 +24,7 @@ import lcsb.mapviewer.model.map.modifier.*; import lcsb.mapviewer.model.map.reaction.*; import lcsb.mapviewer.model.map.reaction.type.*; import lcsb.mapviewer.model.map.species.*; -import lcsb.mapviewer.model.map.species.field.AbstractSiteModification; -import lcsb.mapviewer.model.map.species.field.ModificationResidue; +import lcsb.mapviewer.model.map.species.field.*; import lcsb.mapviewer.modelutils.map.ElementUtils; /** @@ -170,8 +169,8 @@ public class SbgnmlXmlExporter { stateVariableGlyph.setId(newGlyph.getId().concat("-").concat(stateVariableGlyph.getId())); newGlyph.getGlyph().add(stateVariableGlyph); } - if (protein.getStructuralState() != null && !protein.getStructuralState().isEmpty()) { - newGlyph.getGlyph().add(createStateVariableForStructuralState(protein, protein.getStructuralState())); + if (protein.getStructuralState() != null && !protein.getStructuralState().getValue().isEmpty()) { + newGlyph.getGlyph().add(createStateVariableForStructuralState(protein.getStructuralState())); } } @@ -186,8 +185,8 @@ public class SbgnmlXmlExporter { Glyph childGlyph = elementToGlyph(child); newGlyph.getGlyph().add(childGlyph); } - if (complex.getStructuralState() != null && !complex.getStructuralState().isEmpty()) { - newGlyph.getGlyph().add(createStateVariableForStructuralState(complex, complex.getStructuralState())); + if (complex.getStructuralState() != null && !complex.getStructuralState().getValue().isEmpty()) { + newGlyph.getGlyph().add(createStateVariableForStructuralState(complex.getStructuralState())); } } } @@ -196,24 +195,24 @@ public class SbgnmlXmlExporter { return newGlyph; } - private Glyph createStateVariableForStructuralState(Element element, String structuralState) { + private Glyph createStateVariableForStructuralState(StructuralState structuralState) { Glyph glyph = new Glyph(); - glyph.setId(element.getElementId() + "-state"); + glyph.setId(structuralState.getSpecies().getElementId() + "-state"); glyph.setClazz(GlyphClazz.STATE_VARIABLE.getClazz()); Glyph.State state = new Glyph.State(); - state.setValue(structuralState); + state.setValue(structuralState.getValue()); glyph.setState(state); Bbox bbox = new Bbox(); - - float width = (float) (element.getWidth() - 20); - float height = 28.0f; - bbox.setH(width); - bbox.setW(height); - - bbox.setX((float) (element.getX() + 10)); - bbox.setY((float) (element.getY() - height / 2)); + + float width = structuralState.getWidth().floatValue(); + float height = structuralState.getHeight().floatValue(); + bbox.setH(height); + bbox.setW(width); + + bbox.setX((float) structuralState.getPosition().getX()); + bbox.setY((float) structuralState.getPosition().getY()); glyph.setBbox(bbox); diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java index 9423bb9f7c6c77d64b303c5dccd1ff232d4fa6f6..fcc383be6082580f2306d4e6be98410b1064480d 100644 --- a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java +++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java @@ -1,6 +1,6 @@ package lcsb.mapviewer.converter.model.sbgnml; -import java.awt.*; +import java.awt.Color; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.io.File; @@ -34,6 +34,7 @@ import lcsb.mapviewer.model.map.reaction.*; import lcsb.mapviewer.model.map.reaction.type.*; import lcsb.mapviewer.model.map.species.*; import lcsb.mapviewer.model.map.species.field.*; +import lcsb.mapviewer.modelutils.map.ElementUtils; /** * This class is a parser for SBGN-ML files. @@ -590,13 +591,14 @@ public class SbgnmlXmlParser { logger.warn(ex.getMessage()); } } else { - String structuralState = child.getState().getValue(); if (newSpecies instanceof Protein) { Protein protein = (Protein) newSpecies; - protein.setStructuralState(structuralState); + protein.setStructuralState(createStructuralState(child)); } else if (newSpecies instanceof Complex) { Complex complex = (Complex) newSpecies; - complex.setStructuralState(structuralState); + complex.setStructuralState(createStructuralState(child)); + } else { + logger.warn(new ElementUtils().getElementTag(newSpecies) + "State is not supported"); } } } @@ -608,6 +610,23 @@ public class SbgnmlXmlParser { } + private StructuralState createStructuralState(Glyph glyph) { + StructuralState structuralState = new StructuralState(); + + double height = new Double(glyph.getBbox().getH()); + double width = new Double(glyph.getBbox().getW()); + double x = new Double(glyph.getBbox().getX()); + double y = new Double(glyph.getBbox().getY()); + + structuralState.setFontSize(10); + structuralState.setValue(glyph.getState().getValue()); + structuralState.setHeight(height); + structuralState.setWidth(width); + structuralState.setPosition(new Point2D.Double(x, y)); + + return structuralState; + } + /** * {@link ModificationResidue} in element might have slightly off coordinates * (due to different symbol shapes). For that we need to align them to match our diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/CellDesignerToSbgnTest.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/CellDesignerToSbgnTest.java index 54da7290fb6832b0ba4fa5a8452d4207d682a457..f040b806171515f7216a1c6d90a205ce27994221 100644 --- a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/CellDesignerToSbgnTest.java +++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/CellDesignerToSbgnTest.java @@ -18,6 +18,7 @@ import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Protein; +import lcsb.mapviewer.model.map.species.field.StructuralStateComparator; import lcsb.mapviewer.modelutils.map.ElementUtils; public class CellDesignerToSbgnTest extends SbgnmlTestFunctions { @@ -108,7 +109,9 @@ public class CellDesignerToSbgnTest extends SbgnmlTestFunctions { protein1 = model.getElementByElementId("sa2"); protein2 = model2.getElementByElementId("sa2"); - assertEquals(protein1.getStructuralState(), protein2.getStructuralState()); + StructuralStateComparator comparator = new StructuralStateComparator(); + + assertEquals(0, comparator.compare(protein1.getStructuralState(), protein2.getStructuralState())); } } diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/DbSerializationTest.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/DbSerializationTest.java index 7f6000f2a56ada60c4643a425c3fe4f4d8d9d2d1..c2a66df954416f2e6130fed94b951ff32c5aa72e 100644 --- a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/DbSerializationTest.java +++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/DbSerializationTest.java @@ -3,35 +3,61 @@ package lcsb.mapviewer.converter.model.sbgnml; import static org.junit.Assert.assertEquals; import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.*; import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.transaction.annotation.Transactional; import lcsb.mapviewer.model.map.model.*; import lcsb.mapviewer.persist.DbUtils; import lcsb.mapviewer.persist.dao.map.ModelDao; -@Transactional -@ContextConfiguration(classes = SpringSBGNMLConverterTestConfig.class) -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(Parameterized.class) public class DbSerializationTest extends SbgnmlTestFunctions { - @Autowired - ModelDao modelDao; - @Autowired - DbUtils dbUtils; + + static ApplicationContext applicationContext; Logger logger = LogManager.getLogger(DbSerializationTest.class.getName()); - private void makeDbSerializationTest(String filePath) throws Exception { + private String fileName; + + public DbSerializationTest(String filePath) { + this.fileName = filePath; + } + + @Parameters(name = "{index} : {0}") + public static Collection<Object[]> data() throws IOException { + applicationContext = new AnnotationConfigApplicationContext( + SpringSBGNMLConverterTestConfig.class); + + Collection<Object[]> data = new ArrayList<Object[]>(); + data.add(new Object[] {"testFiles/sbgnmlParserTestFiles/sbgnmlFiles/VANTEDdiagram.sbgn"}); + data.add(new Object[] {"testFiles/sbgnmlParserTestFiles/sbgnmlFiles/activated_stat1alpha_induction_of_the_irf1_gene.sbgn"}); + data.add(new Object[] {"testFiles/sbgnmlParserTestFiles/sbgnmlFiles/adh.sbgn"}); + data.add(new Object[] {"testFiles/sbgnmlParserTestFiles/sbgnmlFiles/clone-marker.sbgn"}); + data.add(new Object[] {"testFiles/sbgnmlParserTestFiles/sbgnmlFiles/glycolysis.sbgn"}); + data.add(new Object[] {"testFiles/sbgnmlCellDesignerInompatible/insulin-like_growth_factor_signaling.sbgn"}); + data.add(new Object[] {"testFiles/sbgnmlCellDesignerInompatible/neuronal_muscle_signalling.sbgn"}); + data.add(new Object[] {"testFiles/sbgnmlParserTestFiles/sbgnmlFiles/phenotypeTest.sbgn"}); + return data; + } + + @Test + @Transactional + public void dbSerializationTest() throws Exception { + ModelDao modelDao = applicationContext.getBean(ModelDao.class); + SbgnmlXmlParser parser = new SbgnmlXmlParser(); - String fileName = "testFiles/sbgnmlParserTestFiles/sbgnmlFiles/".concat(filePath); Model model = parser.createModel(fileName, new File(fileName)); modelDao.add(model); @@ -47,6 +73,7 @@ public class DbSerializationTest extends SbgnmlTestFunctions { @Before public void setUp() throws Exception { + DbUtils dbUtils = applicationContext.getBean(DbUtils.class); // we use custom threads because in layoutservice there is commit method // called, and because of that hibernate session injected by spring // cannot @@ -58,48 +85,9 @@ public class DbSerializationTest extends SbgnmlTestFunctions { @After public void tearDown() throws Exception { + DbUtils dbUtils = applicationContext.getBean(DbUtils.class); // close session dbUtils.closeSessionForCurrentThread(); } - @Test - public void VANTEDdiagramTest() throws Exception { - makeDbSerializationTest("VANTEDdiagram.sbgn"); - } - - @Test - public void activatedStat1AlphaTest() throws Exception { - makeDbSerializationTest("activated_stat1alpha_induction_of_the_irf1_gene.sbgn"); - } - - @Test - public void adhTest() throws Exception { - makeDbSerializationTest("adh.sbgn"); - } - - @Test - public void cloneMarkerTest() throws Exception { - makeDbSerializationTest("clone-marker.sbgn"); - } - - @Test - public void glycolysisTest() throws Exception { - makeDbSerializationTest("glycolysis.sbgn"); - } - - @Test - public void insulinLikeGrowthFactorSignalingTest() throws Exception { - makeDbSerializationTest("insulin-like_growth_factor_signaling.sbgn"); - } - - @Test - public void neuronalMuscleSignallingTest() throws Exception { - makeDbSerializationTest("neuronal_muscle_signalling.sbgn"); - } - - @Test - public void phenotypeTest() throws Exception { - makeDbSerializationTest("phenotypeTest.sbgn"); - } - } diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporterTest.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporterTest.java index 6618aa6b875d2537e726727d023248770e913141..e840c5e16d1ed486b4946077d43046a4ed49acf7 100644 --- a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporterTest.java +++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporterTest.java @@ -2,8 +2,7 @@ package lcsb.mapviewer.converter.model.sbgnml; import java.io.File; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.*; import java.util.ArrayList; import java.util.Collection; @@ -23,10 +22,10 @@ public class SbgnmlXmlExporterTest extends SbgnmlTestFunctions { Logger logger = LogManager.getLogger(SbgnmlXmlExporterTest.class.getName()); - private String testName; + private Path filePath; - public SbgnmlXmlExporterTest(String testName) { - this.testName = testName; + public SbgnmlXmlExporterTest(Path filePath) { + this.filePath = filePath; } @Parameters(name = "{index} : {0}") @@ -34,25 +33,29 @@ public class SbgnmlXmlExporterTest extends SbgnmlTestFunctions { Collection<Object[]> data = new ArrayList<Object[]>(); Files.walk(Paths.get("testFiles/sbgnmlParserTestFiles/sbgnmlFiles")).forEach(fPath -> { if (Files.isRegularFile(fPath) && fPath.toString().endsWith(".sbgn")) { - String tName = fPath.getFileName().toString().substring(0, fPath.getFileName().toString().indexOf(".sbgn")); - data.add(new Object[] { tName }); + data.add(new Object[] { fPath}); + } + }); + Files.walk(Paths.get("testFiles/sbgnmlCellDesignerInompatible")).forEach(fPath -> { + if (Files.isRegularFile(fPath) && fPath.toString().endsWith(".sbgn")) { + data.add(new Object[] { fPath}); } }); return data; } - private void parseAndExport(String testName) throws Exception { + private void parseAndExport(Path filePath) throws Exception { Converter converter = new SbgnmlXmlConverter(); Model model = converter.createModel(new ConverterParams() - .filename("testFiles/sbgnmlParserTestFiles/sbgnmlFiles/".concat(testName).concat(".sbgn"))); + .filename(filePath.toAbsolutePath().toString())); converter.model2File(model, File.createTempFile("temp-sbgn-output", ".sbgn").getAbsolutePath()); } @Test public void test() throws Exception { - parseAndExport(testName); + parseAndExport(filePath); } } diff --git a/converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/insulin-like_growth_factor_signaling.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/insulin-like_growth_factor_signaling.sbgn similarity index 100% rename from converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/insulin-like_growth_factor_signaling.sbgn rename to converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/insulin-like_growth_factor_signaling.sbgn diff --git a/converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/mapk_cascade.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/mapk_cascade.sbgn similarity index 100% rename from converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/mapk_cascade.sbgn rename to converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/mapk_cascade.sbgn diff --git a/converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/neuronal_muscle_signalling.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/neuronal_muscle_signalling.sbgn similarity index 100% rename from converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/neuronal_muscle_signalling.sbgn rename to converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/neuronal_muscle_signalling.sbgn diff --git a/converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/neuronal_muscle_signalling_color.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/neuronal_muscle_signalling_color.sbgn similarity index 100% rename from converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/neuronal_muscle_signalling_color.sbgn rename to converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/neuronal_muscle_signalling_color.sbgn diff --git a/converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/states.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/states.sbgn similarity index 100% rename from converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/states.sbgn rename to converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/states.sbgn diff --git a/converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/submap.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/submap.sbgn similarity index 100% rename from converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/submap.sbgn rename to converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/submap.sbgn diff --git a/converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/theWeirdOne.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/theWeirdOne.sbgn similarity index 100% rename from converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/theWeirdOne.sbgn rename to converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/theWeirdOne.sbgn diff --git a/converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/unitOfInformation.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/unitOfInformation.sbgn similarity index 100% rename from converter-SBGNML/testFiles/sbgnmlParserTestFiles/sbgnmlFiles/unitOfInformation.sbgn rename to converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/unitOfInformation.sbgn diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ComplexConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ComplexConverter.java index 5f523dfa78f3e23f30d2f07408f80f10dbaec854..7a91e5485a2907c63f3928490a00193a94e018f4 100644 --- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ComplexConverter.java +++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ComplexConverter.java @@ -52,70 +52,69 @@ public class ComplexConverter extends SpeciesConverter<Complex> { } @Override - protected void drawImpl(final Complex alias, final Graphics2D graphics, final ConverterParams params) { - if (alias.getState().equalsIgnoreCase("complexnoborder")) { + protected void drawImpl(final Complex complex, final Graphics2D graphics, final ConverterParams params) { + if (complex.getState().equalsIgnoreCase("complexnoborder")) { return; } int homodir; if (params.isSbgnFormat()) { - // If the SBGN display mode is set, multimer is shown as two stacked - // glyphs - if (alias.getHomodimer() > 1) { + // If the SBGN display mode is set, multimer is shown as two stacked glyphs + if (complex.getHomodimer() > 1) { homodir = 2; } else { homodir = 1; } } else { - homodir = alias.getHomodimer(); + homodir = complex.getHomodimer(); } - alias.setWidth(alias.getWidth() - SpeciesConverter.HOMODIMER_OFFSET * (alias.getHomodimer() - 1)); - alias.setHeight(alias.getHeight() - SpeciesConverter.HOMODIMER_OFFSET * (alias.getHomodimer() - 1)); + complex.setWidth(complex.getWidth() - SpeciesConverter.HOMODIMER_OFFSET * (complex.getHomodimer() - 1)); + complex.setHeight(complex.getHeight() - SpeciesConverter.HOMODIMER_OFFSET * (complex.getHomodimer() - 1)); - alias.setX(alias.getX() + SpeciesConverter.HOMODIMER_OFFSET * (homodir)); - alias.setY(alias.getY() + SpeciesConverter.HOMODIMER_OFFSET * (homodir)); + complex.setX(complex.getX() + SpeciesConverter.HOMODIMER_OFFSET * (homodir)); + complex.setY(complex.getY() + SpeciesConverter.HOMODIMER_OFFSET * (homodir)); for (int i = 0; i < homodir; i++) { - alias.setX(alias.getX() - SpeciesConverter.HOMODIMER_OFFSET); - alias.setY(alias.getY() - SpeciesConverter.HOMODIMER_OFFSET); + complex.setX(complex.getX() - SpeciesConverter.HOMODIMER_OFFSET); + complex.setY(complex.getY() - SpeciesConverter.HOMODIMER_OFFSET); - GeneralPath path = getAliasPath(alias); + GeneralPath path = getAliasPath(complex); Color c = graphics.getColor(); Stroke stroke = graphics.getStroke(); - graphics.setColor(alias.getColor()); + graphics.setColor(complex.getColor()); graphics.fill(path); graphics.setColor(c); - graphics.setStroke(getBorderLine(alias)); + graphics.setStroke(getBorderLine(complex)); graphics.draw(path); - if (alias.getState().equals("brief")) { - alias.increaseBorder(-INTERNAL_BORDER_DIST); - path = getAliasPath(alias); - alias.increaseBorder(INTERNAL_BORDER_DIST); + if (complex.getState().equals("brief")) { + complex.increaseBorder(-INTERNAL_BORDER_DIST); + path = getAliasPath(complex); + complex.increaseBorder(INTERNAL_BORDER_DIST); graphics.setStroke(LineType.DOTTED.getStroke()); graphics.draw(path); } - if (alias.getActivity() && !params.isSbgnFormat()) { - alias.increaseBorder(INTERNAL_BORDER_DIST); - path = getAliasPath(alias); - alias.increaseBorder(-INTERNAL_BORDER_DIST); + if (complex.getActivity() && !params.isSbgnFormat()) { + complex.increaseBorder(INTERNAL_BORDER_DIST); + path = getAliasPath(complex); + complex.increaseBorder(-INTERNAL_BORDER_DIST); graphics.setStroke(LineType.DOTTED.getStroke()); graphics.draw(path); } graphics.setStroke(stroke); } - alias.setWidth(alias.getWidth() + SpeciesConverter.HOMODIMER_OFFSET * (alias.getHomodimer() - 1)); - alias.setHeight(alias.getHeight() + SpeciesConverter.HOMODIMER_OFFSET * (alias.getHomodimer() - 1)); + complex.setWidth(complex.getWidth() + SpeciesConverter.HOMODIMER_OFFSET * (complex.getHomodimer() - 1)); + complex.setHeight(complex.getHeight() + SpeciesConverter.HOMODIMER_OFFSET * (complex.getHomodimer() - 1)); // SBGN view - multimers are displayed with a unit of information containing // cardinality if (params.isSbgnFormat()) { String unitOfInformationText = null; - if (alias.getStatePrefix() != null && alias.getStateLabel() != null) { - unitOfInformationText = alias.getStatePrefix() + ":" + alias.getStateLabel(); + if (complex.getStatePrefix() != null && complex.getStateLabel() != null) { + unitOfInformationText = complex.getStatePrefix() + ":" + complex.getStateLabel(); } if (homodir == 2 && (unitOfInformationText == null || !unitOfInformationText.contains("N:"))) { if (unitOfInformationText != null) { @@ -123,17 +122,15 @@ public class ComplexConverter extends SpeciesConverter<Complex> { } else { unitOfInformationText = ""; } - unitOfInformationText += "N:" + alias.getHomodimer(); + unitOfInformationText += "N:" + complex.getHomodimer(); } - drawUnitOfInformation(unitOfInformationText, alias, graphics); + drawUnitOfInformation(unitOfInformationText, complex, graphics); } - String text = alias.getStructuralState(); + drawStructuralState(complex.getStructuralState(), graphics); - drawStructuralState(text, alias, graphics); - - drawText(alias, graphics, params); + drawText(complex, graphics, params); } @Override diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ProteinConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ProteinConverter.java index 5f223086fb12bcfbd2b8b391fd916e7c3551081e..4ebc97efca6c927136d6d10bb452dd57ce5318a2 100644 --- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ProteinConverter.java +++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ProteinConverter.java @@ -194,8 +194,7 @@ public class ProteinConverter extends SpeciesConverter<Protein> { unitOfInformationText = null; } - String text = protein.getStructuralState(); - drawStructuralState(text, protein, graphics); + drawStructuralState(protein.getStructuralState(), graphics); drawUnitOfInformation(unitOfInformationText, protein, graphics); drawText(protein, graphics, params); protein.setWidth(protein.getWidth() + SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1)); diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverter.java index eec1afd1cb80bf19db460c2d381facd4f1eb4ac5..65cf866433d187701eedd45620a90e11e3a42d66 100644 --- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverter.java +++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverter.java @@ -43,10 +43,7 @@ public abstract class SpeciesConverter<T extends Species> extends ElementConvert * What is the distance between homodimer aliases when homodimer>1. */ public static final int HOMODIMER_OFFSET = 6; - /** - * Default font size for the modifier description. - */ - protected static final int DEFAULT_SPECIES_MODIFIER_FONT_SIZE = 10; + /** * Default diameter of the modification residues. */ @@ -59,30 +56,25 @@ public abstract class SpeciesConverter<T extends Species> extends ElementConvert * Default species font size. */ protected static final int DEFAULT_SPECIES_FONT_SIZE = 12; - /** - * Height of the ellipse that contain structural state description. - */ - private static final int STRUCTURAL_STATE_HEIGHT = 20; + /** * Height of the rectangle that contains unit of information. */ private static final int UNIT_OF_INFORMATION_HEIGHT = 20; - /** - * Size of the margin in the structural state description. - */ - private static final int TEXT_MARGIN_FOR_STRUCTURAL_STATE_DESC = 40; + /** * Size of the margin in the unit of information description. */ private static final int TEXT_MARGIN_FOR_UNIT_OF_INFORMATION_DESC = 20; - /** - * Minimum width of the structural state ellipse. - */ - private static final int MIN_STRUCTURAL_STATE_WIDTH = 60; + /** * Minimum width of the unit of information rectangle. */ private static final int MIN_UNIT_OF_INFORMATION_WIDTH = 40; + /** + * Default font size for the modifier description. + */ + protected static final int DEFAULT_SPECIES_MODIFIER_FONT_SIZE = 10; /** * Default class logger. */ @@ -93,10 +85,7 @@ public abstract class SpeciesConverter<T extends Species> extends ElementConvert */ private LineTransformation lineTransformation = new LineTransformation(); private ArrowTransformation arrowTransformation = new ArrowTransformation(); - /** - * Default font used to draw structural state of the species. - */ - private Font structuralFont = null; + /** * Default font used to draw unit of information of the species. */ @@ -114,7 +103,6 @@ public abstract class SpeciesConverter<T extends Species> extends ElementConvert * when drawing {@link Species} */ protected SpeciesConverter(ColorExtractor colorExtractor) { - structuralFont = new Font(Font.SANS_SERIF, 0, DEFAULT_SPECIES_MODIFIER_FONT_SIZE); this.colorExtractor = colorExtractor; }; @@ -300,21 +288,6 @@ public abstract class SpeciesConverter<T extends Species> extends ElementConvert this.lineTransformation = lineTransformation; } - /** - * @return the structuralFont - */ - protected Font getStructuralFont() { - return structuralFont; - } - - /** - * @param structuralFont - * the structuralFont to set - */ - protected void setStructuralFont(Font structuralFont) { - this.structuralFont = structuralFont; - } - /** * @return the unitOfInformationFont */ @@ -334,43 +307,40 @@ public abstract class SpeciesConverter<T extends Species> extends ElementConvert * Draws structural state description of the alias (ellipse in the top part of * the alias). * - * @param text + * @param state * state description text * @param species * state description should be drawn on this {@link Species} * @param graphics * where the drawing should be performed */ - protected void drawStructuralState(String text, T species, final Graphics2D graphics) { - if (text == null) { + protected void drawStructuralState(StructuralState state, final Graphics2D graphics) { + if (state == null) { return; } - Point2D p = new Point2D.Double(species.getCenterX(), species.getY()); - - double width = MIN_STRUCTURAL_STATE_WIDTH; - if (!text.trim().equals("")) { - width = Math.max(MIN_STRUCTURAL_STATE_WIDTH, - graphics.getFontMetrics().stringWidth(text) + TEXT_MARGIN_FOR_STRUCTURAL_STATE_DESC); - } - width = Math.min(width, species.getWidth()); - double height = STRUCTURAL_STATE_HEIGHT; + double width = state.getWidth(); + double height = state.getHeight(); - Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - width / 2, p.getY() - height / 2, width, height); + Ellipse2D ellipse = new Ellipse2D.Double(state.getPosition().getX(), state.getPosition().getY(), width, height); Color c = graphics.getColor(); graphics.setColor(Color.WHITE); graphics.fill(ellipse); graphics.setColor(c); graphics.draw(ellipse); - if (!text.trim().equals("")) { - Font font = graphics.getFont(); - graphics.setFont(getStructuralFont()); + if (!state.getValue().equals("")) { + Font tmpFont = graphics.getFont(); + Font font = new Font(Font.SANS_SERIF, 0, state.getFontSize().intValue()); + graphics.setFont(font); - width = graphics.getFontMetrics().stringWidth(text); + width = graphics.getFontMetrics().stringWidth(state.getValue()); height = graphics.getFontMetrics().getAscent() - graphics.getFontMetrics().getDescent(); - graphics.drawString(text, (int) (p.getX() - width / 2), (int) (p.getY() + height / 2)); - graphics.setFont(font); + double x = state.getPosition().getX() + (state.getWidth() - width) / 2; + double y = state.getPosition().getY() + (state.getHeight() + height) / 2; + + graphics.drawString(state.getValue(), (int) x, (int) y); + graphics.setFont(tmpFont); } } @@ -529,6 +499,10 @@ public abstract class SpeciesConverter<T extends Species> extends ElementConvert } } + private Font getStructuralFont() { + return new Font(Font.SANS_SERIF, 0, DEFAULT_SPECIES_MODIFIER_FONT_SIZE); + } + /** * This method draws {@link ModificationSite} of the {@link Species}. If * drawEmptyModification is set to false then modification is not drawn if diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java index a7cf1fdfd142f2eb56c6266bbb900b91d4b2b71d..3688c5e1e8d2ae66297f04c9326e1736a75259a4 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java @@ -32,6 +32,7 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j private SbmlCompartmentExporter compartmentExporter; private int modificationResidueCounter = 0; + private int structuralStateCounter = 0; private Map<String, String> modificationResidueIds = new HashMap<>(); public SbmlSpeciesExporter(Model sbmlModel, @@ -172,14 +173,15 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j private void assignStructuralStateToMulti(Species element, MultiSpeciesPlugin multiExtension, MultiSpeciesType speciesType) { - String structuralState = null; + StructuralState structuralState = null; if (element instanceof Protein) { structuralState = ((Protein) element).getStructuralState(); } else if (element instanceof Complex) { structuralState = ((Complex) element).getStructuralState(); } if (structuralState != null) { - assignValueToFeature(element, multiExtension, speciesType, structuralState, BioEntityFeature.STRUCTURAL_STATE); + assignValueToFeature(element, multiExtension, speciesType, structuralState.getValue(), + BioEntityFeature.STRUCTURAL_STATE); } } @@ -374,13 +376,16 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j String multiDistinguisher = null; if (isExtensionEnabled(SbmlExtension.MULTI)) { - String structuralState = null; + StructuralState structuralState = null; if (element instanceof Protein) { + structuralState = ((Protein) element).getStructuralState(); } else if (element instanceof Complex) { structuralState = ((Complex) element).getStructuralState(); } - multiDistinguisher = structuralState; + if (structuralState != null) { + multiDistinguisher = structuralState.getValue(); + } if (element instanceof SpeciesWithModificationResidue) { List<String> modifications = new ArrayList<>(); @@ -465,6 +470,9 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j createModificationGlyph(mr, speciesGlyph); } } + if (element.getStructuralState() != null) { + createStructuralStateGlyph(element, speciesGlyph); + } } TextGlyph textGlyph = getLayout().createTextGlyph("text_" + element.getElementId(), element.getName()); textGlyph @@ -484,6 +492,44 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j } + private void createStructuralStateGlyph(Species element, AbstractReferenceGlyph speciesGlyph) { + org.sbml.jsbml.Species sbmlSpecies = getSbmlModel().getSpecies(speciesGlyph.getReference()); + + MultiSpeciesPlugin speciesExtension = (MultiSpeciesPlugin) sbmlSpecies.getExtension("multi"); + + SpeciesFeatureType structuralStateFeature = getFeature(element.getClass(), getMultiSpeciesType(element), + BioEntityFeature.STRUCTURAL_STATE); + + PossibleSpeciesFeatureValue possibleSpeciesFeatureValue = getPosibleFeatureIdByName( + element.getStructuralState().getValue(), structuralStateFeature); + + SpeciesFeature feature = null; + for (SpeciesFeature existingFeature : speciesExtension.getListOfSpeciesFeatures()) { + if (existingFeature.getSpeciesFeatureType().equals(structuralStateFeature.getId())) { + feature = existingFeature; + } + } + + SpeciesFeatureValue modificationFeatureValue = null; + for (SpeciesFeatureValue featureValue : feature.getListOfSpeciesFeatureValues()) { + if (possibleSpeciesFeatureValue.getId().equals(featureValue.getValue())) { + modificationFeatureValue = featureValue; + } + } + + modificationFeatureValue.setId(getStructuralStateUniqueId(element.getStructuralState())); + + GeneralGlyph modificationGlyph = getLayout().createGeneralGlyph("structural_state_" + (idCounter++), + modificationFeatureValue.getId()); + ReferenceGlyph referenceGlyph = new ReferenceGlyph("structural_state_reference_" + (idCounter++)); + referenceGlyph.setGlyph(speciesGlyph.getId()); + referenceGlyph.setBoundingBox(createBoundingBoxForStructuralState(element.getStructuralState())); + + modificationGlyph.addReferenceGlyph(referenceGlyph); + modificationGlyph.setBoundingBox(createBoundingBoxForStructuralState(element.getStructuralState())); + + } + @SuppressWarnings("unchecked") private MultiSpeciesType createSpeciesTypeForClass(MultiModelPlugin multiPlugin, Class<? extends Element> clazz) { MultiSpeciesType speciesType = new MultiSpeciesType(); @@ -560,6 +606,20 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j modificationGlyph.setBoundingBox(createBoundingBoxForModification(mr)); } + private BoundingBox createBoundingBoxForStructuralState(StructuralState structuralState) { + double width = structuralState.getWidth(); + double height = structuralState.getHeight(); + double x = structuralState.getPosition().getX(); + double y = structuralState.getPosition().getY(); + BoundingBox boundingBox = new BoundingBox(); + boundingBox.setPosition(new Point(x, y, structuralState.getSpecies().getZ() + 1)); + Dimensions dimensions = new Dimensions(); + dimensions.setWidth(width); + dimensions.setHeight(height); + boundingBox.setDimensions(dimensions); + return boundingBox; + } + private BoundingBox createBoundingBoxForModification(ModificationResidue mr) { double width, height; if (mr instanceof AbstractRegionModification) { @@ -592,4 +652,15 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j return result; } + private String getStructuralStateUniqueId(StructuralState mr) { + String modificationId = "structural_state_" + getSbmlIdKey(mr.getSpecies()); + String result = modificationResidueIds.get(modificationId); + if (result == null) { + result = "structural_state_" + (structuralStateCounter++); + modificationResidueIds.put(modificationId, result); + } + return result; + + } + } diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java index d6c62603e56fed5901a482ff763dccf1af371669..7a98e43eeac412cd360778610a9f8e0596ad0960 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java @@ -2,8 +2,7 @@ package lcsb.mapviewer.converter.model.sbml.species; import java.awt.geom.Point2D; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -31,6 +30,8 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> private static String ARTIFITIAL_SOURCE_ID = "sbml_artifitial_source"; Logger logger = LogManager.getLogger(SbmlSpeciesParser.class); + Map<String, String> structuralStateIdMap = new HashMap<>(); + public SbmlSpeciesParser(Model model, lcsb.mapviewer.model.map.model.Model minervaModel) { super(model, minervaModel); } @@ -65,13 +66,20 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> String featureTypeString = feature.getSpeciesFeatureType(); List<String> featureValues = getFeatureValues(speciesType, feature); if (MultiPackageNamingUtils.isFeatureId(featureTypeString, BioEntityFeature.STRUCTURAL_STATE)) { + String structuralStateId = null; + for (SpeciesFeatureValue featureValue : feature.getListOfSpeciesFeatureValues()) { + if (featureValue.getId() != null) { + structuralStateId = featureValue.getId(); + } + } if (minervaElement instanceof Protein) { - ((Protein) minervaElement).setStructuralState(String.join("; ", featureValues)); + minervaElement.setStructuralState(createStructuralState(featureValues)); } else if (minervaElement instanceof Complex) { - ((Complex) minervaElement).setStructuralState(String.join("; ", featureValues)); + minervaElement.setStructuralState(createStructuralState(featureValues)); } else { logger.warn(warnPrefix + "Structural state not supported"); } + structuralStateIdMap.put(minervaElement.getElementId(), structuralStateId); } else if (MultiPackageNamingUtils.isFeatureId(featureTypeString, BioEntityFeature.POSITION_TO_COMPARTMENT)) { if (featureValues.size() != 1) { logger.warn(warnPrefix + "Position to compartment must have exactly one value"); @@ -161,6 +169,12 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> } } + private StructuralState createStructuralState(List<String> featureValues) { + StructuralState structuralState = new StructuralState(); + structuralState.setValue(String.join("; ", featureValues)); + return structuralState; + } + private List<String> getFeatureValues(MultiSpeciesType speciesType, SpeciesFeature feature) { SpeciesFeatureType featureType = speciesType.getListOfSpeciesFeatureTypes().get(feature.getSpeciesFeatureType()); @@ -320,7 +334,29 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> // find a reference to the alias in layout, so we know it's the proper value ReferenceGlyph referenceGlyph = ((GeneralGlyph) graphicalObject).getListOfReferenceGlyphs().get(0); if (Objects.equal(referenceGlyph.getGlyph(), mr.getSpecies().getElementId())) { -// if (referenceGlyph.getGlyph().equals(mr.getSpecies().getElementId())) { + // if (referenceGlyph.getGlyph().equals(mr.getSpecies().getElementId())) { + residueGlyph = (GeneralGlyph) graphicalObject; + } + } else { + residueGlyph = (GeneralGlyph) graphicalObject; + } + } + } + } + return residueGlyph; + } + + private GeneralGlyph getResidueGlyphForStructuralState(StructuralState mr) { + GeneralGlyph residueGlyph = null; + String structurlaStateId = structuralStateIdMap.get(mr.getSpecies().getElementId()); + for (GraphicalObject graphicalObject : getLayout().getListOfAdditionalGraphicalObjects()) { + if (graphicalObject instanceof GeneralGlyph) { + if (Objects.equal(((GeneralGlyph) graphicalObject).getReference(), structurlaStateId)) { + if (((GeneralGlyph) graphicalObject).getListOfReferenceGlyphs().size() > 0) { + // find a reference to the alias in layout, so we know it's the proper value + ReferenceGlyph referenceGlyph = ((GeneralGlyph) graphicalObject).getListOfReferenceGlyphs().get(0); + if (Objects.equal(referenceGlyph.getGlyph(), mr.getSpecies().getElementId())) { + // if (referenceGlyph.getGlyph().equals(mr.getSpecies().getElementId())) { residueGlyph = (GeneralGlyph) graphicalObject; } } else { @@ -366,21 +402,54 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> for (Element element : result) { String compartmentId = null; + String speciesId = element.getElementId(); if (getLayout().getSpeciesGlyph(element.getElementId()) != null) { compartmentId = ((org.sbml.jsbml.Species) getLayout().getSpeciesGlyph(element.getElementId()) .getSpeciesInstance()).getCompartment(); + speciesId = ((org.sbml.jsbml.Species) getLayout().getSpeciesGlyph(element.getElementId()).getSpeciesInstance()) + .getId(); } else { if (!element.getElementId().equals(ARTIFITIAL_SINK_ID) && !element.getElementId().equals(ARTIFITIAL_SOURCE_ID)) { compartmentId = getSbmlModel().getSpecies(element.getElementId()).getCompartment(); } } + structuralStateIdMap.put(element.getElementId(), structuralStateIdMap.get(speciesId)); assignCompartment(element, compartmentId); assignModificationResiduesLayout(element); + assignStructuralStateLayout(element); } return result; } + private void assignStructuralStateLayout(Element element) { + if (element instanceof Protein || element instanceof Complex) { + StructuralState state = ((Species) element).getStructuralState(); + if (state != null) { + state.setFontSize(10); + state.setHeight(20); + state.setWidth(element.getWidth()); + state.setPosition(new Point2D.Double(element.getX(), element.getY() - 10)); + GeneralGlyph residueGlyph = getResidueGlyphForStructuralState(state); + if (residueGlyph != null) { + if (residueGlyph.getBoundingBox() == null || residueGlyph.getBoundingBox().getDimensions() == null) { + logger.warn( + new ElementUtils().getElementTag(element) + " Layout doesn't contain coordinates for structural state"); + } else { + double width = residueGlyph.getBoundingBox().getDimensions().getWidth(); + double height = residueGlyph.getBoundingBox().getDimensions().getHeight(); + double x = residueGlyph.getBoundingBox().getPosition().getX(); + double y = residueGlyph.getBoundingBox().getPosition().getY(); + state.setPosition(new Point2D.Double(x, y)); + state.setWidth(width); + state.setHeight(height); + } + } + + } + } + } + @Override protected void applyStyleToElement(Element elementWithLayout, LocalStyle style) { super.applyStyleToElement(elementWithLayout, style); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java index 145e36e21ba025019f5d521ee7215783aa88f87d..6a2c07c77127c0aabfe643620122fcb181d75c57 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java @@ -3,7 +3,6 @@ package lcsb.mapviewer.converter.model.sbml; import static org.junit.Assert.*; import java.awt.Color; -import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.io.File; import java.lang.reflect.Modifier; @@ -17,7 +16,6 @@ import org.sbml.jsbml.SBMLDocument; import org.sbml.jsbml.ext.multi.*; import lcsb.mapviewer.common.Configuration; -import lcsb.mapviewer.common.comparator.LineComparator; import lcsb.mapviewer.common.comparator.ListComparator; import lcsb.mapviewer.converter.ConverterParams; import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser; @@ -397,7 +395,7 @@ public class SbmlExporterTest extends SbmlTestFunctions { public void testExportProteinState() throws Exception { Model model = createEmptyModel(); GenericProtein element = createProtein(); - element.setStructuralState("xxx"); + element.setStructuralState(createStructuralState(element)); model.addElement(element); Model deserializedModel = getModelAfterSerializing(model); @@ -430,9 +428,9 @@ public class SbmlExporterTest extends SbmlTestFunctions { @Test public void testMultiExtensionProteinStateInTypes() throws Exception { - String structuralState = "xxx"; Model model = createEmptyModel(); GenericProtein element = createProtein(); + StructuralState structuralState = createStructuralState(element); element.setStructuralState(structuralState); model.addElement(element); org.sbml.jsbml.Model sbmlModel = exporter.toSbmlDocument(model).getModel(); @@ -442,7 +440,7 @@ public class SbmlExporterTest extends SbmlTestFunctions { for (MultiSpeciesType speciesType : multiPlugin.getListOfSpeciesTypes()) { for (SpeciesFeatureType featureType : speciesType.getListOfSpeciesFeatureTypes()) { for (PossibleSpeciesFeatureValue featureValue : featureType.getListOfPossibleSpeciesFeatureValues()) { - if (featureValue.getName().equals(structuralState)) { + if (featureValue.getName().equals(structuralState.getValue())) { structuralStateValueFound = true; } } @@ -454,13 +452,12 @@ public class SbmlExporterTest extends SbmlTestFunctions { @Test public void testMultiExtensionProteinStateSuplicateInTypes() throws Exception { - String structuralState = "xxx"; Model model = createEmptyModel(); GenericProtein element = createProtein(); - element.setStructuralState(structuralState); + element.setStructuralState(createStructuralState(element)); model.addElement(element); element = createProtein(); - element.setStructuralState(structuralState); + element.setStructuralState(createStructuralState(element)); model.addElement(element); org.sbml.jsbml.Model sbmlModel = exporter.toSbmlDocument(model).getModel(); MultiModelPlugin multiPlugin = (MultiModelPlugin) sbmlModel.getExtension("multi"); @@ -498,9 +495,9 @@ public class SbmlExporterTest extends SbmlTestFunctions { @Test public void testMultiExtensionStructuralStateTypeDefinition() throws Exception { - String structuralState = "xxx"; Model model = createEmptyModel(); GenericProtein element = createProtein(); + StructuralState structuralState = createStructuralState(element); element.setStructuralState(structuralState); model.addElement(element); org.sbml.jsbml.Model sbmlModel = exporter.toSbmlDocument(model).getModel(); @@ -512,6 +509,16 @@ public class SbmlExporterTest extends SbmlTestFunctions { speciesExtension.getListOfSpeciesFeatures().size() > 0); } + private StructuralState createStructuralState(Element element) { + StructuralState structuralState = new StructuralState(); + structuralState.setValue("xxx"); + structuralState.setPosition(new Point2D.Double(element.getX(), element.getY() - 10)); + structuralState.setWidth(element.getWidth()); + structuralState.setHeight(20.0); + structuralState.setFontSize(10.0); + return structuralState; + } + @Test public void testExportResidue() throws Exception { Model model = createEmptyModel(); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporterTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporterTest.java index 190972f43443201ddee1a11afdb1c384a9409707..caa0240f2b894166f11938ac505f3fe3254f1830 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporterTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporterTest.java @@ -18,6 +18,7 @@ import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelFullIndexed; import lcsb.mapviewer.model.map.species.*; +import lcsb.mapviewer.model.map.species.field.StructuralState; public class SbmlSpeciesExporterTest extends SbmlTestFunctions { @@ -84,7 +85,9 @@ public class SbmlSpeciesExporterTest extends SbmlTestFunctions { public void testIdsOfSpeciesWithStructuralStates() throws InconsistentModelException { Species protein1 = createProtein(); Protein protein2 = createProtein(); - protein2.setStructuralState("X"); + StructuralState state = new StructuralState(); + state.setValue("X"); + protein2.setStructuralState(state); Model model = new ModelFullIndexed(null); model.addElement(protein1); model.addElement(protein2); diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Complex.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Complex.java index 4c3e4c4e70c7dac30ed8cc5ea1c86891bc676ebd..45c439cffa28965d9e077f2fc6dd22fc0b449583 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/species/Complex.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Complex.java @@ -10,6 +10,7 @@ import org.hibernate.annotations.Cascade; import org.hibernate.annotations.CascadeType; import lcsb.mapviewer.common.exception.NotImplementedException; +import lcsb.mapviewer.model.map.species.field.StructuralState; /** * Class that represents complex in the model. Complex elements contain @@ -40,11 +41,6 @@ public class Complex extends Species { @OneToMany(fetch = FetchType.EAGER, mappedBy = "complex") private List<Species> elements = new ArrayList<>(); - /** - * State of the complex species. - */ - private String structuralState = null; - /** * Empty constructor required by hibernate. */ @@ -65,7 +61,6 @@ public class Complex extends Species { for (Species element : original.getElements()) { addSpecies(element.copy()); } - this.structuralState = original.getStructuralState(); } /** @@ -151,23 +146,6 @@ public class Complex extends Species { } } - /** - * @return the structuralState - * @see #structuralState - */ - public String getStructuralState() { - return structuralState; - } - - /** - * @param structuralState - * the structuralState to set - * @see #structuralState - */ - public void setStructuralState(String structuralState) { - this.structuralState = structuralState; - } - /** * Returns all children and sub-children elements for this element. Only non * {@link Complex} children will be returned. diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/ComplexComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/species/ComplexComparator.java index 07af665d13a33bd851c47e4e0498efbbd2cbade4..5335d79fd1a3e37af0ba84768f1c81bdbb01dc18 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/species/ComplexComparator.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/ComplexComparator.java @@ -9,8 +9,8 @@ import org.apache.logging.log4j.Logger; import lcsb.mapviewer.common.Comparator; import lcsb.mapviewer.common.Configuration; import lcsb.mapviewer.common.comparator.IntegerComparator; -import lcsb.mapviewer.common.comparator.StringComparator; import lcsb.mapviewer.common.exception.InvalidArgumentException; +import lcsb.mapviewer.model.map.species.field.StructuralStateComparator; /** * This class implements comparator interface for {@link Complex}. @@ -88,12 +88,12 @@ public class ComplexComparator extends Comparator<Complex> { } } - StringComparator stringComparator = new StringComparator(); + StructuralStateComparator structuralStateComparator = new StructuralStateComparator(); - if (stringComparator.compare(arg0.getStructuralState(), arg1.getStructuralState()) != 0) { + if (structuralStateComparator.compare(arg0.getStructuralState(), arg1.getStructuralState()) != 0) { logger .debug("Species structuralState different: " + arg0.getStructuralState() + ", " + arg1.getStructuralState()); - return stringComparator.compare(arg0.getStructuralState(), arg1.getStructuralState()); + return structuralStateComparator.compare(arg0.getStructuralState(), arg1.getStructuralState()); } return 0; diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Protein.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Protein.java index 81bec9f3e7c3c7fa5fcea33bb21014af421fbee9..18d932e02658eee1e67420ff2d6dfede0baa0387 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/species/Protein.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Protein.java @@ -26,11 +26,6 @@ public abstract class Protein extends Species implements SpeciesWithBindingRegio */ private static final long serialVersionUID = 1L; - /** - * State of the protein. - */ - private String structuralState = null; - /** * List of modifications for the Protein. */ @@ -53,7 +48,6 @@ public abstract class Protein extends Species implements SpeciesWithBindingRegio */ protected Protein(Protein original) { super(original); - this.structuralState = original.getStructuralState(); for (ModificationResidue mr : original.getModificationResidues()) { addModificationResidue(mr.copy()); } @@ -107,23 +101,6 @@ public abstract class Protein extends Species implements SpeciesWithBindingRegio this.modificationResidues = modificationResidues; } - /** - * @return the structuralState - * @see #structuralState - */ - public String getStructuralState() { - return structuralState; - } - - /** - * @param structuralState - * the structuralState to set - * @see #structuralState - */ - public void setStructuralState(String structuralState) { - this.structuralState = structuralState; - } - @Override public String getStringType() { return "Protein"; diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/ProteinComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/species/ProteinComparator.java index b2930d68d811f270fe4b5488f82502e016f8dd3c..3d60941368c8116e3dd0cd5e54922887a3f8dd5f 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/species/ProteinComparator.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/ProteinComparator.java @@ -8,9 +8,9 @@ import org.apache.logging.log4j.Logger; import lcsb.mapviewer.common.Comparator; import lcsb.mapviewer.common.Configuration; -import lcsb.mapviewer.common.comparator.StringComparator; import lcsb.mapviewer.common.comparator.StringSetComparator; import lcsb.mapviewer.model.map.species.field.ModificationResidue; +import lcsb.mapviewer.model.map.species.field.StructuralStateComparator; /** * Comparator class used for comparing {@link Protein} objects. @@ -59,12 +59,12 @@ public class ProteinComparator extends Comparator<Protein> { @Override protected int internalCompare(Protein arg0, Protein arg1) { - StringComparator stringComparator = new StringComparator(); + StructuralStateComparator structuralStateComparator = new StructuralStateComparator(); StringSetComparator stringSetComparator = new StringSetComparator(); - if (stringComparator.compare(arg0.getStructuralState(), arg1.getStructuralState()) != 0) { + if (structuralStateComparator.compare(arg0.getStructuralState(), arg1.getStructuralState()) != 0) { logger.debug("structural state different: " + arg0.getStructuralState() + ", " + arg1.getStructuralState()); - return stringComparator.compare(arg0.getStructuralState(), arg1.getStructuralState()); + return structuralStateComparator.compare(arg0.getStructuralState(), arg1.getStructuralState()); } Set<String> set1 = new HashSet<>(); diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java index 19eb0d2e4b88567723e5fea893e6483cea81f641..8d39fb32d1cf5d5ca605739b4466e36dd97040ec 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java @@ -12,8 +12,7 @@ import org.hibernate.annotations.CascadeType; import lcsb.mapviewer.model.map.kinetics.SbmlUnit; import lcsb.mapviewer.model.map.kinetics.SbmlUnitType; -import lcsb.mapviewer.model.map.species.field.PositionToCompartment; -import lcsb.mapviewer.model.map.species.field.UniprotRecord; +import lcsb.mapviewer.model.map.species.field.*; /** * Structure used for representing information about single element. @@ -139,6 +138,15 @@ public abstract class Species extends Element { @Cascade({ CascadeType.ALL }) private SbmlUnit substanceUnitComlexType; + /** + * State of the complex/protein species. + */ + // it should be in protein/complex, but due to hibernate reversed mappedBy + // property it + // must be in species. + @OneToOne(orphanRemoval = true, cascade = javax.persistence.CascadeType.ALL) + private StructuralState structuralState = null; + /** * Constructor that set element identifier. * @@ -191,6 +199,9 @@ public abstract class Species extends Element { substanceUnitRawType = original.substanceUnitRawType; uniprots = original.getUniprots(); + if (original.structuralState != null) { + setStructuralState(original.structuralState.copy()); + } // don't copy reaction nodes } @@ -511,4 +522,15 @@ public abstract class Species extends Element { this.substanceUnitRawType = null; } + public StructuralState getStructuralState() { + return structuralState; + } + + public void setStructuralState(StructuralState structuralState) { + this.structuralState = structuralState; + if (structuralState != null) { + structuralState.setSpecies(this); + } + } + } diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/StructuralState.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/StructuralState.java new file mode 100644 index 0000000000000000000000000000000000000000..bc8637150d99ba6c281a751d06579af299d2c57f --- /dev/null +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/StructuralState.java @@ -0,0 +1,146 @@ +package lcsb.mapviewer.model.map.species.field; + +import java.awt.geom.Point2D; +import java.io.Serializable; +import java.text.DecimalFormat; + +import javax.persistence.*; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.hibernate.annotations.Type; + +import lcsb.mapviewer.model.map.species.Species; + +/** + * This class represent structural state of a {@link Species}. + * + * @author Piotr Gawron + * + */ + +@Entity +public class StructuralState implements Serializable { + + private static final long serialVersionUID = 1L; + + @SuppressWarnings("unused") + private static Logger logger = LogManager.getLogger(); + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @Column(nullable = false) + private String value; + + @Type(type = "lcsb.mapviewer.persist.mapper.Point2DMapper") + @Column(nullable = false) + private Point2D position = null; + + @Column(nullable = false) + private Double width; + + @Column(nullable = false) + private Double height; + + @Column(nullable = false) + private Double fontSize; + + @OneToOne(fetch = FetchType.LAZY, cascade = javax.persistence.CascadeType.ALL, mappedBy = "structuralState", optional = false) + private Species species; + + public StructuralState() { + } + + /** + * Constructor that initialize object with the data taken from the parameter. + * + * @param mr + * original object from which data is taken + */ + public StructuralState(StructuralState mr) { + this.value = mr.getValue(); + this.position = mr.position; + this.width = mr.getWidth(); + this.height = mr.getHeight(); + this.fontSize = mr.getFontSize(); + } + + public Species getSpecies() { + return species; + } + + public void setSpecies(Species species) { + this.species = species; + } + + public Point2D getPosition() { + return position; + } + + public void setPosition(Point2D position) { + this.position = position; + } + + public StructuralState copy() { + return new StructuralState(this); + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public String toString() { + DecimalFormat format = new DecimalFormat("#.##"); + String positionString = "Point2D[null]"; + if (getPosition() != null) { + positionString = "Point2D[" + format.format(getPosition().getX()) + "," + format.format(getPosition().getY()) + + "]"; + } + String result = getValue() + "," + positionString; + return result; + } + + public Double getWidth() { + return width; + } + + public void setWidth(Double width) { + this.width = width; + } + + public Double getHeight() { + return height; + } + + public void setHeight(Double height) { + this.height = height; + } + + public void setHeight(Integer height) { + this.height = height.doubleValue(); + } + + public Double getFontSize() { + return fontSize; + } + + public void setFontSize(Double fontSize) { + this.fontSize = fontSize; + } + + public void setFontSize(int fontSize) { + this.fontSize = (double) fontSize; + } + + public Point2D getCenter() { + return new Point2D.Double(position.getX() + width / 2, position.getY() + height / 2); + } + +} diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/StructuralStateComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/StructuralStateComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..86e3334500ae02d0342485a7cf7df8af435771cb --- /dev/null +++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/StructuralStateComparator.java @@ -0,0 +1,52 @@ +package lcsb.mapviewer.model.map.species.field; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import lcsb.mapviewer.common.Comparator; +import lcsb.mapviewer.common.comparator.*; +import lcsb.mapviewer.model.map.MiriamData; + +/** + * Comparator of {@link MiriamData} object. + * + * @author Piotr Gawron + * + */ +public class StructuralStateComparator extends Comparator<StructuralState> { + + private static Logger logger = LogManager.getLogger(); + + /** + * Default constructor. + */ + public StructuralStateComparator() { + super(StructuralState.class); + } + + @Override + protected int internalCompare(StructuralState arg0, StructuralState arg1) { + StringComparator stringComparator = new StringComparator(); + if (stringComparator.compare(arg0.getValue(), arg1.getValue()) != 0) { + return stringComparator.compare(arg0.getValue(), arg1.getValue()); + } + PointComparator pointComparator = new PointComparator(); + if (pointComparator.compare(arg0.getPosition(), arg1.getPosition()) != 0) { + logger.debug("position different: " + arg0.getPosition() + ", " + arg1.getPosition()); + return pointComparator.compare(arg0.getPosition(), arg1.getPosition()); + } + + DoubleComparator doubleComparator = new DoubleComparator(); + if (doubleComparator.compare(arg0.getWidth(), arg1.getWidth()) != 0) { + logger.debug("width different: " + arg0.getWidth() + ", " + arg1.getWidth()); + return doubleComparator.compare(arg0.getWidth(), arg1.getWidth()); + } + if (doubleComparator.compare(arg0.getHeight(), arg1.getHeight()) != 0) { + logger.debug("height different: " + arg0.getHeight() + ", " + arg1.getHeight()); + return doubleComparator.compare(arg0.getHeight(), arg1.getHeight()); + } + + return 0; + } + +} diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/ComplexComparatorTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/ComplexComparatorTest.java index 60ba2db455ff203618e5701b0fb3f288a8230bea..196210dedfe8090877afdae03295eb9d84240433 100644 --- a/model/src/test/java/lcsb/mapviewer/model/map/species/ComplexComparatorTest.java +++ b/model/src/test/java/lcsb/mapviewer/model/map/species/ComplexComparatorTest.java @@ -4,7 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; -import java.awt.*; +import java.awt.Color; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -14,6 +14,7 @@ import org.mockito.Mockito; import lcsb.mapviewer.ModelTestFunctions; import lcsb.mapviewer.common.exception.InvalidArgumentException; import lcsb.mapviewer.common.exception.NotImplementedException; +import lcsb.mapviewer.model.map.species.field.StructuralState; public class ComplexComparatorTest extends ModelTestFunctions { @@ -234,7 +235,7 @@ public class ComplexComparatorTest extends ModelTestFunctions { complex1 = createComplex(); complex2 = createComplex(); - complex1.setStructuralState("str"); + complex1.setStructuralState(new StructuralState()); assertTrue(comparator.compare(complex1, complex2) != 0); assertTrue(comparator.compare(complex2, complex1) != 0); diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinComparatorTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinComparatorTest.java index a0c3b2b7f33c0f0abb6c768e15fa319b812a18c3..60ab973e7c934441f314d70d278fe4ac67a54b76 100644 --- a/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinComparatorTest.java +++ b/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinComparatorTest.java @@ -12,8 +12,7 @@ import org.mockito.Mockito; import lcsb.mapviewer.ModelTestFunctions; import lcsb.mapviewer.common.exception.NotImplementedException; -import lcsb.mapviewer.model.map.species.field.ModificationState; -import lcsb.mapviewer.model.map.species.field.Residue; +import lcsb.mapviewer.model.map.species.field.*; public class ProteinComparatorTest extends ModelTestFunctions { Logger logger = LogManager.getLogger(ProteinComparatorTest.class); @@ -82,12 +81,6 @@ public class ProteinComparatorTest extends ModelTestFunctions { assertTrue(comparator.compare(protein1, protein2) != 0); assertTrue(comparator.compare(protein2, protein1) != 0); - protein1 = createProtein(); - protein2 = createProtein(); - protein1.setStructuralState("a"); - assertTrue(comparator.compare(protein1, protein2) != 0); - assertTrue(comparator.compare(protein2, protein1) != 0); - protein1 = createProtein(); protein2 = createProtein(); protein1.setHomodimer(1); @@ -97,10 +90,21 @@ public class ProteinComparatorTest extends ModelTestFunctions { assertTrue(comparator.compare(new GenericProtein(), new TruncatedProtein()) != 0); } + @Test + public void testDifferentStructuralState() { + GenericProtein protein1 = createProtein(); + GenericProtein protein2 = createProtein(); + StructuralState str = new StructuralState(); + str.setValue("STR"); + protein1.setStructuralState(str); + assertTrue(comparator.compare(protein1, protein2) != 0); + assertTrue(comparator.compare(protein2, protein1) != 0); + } + public GenericProtein createProtein() { GenericProtein result = new GenericProtein(); result.setHomodimer(12); - result.setStructuralState("id1"); + result.setStructuralState(new StructuralState()); result.setHypothetical(true); Residue residue = new Residue(); diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinTest.java index 8fd69b5dc0fd41e7ad3ad682c3bd80fa22bd4094..cdef9115e03b119b77a00c0c72dd142b1198d366 100644 --- a/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinTest.java +++ b/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinTest.java @@ -12,8 +12,7 @@ import org.mockito.Mockito; import lcsb.mapviewer.ModelTestFunctions; import lcsb.mapviewer.common.exception.NotImplementedException; -import lcsb.mapviewer.model.map.species.field.ModificationResidue; -import lcsb.mapviewer.model.map.species.field.Residue; +import lcsb.mapviewer.model.map.species.field.*; public class ProteinTest extends ModelTestFunctions { @@ -33,7 +32,7 @@ public class ProteinTest extends ModelTestFunctions { @Test public void testConstructor1() { GenericProtein protein = new GenericProtein(); - protein.setStructuralState("srt"); + protein.setStructuralState(new StructuralState()); List<ModificationResidue> residues = new ArrayList<>(); residues.add(new Residue()); @@ -45,10 +44,12 @@ public class ProteinTest extends ModelTestFunctions { @Test public void testSetStructuralState() { GenericProtein protein = new GenericProtein(); - protein.setStructuralState("str"); - protein.setStructuralState("str1"); + protein.setStructuralState(new StructuralState()); + StructuralState str = new StructuralState(); + str.setValue("str1"); + protein.setStructuralState(str); - assertEquals("str1", protein.getStructuralState()); + assertEquals("str1", protein.getStructuralState().getValue()); } @Test diff --git a/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/XML/ModelContructor.java b/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/XML/ModelContructor.java index 8b56cec9646a576120bf18bf5212807300dab11e..f8a1a67c3bd28930db8c17856c65953a9bc34ef3 100644 --- a/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/XML/ModelContructor.java +++ b/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/XML/ModelContructor.java @@ -11,8 +11,7 @@ import org.apache.logging.log4j.Logger; import lcsb.mapviewer.common.Configuration; import lcsb.mapviewer.common.Pair; -import lcsb.mapviewer.common.exception.InvalidArgumentException; -import lcsb.mapviewer.common.exception.InvalidStateException; +import lcsb.mapviewer.common.exception.*; import lcsb.mapviewer.common.geometry.PointTransformation; import lcsb.mapviewer.converter.ConverterException; import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter; @@ -338,7 +337,7 @@ public class ModelContructor { if (species instanceof Protein) { Protein protein = ((Protein) species); if (protein.getStructuralState() == null) { - protein.setStructuralState(state.getStructuralState()); + protein.setStructuralState(createStructuralState(state, protein)); } else { logger.warn(state.getWarningPrefix() + " tries to override another state: " + protein.getStructuralState()); } @@ -350,6 +349,18 @@ public class ModelContructor { } } + private StructuralState createStructuralState(State state, Species species) { + Double x = state.getRelX() * species.getWidth() + species.getX(); + Double y = state.getRelY() * species.getHeight() + species.getY(); + StructuralState structuralState= new StructuralState(); + structuralState.setPosition(new Point2D.Double(x, y)); + structuralState.setFontSize(10); + structuralState.setHeight(state.getHeight()); + structuralState.setWidth(state.getWidth()); + structuralState.setValue(state.getStructuralState()); + return structuralState; + } + /** * {@link ModificationResidue} in element might have slightly off coordinates * (due to different symbol shapes). For that we need to align them to match our diff --git a/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java b/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java index ea1b53f84105eaedb7ac7434cf36736d09c5b162..3d7e5bab20526882f1efbb274272ec131cc5fd85 100644 --- a/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java +++ b/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java @@ -351,11 +351,7 @@ public class GPMLToModelTest extends WikipathwaysTestFunctions { Protein protein = (Protein) model1.getElementsByName("Protein").get(0); assertEquals(0, protein.getModificationResidues().size()); - assertEquals("GTP", protein.getStructuralState()); - - Model model2 = serializeModelOverCellDesignerParser(model1); - - assertEquals(0, mc.compare(model1, model2)); + assertNotNull(protein.getStructuralState()); } } diff --git a/persist/src/main/resources/db/migration/15.0.0/V15.0.1.20191022_2__structural_state_table.sql b/persist/src/main/resources/db/migration/15.0.0/V15.0.1.20191022_2__structural_state_table.sql new file mode 100644 index 0000000000000000000000000000000000000000..65934bb21f0aaf2869528fef120c6682781b3d48 --- /dev/null +++ b/persist/src/main/resources/db/migration/15.0.0/V15.0.1.20191022_2__structural_state_table.sql @@ -0,0 +1,43 @@ +CREATE SEQUENCE structural_state_sequence + INCREMENT 1 + MINVALUE 1 + MAXVALUE 9223372036854775807 + START 1 + CACHE 1; + +CREATE TABLE structural_state_table +( + id integer NOT NULL DEFAULT nextval('structural_state_sequence'::regclass), + value varchar NOT NULL, + position varchar NOT NULL, + width numeric(6,2) NOT NULL, + height numeric(6,2) NOT NULL, + font_size numeric(6,2) NOT NULL, + species_id integer NOT NULL, + + CONSTRAINT structural_state_pk PRIMARY KEY (id), + CONSTRAINT structural_state_table_species_fk FOREIGN KEY (species_id) + REFERENCES element_table (id) MATCH SIMPLE + ON UPDATE NO ACTION ON DELETE NO ACTION +) +WITH ( + OIDS=FALSE +); + +alter table element_table add column structural_state_id integer; +alter table element_table add constraint element_table_structural_state_fk FOREIGN KEY (structural_state_id) + REFERENCES structural_state_table (id) MATCH SIMPLE + ON UPDATE NO ACTION ON DELETE NO ACTION; + +insert into structural_state_table (position, width, height, value, font_size, species_id) select + concat(x+width/2-least(greatest(60, 60+4*(length(structural_state)-7)), width)/2,',', y-10), --position + least(greatest(60, 60+4*(length(structural_state)-7)), width), --width + 20, --height + structural_state, --state + 10, --font_size + id + from element_table where structural_state is not null; + +update element_table set structural_state_id = (select id from structural_state_table where species_id = element_table.id); + +alter table element_table drop column structural_state; diff --git a/persist/src/main/resources/db/migration/15.0.0/V15.0.1.20191023__structural_state_table.sql b/persist/src/main/resources/db/migration/15.0.0/V15.0.1.20191023__structural_state_table.sql new file mode 100644 index 0000000000000000000000000000000000000000..362a96dfab82c93cf4d37c2ee6c8218184b9d088 --- /dev/null +++ b/persist/src/main/resources/db/migration/15.0.0/V15.0.1.20191023__structural_state_table.sql @@ -0,0 +1 @@ +alter table structural_state_table alter column species_id drop not null; diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementsRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementsRestImpl.java index 8baf0a46d567d91f0b8bd1e97a01750c3b978597..07056a49770ccc546a504d9c1f1dff720fba20dd 100644 --- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementsRestImpl.java +++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementsRestImpl.java @@ -225,7 +225,7 @@ public class ElementsRestImpl extends BaseRestImpl { protected Map<String, Object> getOthersForElement(Element element) { Map<String, Object> result = new TreeMap<>(); List<Map<String, Object>> modifications = new ArrayList<>(); - String structuralState = null; + StructuralState structuralState = null; Map<String, Object> structures = new TreeMap<>(); if (element instanceof Protein) { Protein protein = ((Protein) element); @@ -234,21 +234,22 @@ public class ElementsRestImpl extends BaseRestImpl { } else if (element instanceof Rna) { Rna rna = ((Rna) element); modifications = getModifications(rna.getRegions()); - structuralState = rna.getState(); } else if (element instanceof AntisenseRna) { AntisenseRna antisenseRna = ((AntisenseRna) element); modifications = getModifications(antisenseRna.getRegions()); - structuralState = antisenseRna.getState(); } else if (element instanceof Gene) { Gene gene = ((Gene) element); modifications = getModifications(gene.getModificationResidues()); - structuralState = gene.getState(); } if (element instanceof Species) { structures = getStructures(((Species) element).getUniprots()); } result.put("modifications", modifications); - result.put("structuralState", structuralState); + if (structuralState != null) { + result.put("structuralState", structuralState.getValue()); + } else { + result.put("structuralState", null); + } result.put("structures", structures); return result; diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementRestImplTest.java index 13e2a706c13e6cb663a71e13403e77cc4e9d560c..c792b27de1d2e9f38a391ecd98b99dd0cef64101 100644 --- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementRestImplTest.java +++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementRestImplTest.java @@ -82,7 +82,8 @@ public class ElementRestImplTest extends RestTestFunctions { @SuppressWarnings("unchecked") @Test public void testGetModificationsForProtein() throws Exception { - String state = "asd"; + StructuralState state = new StructuralState(); + state.setValue("asd"); GenericProtein protein = new GenericProtein("s1"); Residue mr = new Residue(); mr.setState(ModificationState.ACETYLATED); @@ -91,7 +92,7 @@ public class ElementRestImplTest extends RestTestFunctions { protein.setStructuralState(state); Map<String, Object> result = _elementsRestImpl.getOthersForElement(protein); assertNotNull(result.get("modifications")); - assertEquals(state, result.get("structuralState")); + assertEquals(state.getValue(), result.get("structuralState")); List<Map<String, Object>> modifications = (List<Map<String, Object>>) result.get("modifications"); assertEquals(1, modifications.size()); } @@ -99,16 +100,14 @@ public class ElementRestImplTest extends RestTestFunctions { @SuppressWarnings("unchecked") @Test public void testGetModificationsForRna() throws Exception { - String state = "asd"; Rna rna = new Rna("s1"); ModificationSite mr = new ModificationSite(); mr.setState(ModificationState.ACETYLATED); mr.setName("S250"); rna.addModificationSite(mr); - rna.setState(state); Map<String, Object> result = _elementsRestImpl.getOthersForElement(rna); assertNotNull(result.get("modifications")); - assertEquals(state, result.get("structuralState")); + assertEquals(null, result.get("structuralState")); List<Map<String, Object>> modifications = (List<Map<String, Object>>) result.get("modifications"); assertEquals(1, modifications.size()); } @@ -116,15 +115,13 @@ public class ElementRestImplTest extends RestTestFunctions { @SuppressWarnings("unchecked") @Test public void testGetModificationsForAntisenseRna() throws Exception { - String state = "asd"; AntisenseRna antisenseRna = new AntisenseRna("s1"); ModificationSite mr = new ModificationSite(); mr.setName("S250"); antisenseRna.addModificationSite(mr); - antisenseRna.setState(state); Map<String, Object> result = _elementsRestImpl.getOthersForElement(antisenseRna); assertNotNull(result.get("modifications")); - assertEquals(state, result.get("structuralState")); + assertEquals(null, result.get("structuralState")); List<Map<String, Object>> modifications = (List<Map<String, Object>>) result.get("modifications"); assertEquals(1, modifications.size()); }