diff --git a/CHANGELOG b/CHANGELOG index a6e36d2891c1ec9e873814281574adc94ddd82db..86db56ad63814bb83ac79ddd4fb93b101f209299 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ minerva (14.0.0~beta.2) unstable; urgency=low + * Bug fix: exported SBML passes online validation (#831) * Bug fix: allow user to remove own comments (#931) * Bug fix: validation of project name length is provided (#950) * Bug fix: after reducing privileges on himself interface is refreshed (#948) diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java index 4bf203532dbe74413bec5d4d06f29d0be383bcfc..d4184cb7b4e211f4b6370c32635b14e4976af7a3 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java @@ -1,16 +1,15 @@ package lcsb.mapviewer.converter.model.sbml.reaction; -import java.awt.*; +import java.awt.BasicStroke; +import java.awt.Stroke; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.util.*; -import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.sbml.jsbml.*; import org.sbml.jsbml.ext.layout.*; -import org.sbml.jsbml.ext.layout.Point; import org.sbml.jsbml.ext.render.*; import org.w3c.dom.Node; @@ -237,13 +236,45 @@ public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sb reactionGlyph.setBoundingBox(new BoundingBox()); } if (reactionGlyph.getBoundingBox().getPosition() == null) { - reactionGlyph.getBoundingBox().setPosition(new Point()); + reactionGlyph.getBoundingBox().setPosition(curveToPoint(reactionGlyph.getCurve())); + reactionGlyph.getBoundingBox().setDimensions(curveToDimension(reactionGlyph.getCurve())); } reactionGlyph.getBoundingBox().getPosition().setZ(reaction.getZ()); removeColinearPoints(reactionGlyph); } + private Dimensions curveToDimension(Curve curve) { + Point p = curveToPoint(curve); + double x = Double.MIN_VALUE; + double y = Double.MIN_VALUE; + for (int i = 0; i < curve.getCurveSegmentCount(); i++) { + LineSegment segment = (LineSegment) curve.getCurveSegment(i); + x = Math.max(x, segment.getStart().getX()); + x = Math.max(x, segment.getEnd().getX()); + + y = Math.max(y, segment.getStart().getY()); + y = Math.max(y, segment.getEnd().getY()); + + } + return new Dimensions(x - p.getX(), y - p.getY(), 0, getSbmlModel().getLevel(), getSbmlModel().getVersion()); + } + + private Point curveToPoint(Curve curve) { + double x = Double.MAX_VALUE; + double y = Double.MAX_VALUE; + for (int i = 0; i < curve.getCurveSegmentCount(); i++) { + LineSegment segment = (LineSegment) curve.getCurveSegment(i); + x = Math.min(x, segment.getStart().getX()); + x = Math.min(x, segment.getEnd().getX()); + + y = Math.min(y, segment.getStart().getY()); + y = Math.min(y, segment.getEnd().getY()); + + } + return new Point(x, y); + } + @Override protected AbstractReferenceGlyph createElementGlyph(String sbmlElementId, String glyphId) { int separatorIndex = glyphId.indexOf("__"); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/AllSbmlConverterTests.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/AllSbmlConverterTests.java index 69a6def9d470176ca912ff0471997393eaf21efd..bfd1a1fb25345e09d433aabbf1e5449b19457457 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/AllSbmlConverterTests.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/AllSbmlConverterTests.java @@ -26,6 +26,7 @@ import lcsb.mapviewer.converter.model.sbml.species.AllSbmlSpeciesTests; SbmlExporterFromCellDesignerTest.class, SbmlPareserForInvalidReactionTest.class, SbmlParserTest.class, + SbmlValidationTests.class, }) public class AllSbmlConverterTests { diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlValidationTests.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlValidationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..171cd9c3bfd8048a478c0efc245912079228149c --- /dev/null +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlValidationTests.java @@ -0,0 +1,79 @@ +package lcsb.mapviewer.converter.model.sbml; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.*; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import lcsb.mapviewer.common.XmlParser; +import lcsb.mapviewer.converter.ConverterParams; +import lcsb.mapviewer.model.map.model.Model; + +@RunWith(Parameterized.class) +public class SbmlValidationTests extends SbmlTestFunctions { + Logger logger = LogManager.getLogger(); + + String filename; + + public SbmlValidationTests(String filename) { + this.filename = filename; + } + + @Parameters(name = "{0}") + public static Collection<Object[]> data() throws IOException { + List<Object[]> result = new ArrayList<>(); + result.add(new Object[] { "testFiles/small/empty.xml" }); + result.add(new Object[] { "testFiles/small/reaction/dissociation.xml" }); + return result; + } + + @Test + public void testIsValidSbml() throws Exception { + SbmlParser parser = new SbmlParser(); + Model model = parser.createModel(new ConverterParams().filename(filename)); + String xml = parser.model2String(model); + + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpPost uploadFile = new HttpPost("http://sbml.org/validator/"); + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + builder.addTextBody("file", xml, ContentType.TEXT_PLAIN); + builder.addBinaryBody( + "file", + new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)), + ContentType.APPLICATION_OCTET_STREAM, + filename); + builder.addTextBody("output", "xml", ContentType.TEXT_PLAIN); + builder.addTextBody("offcheck", "u,r", ContentType.TEXT_PLAIN); + + HttpEntity multipart = builder.build(); + uploadFile.setEntity(multipart); + CloseableHttpResponse response = httpClient.execute(uploadFile); + String responseXml = EntityUtils.toString(response.getEntity()); + Document document = XmlParser.getXmlDocumentFromString(responseXml); + List<Node> problems = XmlParser.getAllNotNecessirellyDirectChild("problem", document); + if (problems.size() > 0) { + logger.debug(responseXml); + } + assertEquals("SBML is invalid", 0, problems.size()); + } + +}