-package fr.orsay.lri.varna.models.templates;
-
-import java.awt.Point;
-import java.awt.geom.Point2D;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.Stack;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import fr.orsay.lri.varna.exceptions.ExceptionEdgeEndpointAlreadyConnected;
-import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;
-import fr.orsay.lri.varna.exceptions.ExceptionInvalidRNATemplate;
-import fr.orsay.lri.varna.exceptions.ExceptionXMLGeneration;
-import fr.orsay.lri.varna.exceptions.ExceptionXmlLoading;
-import fr.orsay.lri.varna.models.rna.RNA;
-import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateElement.EdgeEndPoint;
-import fr.orsay.lri.varna.models.treealign.Tree;
-
-
-/**
- * A model for RNA templates.
- * A template is a way to display an RNA secondary structure.
- *
- * @author Raphael Champeimont
- */
-public class RNATemplate {
- /**
- * The list of template elements.
- */
- private Collection<RNATemplateElement> elements = new ArrayList<RNATemplateElement>();
-
- /**
- * Tells whether the template contains elements.
- */
- public boolean isEmpty() {
- return elements.isEmpty();
- }
-
- /**
- * The first endpoint (in sequence order) of the template.
- * If there are multiple connected components, the first elements of one
- * connected component will be returned.
- * If the template contains no elements, null is returned.
- * If there is a cycle, an arbitrary endpoint will be returned
- * (as it then does not make sense to define the first endpoint).
- * Time: O(n)
- */
- public RNATemplateElement getFirst() {
- return getFirstEndPoint().getElement();
- }
-
- /**
- * The first endpoint edge endpoint (in sequence order) of the template.
- * If there are multiple connected components, the first elements of one
- * connected component will be returned.
- * If the template contains no elements, null is returned.
- * If there is a cycle, an arbitrary endpoint will be returned
- * (as it then does not make sense to define the first endpoint).
- * Time: O(n)
- */
- public EdgeEndPoint getFirstEndPoint() {
- if (elements.isEmpty()) {
- return null;
- } else {
- Set<EdgeEndPoint> knownEndPoints = new HashSet<EdgeEndPoint>();
- EdgeEndPoint currentEndPoint = getAnyEndPoint();
- while (true) {
- if (knownEndPoints.contains(currentEndPoint)) {
- // There is a cycle in the template, so we stop there
- // to avoid looping infinitely.
- return currentEndPoint;
- }
- knownEndPoints.add(currentEndPoint);
- EdgeEndPoint previousEndPoint = currentEndPoint.getPreviousEndPoint();
- if (previousEndPoint == null) {
- return currentEndPoint;
- } else {
- currentEndPoint = previousEndPoint;
- }
- }
- }
- }
-
- /**
- * Return an arbitrary element of the template,
- * null if empty.
- * Time: O(1)
- */
- public RNATemplateElement getAny() {
- if (elements.isEmpty()) {
- return null;
- } else {
- return elements.iterator().next();
- }
- }
-
- /**
- * Return an arbitrary endpoint of the template,
- * null if empty.
- * Time: O(1)
- */
- public EdgeEndPoint getAnyEndPoint() {
- if (isEmpty()) {
- return null;
- } else {
- return getAny().getIn1EndPoint();
- }
- }
-
- /**
- * Variable containing "this", used by the internal class
- * to access this object.
- */
- private final RNATemplate template = this;
-
-
- /**
- * To get an iterator of this class, use rnaIterator().
- * See rnaIterator() for documentation.
- */
- private class RNAIterator implements Iterator<RNATemplateElement> {
- private Iterator<EdgeEndPoint> iter = vertexIterator();
-
- public boolean hasNext() {
- return iter.hasNext();
- }
-
- public RNATemplateElement next() {
- if (! hasNext()) {
- throw (new NoSuchElementException());
- }
-
- EdgeEndPoint currentEndPoint = iter.next();
- switch (currentEndPoint.getPosition()) {
- // We skip "IN" endpoints, so that we don't return elements twice
- case IN1:
- case IN2:
- // We get the corresponding "OUT" endpoint
- currentEndPoint = iter.next();
- break;
- }
-
- return currentEndPoint.getElement();
- }
-
- public void remove() {
- throw (new UnsupportedOperationException());
- }
-
- }
-
- /**
- * Iterates over the elements of the template, in the sequence order.
- * Helixes will be given twice.
- * Only one connected component will be iterated on.
- * Note that if there is a cycle, the iterator may return a infinite
- * number of elements.
- */
- public Iterator<RNATemplateElement> rnaIterator() {
- return new RNAIterator();
- }
-
- /**
- * Iterates over all elements (each endpoint is given only once)
- * in an arbitrary order.
- */
- public Iterator<RNATemplateElement> classicIterator() {
- return elements.iterator();
- }
-
- private class VertexIterator implements Iterator<EdgeEndPoint> {
- private EdgeEndPoint endpoint = getFirstEndPoint();
-
- public boolean hasNext() {
- return (endpoint != null);
- }
-
- public EdgeEndPoint next() {
- if (endpoint == null) {
- throw (new NoSuchElementException());
- }
-
- EdgeEndPoint currentEndPoint = endpoint;
- endpoint = currentEndPoint.getNextEndPoint();
- return currentEndPoint;
- }
-
- public void remove() {
- throw (new UnsupportedOperationException());
- }
- }
-
- /**
- * Iterates over the elements edge endpoints of the template,
- * in the sequence order.
- * Only one connected component will be iterated on.
- * Note that if there is a cycle, the iterator may return a infinite
- * number of elements.
- */
- public Iterator<EdgeEndPoint> vertexIterator() {
- return new VertexIterator();
- }
-
-
-
- private class MakeEdgeList {
- List<EdgeEndPoint> list = new LinkedList<EdgeEndPoint>();
-
- private void addEdgeIfNecessary(EdgeEndPoint endPoint) {
- if (endPoint.isConnected()) {
- list.add(endPoint);
- }
- }
-
- public List<EdgeEndPoint> make() {
- for (RNATemplateElement element: elements) {
- if (element instanceof RNATemplateHelix) {
- RNATemplateHelix helix = (RNATemplateHelix) element;
- addEdgeIfNecessary(helix.getIn1());
- addEdgeIfNecessary(helix.getIn2());
- } else if (element instanceof RNATemplateUnpairedSequence) {
- RNATemplateUnpairedSequence sequence = (RNATemplateUnpairedSequence) element;
- addEdgeIfNecessary(sequence.getIn());
- }
- }
- return list;
- }
- }
-
- /**
- * Return over all edges in an arbitrary order.
- * For each edge, the first (5' side) endpoint will be given.
- */
- public List<EdgeEndPoint> makeEdgeList() {
- MakeEdgeList listMaker = new MakeEdgeList();
- return listMaker.make();
- }
-
-
-
-
-
- private class RemovePseudoKnots {
- /**
- * The elements of the template as an array, in the order of the
- * RNA sequence. Note that helixes will appear twice,
- * and non-paired sequences don't appear.
- */
- private ArrayList<RNATemplateHelix> helixesSeq;
-
- /**
- * For any i,
- * j = helixesStruct[i] is the index in helixesSeq
- * where the same helix also appears.
- * It means we have for all i:
- * helixesSeq[helixesStruct[i]] == helixesSeq[i]
- */
- private ArrayList<Integer> helixesStruct;
-
- /**
- * The same as helixesStruct, but without the pseudoknots,
- * ie. helixesStructWithoutPseudoKnots[i] may be -1
- * even though helixesStruct[i] != -1 .
- */
- private int[] helixesStructWithoutPseudoKnots;
-
-
- private void initArrays() throws ExceptionInvalidRNATemplate {
- helixesSeq = new ArrayList<RNATemplateHelix>();
- helixesStruct = new ArrayList<Integer>();
- Map<RNATemplateHelix,Integer> knownHelixes = new Hashtable<RNATemplateHelix,Integer>();
- Iterator<RNATemplateElement> iter = rnaIterator();
- while (iter.hasNext()) {
- RNATemplateElement element = iter.next();
- if (element instanceof RNATemplateHelix) {
- helixesSeq.add((RNATemplateHelix) element);
- int index = helixesSeq.size() - 1;
- if (knownHelixes.containsKey(element)) {
- // This is the second time we meet this helix.
- int otherOccurenceIndex = knownHelixes.get(element);
- helixesStruct.add(otherOccurenceIndex);
- if (helixesStruct.get(otherOccurenceIndex) != -1) {
- throw (new ExceptionInvalidRNATemplate("We met an helix 3 times. Is there a cycle?"));
- }
- // Now we know the partner of the other part of
- // the helix.
- helixesStruct.set(otherOccurenceIndex, index);
- } else {
- // This is the first time we meet this helix.
- // Remember its index
- knownHelixes.put((RNATemplateHelix) element, index);
- // For the moment we don't know where the other part
- // of the helix is, but this will be found later.
- helixesStruct.add(-1);
- }
- }
- }
-
- }
-
- /**
- * Tells whether there is a pseudoknot.
- * Adapted from RNAMLParser.isSelfCrossing()
- */
- private boolean isSelfCrossing() {
- Stack<Point> intervals = new Stack<Point>();
- intervals.add(new Point(0, helixesStruct.size() - 1));
- while (!intervals.empty()) {
- Point p = intervals.pop();
- if (p.x <= p.y) {
- if (helixesStruct.get(p.x) == -1) {
- intervals.push(new Point(p.x + 1, p.y));
- } else {
- int i = p.x;
- int j = p.y;
- int k = helixesStruct.get(i);
- if ((k <= i) || (k > j)) {
- return true;
- } else {
- intervals.push(new Point(i + 1, k - 1));
- intervals.push(new Point(k + 1, j));
- }
- }
- }
- }
- return false;
- }
-
- /**
- * We compute helixesStructWithoutPseudoKnots
- * from helixesStruct by replacing values by -1
- * for the helixes we cut (the bases are become non-paired).
- * We try to cut as few base pairs as possible.
- */
- private void removePseudoKnotsAux() {
- if (!isSelfCrossing()) {
- helixesStructWithoutPseudoKnots = new int[helixesStruct.size()];
- for (int i=0; i<helixesStructWithoutPseudoKnots.length; i++) {
- helixesStructWithoutPseudoKnots[i] = helixesStruct.get(i);
- }
- } else {
-
- // We need to get rid of pseudoknots
- // This code was adapted from RNAMLParser.planarize()
- int length = helixesStruct.size();
-
- int[] result = new int[length];
- for (int i = 0; i < result.length; i++) {
- result[i] = -1;
- }
-
- short[][] tab = new short[length][length];
- short[][] backtrack = new short[length][length];
-
- // On the diagonal we have intervals containing only
- // one endpoint. Therefore there can be no helix
- // (because an helix consists of 2 elements).
- for (int i = 0; i < result.length; i++) {
- // tab[i][j] = 0;
- backtrack[i][i] = -1;
- }
-
- for (int n = 1; n < length; n++) {
- for (int i = 0; i < length - n; i++) {
- int j = i + n;
- tab[i][j] = tab[i + 1][j];
- backtrack[i][j] = -1;
- int k = helixesStruct.get(i);
- assert k != -1;
- if ((k <= j) && (i < k)) {
- int tmp = helixesSeq.get(i).getLength();
- if (i + 1 <= k - 1) {
- tmp += tab[i + 1][k - 1];
- }
- if (k + 1 <= j) {
- tmp += tab[k + 1][j];
- }
- if (tmp > tab[i][j]) {
- tab[i][j] = (short) tmp;
- backtrack[i][j] = (short) k;
- }
- }
- }
- }
-
- // debug
- //RNATemplateTests.printShortMatrix(tab);
-
- Stack<Point> intervals = new Stack<Point>();
- intervals.add(new Point(0, length - 1));
- while (!intervals.empty()) {
- Point p = intervals.pop();
- if (p.x <= p.y) {
- if (backtrack[p.x][p.y] == -1) {
- result[p.x] = -1;
- intervals.push(new Point(p.x + 1, p.y));
- } else {
- int i = p.x;
- int j = p.y;
- int k = backtrack[i][j];
- result[i] = k;
- result[k] = i;
- intervals.push(new Point(i + 1, k - 1));
- intervals.push(new Point(k + 1, j));
- }
- }
- }
-
- helixesStructWithoutPseudoKnots = result;
- }
- }
-
- private Set<RNATemplateHelix> makeSet() {
- Set<RNATemplateHelix> removedHelixes = new HashSet<RNATemplateHelix>();
-
- for (int i=0; i<helixesStructWithoutPseudoKnots.length; i++) {
- if (helixesStructWithoutPseudoKnots[i] < 0) {
- removedHelixes.add(helixesSeq.get(i));
- }
- }
-
- return removedHelixes;
- }
-
- public Set<RNATemplateHelix> removePseudoKnots() throws ExceptionInvalidRNATemplate {
- initArrays();
-
- removePseudoKnotsAux();
- // debug
- //printIntArrayList(helixesStruct);
- //printIntArray(helixesStructWithoutPseudoKnots);
-
- return makeSet();
- }
- }
-
- private class ConvertToTree {
- private Set<RNATemplateHelix> removedHelixes;
-
- public ConvertToTree(Set<RNATemplateHelix> removedHelixes) {
- this.removedHelixes = removedHelixes;
- }
-
- private Iterator<RNATemplateElement> iter = template.rnaIterator();
- private Set<RNATemplateHelix> knownHelixes = new HashSet<RNATemplateHelix>();
-
- public Tree<RNANodeValueTemplate> convert() throws ExceptionInvalidRNATemplate {
- Tree<RNANodeValueTemplate> root = new Tree<RNANodeValueTemplate>();
- // No value, this is a fake node because we need a root.
- root.setValue(null);
- makeChildren(root);
- return root;
- }
-
- private void makeChildren(Tree<RNANodeValueTemplate> father) throws ExceptionInvalidRNATemplate {
- List<Tree<RNANodeValueTemplate>> children = father.getChildren();
- while (true) {
- try {
- RNATemplateElement element = iter.next();
- if (element instanceof RNATemplateHelix) {
- RNATemplateHelix helix = (RNATemplateHelix) element;
- if (removedHelixes.contains(helix)) {
- // Helix was removed
-
- boolean firstPartOfHelix;
- if (knownHelixes.contains(helix)) {
- firstPartOfHelix = false;
- } else {
- knownHelixes.add(helix);
- firstPartOfHelix = true;
- }
-
- int helixLength = helix.getLength();
- // Maybe we could allow helixes of length 0?
- // If we want to then this code can be changed in the future.
- if (helixLength < 1) {
- throw (new ExceptionInvalidRNATemplate("Helix length < 1"));
- }
- int firstPosition = firstPartOfHelix ? 0 : helixLength;
- int afterLastPosition = firstPartOfHelix ? helixLength : 2*helixLength;
- for (int i=firstPosition; i<afterLastPosition; i++) {
- RNANodeValueTemplateBrokenBasePair value = new RNANodeValueTemplateBrokenBasePair();
- value.setHelix(helix);
- value.setPositionInHelix(i);
- Tree<RNANodeValueTemplate> child = new Tree<RNANodeValueTemplate>();
- child.setValue(value);
- father.getChildren().add(child);
- }
-
- } else {
- // We have an non-removed helix
-
- if (knownHelixes.contains(helix)) {
- if ((! (father.getValue() instanceof RNANodeValueTemplateBasePair))
- || ((RNANodeValueTemplateBasePair) father.getValue()).getHelix() != helix) {
- // We have already met this helix, so unless it is our father,
- // we have a pseudoknot (didn't we remove them???).
- throw (new ExceptionInvalidRNATemplate("Unexpected helix. Looks like there still are pseudoknots even after we removed them so something is wrong about the template."));
- } else {
- // As we have found the father, we have finished our work
- // with the children.
- return;
- }
- } else {
- knownHelixes.add(helix);
-
- int helixLength = helix.getLength();
- // Maybe we could allow helixes of length 0?
- // If we want to then this code can be changed in the future.
- if (helixLength < 1) {
- throw (new ExceptionInvalidRNATemplate("Helix length < 1"));
- }
- Tree<RNANodeValueTemplate> lastChild = father;
- for (int i=0; i<helixLength; i++) {
- RNANodeValueTemplateBasePair value = new RNANodeValueTemplateBasePair();
- value.setHelix(helix);
- value.setPositionInHelix(i);
- Tree<RNANodeValueTemplate> child = new Tree<RNANodeValueTemplate>();
- child.setValue(value);
- lastChild.getChildren().add(child);
- lastChild = child;
- }
- // Now we put what follows as children of lastChild
- makeChildren(lastChild);
- }
-
-
- }
- } else if (element instanceof RNATemplateUnpairedSequence) {
- RNATemplateUnpairedSequence sequence = (RNATemplateUnpairedSequence) element;
- int seqLength = sequence.getLength();
-
- // Maybe we could allow sequences of length 0?
- // If we want to then this code can be changed in the future.
- if (seqLength < 1) {
- throw (new ExceptionInvalidRNATemplate("Non-paired sequence length < 1"));
- }
-
- RNANodeValueTemplateSequence value = new RNANodeValueTemplateSequence();
- value.setSequence(sequence);
- Tree<RNANodeValueTemplate> child = new Tree<RNANodeValueTemplate>();
- child.setValue(value);
- children.add(child);
- } else {
- throw (new ExceptionInvalidRNATemplate("We have an endpoint which is neither an helix nor a sequence. What is that?"));
- }
-
- } catch (NoSuchElementException e) {
- // We are at the end of elements so if everything is ok
- // the father must be the root.
- if (father.getValue() == null) {
- return; // Work finished.
- } else {
- throw (new ExceptionInvalidRNATemplate("Unexpected end of template endpoint list."));
- }
- }
- }
- }
-
- }
-
- /**
- * Tells whether the connected component to which endPoint belongs to
- * is cyclic.
- */
- public boolean connectedComponentIsCyclic(EdgeEndPoint endPoint) {
- Set<EdgeEndPoint> knownEndPoints = new HashSet<EdgeEndPoint>();
- EdgeEndPoint currentEndPoint = endPoint;
- while (true) {
- if (knownEndPoints.contains(currentEndPoint)) {
- return true;
- }
- knownEndPoints.add(currentEndPoint);
- EdgeEndPoint previousEndPoint = currentEndPoint.getPreviousEndPoint();
- if (previousEndPoint == null) {
- return false;
- } else {
- currentEndPoint = previousEndPoint;
- }
- }
- }
-
- /**
- * Tells whether the template elements are all connected, ie. if the
- * graph (edge endpoints being vertices) is connected.
- */
- public boolean isConnected() {
- if (isEmpty()) {
- return true;
- }
-
- // Count all vertices
- int n = 0;
- for (RNATemplateElement element: elements) {
- if (element instanceof RNATemplateHelix) {
- n += 4;
- } else if (element instanceof RNATemplateUnpairedSequence) {
- n += 2;
- }
- }
-
- // Now try reaching all vertices
- Set<EdgeEndPoint> knownEndPoints = new HashSet<EdgeEndPoint>();
- EdgeEndPoint currentEndPoint = getFirstEndPoint();
- while (true) {
- if (knownEndPoints.contains(currentEndPoint)) {
- // We are back to our original endpoint, so stop
- break;
- }
- knownEndPoints.add(currentEndPoint);
- EdgeEndPoint nextEndPoint = currentEndPoint.getNextEndPoint();
- if (nextEndPoint == null) {
- break;
- } else {
- currentEndPoint = nextEndPoint;
- }
- }
-
- // The graph is connected iff the number of reached vertices
- // is equal to the total number of vertices.
- return (knownEndPoints.size() == n);
-
- }
-
- /**
- * Checks whether this template is a valid RNA template, ie.
- * it is non-empty, it does not contain a cycle and all elements are in one
- * connected component.
- */
- public void checkIsValidTemplate() throws ExceptionInvalidRNATemplate {
- if (isEmpty()) {
- throw (new ExceptionInvalidRNATemplate("The template is empty."));
- }
-
- if (! isConnected()) {
- throw (new ExceptionInvalidRNATemplate("The template is a non-connected graph."));
- }
-
- // Now we know the graph is connected.
-
- if (connectedComponentIsCyclic(getAnyEndPoint())) {
- throw (new ExceptionInvalidRNATemplate("The template is cyclic."));
- }
- }
-
- /**
- * Make a tree of the template. For this, we will remove pseudoknots,
- * taking care to remove as few base pair links as possible.
- * Requires the template to be valid and will check the validity
- * (will call checkIsValidTemplate()).
- * Calling this method will automatically call computeIn1Is().
- */
- public Tree<RNANodeValueTemplate> toTree() throws ExceptionInvalidRNATemplate {
- // Compute the helix in1Is fields.
- // We also rely on computeIn1Is() for checking the template validity.
- computeIn1Is();
-
- // Remove pseudoknots
- RemovePseudoKnots pseudoKnotKiller = new RemovePseudoKnots();
- Set<RNATemplateHelix> removedHelixes = pseudoKnotKiller.removePseudoKnots();
-
- // Convert to tree
- ConvertToTree converter = new ConvertToTree(removedHelixes);
- return converter.convert();
- }
-
-
- /**
- * Generate an RNA sequence that exactly matches the template.
- * Requires the template to be valid and will check the validity
- * (will call checkIsValidTemplate()).
- */
- public RNA toRNA() throws ExceptionInvalidRNATemplate {
- // First, we check this is a valid template
- checkIsValidTemplate();
-
- ArrayList<Integer> str = new ArrayList<Integer>();
- Map<RNATemplateHelix, ArrayList<Integer>> helixes = new HashMap<RNATemplateHelix, ArrayList<Integer>>();
- Iterator<RNATemplateElement> iter = rnaIterator();
- while (iter.hasNext()) {
- RNATemplateElement element = iter.next();
- if (element instanceof RNATemplateHelix) {
- RNATemplateHelix helix = (RNATemplateHelix) element;
- int n = helix.getLength();
- if (helixes.containsKey(helix)) {
- int firstBase = str.size();
- ArrayList<Integer> helixMembers = helixes.get(helix);
- for (int i = 0; i < n; i++) {
- int indexOfAssociatedBase = helixMembers.get(n-1-i);
- str.set(indexOfAssociatedBase, firstBase + i);
- str.add(indexOfAssociatedBase);
- }
- } else {
- int firstBase = str.size();
- ArrayList<Integer> helixMembers = new ArrayList<Integer>();
- for (int i = 0; i < n; i++) {
- // We don't known yet where the associated base is
- str.add(-1);
- helixMembers.add(firstBase + i);
- }
- helixes.put(helix, helixMembers);
- }
- } else if (element instanceof RNATemplateUnpairedSequence) {
- RNATemplateUnpairedSequence sequence = (RNATemplateUnpairedSequence) element;
- int n = sequence.getLength();
- for (int i=0; i<n; i++) {
- str.add(-1);
- }
- } else {
- throw (new ExceptionInvalidRNATemplate("We have an endpoint which is neither an helix nor a sequence. What is that?"));
- }
- }
-
- int[] strAsArray = RNATemplateAlign.intArrayFromList(str);
- String[] seqAsArray = new String[strAsArray.length];
- Arrays.fill(seqAsArray, " ");
- RNA rna = new RNA();
- try {
- rna.setRNA(seqAsArray, strAsArray);
- } catch (ExceptionFileFormatOrSyntax e) {
- throw (new RuntimeException("Bug in toRNA(): setRNA() threw an ExceptionFileFormatOrSyntax exception."));
- }
- return rna;
- }
-
-
- private class ConvertToXml {
- private Map<RNATemplateElement, String> elementNames = new HashMap<RNATemplateElement, String>();
- private Element connectionsXmlElement;
- private Document document;
-
- private void addConnectionIfNecessary(EdgeEndPoint endPoint) {
- if (endPoint != null && endPoint.isConnected()) {
- RNATemplateElement e1 = endPoint.getElement();
- EdgeEndPointPosition p1 = endPoint.getPosition();
- RNATemplateElement e2 = endPoint.getOtherElement();
- EdgeEndPointPosition p2 = endPoint.getOtherEndPoint().getPosition();
- Element xmlElement = document.createElement("edge");
- {
- Element fromXmlElement = document.createElement("from");
- fromXmlElement.setAttribute("endpoint", elementNames.get(e1));
- fromXmlElement.setAttribute("position", p1.toString());
- xmlElement.appendChild(fromXmlElement);
- }
- {
- Element toXmlElement = document.createElement("to");
- toXmlElement.setAttribute("endpoint", elementNames.get(e2));
- toXmlElement.setAttribute("position", p2.toString());
- xmlElement.appendChild(toXmlElement);
- }
- connectionsXmlElement.appendChild(xmlElement);
- }
- }
-
- public Document toXMLDocument() throws ExceptionXMLGeneration, ExceptionInvalidRNATemplate {
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder builder = factory.newDocumentBuilder();
- document = builder.newDocument();
- Element root = document.createElement("RNATemplate");
- document.appendChild(root);
- Element elementsXmlElement = document.createElement("elements");
- root.appendChild(elementsXmlElement);
- connectionsXmlElement = document.createElement("edges");
- root.appendChild(connectionsXmlElement);
-
- // First pass, we create a mapping between java references and names (strings)
- {
- int nextHelix = 1;
- int nextNonPairedSequence = 1;
- for (RNATemplateElement templateElement: elements) {
- if (templateElement instanceof RNATemplateHelix) {
- RNATemplateHelix helix = (RNATemplateHelix) templateElement;
- if (! elementNames.containsKey(helix)) {
- elementNames.put(helix, "H ID " + nextHelix);
- nextHelix++;
- }
- } else if (templateElement instanceof RNATemplateUnpairedSequence) {
- RNATemplateUnpairedSequence sequence = (RNATemplateUnpairedSequence) templateElement;
- if (! elementNames.containsKey(sequence)) {
- elementNames.put(sequence, "S ID " + nextNonPairedSequence);
- nextNonPairedSequence++;
- }
- } else {
- throw (new ExceptionInvalidRNATemplate("We have an endpoint which is neither an helix nor a sequence. What is that?"));
- }
- }
- }
-
- // Now we generate the XML document
- for (RNATemplateElement templateElement: elements) {
- String elementXmlName = elementNames.get(templateElement);
- Element xmlElement;
- if (templateElement instanceof RNATemplateHelix) {
- RNATemplateHelix helix = (RNATemplateHelix) templateElement;
- xmlElement = document.createElement("helix");
- xmlElement.setAttribute("id", elementXmlName);
- xmlElement.setAttribute("length", Integer.toString(helix.getLength()));
- xmlElement.setAttribute("flipped", Boolean.toString(helix.isFlipped()));
- if (helix.hasCaption()) {
- xmlElement.setAttribute("caption", helix.getCaption());
- }
- {
- Element startPositionXmlElement = document.createElement("startPosition");
- startPositionXmlElement.setAttribute("x", Double.toString(helix.getStartPosition().x));
- startPositionXmlElement.setAttribute("y", Double.toString(helix.getStartPosition().y));
- xmlElement.appendChild(startPositionXmlElement);
- }
- {
- Element endPositionXmlElement = document.createElement("endPosition");
- endPositionXmlElement.setAttribute("x", Double.toString(helix.getEndPosition().x));
- endPositionXmlElement.setAttribute("y", Double.toString(helix.getEndPosition().y));
- xmlElement.appendChild(endPositionXmlElement);
- }
- addConnectionIfNecessary(helix.getOut1());
- addConnectionIfNecessary(helix.getOut2());
- } else if (templateElement instanceof RNATemplateUnpairedSequence) {
- RNATemplateUnpairedSequence sequence = (RNATemplateUnpairedSequence) templateElement;
- xmlElement = document.createElement("sequence");
- xmlElement.setAttribute("id", elementXmlName);
- xmlElement.setAttribute("length", Integer.toString(sequence.getLength()));
- {
- Element vertex5XmlElement = document.createElement("vertex5");
- vertex5XmlElement.setAttribute("x", Double.toString(sequence.getVertex5().x));
- vertex5XmlElement.setAttribute("y", Double.toString(sequence.getVertex5().y));
- xmlElement.appendChild(vertex5XmlElement);
- }
- {
- Element vertex3XmlElement = document.createElement("vertex3");
- vertex3XmlElement.setAttribute("x", Double.toString(sequence.getVertex3().x));
- vertex3XmlElement.setAttribute("y", Double.toString(sequence.getVertex3().y));
- xmlElement.appendChild(vertex3XmlElement);
- }
- {
- Element inTangentVectorXmlElement = document.createElement("inTangentVector");
- inTangentVectorXmlElement.setAttribute("angle", Double.toString(sequence.getInTangentVectorAngle()));
- inTangentVectorXmlElement.setAttribute("length", Double.toString(sequence.getInTangentVectorLength()));
- xmlElement.appendChild(inTangentVectorXmlElement);
- }
- {
- Element outTangentVectorXmlElement = document.createElement("outTangentVector");
- outTangentVectorXmlElement.setAttribute("angle", Double.toString(sequence.getOutTangentVectorAngle()));
- outTangentVectorXmlElement.setAttribute("length", Double.toString(sequence.getOutTangentVectorLength()));
- xmlElement.appendChild(outTangentVectorXmlElement);
- }
- addConnectionIfNecessary(sequence.getOut());
- } else {
- throw (new ExceptionInvalidRNATemplate("We have an endpoint which is neither an helix nor a sequence. What is that?"));
- }
- elementsXmlElement.appendChild(xmlElement);
- }
-
- return document;
- } catch (ParserConfigurationException e) {
- throw (new ExceptionXMLGeneration("ParserConfigurationException: " + e.getMessage()));
- }
- }
- }
-
-
-
- public void toXMLFile(File file) throws ExceptionXMLGeneration, ExceptionInvalidRNATemplate {
- try {
- Document xmlDocument = toXMLDocument();
- Source source = new DOMSource(xmlDocument);
- Result result = new StreamResult(file);
- Transformer transformer;
- transformer = TransformerFactory.newInstance().newTransformer();
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.transform(source, result);
- } catch (TransformerConfigurationException e) {
- throw (new ExceptionXMLGeneration("TransformerConfigurationException: " + e.getMessage()));
- } catch (TransformerFactoryConfigurationError e) {
- throw (new ExceptionXMLGeneration("TransformerFactoryConfigurationError: " + e.getMessage()));
- } catch (TransformerException e) {
- throw (new ExceptionXMLGeneration("TransformerException: " + e.getMessage()));
- }
- }
-
-
- public Document toXMLDocument() throws ExceptionXMLGeneration, ExceptionInvalidRNATemplate {
- ConvertToXml converter = new ConvertToXml();
- return converter.toXMLDocument();
- }
-
-
- private class LoadFromXml {
- private Document xmlDocument;
- private Map<String, RNATemplateElement> elementNames = new HashMap<String, RNATemplateElement>();
-
- public LoadFromXml(Document xmlDocument) {
- this.xmlDocument = xmlDocument;
- }
-
- private Point2D.Double pointFromXml(Element xmlPoint) {
- Point2D.Double point = new Point2D.Double();
- point.x = Double.parseDouble(xmlPoint.getAttribute("x"));
- point.y = Double.parseDouble(xmlPoint.getAttribute("y"));
- return point;
- }
-
- private double vectorLengthFromXml(Element xmlVector) {
- return Double.parseDouble(xmlVector.getAttribute("length"));
- }
-
- private double vectorAngleFromXml(Element xmlVector) {
- return Double.parseDouble(xmlVector.getAttribute("angle"));
- }
-
- /**
- * Takes an element of the form:
- * <anything endpoint="an element id" position="a valid EdgeEndPointPosition"/>
- * and returns the corresponding EdgeEndPoint object.
- */
- private EdgeEndPoint endPointFromXml(Element xmlEdgeEndPoint) throws ExceptionXmlLoading {
- String elementId = xmlEdgeEndPoint.getAttribute("endpoint");
- if (elementId == null || elementId == "")
- throw (new ExceptionXmlLoading ("Missing endpoint attribute on " + xmlEdgeEndPoint));
- String positionOnElement = xmlEdgeEndPoint.getAttribute("position");
- if (positionOnElement == null || positionOnElement == "")
- throw (new ExceptionXmlLoading ("Missing position attribute on " + xmlEdgeEndPoint));
- if (elementNames.containsKey(elementId)) {
- RNATemplateElement templateElement = elementNames.get(elementId);
- EdgeEndPointPosition relativePosition = EdgeEndPointPosition.valueOf(positionOnElement);
- if (relativePosition == null)
- throw (new ExceptionXmlLoading ("Could not compute relativePosition"));
- return templateElement.getEndPointFromPosition(relativePosition);
- } else {
- throw (new ExceptionXmlLoading("Edge is connected on unkown element: " + elementId));
- }
- }
-
- private String connectErrMsg(EdgeEndPoint v1, EdgeEndPoint v2, String reason) {
- return "Error while connecting\n"
- + v1.toString() + " to\n"
- + v2.toString() + " because:\n"
- + reason;
- }
-
- private void connect(EdgeEndPoint v1, EdgeEndPoint v2) throws ExceptionXmlLoading {
- if (v1 == null || v2 == null) {
- throw (new ExceptionXmlLoading("Invalid edge: missing endpoint\n v1 = " + v1 + "\n v2 = " + v2));
- }
- if (v2.isConnected()) {
- throw (new ExceptionXmlLoading(connectErrMsg(v1, v2, "Second vertex is already connected to " + v2.getOtherElement().toString())));
- }
- if (v1.isConnected()) {
- throw (new ExceptionXmlLoading(connectErrMsg(v1, v2, "First vertex is already connected to " + v1.getOtherElement().toString())));
- }
-
- try {
- v1.connectTo(v2);
- } catch (ExceptionEdgeEndpointAlreadyConnected e) {
- throw (new ExceptionXmlLoading("A vertex is on two edges at the same time: " + e.getMessage()));
- } catch (ExceptionInvalidRNATemplate e) {
- throw (new ExceptionXmlLoading("ExceptionInvalidRNATemplate: " + e.getMessage()));
- }
- }
-
- public void load() throws ExceptionXmlLoading {
- // First part: we load all elements from the XML tree
- Element xmlElements = (Element) xmlDocument.getElementsByTagName("elements").item(0);
- {
- NodeList xmlElementsChildren = xmlElements.getChildNodes();
- for (int i=0; i<xmlElementsChildren.getLength(); i++) {
- Node xmlElementsChild = xmlElementsChildren.item(i);
- if (xmlElementsChild instanceof Element) {
- Element xmlTemplateElement = (Element) xmlElementsChild;
- String tagName = xmlTemplateElement.getTagName();
- if (tagName == "helix") {
- RNATemplateHelix helix = new RNATemplateHelix(xmlTemplateElement.getAttribute("id"));
- helix.setFlipped(Boolean.parseBoolean(xmlTemplateElement.getAttribute("flipped")));
- helix.setLength(Integer.parseInt(xmlTemplateElement.getAttribute("length")));
- if (xmlTemplateElement.hasAttribute("caption")) {
- helix.setCaption(xmlTemplateElement.getAttribute("caption"));
- }
- elementNames.put(xmlTemplateElement.getAttribute("id"), helix);
- NodeList xmlHelixChildren = xmlTemplateElement.getChildNodes();
- for (int j=0; j<xmlHelixChildren.getLength(); j++) {
- Node xmlHelixChild = xmlHelixChildren.item(j);
- if (xmlHelixChild instanceof Element) {
- Element xmlHelixChildElement = (Element) xmlHelixChild;
- String helixChildTagName = xmlHelixChildElement.getTagName();
- if (helixChildTagName == "startPosition") {
- helix.setStartPosition(pointFromXml(xmlHelixChildElement));
- } else if (helixChildTagName == "endPosition") {
- helix.setEndPosition(pointFromXml(xmlHelixChildElement));
- }
- }
- }
- } else if (tagName == "sequence") {
- RNATemplateUnpairedSequence sequence = new RNATemplateUnpairedSequence(xmlTemplateElement.getAttribute("id"));
- sequence.setLength(Integer.parseInt(xmlTemplateElement.getAttribute("length")));
- elementNames.put(xmlTemplateElement.getAttribute("id"), sequence);
- NodeList xmlSequenceChildren = xmlTemplateElement.getChildNodes();
- for (int j=0; j<xmlSequenceChildren.getLength(); j++) {
- Node xmlSequenceChild = xmlSequenceChildren.item(j);
- if (xmlSequenceChild instanceof Element) {
- Element xmlSequenceChildElement = (Element) xmlSequenceChild;
- String sequenceChildTagName = xmlSequenceChildElement.getTagName();
- if (sequenceChildTagName == "inTangentVector") {
- sequence.setInTangentVectorLength(vectorLengthFromXml(xmlSequenceChildElement));
- sequence.setInTangentVectorAngle(vectorAngleFromXml(xmlSequenceChildElement));
- } else if (sequenceChildTagName == "outTangentVector") {
- sequence.setOutTangentVectorLength(vectorLengthFromXml(xmlSequenceChildElement));
- sequence.setOutTangentVectorAngle(vectorAngleFromXml(xmlSequenceChildElement));
- } else if (sequenceChildTagName == "vertex5") {
- sequence.setVertex5(pointFromXml(xmlSequenceChildElement));
- } else if (sequenceChildTagName == "vertex3") {
- sequence.setVertex3(pointFromXml(xmlSequenceChildElement));
- }
- }
- }
- }
- }
- }
- }
-
- // Second part: We read the edges from the XML tree
- Element xmlEdges = (Element) xmlDocument.getElementsByTagName("edges").item(0);
- {
- NodeList xmlEdgesChildren = xmlEdges.getChildNodes();
- for (int i=0; i<xmlEdgesChildren.getLength(); i++) {
- Node xmlEdgesChild = xmlEdgesChildren.item(i);
- if (xmlEdgesChild instanceof Element) {
- Element xmlTemplateEdge = (Element) xmlEdgesChild;
- if (xmlTemplateEdge.getTagName() == "edge") {
- EdgeEndPoint v1 = null, v2 = null;
- NodeList xmlEdgeChildren = xmlTemplateEdge.getChildNodes();
- for (int j=0; j<xmlEdgeChildren.getLength(); j++) {
- Node xmlEdgeChild = xmlEdgeChildren.item(j);
- if (xmlEdgeChild instanceof Element) {
- Element xmlEdgeChildElement = (Element) xmlEdgeChild;
- String edgeChildTagName = xmlEdgeChildElement.getTagName();
- if (edgeChildTagName == "from") {
- v1 = endPointFromXml(xmlEdgeChildElement);
- } else if (edgeChildTagName == "to") {
- v2 = endPointFromXml(xmlEdgeChildElement);
- }
- }
- }
- if (v1 == null)
- throw (new ExceptionXmlLoading("Invalid edge: missing \"from\" declaration"));
- if (v2 == null)
- throw (new ExceptionXmlLoading("Invalid edge: missing \"to\" declaration"));
- connect(v1, v2);
- }
- }
- }
-
- }
- }
- }
-
-
- public static RNATemplate fromXMLFile(File file) throws ExceptionXmlLoading {
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setIgnoringElementContentWhitespace(true);
- DocumentBuilder builder = factory.newDocumentBuilder();
- Document xmlDocument = builder.parse(file);
- return fromXMLDocument(xmlDocument);
- } catch (ParserConfigurationException e) {
- throw (new ExceptionXmlLoading("ParserConfigurationException: " + e.getMessage()));
- } catch (SAXException e) {
- throw (new ExceptionXmlLoading("SAXException: " + e.getMessage()));
- } catch (IOException e) {
- throw (new ExceptionXmlLoading("IOException: " + e.getMessage()));
- }
- }
-
-
- public static RNATemplate fromXMLDocument(Document xmlDocument) throws ExceptionXmlLoading {
- RNATemplate template = new RNATemplate();
- LoadFromXml loader = template.new LoadFromXml(xmlDocument);
- loader.load();
- return template;
- }
-
-
-
- /**
- * For an helix, tells us whether IN1/OUT1 is the 5' strand
- * (the first strand we meet if we follow the RNA sequence)
- * or the 3' strand (the second we meet if we follow the RNA sequence).
- */
- public enum In1Is {
- IN1_IS_5PRIME, IN1_IS_3PRIME
- }
-
-
- /**
- * For each helix, compute the in1Is field.
- * If helices connections are changed, the value may become obsolete,
- * so you need to call this method again before accessing the in1Is
- * fields if you have modified connections in the template.
- * Requires the template to be valid and will check the validity
- * (will call checkIsValidTemplate()).
- */
- public void computeIn1Is() throws ExceptionInvalidRNATemplate {
- checkIsValidTemplate();
-
- Iterator<EdgeEndPoint> iter = vertexIterator();
- Set<RNATemplateHelix> knownHelices = new HashSet<RNATemplateHelix>();
- while (iter.hasNext()) {
- EdgeEndPoint endPoint = iter.next();
- RNATemplateElement templateElement = endPoint.getElement();
- if (templateElement instanceof RNATemplateHelix) {
- RNATemplateHelix helix = (RNATemplateHelix) templateElement;
- if (! knownHelices.contains(helix)) {
- // first time we meet this helix
- switch (endPoint.getPosition()) {
- case IN1:
- case OUT1:
- helix.setIn1Is(In1Is.IN1_IS_5PRIME);
- break;
- case IN2:
- case OUT2:
- helix.setIn1Is(In1Is.IN1_IS_3PRIME);
- break;
- }
- knownHelices.add(helix);
- }
- }
- }
- }
-
-
-
- /**
- * Remove the element from the template.
- * The element is automatically disconnected from any other element.
- * Returns true if and only if the element was present in the template,
- * otherwise nothing was done.
- */
- public boolean removeElement(RNATemplateElement element) throws ExceptionInvalidRNATemplate {
- if (elements.contains(element)) {
- element.disconnectFromAny();
- elements.remove(element);
- return true;
- } else {
- return false;
- }
- }
-
-
- /**
- * Position of an endpoint on an endpoint.
- * Not all values make sense for any endpoint.
- * For an helix, all four make sense, but for a non-paired
- * sequence, only IN1 and OUT1 make sense.
- */
- public enum EdgeEndPointPosition {
- IN1, IN2, OUT1, OUT2;
- }
-
-
- private static int NEXT_ID = 1;
-
- /**
- * An endpoint of an RNA template,
- * it can be an helix or a sequence of non-paired bases.
- *
- * You cannot create an object of this class directly,
- * use RNATemplateHelix or RNATemplateUnpairedSequence instead.
- *
- * @author Raphael Champeimont
- */
- public abstract class RNATemplateElement {
-
- public int _id = NEXT_ID++;
-
- public String getName()
- {return "RNATemplate"+_id; }
-
-
- /**
- * This variable is just there so that "this" can be accessed by a name
- * from the internal class EdgeEndPoint.
- */
- private final RNATemplateElement element = this;
-
- /**
- * When the endpoint is created, it is added to the list of elements
- * in this template. To remove it, call RNATemplate.removeElement().
- */
- public RNATemplateElement() {
- elements.add(this);
- }
-
- /**
- * Disconnect this endpoint from any other elements it may be connected to.
- */
- public abstract void disconnectFromAny();
-
- /**
- * Get the the IN endpoint in the case of a sequence
- * and the IN1 endpoint in the case of an helix.
- */
- public abstract EdgeEndPoint getIn1EndPoint();
-
- /**
- * Returns the template to which this endpoint belongs.
- */
- public RNATemplate getParentTemplate() {
- return template;
- }
-
- /**
- * Provided endpoint is an endpoint of this endpoint, get the next
- * endpoint, either on this same endpoint, or or the connected endpoint.
- * Note that you should use the getNextEndPoint() method of the endpoint
- * itself directly.
- */
- protected abstract EdgeEndPoint getNextEndPoint(EdgeEndPoint endpoint);
-
- /**
- * Provided endpoint is an endpoint of this endpoint, get the previous
- * endpoint, either on this same endpoint, or or the connected endpoint.
- * Note that you should use the getPreviousEndPoint() method of the endpoint
- * itself directly.
- */
- protected abstract EdgeEndPoint getPreviousEndPoint(EdgeEndPoint endpoint);
-
-
- /**
- * An edge endpoint is where an edge can connect.
- */
- public class EdgeEndPoint {
- private EdgeEndPoint() {
- }
-
- /**
- * Get the next endpoint. If this endpoint is an "in" endpoint,
- * returns the corresponding "out" endpoint. If this endpoint
- * is an "out" endpoint, return the connected endpoint if there is
- * one, otherwise return null.
- */
- public EdgeEndPoint getNextEndPoint() {
- return element.getNextEndPoint(this);
- }
-
-
- /**
- * Same as getNextEndPoint(), but with the previous endpoint.
- */
- public EdgeEndPoint getPreviousEndPoint() {
- return element.getPreviousEndPoint(this);
- }
-
-
- /**
- * Get the position on the endpoint where this endpoint is.
- */
- public EdgeEndPointPosition getPosition() {
- return element.getPositionFromEndPoint(this);
- }
-
-
- private EdgeEndPoint otherEndPoint;
-
- /**
- * Returns the endpoint on which this edge endpoint is.
- */
- public RNATemplateElement getElement() {
- return element;
- }
-
- /**
- * Returns the other endpoint of the edge.
- * Will be null if there is no edge connecter to this endpoint.
- */
- public EdgeEndPoint getOtherEndPoint() {
- return otherEndPoint;
- }
- /**
- * Returns the endpoint at the other endpoint of the edge.
- * Will be null if there is no edge connecter to this endpoint.
- */
- public RNATemplateElement getOtherElement() {
- return (otherEndPoint != null) ? otherEndPoint.getElement() : null;
- }
-
- /**
- * Disconnect this endpoint from the other, ie. delete the edge
- * between them. Note that this will modify both endpoints, and that
- * x.disconnect() is equivalent to x.getOtherEndPoint().disconnect().
- * If this endpoint is not connected, does nothing.
- */
- public void disconnect() {
- if (otherEndPoint != null) {
- otherEndPoint.otherEndPoint = null;
- otherEndPoint = null;
- }
- }
-
- /**
- * Tells whether this endpoint is connected with an edge to
- * an other endpoint.
- */
- public boolean isConnected() {
- return (otherEndPoint != null);
- }
-
-
- /**
- * Create an edge between two edge endpoints.
- * This is a symmetric operation and it will modify both endpoints.
- * It means x.connectTo(y) is equivalent to y.connectTo(x).
- * The edge endpoint must be free (ie. not yet connected).
- * Also, elements connected together must belong to the same template.
- */
- public void connectTo(EdgeEndPoint otherEndPoint) throws ExceptionEdgeEndpointAlreadyConnected, ExceptionInvalidRNATemplate {
- if (this.otherEndPoint != null || otherEndPoint.otherEndPoint != null) {
- throw (new ExceptionEdgeEndpointAlreadyConnected());
- }
- if (template != otherEndPoint.getElement().getParentTemplate()) {
- throw (new ExceptionInvalidRNATemplate("Elements from different templates cannot be connected with each other."));
- }
- this.otherEndPoint = otherEndPoint;
- otherEndPoint.otherEndPoint = this;
- }
-
-
- public String toString() {
- return "Edge endpoint on element " + element.toString() + " at position " + getPosition().toString();
- }
- }
-
-
- /**
- * Get the EdgeEndPoint object corresponding to the the given
- * position on this endpoint.
- */
- public abstract EdgeEndPoint getEndPointFromPosition(EdgeEndPointPosition position);
-
-
- /**
- * The inverse of getEndPointFromPosition.
- */
- public abstract EdgeEndPointPosition getPositionFromEndPoint(EdgeEndPoint endPoint);
-
-
- /**
- * Connect the endpoint at position positionHere of this endpoint
- * to the otherEndPoint.
- */
- public void connectTo(
- EdgeEndPointPosition positionHere,
- EdgeEndPoint otherEndPoint)
- throws ExceptionEdgeEndpointAlreadyConnected, ExceptionInvalidRNATemplate {
- EdgeEndPoint endPointHere = getEndPointFromPosition(positionHere);
- endPointHere.connectTo(otherEndPoint);
- }
-
- /**
- * Connect the endpoint at position positionHere of this endpoint
- * to the endpoint of otherElement at position positionOnOtherElement.
- * @throws ExceptionInvalidRNATemplate
- * @throws ExceptionEdgeEndpointAlreadyConnected, ExceptionEdgeEndpointAlreadyConnected
- */
- public void connectTo(
- EdgeEndPointPosition positionHere,
- RNATemplateElement otherElement,
- EdgeEndPointPosition positionOnOtherElement)
- throws ExceptionEdgeEndpointAlreadyConnected, ExceptionEdgeEndpointAlreadyConnected, ExceptionInvalidRNATemplate {
- EdgeEndPoint otherEndPoint = otherElement.getEndPointFromPosition(positionOnOtherElement);
- connectTo(positionHere, otherEndPoint);
- }
-
-
- }
-
-
- /**
- * An helix in an RNA template.
- *
- * @author Raphael Champeimont
- */
- public class RNATemplateHelix extends RNATemplateElement {
- /**
- * Number of base pairs in the helix.
- */
- private int length;
-
- /**
- * Position of the helix start point,
- * ie. the middle in the line [x,y] where (x,y)
- * x is the base at the IN1 edge endpoint and
- * y is the base at the OUT2 edge endpoint.
- */
- private Point2D.Double startPosition;
-
- /**
- * Position of the helix end point,
- * ie. the middle in the line [x,y] where (x,y)
- * x is the base at the OUT1 edge endpoint and
- * y is the base at the IN2 edge endpoint.
- */
- private Point2D.Double endPosition;
-
-
- /**
- * Tells whether the helix is flipped.
- */
- private boolean flipped = false;
-
- public boolean isFlipped() {
- return flipped;
- }
-
- public void setFlipped(boolean flipped) {
- this.flipped = flipped;
- }
-
- /**
- * For an helix, tells us whether IN1/OUT1 is the 5' strand
- * (the first strand we meet if we follow the RNA sequence)
- * or the 3' strand (the second we meet if we follow the RNA sequence).
- * This information cannot be known locally, we need the complete
- * template to compute it, see RNATemplate.computeIn1Is().
- */
- private In1Is in1Is = null;
-
- public In1Is getIn1Is() {
- return in1Is;
- }
-
- public void setIn1Is(In1Is in1Is) {
- this.in1Is = in1Is;
- }
-
-
-
- /**
- * A string displayed on the helix.
- */
- private String caption = null;
-
- public String getCaption() {
- return caption;
- }
-
- public void setCaption(String caption) {
- this.caption = caption;
- }
-
- public boolean hasCaption() {
- return caption != null;
- }
-
-
-
-
- /**
- * If we go through all bases of the RNA from first to last,
- * we will pass twice through this helix. On time, we arrive
- * from in1, and leave by out2, and the other time we arrive from
- * in2 and leave by out2.
- * Whether we go through in1/out1 or in2/out2 the first time
- * is written in the in1Is field.
- */
- private final EdgeEndPoint in1, out1, in2, out2;
- private String _name;
-
- public RNATemplateHelix(String name) {
- in1 = new EdgeEndPoint();
- out1 = new EdgeEndPoint();
- in2 = new EdgeEndPoint();
- out2 = new EdgeEndPoint();
- _name = name;
- }
-
-
-
-
-
- public String toString() {
- return "Helix @" + Integer.toHexString(hashCode()) + " len=" + length + " caption=" + caption;
- }
-
- public String getName()
- {return ""+_name; }
-
-
-
- public int getLength() {
- return length;
- }
-
- public void setLength(int length) {
- this.length = length;
- }
-
- public Point2D.Double getStartPosition() {
- return startPosition;
- }
-
- public void setStartPosition(Point2D.Double startPosition) {
- this.startPosition = startPosition;
- }
-
- public Point2D.Double getEndPosition() {
- return endPosition;
- }
-
- public void setEndPosition(Point2D.Double endPosition) {
- this.endPosition = endPosition;
- }
-
- public EdgeEndPoint getIn1() {
- return in1;
- }
-
- public EdgeEndPoint getOut1() {
- return out1;
- }
-
- public EdgeEndPoint getIn2() {
- return in2;
- }
-
- public EdgeEndPoint getOut2() {
- return out2;
- }
-
- public void disconnectFromAny() {
- getIn1().disconnect();
- getIn2().disconnect();
- getOut1().disconnect();
- getOut2().disconnect();
- }
-
-
- protected EdgeEndPoint getNextEndPoint(EdgeEndPoint endpoint) {
- if (endpoint == in1) {
- return out1;
- } else if (endpoint == in2) {
- return out2;
- } else {
- return endpoint.getOtherEndPoint();
- }
- }
-
-
- protected EdgeEndPoint getPreviousEndPoint(EdgeEndPoint endpoint) {
- if (endpoint == out1) {
- return in1;
- } else if (endpoint == out2) {
- return in2;
- } else {
- return endpoint.getOtherEndPoint();
- }
- }
-
-
- public EdgeEndPoint getIn1EndPoint() {
- return in1;
- }
-
- public EdgeEndPoint getEndPointFromPosition(
- EdgeEndPointPosition position) {
- switch (position) {
- case IN1:
- return getIn1();
- case IN2:
- return getIn2();
- case OUT1:
- return getOut1();
- case OUT2:
- return getOut2();
- default:
- return null;
- }
- }
-
- public EdgeEndPointPosition getPositionFromEndPoint(
- EdgeEndPoint endPoint) {
- if (endPoint == in1) {
- return EdgeEndPointPosition.IN1;
- } else if (endPoint == in2) {
- return EdgeEndPointPosition.IN2;
- } else if (endPoint == out1) {
- return EdgeEndPointPosition.OUT1;
- } else if (endPoint == out2) {
- return EdgeEndPointPosition.OUT2;
- } else {
- return null;
- }
- }
-
-
- }
-
-
-
- /**
- * A sequence of non-paired bases in an RNA template.
- *
- * @author Raphael Champeimont
- */
- public class RNATemplateUnpairedSequence extends RNATemplateElement {
- /**
- * Number of (non-paired) bases.
- */
- private int length;
-
- private static final double defaultTangentVectorAngle = Math.PI / 2;
- private static final double defaultTangentVectorLength = 100;
-
- /**
- * The sequence is drawn along a cubic Bezier curve.
- * The curve can be defined by 2 vectors, one for the start of the line
- * and the other for the end. They are the tangents to the line at
- * the beginning and the end of the line.
- * Each vector can be defined by its length and its absolute angle.
- * The angles are given in radians.
- */
- private double inTangentVectorAngle = defaultTangentVectorAngle,
- inTangentVectorLength = defaultTangentVectorLength,
- outTangentVectorAngle = defaultTangentVectorAngle,
- outTangentVectorLength = defaultTangentVectorLength;
-
-
-
-
- /**
- * Position of the begginning (at the "in" endpoint) of the line.
- * It is only useful when the sequence is not yet connected to an helix.
- * (Otherwise we can deduce it from this helix position).
- */
- private Point2D.Double vertex5;
-
- /**
- * Position of the end (at the "out" endpoint) of the line.
- * It is only useful when the sequence is not yet connected to an helix.
- * (Otherwise we can deduce it from this helix position).
- */
- private Point2D.Double vertex3;
-
-
- public Point2D.Double getVertex5() {
- return vertex5;
- }
-
- public void setVertex5(Point2D.Double vertex5) {
- this.vertex5 = vertex5;
- }
-
- public Point2D.Double getVertex3() {
- return vertex3;
- }
-
- public void setVertex3(Point2D.Double vertex3) {
- this.vertex3 = vertex3;
- }
-
-
-
-
- /**
- * The helixes connected on both sides.
- * They must be helixes because only helixes have absolute positions,
- * and the positions of the starting and ending points of the sequence
- * are those stored in the helixes.
- */
- private final EdgeEndPoint in, out;
-
- private String _name;
-
- public RNATemplateUnpairedSequence(String name) {
- in = new EdgeEndPoint();
- out = new EdgeEndPoint();
- _name = name;
- }
-
-
- public String toString() {
- return "Sequence @" + Integer.toHexString(hashCode()) + " len=" + length;
- }
-
- public String getName()
- {return ""+_name; }
-
-
-
- public int getLength() {
- return length;
- }
-
- public void setLength(int length) {
- this.length = length;
- }
-
- public double getInTangentVectorAngle() {
- return inTangentVectorAngle;
- }
-
- public void setInTangentVectorAngle(double inTangentVectorAngle) {
- this.inTangentVectorAngle = inTangentVectorAngle;
- }
-
- public double getInTangentVectorLength() {
- return inTangentVectorLength;
- }
-
- public void setInTangentVectorLength(double inTangentVectorLength) {
- this.inTangentVectorLength = inTangentVectorLength;
- }
-
- public double getOutTangentVectorAngle() {
- return outTangentVectorAngle;
- }
-
- public void setOutTangentVectorAngle(double outTangentVectorAngle) {
- this.outTangentVectorAngle = outTangentVectorAngle;
- }
-
- public double getOutTangentVectorLength() {
- return outTangentVectorLength;
- }
-
- public void setOutTangentVectorLength(double outTangentVectorLength) {
- this.outTangentVectorLength = outTangentVectorLength;
- }
-
- public EdgeEndPoint getIn() {
- return in;
- }
-
- public EdgeEndPoint getOut() {
- return out;
- }
-
- public void disconnectFromAny() {
- getIn().disconnect();
- getOut().disconnect();
- }
-
-
- protected EdgeEndPoint getNextEndPoint(EdgeEndPoint endpoint) {
- if (endpoint == in) {
- return out;
- } else {
- return endpoint.getOtherEndPoint();
- }
- }
-
- protected EdgeEndPoint getPreviousEndPoint(EdgeEndPoint endpoint) {
- if (endpoint == out) {
- return in;
- } else {
- return endpoint.getOtherEndPoint();
- }
- }
-
- public EdgeEndPoint getIn1EndPoint() {
- return in;
- }
-
-
- public EdgeEndPoint getEndPointFromPosition(
- EdgeEndPointPosition position) {
- switch (position) {
- case IN1:
- return getIn();
- case OUT1:
- return getOut();
- default:
- return null;
- }
- }
-
-
- public EdgeEndPointPosition getPositionFromEndPoint(
- EdgeEndPoint endPoint) {
- if (endPoint == in) {
- return EdgeEndPointPosition.IN1;
- } else if (endPoint == out) {
- return EdgeEndPointPosition.OUT1;
- } else {
- return null;
- }
- }
-
-
- }
-
-
-}