JAL-3032 upgrade to Jmol 14.29.17; clearing of src2 directory
[jalview.git] / src2 / fr / orsay / lri / varna / models / rna / DrawRNATemplate.java
diff --git a/src2/fr/orsay/lri/varna/models/rna/DrawRNATemplate.java b/src2/fr/orsay/lri/varna/models/rna/DrawRNATemplate.java
deleted file mode 100644 (file)
index 37b41b8..0000000
+++ /dev/null
@@ -1,1421 +0,0 @@
-/**
- * File written by Raphael Champeimont
- * UMR 7238 Genomique des Microorganismes
- */
-package fr.orsay.lri.varna.models.rna;
-
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Line2D;
-import java.awt.geom.Point2D;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import fr.orsay.lri.varna.exceptions.ExceptionInvalidRNATemplate;
-import fr.orsay.lri.varna.models.VARNAConfig;
-import fr.orsay.lri.varna.models.geom.ComputeArcCenter;
-import fr.orsay.lri.varna.models.geom.ComputeEllipseAxis;
-import fr.orsay.lri.varna.models.geom.CubicBezierCurve;
-import fr.orsay.lri.varna.models.geom.HalfEllipse;
-import fr.orsay.lri.varna.models.geom.LinesIntersect;
-import fr.orsay.lri.varna.models.geom.MiscGeom;
-import fr.orsay.lri.varna.models.templates.DrawRNATemplateCurveMethod;
-import fr.orsay.lri.varna.models.templates.DrawRNATemplateMethod;
-import fr.orsay.lri.varna.models.templates.RNANodeValueTemplate;
-import fr.orsay.lri.varna.models.templates.RNANodeValueTemplateBasePair;
-import fr.orsay.lri.varna.models.templates.RNATemplate;
-import fr.orsay.lri.varna.models.templates.RNATemplateAlign;
-import fr.orsay.lri.varna.models.templates.RNATemplateDrawingAlgorithmException;
-import fr.orsay.lri.varna.models.templates.RNATemplateMapping;
-import fr.orsay.lri.varna.models.templates.RNATemplate.EdgeEndPointPosition;
-import fr.orsay.lri.varna.models.templates.RNATemplate.In1Is;
-import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateElement;
-import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateHelix;
-import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateUnpairedSequence;
-import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateElement.EdgeEndPoint;
-import fr.orsay.lri.varna.models.treealign.Tree;
-
-public class DrawRNATemplate {
-       private RNA rna;
-       private RNATemplateMapping mapping;
-       private ArrayList<ModeleBase> _listeBases;
-       
-       
-       public DrawRNATemplate(RNA rna) {
-               this.rna = rna;
-               this._listeBases = rna.getListeBases();
-       }
-       
-       public RNATemplateMapping getMapping() {
-               return mapping;
-       }
-       
-       
-       
-       /**
-        * Draw this RNA like the given template.
-        * The helixLengthAdjustmentMethod argument tells what to do in case
-        * some helices are of a different length in the template and the
-        * actual helix. See class DrawRNATemplateMethod above for possible values.
-        * @param straightBulges 
-        */
-       public void drawRNATemplate(
-                       RNATemplate template,
-                       VARNAConfig conf,
-                       DrawRNATemplateMethod helixLengthAdjustmentMethod,
-                       DrawRNATemplateCurveMethod curveMethod, boolean straightBulges)
-       throws RNATemplateDrawingAlgorithmException {
-               
-               // debug
-//             try {
-//                     RNA perfectMatchingRNA = template.toRNA();
-//                     System.out.println("An RNA that would perfectly match this template would be:");
-//                     System.out.println(perfectMatchingRNA.getStructDBN());
-//             } catch (ExceptionInvalidRNATemplate e) {
-//                     e.printStackTrace();
-//             }
-               
-               mapping = RNATemplateAlign.mapRNAWithTemplate(rna, template);
-               //System.out.println(mapping.showCompact(this));
-               
-               // debug
-//                     RNATemplateAlign.printMapping(mapping, template, getSeq());
-//                     try {
-//                             TreeGraphviz.treeToGraphvizPostscript(alignment, "alignment_graphviz.ps");
-//                     } catch (IOException e) {
-//                             e.printStackTrace();
-//                     }
-               
-               
-
-               Iterator<RNATemplateElement> iter;
-               double globalIncreaseFactor = 1;
-               Map<RNATemplateHelix, Point2D.Double> translateVectors = null;
-               if (helixLengthAdjustmentMethod == DrawRNATemplateMethod.MAXSCALINGFACTOR) {
-                       // Compute increase factors for helices.
-                       Map<RNATemplateHelix, Double> lengthIncreaseFactor = new HashMap<RNATemplateHelix, Double>();
-                       double maxLengthIncreaseFactor = Double.NEGATIVE_INFINITY;
-                       //RNATemplateHelix maxIncreaseHelix = null;
-                       iter = template.rnaIterator();
-                       while (iter.hasNext()) {
-                               RNATemplateElement element = iter.next();
-                               if (element instanceof RNATemplateHelix
-                                               && mapping.getAncestor(element) != null
-                                               && !lengthIncreaseFactor.containsKey(element)) {
-                                       RNATemplateHelix helix = (RNATemplateHelix) element;
-                                       int[] basesInHelixArray = RNATemplateAlign.intArrayFromList(mapping.getAncestor(helix));
-                                       Arrays.sort(basesInHelixArray);
-                                       double l = computeLengthIncreaseFactor(basesInHelixArray, helix, straightBulges);
-                                       lengthIncreaseFactor.put(helix, l);
-                                       if (l > maxLengthIncreaseFactor) {
-                                               maxLengthIncreaseFactor = l;
-                                               //maxIncreaseHelix = helix;
-                                       }
-                               }
-                       }
-                       
-                       // debug
-                       //System.out.println("Max helix length increase factor = " + maxLengthIncreaseFactor + " reached with helix " + maxIncreaseHelix);;
-                       
-                       globalIncreaseFactor = Math.max(1, maxLengthIncreaseFactor);
-                       
-               } else if (helixLengthAdjustmentMethod == DrawRNATemplateMethod.HELIXTRANSLATE) {
-                       try {
-                               // Now we need to propagate this helices translations
-                               Tree<RNANodeValueTemplate> templateAsTree = template.toTree();
-                               translateVectors = computeHelixTranslations(templateAsTree, mapping, straightBulges);
-                       
-                       } catch (ExceptionInvalidRNATemplate e) {
-                               throw (new RNATemplateDrawingAlgorithmException("ExceptionInvalidRNATemplate: " + e.getMessage()));
-                       }
-               }
-               
-               // Allocate the coords and centers arrays
-               // We create Point2D.Double objects in it but the algorithms
-               // we use may choose to create new Point2D.Double objects or to
-               // modify those created here.
-               Point2D.Double[] coords = new Point2D.Double[_listeBases.size()];
-               Point2D.Double[] centers = new Point2D.Double[_listeBases.size()];
-               double[] angles = new double[_listeBases.size()];
-               for (int i = 0; i < _listeBases.size(); i++) {
-                       coords[i] = new Point2D.Double(0, 0);
-                       centers[i] = new Point2D.Double(0, 0);
-               }
-               
-               boolean computeCoords = true;
-               while (computeCoords) {
-                       computeCoords = false;
-                       // Compute coords and centers
-                       Set<RNATemplateHelix> alreadyDrawnHelixes = new HashSet<RNATemplateHelix>();
-                       RNATemplateHelix lastMappedHelix = null;
-                       EdgeEndPoint howWeGotOutOfLastHelix = null;
-                       int howWeGotOutOfLastHelixBaseIndex = 0;
-                       iter = template.rnaIterator();
-                       RNATemplateElement element = null;
-                       while (iter.hasNext()) {
-                               element = iter.next();
-                               if (element instanceof RNATemplateHelix
-                                               && mapping.getAncestor(element) != null) {
-                                       // We have a mapping between an helix in the RNA sequence
-                                       // and an helix in the template.
-                                       
-                                       RNATemplateHelix helix = (RNATemplateHelix) element;
-                                       boolean firstTimeWeMeetThisHelix;
-                                       int[] basesInHelixArray = RNATemplateAlign.intArrayFromList(mapping.getAncestor(helix));
-                                       Arrays.sort(basesInHelixArray);
-                                       
-                                       // Draw this helix if it has not already been done
-                                       if (!alreadyDrawnHelixes.contains(helix)) {
-                                               firstTimeWeMeetThisHelix = true;
-                                               drawHelixLikeTemplateHelix(basesInHelixArray, helix, coords, centers,angles, globalIncreaseFactor, translateVectors, straightBulges);
-                                               alreadyDrawnHelixes.add(helix);
-                                       } else {
-                                               firstTimeWeMeetThisHelix = false;
-                                       }
-                                       
-                                       EdgeEndPoint howWeGetInCurrentHelix;
-                                       if (firstTimeWeMeetThisHelix) {
-                                               if (helix.getIn1Is() == In1Is.IN1_IS_5PRIME) {
-                                                       howWeGetInCurrentHelix = helix.getIn1();
-                                               } else {
-                                                       howWeGetInCurrentHelix = helix.getIn2();
-                                               }
-                                       } else {
-                                               if (helix.getIn1Is() == In1Is.IN1_IS_5PRIME) {
-                                                       howWeGetInCurrentHelix = helix.getIn2();
-                                               } else {
-                                                       howWeGetInCurrentHelix = helix.getIn1();
-                                               }
-                                       }
-                                       
-                                       Point2D.Double P0 = new Point2D.Double();
-                                       Point2D.Double P3 = new Point2D.Double();
-                                       
-                                       if (lastMappedHelix != null) {
-                                               // Now draw the RNA sequence (possibly containing helixes)
-                                               // between the last template drawn helix and this one.
-       
-                                               if (lastMappedHelix == helix) {
-                                                       // Last helix is the same as the current one so
-                                                       // nothing matched (or at best a single
-                                                       // non-paired sequence) so we will just
-                                                       // use the Radiate algorithm
-                                                       
-                                                       Point2D.Double helixVector = new Point2D.Double();
-                                                       computeHelixEndPointDirections(howWeGotOutOfLastHelix, helixVector, new Point2D.Double());
-                                                       
-                                                       double angle = MiscGeom.angleFromVector(helixVector);
-                                                       int b1 = basesInHelixArray[basesInHelixArray.length/2 - 1];
-                                                       P0.setLocation(coords[b1]);
-                                                       int b2 = basesInHelixArray[basesInHelixArray.length/2];
-                                                       P3.setLocation(coords[b2]);
-                                                       Point2D.Double loopCenter = new Point2D.Double((P0.x + P3.x)/2, (P0.y + P3.y)/2);
-                                                       rna.drawLoop(b1,
-                                                                        b2,
-                                                                        loopCenter.x,
-                                                                        loopCenter.y,
-                                                                        angle,
-                                                                        coords,
-                                                                        centers,
-                                                                        angles,
-                                                                        straightBulges);
-                                                       // If the helix is flipped, we need to compute the symmetric
-                                                       // of the whole loop.
-                                                       if (helix.isFlipped()) {
-                                                               symmetric(loopCenter, helixVector, coords, b1, b2);
-                                                               symmetric(loopCenter, helixVector, centers, b1, b2);
-                                                       }
-                                               } else {
-                                                       // No helices matched between the last helix and
-                                                       // the current one, so we draw what is between
-                                                       // using the radiate algorithm but on the Bezier curve.
-                                                       
-                                                       int b1 = howWeGotOutOfLastHelixBaseIndex;
-                                                       int b2 = firstTimeWeMeetThisHelix ? basesInHelixArray[0] : basesInHelixArray[basesInHelixArray.length/2];
-                                                       P0.setLocation(coords[b1]);
-                                                       P3.setLocation(coords[b2]);
-                                                       
-                                                       Point2D.Double P1, P2;
-                                                       
-                                                       if (howWeGotOutOfLastHelix.getOtherElement() instanceof RNATemplateUnpairedSequence
-                                                                       && howWeGetInCurrentHelix.getOtherElement() instanceof RNATemplateUnpairedSequence) {
-                                                               // We will draw the bases on a Bezier curve
-                                                               P1 = new Point2D.Double();
-                                                               computeBezierTangentVectorTarget(howWeGotOutOfLastHelix, P0, P1);
-                                                               
-                                                               P2 = new Point2D.Double();
-                                                               computeBezierTangentVectorTarget(howWeGetInCurrentHelix, P3, P2);
-                                                       } else {
-                                                               // We will draw the bases on a straight line between P0 and P3
-                                                               P1 = null;
-                                                               P2 = null;
-                                                       }
-                                                       
-                                                       drawAlongCurve(b1, b2, P0, P1, P2, P3, coords, centers, angles, curveMethod, lastMappedHelix.isFlipped(), straightBulges);
-                                               }
-                                               
-                                       } else if (basesInHelixArray[0] > 0) {
-                                               // Here we draw what is before the first mapped helix.
-       
-                                               RNATemplateUnpairedSequence templateSequence;
-                                               // Try to find our template sequence as the mapped element of base 0
-                                               RNATemplateElement templateSequenceCandidate = mapping.getPartner(0);
-                                               if (templateSequenceCandidate != null
-                                                               && templateSequenceCandidate instanceof RNATemplateUnpairedSequence) {
-                                                       templateSequence = (RNATemplateUnpairedSequence) templateSequenceCandidate;
-                                               } else {
-                                                       // Try other idea: first template element if it is a sequence
-                                                       templateSequenceCandidate = template.getFirst();
-                                                       if (templateSequenceCandidate != null
-                                                                       && templateSequenceCandidate instanceof RNATemplateUnpairedSequence) {
-                                                               templateSequence = (RNATemplateUnpairedSequence) templateSequenceCandidate;
-                                                       } else {
-                                                               // We don't know where to start
-                                                               templateSequence = null;
-                                                       }
-                                               }
-                                               
-                                               int b1 = 0;
-                                               int b2 = firstTimeWeMeetThisHelix ? basesInHelixArray[0] : basesInHelixArray[basesInHelixArray.length/2];
-                                               P3.setLocation(coords[b2]);
-                                               
-                                               if (templateSequence != null) {
-                                                       coords[0].setLocation(templateSequence.getVertex5());
-                                                       coords[0].x *= globalIncreaseFactor;
-                                                       coords[0].y *= globalIncreaseFactor;
-                                               } else {
-                                                       // Put b1 at an ideal distance from b2, using the "flat exterior loop" method
-                                                       double idealLength = computeStraightLineIdealLength(b1, b2);
-                                                       Point2D.Double j = new Point2D.Double();
-                                                       if (howWeGetInCurrentHelix != null) {
-                                                               computeHelixEndPointDirections(howWeGetInCurrentHelix, new Point2D.Double(), j);
-                                                       } else {
-                                                               j.setLocation(1, 0);
-                                                       }
-                                                       coords[b1].setLocation(coords[b2].x + j.x*idealLength, coords[b2].y + j.y*idealLength);
-                                               }
-                                               P0.setLocation(coords[0]);
-                                               
-                                               Point2D.Double P1, P2;
-                                               
-                                               if (howWeGetInCurrentHelix.getOtherElement() instanceof RNATemplateUnpairedSequence
-                                                               && templateSequence != null) {
-                                                       // We will draw the bases on a Bezier curve
-                                                       P1 = new Point2D.Double();
-                                                       computeBezierTangentVectorTarget(templateSequence.getIn(), P0, P1);
-                                                       
-                                                       P2 = new Point2D.Double();
-                                                       computeBezierTangentVectorTarget(howWeGetInCurrentHelix, P3, P2);
-                                               } else {
-                                                       // We will draw the bases on a straight line between P0 and P3
-                                                       P1 = null;
-                                                       P2 = null;
-                                               }
-                                               
-                                               drawAlongCurve(b1, b2, P0, P1, P2, P3, coords, centers, angles, curveMethod, false, straightBulges);
-                                       }
-                                       
-                                       lastMappedHelix = helix;
-                                       howWeGotOutOfLastHelix = howWeGetInCurrentHelix.getNextEndPoint();
-                                       if (firstTimeWeMeetThisHelix) {
-                                               howWeGotOutOfLastHelixBaseIndex = basesInHelixArray[basesInHelixArray.length/2-1];
-                                       } else {
-                                               howWeGotOutOfLastHelixBaseIndex = basesInHelixArray[basesInHelixArray.length-1];
-                                       }
-                               }
-                       } // end template iteration
-                       
-                       
-                       // Now we need to draw what is after the last mapped helix.
-                       if (howWeGotOutOfLastHelixBaseIndex < coords.length-1
-                                       && element != null
-                                       && coords.length > 1) {
-                               
-                               RNATemplateUnpairedSequence beginTemplateSequence = null;
-                               if (lastMappedHelix == null) {
-                                       // No helix at all matched between the template and RNA!
-                                       // So the sequence we want to draw is the full RNA.
-                                       
-                                       // Try to find our template sequence as the mapped element of base 0
-                                       RNATemplateElement templateSequenceCandidate = mapping.getPartner(0);
-                                       if (templateSequenceCandidate != null
-                                                       && templateSequenceCandidate instanceof RNATemplateUnpairedSequence) {
-                                               beginTemplateSequence = (RNATemplateUnpairedSequence) templateSequenceCandidate;
-                                       } else {
-                                               // Try other idea: first template element if it is a sequence
-                                               templateSequenceCandidate = template.getFirst();
-                                               if (templateSequenceCandidate != null
-                                                               && templateSequenceCandidate instanceof RNATemplateUnpairedSequence) {
-                                                       beginTemplateSequence = (RNATemplateUnpairedSequence) templateSequenceCandidate;
-                                               } else {
-                                                       // We don't know where to start
-                                                       beginTemplateSequence = null;
-                                               }
-                                       }
-                                       
-                                       if (beginTemplateSequence != null) {
-                                               coords[0].setLocation(beginTemplateSequence.getVertex5());
-                                               coords[0].x *= globalIncreaseFactor;
-                                               coords[0].y *= globalIncreaseFactor;
-                                       }
-                                       
-                               }
-                               
-                               RNATemplateUnpairedSequence endTemplateSequence;
-                               // Try to find our template sequence as the mapped element of last base
-                               RNATemplateElement templateSequenceCandidate = mapping.getPartner(coords.length-1);
-                               if (templateSequenceCandidate != null
-                                               && templateSequenceCandidate instanceof RNATemplateUnpairedSequence) {
-                                       endTemplateSequence = (RNATemplateUnpairedSequence) templateSequenceCandidate;
-                               } else {
-                                       // Try other idea: last template element if it is a sequence
-                                       templateSequenceCandidate = element;
-                                       if (templateSequenceCandidate != null
-                                                       && templateSequenceCandidate instanceof RNATemplateUnpairedSequence) {
-                                               endTemplateSequence = (RNATemplateUnpairedSequence) templateSequenceCandidate;
-                                       } else {
-                                               // We don't know where to end
-                                               endTemplateSequence = null;
-                                       }
-                               }
-                               
-                               int b1 = howWeGotOutOfLastHelixBaseIndex;
-                               int b2 = coords.length - 1;
-                               
-                               if (endTemplateSequence != null) {
-                                       coords[b2].setLocation(endTemplateSequence.getVertex3());
-                                       coords[b2].x *= globalIncreaseFactor;
-                                       coords[b2].y *= globalIncreaseFactor;
-                               } else {
-                                       // Put b2 at an ideal distance from b1, using the "flat exterior loop" method
-                                       double idealLength = computeStraightLineIdealLength(b1, b2);
-                                       Point2D.Double j = new Point2D.Double();
-                                       if (howWeGotOutOfLastHelix != null) {
-                                               computeHelixEndPointDirections(howWeGotOutOfLastHelix, new Point2D.Double(), j);
-                                       } else {
-                                               j.setLocation(1, 0);
-                                       }
-                                       coords[b2].setLocation(coords[b1].x + j.x*idealLength, coords[b1].y + j.y*idealLength);
-                               }
-
-                               
-                               Point2D.Double P0 = new Point2D.Double();
-                               Point2D.Double P3 = new Point2D.Double();
-                               
-                               P0.setLocation(coords[b1]);
-                               P3.setLocation(coords[b2]);
-                               
-                               Point2D.Double P1, P2;
-                               
-                               if (howWeGotOutOfLastHelix != null
-                                               && howWeGotOutOfLastHelix.getOtherElement() instanceof RNATemplateUnpairedSequence
-                                               && endTemplateSequence != null) {
-                                       // We will draw the bases on a Bezier curve
-                                       P1 = new Point2D.Double();
-                                       computeBezierTangentVectorTarget(howWeGotOutOfLastHelix, P0, P1);
-                                       
-                                       P2 = new Point2D.Double();
-                                       computeBezierTangentVectorTarget(endTemplateSequence.getOut(), P3, P2);
-                               } else if (lastMappedHelix == null
-                                               && beginTemplateSequence != null
-                                               && endTemplateSequence != null) {
-                                       // We will draw the bases on a Bezier curve
-                                       P1 = new Point2D.Double();
-                                       computeBezierTangentVectorTarget(beginTemplateSequence.getIn(), P0, P1);
-                                       
-                                       P2 = new Point2D.Double();
-                                       computeBezierTangentVectorTarget(endTemplateSequence.getOut(), P3, P2);
-                               } else {
-                                       // We will draw the bases on a straight line between P0 and P3
-                                       P1 = null;
-                                       P2 = null;
-                               }
-                               
-                               drawAlongCurve(b1, b2, P0, P1, P2, P3, coords, centers, angles, curveMethod, lastMappedHelix != null ? lastMappedHelix.isFlipped() : false, straightBulges);
-                       
-                       }
-                       
-                       
-                       if (helixLengthAdjustmentMethod == DrawRNATemplateMethod.NOINTERSECT && coords.length > 3) {
-                               // Are we happy with this value of globalIncreaseFactor?
-                               Line2D.Double[] lines = new Line2D.Double[coords.length-1];
-                               for (int i=0; i<coords.length-1; i++) {
-                                       lines[i] = new Line2D.Double(coords[i], coords[i+1]);
-                               }
-                               int intersectLines = 0;
-                               for (int i=0; i<lines.length; i++) {
-                                       for (int j=i+2; j<lines.length; j++) {
-                                               if (LinesIntersect.linesIntersect(lines[i], lines[j])) {
-                                                       intersectLines++;
-                                               }
-                                       }
-                               }
-                               // If no intersection we keep this globalIncreaseFactor value
-                               if (intersectLines > 0) {
-                                       // Don't increase more than a maximum value
-                                       if (globalIncreaseFactor < 3) {
-                                               globalIncreaseFactor += 0.1;
-                                               //System.out.println("globalIncreaseFactor increased to " + globalIncreaseFactor);
-                                               // Compute the drawing again
-                                               computeCoords = true;
-                                       }
-                               }
-                       }
-                       
-               }
-               
-               // debug
-               if (helixLengthAdjustmentMethod == DrawRNATemplateMethod.MAXSCALINGFACTOR
-                               || helixLengthAdjustmentMethod == DrawRNATemplateMethod.NOINTERSECT) {
-                       //System.out.println("globalIncreaseFactor = " + globalIncreaseFactor);
-               }
-               
-               // Now we actually move the bases, according to arrays coords and centers
-               // and taking in account the space between bases parameter.
-               for (int i = 0; i < _listeBases.size(); i++) {
-                       _listeBases.get(i).setCoords(
-                                       new Point2D.Double(coords[i].x * conf._spaceBetweenBases,
-                                                       coords[i].y * conf._spaceBetweenBases));
-                       _listeBases.get(i).setCenter(
-                                       new Point2D.Double(centers[i].x * conf._spaceBetweenBases,
-                                                       centers[i].y * conf._spaceBetweenBases));
-               }
-       
-       }
-       
-       
-       
-       
-       
-       
-       /**
-        * IN: Argument helixEndPoint is an IN argument (will be read),
-        * and must contain an helix edge endpoint.
-        * 
-        * The other arguments are OUT arguments
-        * (must be existing objects, content will be overwritten).
-        * 
-        * OUT: The i argument will contain a vector colinear to the vector
-        * from the helix startPosition to endPosition or the opposite
-        * depending on there the endpoint is (the endpoint will be on the
-        * destination side of the vector). ||i|| = 1
-        * 
-        * OUT: The j vector will contain an vector that is colinear
-        * to the last/first base pair connection on the side of this endpoint.
-        * The vector will be oriented to the side of the given endpoint.
-        * ||j|| = 1
-        */
-       private void computeHelixEndPointDirections(
-                       EdgeEndPoint helixEndPoint, // IN
-                       Point2D.Double i, // OUT
-                       Point2D.Double j // OUT
-                       ) {
-               RNATemplateHelix helix = (RNATemplateHelix) helixEndPoint.getElement();
-               Point2D.Double startpos = helix.getStartPosition();
-               Point2D.Double endpos = helix.getEndPosition();
-               Point2D.Double helixVector = new Point2D.Double();
-               switch (helixEndPoint.getPosition()) {
-               case IN1:
-               case OUT2:
-                       helixVector.x = startpos.x - endpos.x;
-                       helixVector.y = startpos.y - endpos.y;
-                       break;
-               case IN2:
-               case OUT1:
-                       helixVector.x = endpos.x - startpos.x;
-                       helixVector.y = endpos.y - startpos.y;
-                       break;
-               }
-               double helixVectorLength = Math.hypot(helixVector.x, helixVector.y);
-               // i is the vector which is colinear to helixVector and such that ||i|| = 1
-               i.x = helixVector.x / helixVectorLength;
-               i.y = helixVector.y / helixVectorLength;
-               // Find j such that it is orthogonal to i, ||j|| = 1
-               // and j goes to the side where the sequence will be connected
-               switch (helixEndPoint.getPosition()) {
-               case IN1:
-               case IN2:
-                       // rotation of +pi/2
-                       j.x = - i.y;
-                       j.y =   i.x;
-                       break;
-               case OUT1:
-               case OUT2:
-                       // rotation of -pi/2
-                       j.x =   i.y;
-                       j.y = - i.x;
-                       break;
-               }
-               if (helix.isFlipped()) {
-                       j.x = - j.x;
-                       j.y = - j.y;
-               }
-
-       }
-       
-       /**
-        * A cubic Bezier curve can be defined by 4 points,
-        * see http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves
-        * For each of the curve end points, there is the last/first point of the
-        * curve and a point which gives the direction and length of the tangent
-        * vector on that side. This two points are respectively curveEndPoint
-        * and curveVectorOtherPoint.
-        * IN:  Argument helixVector is the vector formed by the helix,
-        *      in the right direction for our sequence.
-        * IN:  Argument curveEndPoint is the position of the endpoint on the helix.
-        * OUT: Argument curveVectorOtherPoint must be allocated
-        *      and the values will be modified.
-        */
-       private void computeBezierTangentVectorTarget(
-                       EdgeEndPoint endPoint,
-                       Point2D.Double curveEndPoint,
-                       Point2D.Double curveVectorOtherPoint)
-                       throws RNATemplateDrawingAlgorithmException {
-               
-               boolean sequenceEndPointIsIn;
-               RNATemplateUnpairedSequence sequence;
-               
-               if (endPoint.getElement() instanceof RNATemplateHelix) {
-                       sequence = (RNATemplateUnpairedSequence) endPoint.getOtherElement();
-                       EdgeEndPointPosition endPointPositionOnHelix = endPoint.getPosition();
-                       switch (endPointPositionOnHelix) {
-                       case IN1:
-                       case IN2:
-                               sequenceEndPointIsIn = false;
-                               break;
-                       default:
-                               sequenceEndPointIsIn = true;
-                       }
-                       
-                       EdgeEndPoint endPointOnHelix =
-                               sequenceEndPointIsIn ?
-                                               sequence.getIn().getOtherEndPoint() :
-                                               sequence.getOut().getOtherEndPoint();
-                       if (endPointOnHelix == null) {
-                               throw (new RNATemplateDrawingAlgorithmException("Sequence is not connected to an helix."));
-                       }
-               } else {
-                       // The endpoint is on an unpaired sequence.
-                       sequence = (RNATemplateUnpairedSequence) endPoint.getElement();
-                       if (endPoint == sequence.getIn()) {
-                               // endpoint is 5'
-                               sequenceEndPointIsIn = true;
-                       } else {
-                               sequenceEndPointIsIn = false;
-                       }
-               }
-
-               double l =
-                       sequenceEndPointIsIn ?
-                               sequence.getInTangentVectorLength() :
-                               sequence.getOutTangentVectorLength();
-               
-               // Compute the absolute angle our line makes to the helix
-               double theta =
-                       sequenceEndPointIsIn ?
-                               sequence.getInTangentVectorAngle() :
-                               sequence.getOutTangentVectorAngle();
-               
-               // Compute v, the tangent vector of the Bezier curve
-               Point2D.Double v = new Point2D.Double();
-               v.x = l * Math.cos(theta);
-               v.y = l * Math.sin(theta);
-               curveVectorOtherPoint.x = curveEndPoint.x + v.x;
-               curveVectorOtherPoint.y = curveEndPoint.y + v.y;
-       }
-       
-
-       /**
-        * Compute (actual helix length / helix length in template).
-        * @param straightBulges 
-        */
-       private double computeLengthIncreaseFactor(
-                       int[] basesInHelixArray,  // IN
-                       RNATemplateHelix helix,    // IN
-                       boolean straightBulges
-                       ) {
-               double templateLength = computeHelixTemplateLength(helix);
-               double realLength = computeHelixRealLength(basesInHelixArray,straightBulges);
-               return realLength / templateLength;
-       }
-       
-       /**
-        * Compute (actual helix vector - helix vector in template).
-        */
-       private Point2D.Double computeLengthIncreaseDelta(
-                       int[] basesInHelixArray,  // IN
-                       RNATemplateHelix helix,   // IN
-                       boolean straightBulges
-                       ) {
-               double templateLength = computeHelixTemplateLength(helix);
-               double realLength = computeHelixRealLength(basesInHelixArray,straightBulges);
-               Point2D.Double i = new Point2D.Double();
-               computeTemplateHelixVectors(helix, null, i, null);
-               return new Point2D.Double(i.x*(realLength-templateLength), i.y*(realLength-templateLength));
-       }
-       
-       /**
-        * Compute helix interesting vectors from template helix.
-        * @param helix The template helix you want to compute the vectors from.
-        * @param o This point coordinates will be set the origin of the helix (or not if null),
-        *          ie. the point in the middle of the base pair with the two most extreme bases.
-        * @param i Will be set to the normalized helix vector. (nothing done if null)
-        * @param j Will be set to the normalized helix base pair vector (5' -> 3'). (nothing done if null)
-        */
-       private void computeTemplateHelixVectors(
-                       RNATemplateHelix helix,  // IN
-                       Point2D.Double o,        // OUT
-                       Point2D.Double i,        // OUT
-                       Point2D.Double j         // OUT
-                       ) {
-               Point2D.Double startpos, endpos;
-               if (helix.getIn1Is() == In1Is.IN1_IS_5PRIME) {
-                       startpos = helix.getStartPosition();
-                       endpos = helix.getEndPosition();
-               } else {
-                       endpos = helix.getStartPosition();
-                       startpos = helix.getEndPosition();
-               }
-               if (o != null) {
-                       o.x = startpos.x;
-                       o.y = startpos.y;
-               }
-               if (i != null || j != null) {
-                       // (i_x,i_y) is the vector between two consecutive bases of the same side of an helix
-                       if (i == null)
-                               i = new Point2D.Double();
-                       i.x = (endpos.x - startpos.x);
-                       i.y = (endpos.y - startpos.y);
-                       double i_original_norm = Math.hypot(i.x, i.y);
-                       // change its norm to 1
-                       i.x = i.x / i_original_norm;
-                       i.y = i.y / i_original_norm;
-                       if (j != null) {
-                               j.x = - i.y;
-                               j.y =   i.x;
-                               if (helix.isFlipped()) {
-                                       j.x = - j.x;
-                                       j.y = - j.y;
-                               }
-                               double j_original_norm = Math.hypot(j.x, j.y);
-                               // change (j_x,j_y) so that its norm is 1
-                               j.x = j.x / j_original_norm;
-                               j.y = j.y / j_original_norm;
-                       }
-               }
-       }
-       
-       
-       /**
-        * Estimate bulge arc length.
-        */
-       private double estimateBulgeArcLength(int firstBase, int lastBase) {
-               if (firstBase + 1 == lastBase)
-                       return RNA.LOOP_DISTANCE; // there is actually no bulge
-               double len = 0.0;
-               int k = firstBase;
-               while (k < lastBase) {
-                       int l = _listeBases.get(k).getElementStructure();
-                       if (k < l && l < lastBase) {
-                               len += RNA.BASE_PAIR_DISTANCE;
-                               k = l;
-                       } else {
-                               len += RNA.LOOP_DISTANCE;
-                               k++;
-                       }
-               }
-               return len;
-       }
-       
-       
-       /**
-        * Estimate bulge width, the given first and last bases must be those in the helix.
-        */
-       private double estimateBulgeWidth(int firstBase, int lastBase) {
-               double len = estimateBulgeArcLength(firstBase, lastBase);
-               return 2 * (len / Math.PI);
-       }
-       
-       
-       /**
-        * Get helix length in template.
-        */
-       private double computeHelixTemplateLength(RNATemplateHelix helix) {
-               return Math.hypot(helix.getStartPosition().x - helix.getEndPosition().x,
-                               helix.getStartPosition().y - helix.getEndPosition().y);
-       }
-       
-       
-       /**
-        * Compute helix actual length (as drawHelixLikeTemplateHelix() would draw it).
-        */
-       private double computeHelixRealLength(int[] basesInHelixArray, boolean straightBulges) {
-               return drawHelixLikeTemplateHelix(basesInHelixArray, null, null, null, null, 0, null,straightBulges);
-       }
-       
-       
-       /**
-        * Result type of countUnpairedLine(), see below.
-        */
-       private static class UnpairedLineCounts {
-               public int nBP, nLD, total;
-       }
-       /**
-        * If we are drawing an unpaired region that may contains helices,
-        * and we are drawing it on a line (curve or straight, doesn't matter),
-        * how many intervals should have a base-pair length (start of an helix)
-        * and how many should have a consecutive unpaired bases length?
-        * Returns an array with three elements:
-        * - answer to first question
-        * - answer to second question
-        * - sum of both, ie. total number of intervals
-        *   (this is NOT lastBase-firstBase because bases deep in helices do not count)
-        */
-       private UnpairedLineCounts countUnpairedLine(int firstBase, int lastBase) {
-               UnpairedLineCounts counts = new UnpairedLineCounts();
-               int nBP = 0;
-               int nLD = 0;
-               {
-                       int b = firstBase;
-                       while (b < lastBase) {
-                               int l = _listeBases.get(b).getElementStructure();
-                               if (b < l && l < lastBase) {
-                                       nBP++;
-                                       b = l;
-                               } else {
-                                       nLD++;
-                                       b++;
-                               }
-                       }
-               }
-               counts.nBP = nBP;
-               counts.nLD = nLD;
-               counts.total = nBP + nLD;
-               return counts;
-       }
-       
-       
-       /**
-        * Draw the given helix (given as a *SORTED* array of indexes)
-        * like defined in the given template helix.
-        * OUT: The bases positions are not changed in fact,
-        *      instead the coords and centers arrays are modified.
-        * IN:  The helix origin position is multiplied by scaleHelixOrigin
-        *      and translateVectors.get(helix) is added.
-        * RETURN VALUE:
-        *      The length of the drawn helix.
-        * @param straightBulges 
-        * 
-        */
-       private double drawHelixLikeTemplateHelix(
-                       int[] basesInHelixArray,  // IN
-                       RNATemplateHelix helix,   // IN  (optional, ie. may be null)
-                       Point2D.Double[] coords,  // OUT (optional, ie. may be null)
-                       Point2D.Double[] centers, // OUT (optional, ie. may be null)
-                       double[] angles,  // OUT 
-                       double scaleHelixOrigin,  // IN
-                       Map<RNATemplateHelix, Point2D.Double> translateVectors // IN (optional, ie. may be null)
-, boolean straightBulges
-                       ) {
-               int n = basesInHelixArray.length / 2;
-               if (n == 0)
-                       return 0;
-                // Default values when not template helix is provided:
-               Point2D.Double o = new Point2D.Double(0, 0);
-               Point2D.Double i = new Point2D.Double(1, 0);
-               Point2D.Double j = new Point2D.Double(0, 1);
-               boolean flipped = false;
-               if (helix != null) {
-                       computeTemplateHelixVectors(helix, o, i, j);
-                       flipped = helix.isFlipped();
-               }
-               Point2D.Double li = new Point2D.Double(i.x*RNA.LOOP_DISTANCE, i.y*RNA.LOOP_DISTANCE);
-               // We want o to be the point where the first base (5' end) is
-               o.x = (o.x - j.x * RNA.BASE_PAIR_DISTANCE / 2) * scaleHelixOrigin;
-               o.y = (o.y - j.y * RNA.BASE_PAIR_DISTANCE / 2) * scaleHelixOrigin;
-               if (translateVectors != null && translateVectors.containsKey(helix)) {
-                       Point2D.Double v = translateVectors.get(helix);
-                       o.x = o.x + v.x;
-                       o.y = o.y + v.y;
-               }
-               
-               // We need this array so that we can store positions even if coords == null
-               Point2D.Double[] helixBasesPositions = new Point2D.Double[basesInHelixArray.length];
-               for (int k=0; k<helixBasesPositions.length; k++) {
-                       helixBasesPositions[k] = new Point2D.Double();  
-               }
-               Point2D.Double accDelta = new Point2D.Double(0, 0);
-               for (int k=0; k<n; k++) {
-                       int kp = 2*n-k-1;
-                       Point2D.Double p1 = helixBasesPositions[k]; // we assign the point *reference*
-                       Point2D.Double p2 = helixBasesPositions[kp];
-                       // Do we have a bulge between previous base pair and this one?
-                       boolean bulge = k >= 1 && (basesInHelixArray[k] != basesInHelixArray[k-1] + 1
-                                                          || basesInHelixArray[kp+1] != basesInHelixArray[kp] + 1);
-                       if (k >= 1) {
-                               if (basesInHelixArray[k] < basesInHelixArray[k-1]
-                                   || basesInHelixArray[kp+1] < basesInHelixArray[kp]) {
-                                       throw new Error("Internal bug: basesInHelixArray must be sorted");
-                               }
-                               if (bulge) {
-                                       // Estimate a good distance (delta) between the previous base pair and this one
-                                       double delta1 = estimateBulgeWidth(basesInHelixArray[k-1], basesInHelixArray[k]);
-                                       double delta2 = estimateBulgeWidth(basesInHelixArray[kp], basesInHelixArray[kp+1]);
-                                       // The biggest bulge defines the width
-                                       double delta = Math.max(delta1, delta2);
-
-                                       if (coords != null) {
-                                               // Now, where do we put the bases that are part of the bulge?
-                                               for (int side=0; side<2; side++) {
-                                                       Point2D.Double pstart = new Point2D.Double();
-                                                       Point2D.Double pend = new Point2D.Double();
-                                                       Point2D.Double bisectVect = new Point2D.Double();
-                                                       Point2D.Double is = new Point2D.Double();
-                                                       int firstBase, lastBase;
-                                                       double alphasign = flipped ? -1 : 1;
-                                                       if (side == 0) {
-                                                               firstBase = basesInHelixArray[k-1];
-                                                               lastBase  = basesInHelixArray[k];
-                                                               pstart.setLocation(o.x + accDelta.x,
-                                                                                  o.y + accDelta.y);
-                                                               pend.setLocation(o.x + accDelta.x + i.x*delta,
-                                                                                o.y + accDelta.y + i.y*delta);
-                                                               bisectVect.setLocation(-j.x, -j.y);
-                                                               is.setLocation(i);
-                                                       } else {
-                                                               firstBase = basesInHelixArray[kp];
-                                                               lastBase  = basesInHelixArray[kp+1];
-                                                               pstart.setLocation(o.x + accDelta.x + i.x*delta + j.x*RNA.BASE_PAIR_DISTANCE,
-                                                                          o.y + accDelta.y + i.y*delta + j.y*RNA.BASE_PAIR_DISTANCE);
-                                                               pend.setLocation(o.x + accDelta.x + j.x*RNA.BASE_PAIR_DISTANCE,
-                                                                                o.y + accDelta.y + j.y*RNA.BASE_PAIR_DISTANCE);
-
-                                                               bisectVect.setLocation(j);
-                                                               is.setLocation(-i.x, -i.y);
-                                                       }
-                                                       double arclen = estimateBulgeArcLength(firstBase, lastBase);
-                                                       double centerOnBisect = ComputeArcCenter.computeArcCenter(delta, arclen);
-                                                       
-                                                       // Should we draw the base on an arc or simply use a line?
-                                                       if (centerOnBisect > -1000) {
-                                                               Point2D.Double center = new Point2D.Double(pstart.x + is.x*delta/2 + bisectVect.x*centerOnBisect,
-                                                                                                          pstart.y + is.y*delta/2 + bisectVect.y*centerOnBisect);
-                                                               int b = firstBase;
-                                                               double len = 0;
-                                                               double r = Math.hypot(pstart.x - center.x, pstart.y - center.y);
-                                                               double alpha0 = MiscGeom.angleFromVector(pstart.x - center.x, pstart.y - center.y);
-                                                               while (b < lastBase) {
-                                                                       int l = _listeBases.get(b).getElementStructure();
-                                                                       if (b < l && l < lastBase) {
-                                                                               len += RNA.BASE_PAIR_DISTANCE;
-                                                                               b = l;
-                                                                       } else {
-                                                                               len += RNA.LOOP_DISTANCE;
-                                                                               b++;
-                                                                       }
-                                                                       if (b < lastBase) {
-                                                                               coords[b].x = center.x + r*Math.cos(alpha0 + alphasign*len/r);
-                                                                               coords[b].y = center.y + r*Math.sin(alpha0 + alphasign*len/r);
-                                                                       }
-                                                               }
-                                                       } else {
-                                                               // Draw on a line
-                                                               
-                                                               // Distance between paired bases cannot be changed
-                                                               // (imposed by helix width) but distance between other
-                                                               // bases can be adjusted.
-                                                               UnpairedLineCounts counts = countUnpairedLine(firstBase, lastBase);
-                                                               double LD = Math.max((delta - counts.nBP*RNA.BASE_PAIR_DISTANCE) / (double) counts.nLD, 0);
-                                                               //System.out.println("nBP=" + nBP + " nLD=" + nLD);
-                                                               double len = 0;
-                                                               {
-                                                                       int b = firstBase;
-                                                                       while (b < lastBase) {
-                                                                               int l = _listeBases.get(b).getElementStructure();
-                                                                               if (b < l && l < lastBase) {
-                                                                                       len += RNA.BASE_PAIR_DISTANCE;
-                                                                                       b = l;
-                                                                               } else {
-                                                                                       len += LD;
-                                                                                       b++;
-                                                                               }
-                                                                               if (b < lastBase) {
-                                                                                       coords[b].x = pstart.x + is.x*len;
-                                                                                       coords[b].y = pstart.y + is.y*len;
-                                                                               }
-                                                                       }
-                                                               }
-                                                               //System.out.println("len=" + len + " delta=" + delta + " d(pstart,pend)=" + Math.hypot(pend.x-pstart.x, pend.y-pstart.y));
-                                                       }
-                                                       
-                                                       // Does the bulge contain an helix?
-                                                       // If so, use drawLoop() to draw it.
-                                                       {
-                                                               int b = firstBase;
-                                                               while (b < lastBase) {
-                                                                       int l = _listeBases.get(b).getElementStructure();
-                                                                       if (b < l && l < lastBase) {
-                                                                               // Helix present in bulge
-                                                                               Point2D.Double b1pos = coords[b];
-                                                                               Point2D.Double b2pos = coords[l];
-                                                                               double beta = MiscGeom.angleFromVector(b2pos.x - b1pos.x, b2pos.y - b1pos.y) - Math.PI / 2 + (flipped ? Math.PI : 0);
-                                                                               Point2D.Double loopCenter = new Point2D.Double((b1pos.x + b2pos.x)/2, (b1pos.y + b2pos.y)/2);
-                                                                               rna.drawLoop(b,
-                                                                                                l,
-                                                                                                loopCenter.x,
-                                                                                                loopCenter.y,
-                                                                                                beta,
-                                                                                                coords,
-                                                                                                centers,
-                                                                                                angles,
-                                                                                                straightBulges);
-                                                                               // If the helix is flipped, we need to compute the symmetric
-                                                                               // of the whole loop.
-                                                                               if (helix.isFlipped()) {
-                                                                                       Point2D.Double v = new Point2D.Double(Math.cos(beta), Math.sin(beta));
-                                                                                       symmetric(loopCenter, v, coords, b, l);
-                                                                                       symmetric(loopCenter, v, centers, b, l);
-                                                                               }
-                                                                               // Continue
-                                                                               b = l;
-                                                                       } else {
-                                                                               b++;
-                                                                       }
-                                                               }
-                                                       }
-                                               }
-                                       }
-                                       
-                                       accDelta.x += i.x*delta;
-                                       accDelta.y += i.y*delta;
-                                       p1.x = o.x + accDelta.x;
-                                       p1.y = o.y + accDelta.y;
-                                       p2.x = p1.x + j.x*RNA.BASE_PAIR_DISTANCE;
-                                       p2.y = p1.y + j.y*RNA.BASE_PAIR_DISTANCE;
-                                       
-                               } else {
-                                       accDelta.x += li.x;
-                                       accDelta.y += li.y;
-                                       p1.x = o.x + accDelta.x;
-                                       p1.y = o.y + accDelta.y;
-                                       p2.x = p1.x + j.x*RNA.BASE_PAIR_DISTANCE;
-                                       p2.y = p1.y + j.y*RNA.BASE_PAIR_DISTANCE;
-                               }
-                       } else {
-                               // First base pair
-                               p1.x = o.x;
-                               p1.y = o.y;
-                               p2.x = p1.x + j.x*RNA.BASE_PAIR_DISTANCE;
-                               p2.y = p1.y + j.y*RNA.BASE_PAIR_DISTANCE;
-                       }
-               }
-               
-               Point2D.Double p1 = helixBasesPositions[0];
-               Point2D.Double p2 = helixBasesPositions[n-1];
-               
-               if (coords != null) {
-                       for (int k=0; k<helixBasesPositions.length; k++) {
-                               coords[basesInHelixArray[k]] = helixBasesPositions[k];
-                       }
-               }
-               
-               return Math.hypot(p2.x-p1.x, p2.y-p1.y);
-       }
-       
-       
-       
-
-       /**
-        * Return ideal length to draw unpaired region from firstBase to lastBase.
-        */
-       private double computeStraightLineIdealLength(int firstBase, int lastBase) {
-               UnpairedLineCounts counts = countUnpairedLine(firstBase, lastBase);
-               return RNA.BASE_PAIR_DISTANCE*counts.nBP + RNA.LOOP_DISTANCE*counts.nLD;
-       }
-       
-       /**
-        * Like drawOnBezierCurve(), but on a straight line.
-        */
-       private boolean drawOnStraightLine(
-                       int firstBase,
-                       int lastBase,
-                       Point2D.Double P0,
-                       Point2D.Double P3,
-                       Point2D.Double[] coords,
-                       Point2D.Double[] centers,
-                       boolean cancelIfNotGood) {
-               
-               Point2D.Double vector = new Point2D.Double(P3.x - P0.x, P3.y - P0.y); 
-               double vectorNorm = Math.hypot(vector.x, vector.y);
-
-               UnpairedLineCounts counts = countUnpairedLine(firstBase, lastBase);
-               double LD = Math.max((vectorNorm - counts.nBP*RNA.BASE_PAIR_DISTANCE) / (double) counts.nLD, 0);
-               
-               if (cancelIfNotGood && LD < RNA.LOOP_DISTANCE*0.75) {
-                       // Bases would be drawn "too" near (0.75 is heuristic)
-                       return false;
-               }
-               
-               double len = 0;
-               {
-                       int b = firstBase;
-                       while (b <= lastBase) {
-                               coords[b].x = P0.x + vector.x*len/vectorNorm;
-                               coords[b].y = P0.y + vector.y*len/vectorNorm;
-                               int l = _listeBases.get(b).getElementStructure();
-                               if (b < l && l < lastBase) {
-                                       len += RNA.BASE_PAIR_DISTANCE;
-                                       b = l;
-                               } else {
-                                       len += LD;
-                                       b++;
-                               }
-                       }
-               }
-               
-               return true;
-       }
-       
-       
-
-
-       /**
-        * A Bezier curve can be defined by four points,
-        * see http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves
-        * Here we give this four points and an array of bases indexes
-        * (which must be indexes in this RNA sequence) which will be moved
-        * to be on the Bezier curve.
-        * The bases positions are not changed in fact, instead the coords and
-        * centers arrays are modified.
-        * If cancelIfNotGood, draw only if it would look good,
-        * otherwise just return false.
-        */
-       private boolean drawOnBezierCurve(
-                       int firstBase,
-                       int lastBase,
-                       Point2D.Double P0,
-                       Point2D.Double P1,
-                       Point2D.Double P2,
-                       Point2D.Double P3,
-                       Point2D.Double[] coords,
-                       Point2D.Double[] centers,
-                       boolean cancelIfNotGood) {
-               
-               UnpairedLineCounts counts = countUnpairedLine(firstBase, lastBase);
-               
-               // Draw the bases of the sequence along a Bezier curve
-               int n = counts.total;
-               
-               // We choose to approximate the Bezier curve by 10*n straight lines.
-               CubicBezierCurve bezier = new CubicBezierCurve(P0, P1, P2, P3, 10*n);
-               double curveLength = bezier.getApproxCurveLength();
-               
-               
-               double LD = Math.max((curveLength - counts.nBP*RNA.BASE_PAIR_DISTANCE) / (double) counts.nLD, 0);
-               
-               if (cancelIfNotGood && LD < RNA.LOOP_DISTANCE*0.75) {
-                       // Bases would be drawn "too" near (0.75 is heuristic)
-                       return false;
-               }
-               
-               double[] t = new double[n+1];
-
-               {
-                       double len = 0;
-                       int k = 0;
-                       int b = firstBase;
-                       while (b <= lastBase) {
-                               t[k] = len;
-                               k++;
-                               
-                               int l = _listeBases.get(b).getElementStructure();
-                               if (b < l && l < lastBase) {
-                                       len += RNA.BASE_PAIR_DISTANCE;
-                                       b = l;
-                               } else {
-                                       len += LD;
-                                       b++;
-                               }
-                       }
-               }
-               
-               Point2D.Double[] sequenceBasesCoords = bezier.uniformParam(t);
-               
-               {
-                       int k = 0;
-                       int b = firstBase;
-                       while (b <= lastBase) {
-                               coords[b] = sequenceBasesCoords[k];
-                               int l = _listeBases.get(b).getElementStructure();
-                               if (b < l && l < lastBase) {
-                                       b = l;
-                               } else {
-                                       b++;
-                               }
-                               k++;
-                       }
-               }
-
-               return true;
-       }
-       
-       
-       
-       private void drawOnEllipse(
-                       int firstBase,
-                       int lastBase,
-                       Point2D.Double P0,
-                       Point2D.Double P3,
-                       Point2D.Double[] coords,
-                       Point2D.Double[] centers,
-                       boolean reverse) {              
-
-               UnpairedLineCounts counts = countUnpairedLine(firstBase, lastBase);
-               double halfEllipseLength = RNA.BASE_PAIR_DISTANCE*counts.nBP + RNA.LOOP_DISTANCE*counts.nLD;
-               double fullEllipseLength = halfEllipseLength*2;
-               
-               double axisA = P0.distance(P3)/2;
-               double axisB = ComputeEllipseAxis.computeEllipseAxis(axisA, fullEllipseLength);
-               
-               if (axisB == 0) {
-                       // Ellipse is in fact a line, and it is much faster to draw it as such.
-                       drawOnStraightLine(firstBase, lastBase, P0, P3, coords, centers, false);
-                       return;
-               }
-               
-               //System.out.println("Ellipse a=" + axisA + " b=" + axisB);
-               
-               int n = counts.total;
-               
-               // We choose to approximate the Bezier curve by 10*n straight lines.
-               HalfEllipse curve = new HalfEllipse(axisA, axisB, 10*n);
-               double curveLength = curve.getApproxCurveLength();
-               
-               
-               double LD = Math.max((curveLength - counts.nBP*RNA.BASE_PAIR_DISTANCE) / (double) counts.nLD, 0);
-               
-               double[] t = new double[n+1];
-
-               {
-                       double len = 0;
-                       int k = 0;
-                       int b = firstBase;
-                       while (b <= lastBase) {
-                               t[k] = len;
-                               k++;
-                               
-                               int l = _listeBases.get(b).getElementStructure();
-                               if (b < l && l < lastBase) {
-                                       len += RNA.BASE_PAIR_DISTANCE;
-                                       b = l;
-                               } else {
-                                       len += LD;
-                                       b++;
-                               }
-                       }
-               }
-               
-               // Ellipse with axis = X,Y
-               Point2D.Double[] sequenceBasesCoords = curve.uniformParam(t);
-               
-               // Compute the symmetric half-ellipse
-               if (reverse) {
-                       AffineTransform tranform1 = new AffineTransform();
-                       tranform1.scale(1, -1);
-                       tranform1.transform(sequenceBasesCoords, 0, sequenceBasesCoords, 0, sequenceBasesCoords.length);
-               }
-
-               // Translate + rotate such that ellipse is at the right place
-               AffineTransform tranform = HalfEllipse.matchAxisA(P0, P3);
-               tranform.transform(sequenceBasesCoords, 0, sequenceBasesCoords, 0, sequenceBasesCoords.length);
-               
-               {
-                       int k = 0;
-                       int b = firstBase;
-                       while (b <= lastBase) {
-                               coords[b] = sequenceBasesCoords[k];
-                               //coords[b] = curve.standardParam((double) k/n);
-                               //System.out.println(b + " " + coords[b]);
-                               int l = _listeBases.get(b).getElementStructure();
-                               if (b < l && l < lastBase) {
-                                       b = l;
-                               } else {
-                                       b++;
-                               }
-                               k++;
-                       }
-               }
-
-       }
-       
-       /**
-        * This functions draws the RNA sequence between (including)
-        * firstBase and lastBase along a curve.
-        * The sequence may contain helices.
-        * 
-        * Bezier curve:
-        * A Bezier curve can be defined by four points,
-        * see http://en.wikipedia.org/wiki/Bezier_curve#Cubic_B.C3.A9zier_curves
-        * 
-        * Straight line:
-        * If P1 and P2 are null, the bases are drawn on a straight line.
-        * 
-        * OUT: The bases positions are not changed in fact,
-        * instead the coords and centers arrays are modified.
-        * 
-        * Argument reverse says if we should reverse the direction of inserted helices.
-        */
-       private void drawAlongCurve(
-                       int firstBase,
-                       int lastBase,
-                       Point2D.Double P0,
-                       Point2D.Double P1,
-                       Point2D.Double P2,
-                       Point2D.Double P3,
-                       Point2D.Double[] coords,
-                       Point2D.Double[] centers,
-                       double[] angles,
-                       DrawRNATemplateCurveMethod curveMethod,
-                       boolean reverse,
-                       boolean straightBulges) {
-               
-               // First we find the bases which are directly on the Bezier curve
-               ArrayList<Integer> alongBezierCurve = new ArrayList<Integer>();
-               for (int depth=0, i=firstBase; i<=lastBase; i++) {
-                       int k = _listeBases.get(i).getElementStructure();
-                       if (k < 0 || k > lastBase || k < firstBase) {
-                               if (depth == 0) {
-                                       alongBezierCurve.add(i);
-                               }
-                       } else {
-                               if (i < k) {
-                                       if (depth == 0) {
-                                               alongBezierCurve.add(i);
-                                               alongBezierCurve.add(k);
-                                       }
-                                       depth++;
-                               } else {
-                                       depth--;
-                               }
-                       }
-               }
-               // number of bases along the Bezier curve
-               int n = alongBezierCurve.size();
-               int[] alongBezierCurveArray = RNATemplateAlign.intArrayFromList(alongBezierCurve);
-               if (n > 0) {
-                       if (curveMethod == DrawRNATemplateCurveMethod.ALWAYS_REPLACE_BY_ELLIPSES) {
-                               drawOnEllipse(firstBase, lastBase, P0, P3, coords, centers, reverse);
-                       } else if (curveMethod == DrawRNATemplateCurveMethod.SMART) {
-                               boolean passed;
-                               if (P1 != null && P2 != null) {
-                                       passed = drawOnBezierCurve(firstBase, lastBase, P0, P1, P2, P3, coords, centers, true);
-                               } else {
-                                       passed = drawOnStraightLine(firstBase, lastBase, P0, P3, coords, centers, true);
-                               }
-                               if (!passed) {
-                                       drawOnEllipse(firstBase, lastBase, P0, P3, coords, centers, reverse);
-                               }
-                       } else {
-                               if (P1 != null && P2 != null) {
-                                       drawOnBezierCurve(firstBase, lastBase, P0, P1, P2, P3, coords, centers, false);
-                               } else {
-                                       drawOnStraightLine(firstBase, lastBase, P0, P3, coords, centers, false);
-                               }
-                       }
-               }
-               // Now use the radiate algorithm to draw the helixes
-               for (int k=0; k<n-1; k++) {
-                       int b1 = alongBezierCurveArray[k];
-                       int b2 = alongBezierCurveArray[k+1];
-                       if (_listeBases.get(b1).getElementStructure() == b2) {
-                               Point2D.Double b1pos = coords[b1];
-                               Point2D.Double b2pos = coords[b2];
-                               double alpha = MiscGeom.angleFromVector(b2pos.x - b1pos.x, b2pos.y - b1pos.y);
-                               rna.drawLoop(b1,
-                                                b2,
-                                                (b1pos.x + b2pos.x)/2,
-                                                (b1pos.y + b2pos.y)/2,
-                                                alpha - Math.PI / 2,
-                                                coords,
-                                                centers,
-                                                angles,
-                                                straightBulges);
-                               if (reverse) {
-                                       Point2D.Double symAxisVect = new Point2D.Double(coords[b2].x - coords[b1].x, coords[b2].y - coords[b1].y); 
-                                       symmetric(coords[b1], symAxisVect, coords, b1, b2);
-                                       symmetric(coords[b1], symAxisVect, centers, b1, b2);
-                               }
-                       }
-               }       
-       }
-       
-       
-       /**
-        * Compute the symmetric of all the points from first to last in the points array
-        * relative to the line that goes through p and has director vector v.
-        * The array is modified in-place.
-        */
-       private static void symmetric(
-                       Point2D.Double p,
-                       Point2D.Double v,
-                       Point2D.Double[] points,
-                       int first,
-                       int last) {
-               // ||v||^2
-               double lv = v.x*v.x + v.y*v.y;
-               for (int i=first; i<=last; i++) {
-                       // A is the coordinates of points[i] after moving the origin at p
-                       Point2D.Double A = new Point2D.Double(points[i].x - p.x, points[i].y - p.y);
-                       // Symmetric of A
-                       Point2D.Double B = new Point2D.Double(
-                                       -(A.x*v.y*v.y - 2*A.y*v.x*v.y - A.x*v.x*v.x) / lv,
-                                        (A.y*v.y*v.y + 2*A.x*v.x*v.y - A.y*v.x*v.x) / lv);
-                       // Change the origin back
-                       points[i].x = B.x + p.x;
-                       points[i].y = B.y + p.y;
-               }
-       }
-       
-       private void computeHelixTranslations(
-                       Tree<RNANodeValueTemplate> tree, // IN
-                       Map<RNATemplateHelix, Point2D.Double> translateVectors, // OUT (must be initialized)
-                       RNATemplateMapping mapping,      // IN
-                       Point2D.Double parentDeltaVector, // IN
-                       boolean straightBulges
-       ) {
-               RNANodeValueTemplate nvt = tree.getValue();
-               Point2D.Double newDeltaVector = parentDeltaVector;
-               if (nvt instanceof RNANodeValueTemplateBasePair) {
-                       RNATemplateHelix helix = ((RNANodeValueTemplateBasePair) nvt).getHelix();
-                       if (! translateVectors.containsKey(helix)) {
-                               translateVectors.put(helix, parentDeltaVector);
-                               int[] basesInHelixArray;
-                               if (mapping.getAncestor(helix) != null) {
-                                       basesInHelixArray = RNATemplateAlign.intArrayFromList(mapping.getAncestor(helix));
-                                       Arrays.sort(basesInHelixArray);
-                               } else {
-                                       basesInHelixArray = new int[0];
-                               }
-                               Point2D.Double helixDeltaVector = computeLengthIncreaseDelta(basesInHelixArray, helix, straightBulges);
-                               newDeltaVector = new Point2D.Double(parentDeltaVector.x+helixDeltaVector.x, parentDeltaVector.y+helixDeltaVector.y);
-                       } 
-               }
-               for (Tree<RNANodeValueTemplate> subtree: tree.getChildren()) {
-                       computeHelixTranslations(subtree, translateVectors, mapping, newDeltaVector, straightBulges);
-               }
-       }
-       
-       private Map<RNATemplateHelix, Point2D.Double> computeHelixTranslations(
-                       Tree<RNANodeValueTemplate> tree, // IN
-                       RNATemplateMapping mapping,       // IN
-                       boolean straightBulges
-       ) {
-               Map<RNATemplateHelix, Point2D.Double> translateVectors = new HashMap<RNATemplateHelix, Point2D.Double>();
-               computeHelixTranslations(tree, translateVectors, mapping, new Point2D.Double(0,0), straightBulges);
-               return translateVectors;
-       }
-}