Commit 0e7449a4 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

when reaction line was short (1 segment) and there was need for operator in...

when reaction line was short (1 segment) and there was need for operator in product/reactant side the layout was regenerated
parent 2e142293
......@@ -31,6 +31,7 @@ import org.sbml.jsbml.ext.render.RenderGroup;
import org.w3c.dom.Node;
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.converter.InvalidInputDataExecption;
......@@ -117,8 +118,8 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
Reaction reactionWithLayout = source.copy();
// getId doesn't have to be unique, therefore we concatenate with reaction
reactionWithLayout.setIdReaction(glyph.getReaction() + "__" + glyph.getId());
//z index
// z index
if (glyph.getBoundingBox() != null && glyph.getBoundingBox().getPosition() != null
&& glyph.getBoundingBox().getPosition().isSetZ()) {
reactionWithLayout.setZ((int) glyph.getBoundingBox().getPosition().getZ());
......@@ -281,23 +282,6 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
}
private NodeOperator createOutputOperator(Reaction reactionWithLayout, ReactionGlyph reactionGlyph) {
PolylineData line = new PolylineData();
Curve curve = extractCurve(reactionGlyph, reactionWithLayout);
// 1 is for the process in the center
int min = 1;
if (reactionWithLayout.getReactants().size() > 1) {
// with operator in the output we need to leave something for the operator
min++;
}
for (int i = min; i < curve.getCurveSegmentCount(); i++) {
CurveSegment segment = curve.getCurveSegment(i);
if (line.getPoints().size() == 0) {
line.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
}
line.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
NodeOperator operator;
if (reactionWithLayout instanceof TruncationReaction) {
operator = new TruncationOperator();
......@@ -306,34 +290,14 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
} else {
operator = new SplitOperator();
}
PolylineData line = extractCurve(reactionGlyph, reactionWithLayout, operator.getClass());
operator.addOutputs(reactionWithLayout.getProducts());
operator.setLine(line.reverse());
return operator;
}
private NodeOperator createInputOperator(Reaction reactionWithLayout, ReactionGlyph reactionGlyph) {
PolylineData line = new PolylineData();
Curve curve = extractCurve(reactionGlyph, reactionWithLayout);
// -1 is for the process in the center
int max = curve.getCurveSegmentCount() - 1;
if (reactionWithLayout.getProducts().size() > 1) {
// with operator in the output we need to leave something for the operator
max--;
}
for (int i = 0; i < max; i++) {
CurveSegment segment = curve.getCurveSegment(i);
if (line.getPoints().size() == 0) {
line.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
}
line.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
if (line.getPoints().size() == 0) {
Point2D point = reactionWithLayout.getReactants().get(0).getLine().getEndPoint();
line.addPoint(new Point2D.Double(point.getX(), point.getY()));
line.addPoint(new Point2D.Double(point.getX(), point.getY()));
}
NodeOperator operator;
if (reactionWithLayout instanceof HeterodimerAssociationReaction) {
......@@ -341,6 +305,7 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
} else {
operator = new AndOperator();
}
PolylineData line = extractCurve(reactionGlyph, reactionWithLayout, operator.getClass());
operator.addInputs(reactionWithLayout.getReactants());
operator.setLine(line);
return operator;
......@@ -352,9 +317,14 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
* specification).
*
* @param reactionGlyph
* @param operator
* class of {@link NodeOperator} that requires the line (this line can
* be separated into 3 different segments - reactant, center, product
* parts)
* @return
*/
private Curve extractCurve(ReactionGlyph reactionGlyph, Reaction reaction) {
private PolylineData extractCurve(ReactionGlyph reactionGlyph, Reaction reaction,
Class<? extends NodeOperator> operator) {
Curve curve = reactionGlyph.getCurve();
if (curve == null) {
curve = new Curve(getSbmlModel().getLevel(), getSbmlModel().getVersion());
......@@ -370,7 +340,85 @@ public class SbmlReactionParser extends SbmlBioEntityParser {
+ reactionGlyph.getId() + ")");
}
}
return curve;
if (curve.getCurveSegmentCount() == 0) {
return new PolylineData();
}
int requiredLines = 1;
if (reaction.getReactants().size() > 1) {
requiredLines++;
}
if (reaction.getProducts().size() > 1) {
requiredLines++;
}
int existingLines = curve.getCurveSegmentCount();
int reactantBreak;
int productBreak;
if (requiredLines == 3) {
reactantBreak = (existingLines - 1) / 2;
} else if (requiredLines == 2 && reaction.getReactants().size() > 1) {
reactantBreak = existingLines - 1;
} else if (requiredLines == 2 && reaction.getProducts().size() > 1) {
reactantBreak = 0;
} else {
throw new InvalidArgumentException(
new ElementUtils().getElementTag(reaction) + "Reaction has no products and reactants");
}
productBreak = reactantBreak + 1;
PolylineData result = new PolylineData();
if (operator == TruncationOperator.class ||
operator == DissociationOperator.class ||
operator == SplitOperator.class) {
// Product operator
if (existingLines >= requiredLines) {
CurveSegment segment = curve.getCurveSegment(productBreak);
result.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
for (int i = productBreak; i < curve.getCurveSegmentCount(); i++) {
segment = curve.getCurveSegment(i);
result.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
} else if (existingLines == 1) {
CurveSegment segment = curve.getCurveSegment(0);
double startX = segment.getStart().getX() + (segment.getEnd().getX() - segment.getStart().getX()) * (requiredLines-1) / requiredLines;
double startY = segment.getStart().getY() + (segment.getEnd().getY() - segment.getStart().getY()) * (requiredLines-1) / requiredLines;
result.addPoint(new Point2D.Double(startX, startY));
result.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
} else {
CurveSegment segment = curve.getCurveSegment(1);
result.addPoint(new Point2D.Double(segment.getStart().getX(), segment.getStart().getY()));
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 < reactantBreak; i++) {
segment = curve.getCurveSegment(i);
result.addPoint(new Point2D.Double(segment.getEnd().getX(), segment.getEnd().getY()));
}
} else if (existingLines == 1) {
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()) / requiredLines;
double endY = segment.getStart().getY() + (segment.getEnd().getY() - segment.getStart().getY()) / requiredLines;
result.addPoint(new Point2D.Double(endX, endY));
} 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));
}
} else {
throw new InvalidArgumentException("Unknown operator class: " + operator);
}
return result;
}
private Class<? extends ReactionNode> getReactionNodeClass(SpeciesReferenceGlyph speciesRefernceGlyph) {
......
......@@ -17,11 +17,13 @@ import org.junit.Before;
import org.junit.Test;
import lcsb.mapviewer.commands.CreateHierarchyCommand;
import lcsb.mapviewer.common.Configuration;
import lcsb.mapviewer.common.EventStorageLoggerAppender;
import lcsb.mapviewer.converter.ConverterParams;
import lcsb.mapviewer.converter.InvalidInputDataExecption;
import lcsb.mapviewer.model.map.compartment.Compartment;
import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.reaction.Reactant;
import lcsb.mapviewer.model.map.reaction.Reaction;
import lcsb.mapviewer.model.map.reaction.ReactionNode;
import lcsb.mapviewer.model.map.species.Element;
......@@ -188,12 +190,6 @@ public class SbmlParserTest {
assertEquals(1, model.getCompartments().iterator().next().getMiriamData().size());
}
@Test(expected = InvalidInputDataExecption.class)
public void testInvalidReactionLayout() throws Exception {
parser.createModel(
new ConverterParams().filename("testFiles/invalidReaction/reaction_with_missing_part_of_layout.xml"));
}
@Test
public void testEmpyModel() throws Exception {
Model model = parser.createModel(new ConverterParams().filename("testFiles/small/empty.xml"));
......@@ -259,4 +255,19 @@ public class SbmlParserTest {
assertNotNull("Creation date is not defined", model.getCreationDate());
}
@Test
public void testParseProblematicLayout() throws Exception {
try {
Model model = parser
.createModel(new ConverterParams().filename("testFiles/small/problematic_layout.xml"));
Reaction reaction = model.getReactions().iterator().next();
Reactant reactant = reaction.getReactants().get(0);
assertEquals("Reactant line should start at position 120, 40", 0,
reactant.getLine().getBeginPoint().distance(120, 40), Configuration.EPSILON);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<sbml xmlns="http://www.sbml.org/sbml/level3/version1/core" xmlns:layout="http://www.sbml.org/sbml/level3/version1/layout/version1" level="3" version="1" layout:required="false">
<model substanceUnits="mole" timeUnits="second" extentUnits="mole">
<listOfUnitDefinitions>
<unitDefinition id="per_second">
<listOfUnits>
<unit kind="second" exponent="-1" scale="0" multiplier="1"/>
</listOfUnits>
</unitDefinition>
</listOfUnitDefinitions>
<listOfCompartments>
<compartment id="default" constant="false"/>
</listOfCompartments>
<listOfSpecies>
<species sboTerm="SBO:0000252" id="species_1" name="s2" compartment="default" initialAmount="0" hasOnlySubstanceUnits="true" boundaryCondition="false" constant="false"/>
<species sboTerm="SBO:0000252" id="species_0" name="s1" compartment="default" initialAmount="0" hasOnlySubstanceUnits="true" boundaryCondition="false" constant="false"/>
<species sboTerm="SBO:0000252" id="species_2" name="s3" compartment="default" initialAmount="0" hasOnlySubstanceUnits="true" boundaryCondition="false" constant="false"/>
</listOfSpecies>
<listOfReactions>
<reaction sboTerm="SBO:0000176" id="re3" reversible="false" fast="false">
<listOfReactants>
<speciesReference species="species_1" constant="false"/>
<speciesReference species="species_0" constant="false"/>
</listOfReactants>
<listOfProducts>
<speciesReference species="species_2" constant="false"/>
</listOfProducts>
</reaction>
</listOfReactions>
<layout:listOfLayouts xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:layout="http://www.sbml.org/sbml/level3/version1/layout/version1">
<layout:layout layout:id="predicted_layout">
<layout:dimensions layout:width="564" layout:height="217"/>
<layout:listOfCompartmentGlyphs>
<layout:compartmentGlyph layout:id="cg_default" layout:compartment="default">
<layout:boundingBox layout:id="bb_cg_default">
<layout:position layout:x="0" layout:y="0"/>
<layout:dimensions layout:width="484" layout:height="177"/>
</layout:boundingBox>
</layout:compartmentGlyph>
</layout:listOfCompartmentGlyphs>
<layout:listOfSpeciesGlyphs>
<layout:speciesGlyph layout:id="sg_re3_0_sa2" layout:species="species_1">
<layout:boundingBox layout:id="bb_sg_re3_0_sa2">
<layout:position layout:x="40" layout:y="20"/>
<layout:dimensions layout:width="80" layout:height="40"/>
</layout:boundingBox>
</layout:speciesGlyph>
<layout:speciesGlyph layout:id="sg_re3_0_sa1" layout:species="species_0">
<layout:boundingBox layout:id="bb_sg_re3_0_sa1">
<layout:position layout:x="46" layout:y="117"/>
<layout:dimensions layout:width="80" layout:height="40"/>
</layout:boundingBox>
</layout:speciesGlyph>
<layout:speciesGlyph layout:id="sg_re3_0_sa3" layout:species="species_2">
<layout:boundingBox layout:id="bb_sg_re3_0_sa3">
<layout:position layout:x="364" layout:y="96"/>
<layout:dimensions layout:width="80" layout:height="40"/>
</layout:boundingBox>
</layout:speciesGlyph>
</layout:listOfSpeciesGlyphs>
<layout:listOfReactionGlyphs>
<layout:reactionGlyph layout:id="rg_re3_0" layout:reaction="re3">
<layout:curve>
<layout:listOfCurveSegments>
<layout:curveSegment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LineSegment">
<layout:start layout:x="209.6" layout:y="70.4"/>
<layout:end layout:x="242" layout:y="78"/>
</layout:curveSegment>
</layout:listOfCurveSegments>
</layout:curve>
<layout:listOfSpeciesReferenceGlyphs>
<layout:speciesReferenceGlyph layout:id="srg_re3_0_sa2_SUBSTRATE_1" layout:speciesGlyph="sg_re3_0_sa2">
<layout:curve>
<layout:listOfCurveSegments>
<layout:curveSegment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LineSegment">
<layout:start layout:x="209.6" layout:y="70.4"/>
<layout:end layout:x="120" layout:y="40"/>
</layout:curveSegment>
</layout:listOfCurveSegments>
</layout:curve>
</layout:speciesReferenceGlyph>
<layout:speciesReferenceGlyph layout:id="srg_re3_0_sa1_SIDESUBSTRATE_1" layout:speciesGlyph="sg_re3_0_sa1">
<layout:curve>
<layout:listOfCurveSegments>
<layout:curveSegment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LineSegment">
<layout:start layout:x="209.6" layout:y="70.4"/>
<layout:end layout:x="126" layout:y="137"/>
</layout:curveSegment>
</layout:listOfCurveSegments>
</layout:curve>
</layout:speciesReferenceGlyph>
<layout:speciesReferenceGlyph layout:id="srg_re3_0_sa3_PRODUCT_1" layout:speciesGlyph="sg_re3_0_sa3">
<layout:curve>
<layout:listOfCurveSegments>
<layout:curveSegment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="LineSegment">
<layout:start layout:x="242" layout:y="78"/>
<layout:end layout:x="364" layout:y="116"/>
</layout:curveSegment>
</layout:listOfCurveSegments>
</layout:curve>
</layout:speciesReferenceGlyph>
</layout:listOfSpeciesReferenceGlyphs>
</layout:reactionGlyph>
</layout:listOfReactionGlyphs>
<layout:listOfTextGlyphs>
<layout:textGlyph layout:id="tg_re3_0_sa2" layout:originOfText="sg_re3_0_sa2" layout:graphicalObject="sg_re3_0_sa2">
<layout:boundingBox layout:id="bb_tg_re3_0_sa2">
<layout:position layout:x="40" layout:y="20"/>
<layout:dimensions layout:width="80" layout:height="40"/>
</layout:boundingBox>
</layout:textGlyph>
<layout:textGlyph layout:id="tg_re3_0_sa1" layout:originOfText="sg_re3_0_sa1" layout:graphicalObject="sg_re3_0_sa1">
<layout:boundingBox layout:id="bb_tg_re3_0_sa1">
<layout:position layout:x="46" layout:y="117"/>
<layout:dimensions layout:width="80" layout:height="40"/>
</layout:boundingBox>
</layout:textGlyph>
<layout:textGlyph layout:id="tg_re3_0_sa3" layout:originOfText="sg_re3_0_sa3" layout:graphicalObject="sg_re3_0_sa3">
<layout:boundingBox layout:id="bb_tg_re3_0_sa3">
<layout:position layout:x="364" layout:y="96"/>
<layout:dimensions layout:width="80" layout:height="40"/>
</layout:boundingBox>
</layout:textGlyph>
</layout:listOfTextGlyphs>
</layout:layout>
</layout:listOfLayouts>
</model>
</sbml>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment