Commit 6068057b authored by Piotr Gawron's avatar Piotr Gawron
Browse files

central line is exported/imported in sbml

parent 8682a18e
......@@ -10,7 +10,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.sbml.jsbml.ASTNode;
import org.sbml.jsbml.KineticLaw;
import org.sbml.jsbml.LocalParameter;
......@@ -199,8 +200,6 @@ public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sb
boolean firstReactant = true;
reactionGlyph.setCurve(new Curve());
Point2D reactantEndPoint = null;
Point2D productStartPoint = null;
for (Reactant reactant : reaction.getReactants()) {
SpeciesReferenceGlyph reactantGlyph = createNodeGlyph(reactionGlyph, reactant);
if (firstReactant) {
......@@ -221,24 +220,12 @@ public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sb
assignStyleToGlyph(reactantGlyph, style);
}
if (reactantGlyph.getCurve().getCurveSegmentCount() > 0) {
Point p = reactantGlyph.getCurve().getCurveSegment(0).getStart();
reactantEndPoint = new Point2D.Double(p.getX(), p.getY());
} else {
reactantEndPoint = new Point2D.Double(reactant.getElement().getCenterX(), reactant.getElement().getCenterY());
}
}
if (reactionGlyph.getCurve().getCurveSegmentCount() > 0) {
Point p = reactionGlyph.getCurve().getCurveSegment(reactionGlyph.getCurve().getCurveSegmentCount() - 1).getEnd();
reactantEndPoint = new Point2D.Double(p.getX(), p.getY());
Curve curve = createCurve(reaction.getLine(), false);
for (int i = 0; i < curve.getCurveSegmentCount(); i++) {
reactionGlyph.getCurve().addCurveSegment(new LineSegment(curve.getCurveSegment(i)));
}
LineSegment segment = new LineSegment();
segment.setStart(new Point(reactantEndPoint.getX(), reactantEndPoint.getY()));
segment.setEnd(new Point(reactantEndPoint.getX(), reactantEndPoint.getY()));
reactionGlyph.getCurve().addCurveSegment(segment);
int segmentCount = reactionGlyph.getCurve().getCurveSegmentCount();
boolean firstProduct = true;
for (Product product : reaction.getProducts()) {
......@@ -263,20 +250,7 @@ public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sb
assignStyleToGlyph(productGlyph, style);
}
if (productGlyph.getCurve().getCurveSegmentCount() > 0) {
Point p = productGlyph.getCurve().getCurveSegment(0).getStart();
productStartPoint = new Point2D.Double(p.getX(), p.getY());
} else {
productStartPoint = new Point2D.Double(product.getElement().getCenterX(), product.getElement().getCenterY());
}
}
if (segmentCount < reactionGlyph.getCurve().getCurveSegmentCount()) {
// there was product operator
Point p = reactionGlyph.getCurve().getCurveSegment(segmentCount).getStart();
productStartPoint = new Point2D.Double(p.getX(), p.getY());
}
segment.setEnd(new Point(productStartPoint.getX(), productStartPoint.getY()));
for (Modifier modifier : reaction.getModifiers()) {
SpeciesReferenceGlyph modifierGlyph = createNodeGlyph(reactionGlyph, modifier);
......
......@@ -11,7 +11,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.logging.log4j.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.sbml.jsbml.KineticLaw;
import org.sbml.jsbml.ListOf;
import org.sbml.jsbml.LocalParameter;
......@@ -30,11 +31,14 @@ import org.sbml.jsbml.ext.render.LocalStyle;
import org.sbml.jsbml.ext.render.RenderGroup;
import org.w3c.dom.Node;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.common.XmlParser;
import lcsb.mapviewer.common.exception.InvalidArgumentException;
import lcsb.mapviewer.common.exception.InvalidStateException;
import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
import lcsb.mapviewer.common.geometry.PointTransformation;
import lcsb.mapviewer.converter.InvalidInputDataExecption;
import lcsb.mapviewer.converter.model.celldesigner.geometry.ReactionCellDesignerConverter;
import lcsb.mapviewer.converter.model.celldesigner.types.ModifierType;
import lcsb.mapviewer.converter.model.sbml.SbmlBioEntityParser;
import lcsb.mapviewer.converter.model.sbml.SbmlParameterParser;
......@@ -70,12 +74,14 @@ import lcsb.mapviewer.model.map.species.Species;
import lcsb.mapviewer.modelutils.map.ElementUtils;
public class SbmlReactionParser extends SbmlBioEntityParser {
Logger logger = LogManager.getLogger(SbmlReactionParser.class);
private static Logger logger = LogManager.getLogger(SbmlReactionParser.class);
ElementUtils eu = new ElementUtils();
private ElementUtils eu = new ElementUtils();
SbmlSpeciesParser speciesParser;
SbmlCompartmentParser compartmentParser;
private SbmlSpeciesParser speciesParser;
private SbmlCompartmentParser compartmentParser;
private PointTransformation pt = new PointTransformation();
public SbmlReactionParser(Model sbmlModel, lcsb.mapviewer.model.map.model.Model minervaModel,
SbmlSpeciesParser speciesParser, SbmlCompartmentParser compartmentParser) {
......@@ -205,6 +211,7 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
}
}
}
if (reactionWithLayout.getReactants().size() > 1 && reactionWithLayout.getProducts().size() > 0) {
NodeOperator operator = createInputOperator(reactionWithLayout, glyph);
reactionWithLayout.addNode(operator);
......@@ -222,7 +229,11 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
}
}
reactionWithLayout.setLine(extractCurve(glyph, reactionWithLayout, null));
createCenterLineForReaction(reactionWithLayout);
getMinervaModel().addReaction(reactionWithLayout);
} catch (Exception e) {
throw new InvalidInputDataExecption(
new ElementUtils().getElementTag(source) + "Problem with parsing reaction layout", e);
......@@ -245,6 +256,42 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
}
}
/**
* Creates center line for assembled reaction with operators.
*
* @param reaction
*/
private void createCenterLineForReaction(Reaction reaction) {
if (reaction.getLine().length() == 0) {
AbstractNode startNode = reaction.getReactants().get(0);
AbstractNode endNode = reaction.getProducts().get(0);
for (NodeOperator operator : reaction.getOperators()) {
if (operator.isReactantOperator()) {
startNode = operator;
}
}
for (NodeOperator operator : reaction.getOperators()) {
if (operator.isProductOperator()) {
endNode = operator;
}
}
PolylineData line = new PolylineData();
reaction.setLine(line);
// if there is no layout don't create center line
if (startNode.getLine() != null && startNode.getLine().length() > Configuration.EPSILON &&
endNode.getLine() != null && endNode.getLine().length() > Configuration.EPSILON) {
startNode.getLine().trimEnd(ReactionCellDesignerConverter.RECT_SIZE);
endNode.getLine().trimBegin(ReactionCellDesignerConverter.RECT_SIZE);
line.addPoint(pt.copyPoint(startNode.getLine().getEndPoint()));
line.addPoint(pt.copyPoint(endNode.getLine().getBeginPoint()));
}
}
}
private void assignRenderDataToReactionNode(SpeciesReferenceGlyph glyph, ReactionNode modifier, boolean reverse)
throws InvalidInputDataExecption {
LocalStyle style = getStyleForGlyph(glyph);
......@@ -316,9 +363,15 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
}
/**
* Returns {@link Curve} associated to {@link ReactionGlyph}. If curve doesn't
* Extracts {@link Curve} associated to {@link ReactionGlyph}. If curve doesn't
* exist then method will try to create it from {@link BoundingBox} (due to SBML
* specification).
* specification). This {@link Curve} is split into parts belonging to:
* <ul>
* <li>input operator</li>
* <li>center line</li>
* <li>output operator</li>
* </ul>
* . {@link PolylineData} corresponding to the proper part is returned.
*
* @param reactionGlyph
* @param operator
......@@ -327,28 +380,19 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
* parts)
* @return
*/
private PolylineData extractCurve(ReactionGlyph reactionGlyph, Reaction reaction,
PolylineData extractCurve(ReactionGlyph reactionGlyph, Reaction reaction,
Class<? extends NodeOperator> operator) {
Curve curve = reactionGlyph.getCurve();
Curve curve = getCurve(reactionGlyph);
if (curve == null) {
curve = new Curve(getSbmlModel().getLevel(), getSbmlModel().getVersion());
BoundingBox box = reactionGlyph.getBoundingBox();
if (box != null && box.getDimensions() != null && box.getPosition() != null) {
LineSegment curveSegment = new LineSegment(getSbmlModel().getLevel(), getSbmlModel().getVersion());
curveSegment.setStart(new Point(box.getPosition()));
curveSegment.setEnd(new Point(box.getPosition().getX() + box.getDimensions().getWidth(),
box.getPosition().getY() + box.getDimensions().getHeight()));
curve.addCurveSegment(curveSegment);
} else {
logger.warn(new ElementUtils().getElementTag(reaction) + " invalid curve line for reaction (node: "
+ reactionGlyph.getId() + ")");
}
logger.warn(new ElementUtils().getElementTag(reaction) + " invalid curve line for reaction (node: "
+ reactionGlyph.getId() + ")");
}
if (curve.getCurveSegmentCount() == 0) {
return new PolylineData();
}
int requiredLines = 0;
int requiredLines = 1;
if (reaction.getReactants().size() > 1) {
requiredLines++;
}
......@@ -357,13 +401,70 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
}
int existingLines = curve.getCurveSegmentCount();
int breakPoint;
if (requiredLines == 2) {
breakPoint = existingLines / 2;
if (requiredLines == 3 && existingLines == 1) {
CurveSegment segment = curve.getCurveSegment(0);
Point secondPoint = getPointOnSegment(segment, 0.4);
Point thirdPoint = getPointOnSegment(segment, 0.6);
LineSegment curveSegment = new LineSegment(getSbmlModel().getLevel(), getSbmlModel().getVersion());
curveSegment.setStart(secondPoint);
curveSegment.setEnd(thirdPoint);
curve.addCurveSegment(curveSegment);
curveSegment = new LineSegment(getSbmlModel().getLevel(), getSbmlModel().getVersion());
curveSegment.setStart(thirdPoint);
curveSegment.setEnd(segment.getEnd());
curve.addCurveSegment(curveSegment);
segment.setEnd(secondPoint);
} else if (requiredLines == 3 && existingLines == 2) {
if (getSegmentLength(curve.getCurveSegment(0)) > getSegmentLength(curve.getCurveSegment(1))) {
CurveSegment segment = curve.getCurveSegment(0);
Point centerPoint = getCenter(segment);
LineSegment curveSegment = new LineSegment(getSbmlModel().getLevel(), getSbmlModel().getVersion());
curveSegment.setStart(centerPoint);
curveSegment.setEnd(segment.getEnd());
curve.addCurveSegment(1, curveSegment);
segment.setEnd(centerPoint);
} else {
CurveSegment segment = curve.getCurveSegment(1);
Point centerPoint = getCenter(segment);
LineSegment curveSegment = new LineSegment(getSbmlModel().getLevel(), getSbmlModel().getVersion());
curveSegment.setStart(centerPoint);
curveSegment.setEnd(segment.getEnd());
curve.addCurveSegment(curveSegment);
segment.setEnd(centerPoint);
}
} else if (requiredLines == 2 && existingLines == 1) {
CurveSegment segment = curve.getCurveSegment(0);
Point centerPoint = getCenter(segment);
LineSegment curveSegment = new LineSegment(getSbmlModel().getLevel(), getSbmlModel().getVersion());
curveSegment.setStart(centerPoint);
curveSegment.setEnd(segment.getEnd());
curve.addCurveSegment(curveSegment);
segment.setEnd(centerPoint);
}
existingLines = curve.getCurveSegmentCount();
Integer reactantLineEnds;
Integer productLineStarts;
if (requiredLines == 3) {
reactantLineEnds = existingLines / 2;
productLineStarts = reactantLineEnds + 1;
} else if (reaction.getReactants().size() > 1) {
breakPoint = existingLines;
reactantLineEnds = existingLines - 1;
productLineStarts = reactantLineEnds + 1;
} else if (reaction.getProducts().size() > 1) {
breakPoint = 0;
reactantLineEnds = 0;
productLineStarts = reactantLineEnds + 1;
} else if (requiredLines == 1) {
reactantLineEnds = 0;
productLineStarts = existingLines;
} else {
throw new InvalidArgumentException(
new ElementUtils().getElementTag(reaction) + "Reaction has no products and reactants");
......@@ -375,37 +476,27 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
operator == SplitOperator.class) {
// Product operator
if (existingLines >= requiredLines) {
CurveSegment segment = curve.getCurveSegment(breakPoint);
result.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
for (int i = breakPoint; i < curve.getCurveSegmentCount(); i++) {
segment = curve.getCurveSegment(i);
result.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
} else {
CurveSegment segment = curve.getCurveSegment(0);
double startX = segment.getStart().getX() + (segment.getEnd().getX() - segment.getStart().getX()) / 2;
double startY = segment.getStart().getY() + (segment.getEnd().getY() - segment.getStart().getY()) / 2;
result.addPoint(new Point2D.Double(startX, startY));
CurveSegment segment = curve.getCurveSegment(productLineStarts);
result.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
for (int i = productLineStarts; i < curve.getCurveSegmentCount(); i++) {
segment = curve.getCurveSegment(i);
result.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
} else if (operator == AssociationOperator.class || operator == AndOperator.class) {
// Reactant operator
if (existingLines >= requiredLines) {
CurveSegment segment = curve.getCurveSegment(0);
result.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
for (int i = 0; i < breakPoint; i++) {
segment = curve.getCurveSegment(i);
result.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
} else {
CurveSegment segment = curve.getCurveSegment(0);
result.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
double endX = segment.getStart().getX() + (segment.getEnd().getX() - segment.getStart().getX()) / 2;
double endY = segment.getStart().getY() + (segment.getEnd().getY() - segment.getStart().getY()) / 2;
result.addPoint(new Point2D.Double(endX, endY));
CurveSegment segment = curve.getCurveSegment(0);
result.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
for (int i = 0; i < reactantLineEnds; i++) {
segment = curve.getCurveSegment(i);
result.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
} else if (operator == null) {
// Center line
CurveSegment segment = curve.getCurveSegment(reactantLineEnds);
result.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
for (int i = reactantLineEnds; i < productLineStarts; i++) {
segment = curve.getCurveSegment(i);
result.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
} else {
throw new InvalidArgumentException("Unknown operator class: " + operator);
......@@ -413,6 +504,43 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
return result;
}
private double getSegmentLength(CurveSegment curveSegment) {
double dx = curveSegment.getStart().getX() - curveSegment.getEnd().getX();
double dy = curveSegment.getStart().getY() - curveSegment.getEnd().getY();
return Math.sqrt(dx * dx + dy * dy);
}
private Point getCenter(CurveSegment segment) {
return getPointOnSegment(segment, 0.5);
}
private Point getPointOnSegment(CurveSegment segment, double coef) {
double centerX = (segment.getStart().getX() + segment.getEnd().getX()) * coef;
double centerY = (segment.getStart().getY() + segment.getEnd().getY()) * coef;
Point centerPoint = new Point(getSbmlModel().getLevel(), getSbmlModel().getVersion());
centerPoint.setX(centerX);
centerPoint.setY(centerY);
return centerPoint;
}
private Curve getCurve(ReactionGlyph reactionGlyph) {
Curve curve = reactionGlyph.getCurve();
if (curve == null) {
BoundingBox box = reactionGlyph.getBoundingBox();
if (box != null && box.getDimensions() != null && box.getPosition() != null) {
curve = new Curve(getSbmlModel().getLevel(), getSbmlModel().getVersion());
LineSegment curveSegment = new LineSegment(getSbmlModel().getLevel(), getSbmlModel().getVersion());
curveSegment.setStart(new Point(box.getPosition()));
curveSegment.setEnd(new Point(box.getPosition().getX() + box.getDimensions().getWidth(),
box.getPosition().getY() + box.getDimensions().getHeight()));
curve.addCurveSegment(curveSegment);
} else {
curve = null;
}
}
return curve;
}
private Class<? extends ReactionNode> getReactionNodeClass(SpeciesReferenceGlyph speciesRefernceGlyph) {
Class<? extends ReactionNode> nodeClass = null;
if (speciesRefernceGlyph.getRole() != null) {
......
......@@ -14,7 +14,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.apache.logging.log4j.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Test;
import org.reflections.Reflections;
import org.sbml.jsbml.SBMLDocument;
......@@ -34,6 +35,8 @@ import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.model.ModelComparator;
import lcsb.mapviewer.model.map.model.ModelFullIndexed;
import lcsb.mapviewer.model.map.reaction.AbstractNode;
import lcsb.mapviewer.model.map.reaction.NodeOperator;
import lcsb.mapviewer.model.map.reaction.Product;
import lcsb.mapviewer.model.map.reaction.Reaction;
import lcsb.mapviewer.model.map.reaction.ReactionNode;
import lcsb.mapviewer.model.map.species.Element;
......@@ -570,10 +573,14 @@ public class SbmlExporterTest extends SbmlTestFunctions {
Model model = getModelAfterSerializing(originalModel);
Reaction r1 = originalModel.getReactions().iterator().next();
Reaction r2 = model.getReactions().iterator().next();
Line2D line1 = r1.getCenterLine();
Line2D line2 = r2.getCenterLine();
Product p1 = r1.getProducts().get(0);
Product p2 = r1.getProducts().get(0);
NodeOperator o1 = r1.getOperators().get(0);
NodeOperator o11 = r1.getOperators().get(1);
NodeOperator o2 = r2.getOperators().get(0);
assertEquals(0, new LineComparator().compare(line1, line2));
assertEquals(p1.getLine().length()+o1.getLine().length()+o11.getLine().length()+r1.getLine().length(),
p2.getLine().length()+o2.getLine().length()+r2.getLine().length(), Configuration.EPSILON);
}
......
......@@ -32,8 +32,8 @@ import lcsb.mapviewer.model.map.species.GenericProtein;
public class SbmlTestFunctions {
@SuppressWarnings("unused")
private Logger logger = Logger.getLogger(SbmlTestFunctions .class);
private Logger logger = Logger.getLogger(SbmlTestFunctions.class);
private MinervaLoggerAppender appender;
private static int identifierCounter = 0;
......@@ -94,33 +94,39 @@ public class SbmlTestFunctions {
Reaction reaction = new StateTransitionReaction("r" + (identifierCounter++));
Reactant reactant = new Reactant(p1);
Product product = new Product(p2);
Point2D center = new Point2D.Double((p1.getCenter().getX()+p2.getCenter().getX())/2, (p1.getCenter().getY()+p2.getCenter().getY())/2);
Point2D centerLineStart = new Point2D.Double((p1.getCenter().getX() + p2.getCenter().getX()) / 3,
(p1.getCenter().getY() + p2.getCenter().getY()) / 3);
Point2D centerLineEnd = new Point2D.Double(2 * (p1.getCenter().getX() + p2.getCenter().getX()) / 3,
2 * (p1.getCenter().getY() + p2.getCenter().getY()) / 3);
PolylineData reactantLine = new PolylineData();
reactantLine.addPoint(p1.getCenter());
reactantLine.addPoint(center);
reactantLine.addPoint(centerLineStart);
reactant.setLine(reactantLine);
PolylineData productLine = new PolylineData();
productLine.addPoint(center);
productLine.addPoint(centerLineEnd);
productLine.addPoint(p2.getCenter());
product.setLine(productLine);
reaction.addReactant(reactant);
reaction.addProduct(product);
reaction.setZ(125);
PolylineData centerLine = new PolylineData(centerLineStart, centerLineEnd);
reaction.setLine(centerLine);
return reaction;
}
protected Model getModelAfterSerializing(Model originalModel) throws Exception {
String xml = exporter.toXml(originalModel);
// logger.debug(xml);
// logger.debug(xml);
ByteArrayInputStream stream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
Model result = parser.createModel(new ConverterParams().inputStream(stream));
// showImage(originalModel);
// showImage(result);
return result;
}
protected Model getModelAfterCellDEsignerSerializing(Model model) throws Exception {
CellDesignerXmlParser parser = new CellDesignerXmlParser();
String xmlString = parser.model2String(model);
......@@ -136,7 +142,4 @@ public class SbmlTestFunctions {
return model2;
}
}
......@@ -7,7 +7,8 @@ import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ SbmlReactionExportArrowType.class,
SbmlReactionExporterTest.class,
SbmlReactionParserTest.class
SbmlReactionParserTest.class,
SbmlReactionParserExtractCurveTest.class
})
public class AllSbmlReactionParserTests {
......
......@@ -110,6 +110,7 @@ public class SbmlReactionExportArrowType {
} else {
throw new NotImplementedException();
}
reaction.setLine(new PolylineData(new Point2D.Double(10, 40), new Point2D.Double(10, 60)));
model.addReaction(reaction);
CellDesignerXmlParser cellDesignerXmlParser = new CellDesignerXmlParser();
......
package lcsb.mapviewer.converter.model.sbml.reaction;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
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.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.sbml.jsbml.Model;
import org.sbml.jsbml.ext.layout.Curve;
import org.sbml.jsbml.ext.layout.LineSegment;
import org.sbml.jsbml.ext.layout.Point;
import org.sbml.jsbml.ext.layout.ReactionGlyph;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.converter.model.sbml.SbmlTestFunctions;