2 VARNA is a tool for the automated drawing, visualization and annotation of the secondary structure of RNA, designed as a companion software for web servers and databases.
3 Copyright (C) 2008 Kevin Darty, Alain Denise and Yann Ponty.
4 electronic mail : Yann.Ponty@lri.fr
5 paper mail : LRI, bat 490 Université Paris-Sud 91405 Orsay Cedex France
7 This file is part of VARNA version 3.1.
8 VARNA version 3.1 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 VARNA version 3.1 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along with VARNA version 3.1.
16 If not, see http://www.gnu.org/licenses.
18 package fr.orsay.lri.varna.models.rna;
20 import java.awt.Color;
21 import java.awt.Point;
22 import java.awt.geom.GeneralPath;
23 import java.awt.geom.Point2D;
24 import java.awt.geom.Rectangle2D;
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.FileOutputStream;
28 import java.io.FileWriter;
29 import java.io.IOException;
30 import java.io.ObjectInputStream;
31 import java.io.ObjectOutputStream;
32 import java.io.OutputStreamWriter;
33 import java.io.Reader;
34 import java.io.Serializable;
35 import java.io.StreamTokenizer;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.Comparator;
40 import java.util.HashSet;
41 import java.util.Hashtable;
42 import java.util.List;
44 import java.util.Stack;
45 import java.util.Vector;
47 import javax.xml.transform.sax.TransformerHandler;
49 import org.xml.sax.SAXException;
50 import org.xml.sax.helpers.AttributesImpl;
52 import fr.orsay.lri.varna.VARNAPanel;
53 import fr.orsay.lri.varna.applications.templateEditor.Couple;
54 import fr.orsay.lri.varna.exceptions.ExceptionExportFailed;
55 import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax;
56 import fr.orsay.lri.varna.exceptions.ExceptionNAViewAlgorithm;
57 import fr.orsay.lri.varna.exceptions.ExceptionPermissionDenied;
58 import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses;
59 import fr.orsay.lri.varna.exceptions.ExceptionWritingForbidden;
60 import fr.orsay.lri.varna.factories.RNAFactory;
61 import fr.orsay.lri.varna.interfaces.InterfaceVARNAListener;
62 import fr.orsay.lri.varna.interfaces.InterfaceVARNAObservable;
63 import fr.orsay.lri.varna.models.VARNAConfig;
64 import fr.orsay.lri.varna.models.VARNAConfig.BP_STYLE;
65 import fr.orsay.lri.varna.models.annotations.ChemProbAnnotation;
66 import fr.orsay.lri.varna.models.annotations.HighlightRegionAnnotation;
67 import fr.orsay.lri.varna.models.annotations.TextAnnotation;
68 import fr.orsay.lri.varna.models.export.PSExport;
69 import fr.orsay.lri.varna.models.export.SVGExport;
70 import fr.orsay.lri.varna.models.export.SecStrDrawingProducer;
71 import fr.orsay.lri.varna.models.export.TikzExport;
72 import fr.orsay.lri.varna.models.export.XFIGExport;
73 import fr.orsay.lri.varna.models.naView.NAView;
74 import fr.orsay.lri.varna.models.rna.ModeleBackboneElement.BackboneType;
75 import fr.orsay.lri.varna.models.templates.DrawRNATemplateCurveMethod;
76 import fr.orsay.lri.varna.models.templates.DrawRNATemplateMethod;
77 import fr.orsay.lri.varna.models.templates.RNATemplate;
78 import fr.orsay.lri.varna.models.templates.RNATemplateDrawingAlgorithmException;
79 import fr.orsay.lri.varna.models.templates.RNATemplateMapping;
80 import fr.orsay.lri.varna.utils.RNAMLParser;
81 import fr.orsay.lri.varna.utils.XMLUtils;
82 import fr.orsay.lri.varna.views.VueUI;
85 * The RNA model which contain the base list and the draw algorithm mode
90 public class RNA extends InterfaceVARNAObservable implements Serializable {
94 private static final long serialVersionUID = 7541274455751497303L;
97 * Selects the "Feynman diagram" drawing algorithm that places the bases on
98 * a circle and draws the base-pairings as chords of the circle graph.
101 public static final int DRAW_MODE_CIRCULAR = 1;
103 * Selects the "tree drawing" algorithm. Draws each loop on a circle whose
104 * radius depends on the number of bases involved in the loop. As some
105 * helices can be overlapping in the result, basic interaction is provided
106 * so that the user can "disentangle" the drawing by spinning the helices
107 * around the axis defined by their multiloop (bulge or internal loop)
108 * origin. This is roughly the initial placement strategy of RNAViz.
110 * @see <a href="http://rnaviz.sourceforge.net/">RNAViz</a>
112 public static final int DRAW_MODE_RADIATE = 2;
115 * Selects the NAView algorithm.
117 public static final int DRAW_MODE_NAVIEW = 3;
119 * Selects the linear algorithm.
121 public static final int DRAW_MODE_LINEAR = 4;
123 public static final int DRAW_MODE_VARNA_VIEW = 5;
126 * Selects the RNAView algorithm.
128 public static final int DRAW_MODE_MOTIFVIEW = 6;
130 public static final int DRAW_MODE_TEMPLATE = 7;
132 public static final int DEFAULT_DRAW_MODE = DRAW_MODE_RADIATE;
134 public int BASE_RADIUS = 10;
135 public static final double LOOP_DISTANCE = 40.0; // distance between base
137 public static final double BASE_PAIR_DISTANCE = 65.0; // distance between
140 public static final double MULTILOOP_DISTANCE = 35.0;
141 public static final double VIRTUAL_LOOP_RADIUS = 40.0;
143 public double CHEM_PROB_DIST = 14;
144 public double CHEM_PROB_BASE_LENGTH = 30;
145 public double CHEM_PROB_ARROW_HEIGHT = 10;
146 public double CHEM_PROB_ARROW_WIDTH = 5;
147 public double CHEM_PROB_TRIANGLE_WIDTH = 2.5;
148 public double CHEM_PROB_PIN_SEMIDIAG = 6;
149 public double CHEM_PROB_DOT_RADIUS = 6.;
150 public static double CHEM_PROB_ARROW_THICKNESS = 2.0;
152 public static ArrayList<String> NormalBases = new ArrayList<String>();
154 NormalBases.add("a");
155 NormalBases.add("c");
156 NormalBases.add("g");
157 NormalBases.add("u");
158 NormalBases.add("t");
161 public GeneralPath _debugShape = null;
164 * The draw algorithm mode
166 private int _drawMode = DRAW_MODE_RADIATE;
167 private boolean _drawn = false;
168 private String _name = "";
169 private String _id = "";
170 public double _bpHeightIncrement = VARNAConfig.DEFAULT_BP_INCREMENT;
174 private ArrayList<ModeleBase> _listeBases;
178 StructureTemp _listStrands = new StructureTemp();
180 * Additional bonds and info can be specified here.
182 private ArrayList<ModeleBP> _structureAux = new ArrayList<ModeleBP>();
183 private ArrayList<TextAnnotation> _listeAnnotations = new ArrayList<TextAnnotation>();
184 private ArrayList<HighlightRegionAnnotation> _listeRegionHighlights = new ArrayList<HighlightRegionAnnotation>();
185 private ArrayList<ChemProbAnnotation> _chemProbAnnotations = new ArrayList<ChemProbAnnotation>();
186 private ModeleBackbone _backbone = new ModeleBackbone();
188 public static String XML_ELEMENT_NAME = "RNA";
189 public static String XML_VAR_BASE_SPACING_NAME = "spacing";
190 public static String XML_VAR_DRAWN_NAME = "drawn";
191 public static String XML_VAR_NAME_NAME = "name";
192 public static String XML_VAR_DRAWN_MODE_NAME = "mode";
193 public static String XML_VAR_ID_NAME = "id";
194 public static String XML_VAR_BP_HEIGHT_NAME = "delta";
195 public static String XML_VAR_BASES_NAME = "bases";
196 public static String XML_VAR_BASEPAIRS_NAME = "BPs";
197 public static String XML_VAR_ANNOTATIONS_NAME = "annotations";
198 public static String XML_VAR_BACKBONE_NAME = "backbone";
200 public void toXML(TransformerHandler hd) throws SAXException {
201 AttributesImpl atts = new AttributesImpl();
202 atts.addAttribute("", "", XML_VAR_DRAWN_NAME, "CDATA", "" + _drawn);
203 atts.addAttribute("", "", XML_VAR_DRAWN_MODE_NAME, "CDATA", ""
205 atts.addAttribute("", "", XML_VAR_ID_NAME, "CDATA", "" + _id);
206 atts.addAttribute("", "", XML_VAR_BP_HEIGHT_NAME, "CDATA", ""
207 + _bpHeightIncrement);
208 hd.startElement("", "", XML_ELEMENT_NAME, atts);
211 hd.startElement("", "", XML_VAR_NAME_NAME, atts);
212 XMLUtils.exportCDATAString(hd, "" + _name);
213 hd.endElement("", "", XML_VAR_NAME_NAME);
216 hd.startElement("", "", XML_VAR_BASES_NAME, atts);
217 for (ModeleBase mb : _listeBases) {
220 hd.endElement("", "", XML_VAR_BASES_NAME);
223 hd.startElement("", "", XML_VAR_BASEPAIRS_NAME, atts);
224 for (ModeleBP mbp : getSecStrBPs()) {
227 for (ModeleBP mbp : _structureAux) {
228 mbp.toXML(hd, false);
230 hd.endElement("", "", XML_VAR_BASEPAIRS_NAME);
233 getBackbone().toXML(hd);
236 hd.startElement("", "", XML_VAR_ANNOTATIONS_NAME, atts);
237 for (TextAnnotation ta : _listeAnnotations) {
240 for (HighlightRegionAnnotation hra : _listeRegionHighlights) {
243 for (ChemProbAnnotation cpa : _chemProbAnnotations) {
246 hd.endElement("", "", XML_VAR_ANNOTATIONS_NAME);
247 hd.endElement("", "", XML_ELEMENT_NAME);
250 public ModeleBackbone getBackbone() {
254 public void setBackbone(ModeleBackbone b) {
258 transient private ArrayList<InterfaceVARNAListener> _listeVARNAListener = new ArrayList<InterfaceVARNAListener>();
264 public RNA(String name) {
266 _listeBases = new ArrayList<ModeleBase>();
271 public String toString() {
272 if (_name.equals("")) {
273 return getStructDBN();
280 _drawMode = r._drawMode;
281 _listeBases.addAll(r._listeBases);
282 _listeVARNAListener = (ArrayList<InterfaceVARNAListener>) r._listeVARNAListener;
290 public void saveRNADBN(String path, String title)
291 throws ExceptionWritingForbidden {
293 FileWriter out = new FileWriter(path);
294 if (!title.equals("")) {
295 out.write("> " + title + "\n");
297 out.write(getListeBasesToString());
300 for (int i = 0; i < _listeBases.size(); i++) {
301 if (_listeBases.get(i).getElementStructure() == -1) {
304 if (_listeBases.get(i).getElementStructure() > i) {
314 } catch (IOException e) {
315 throw new ExceptionWritingForbidden(e.getMessage());
319 public Color getBaseInnerColor(int i, VARNAConfig conf) {
320 Color result = _listeBases.get(i).getStyleBase().getBaseInnerColor();
321 String res = _listeBases.get(i).getContent();
322 if (conf._drawColorMap) {
323 result = conf._cm.getColorForValue(_listeBases.get(i).getValue());
324 } else if ((conf._colorDashBases && (res.contains("-")))) {
325 result = conf._dashBasesColor;
326 } else if ((conf._colorSpecialBases && !NormalBases.contains(res
328 result = conf._specialBasesColor;
333 public Color getBaseOuterColor(int i, VARNAConfig conf) {
334 Color result = _listeBases.get(i).getStyleBase()
335 .getBaseOutlineColor();
339 private static double correctComponent(double c)
345 c = Math.pow(((c+0.055)/1.055) , 2.4);
348 public static double getLuminance(Color c)
350 return 0.2126 * correctComponent(c.getRed()) + 0.7152 * correctComponent(c.getGreen()) + 0.0722 * correctComponent(c.getBlue());
353 public static boolean whiteLabelPreferrable(Color c)
355 if (getLuminance(c) > 0.32)
362 public Color getBaseNameColor(int i, VARNAConfig conf) {
363 Color result = _listeBases.get(i).getStyleBase().getBaseNameColor();
364 if ( RNA.whiteLabelPreferrable(getBaseInnerColor(i, conf)))
372 public Color getBasePairColor(ModeleBP bp, VARNAConfig conf) {
373 Color bondColor = conf._bondColor;
374 if (conf._useBaseColorsForBPs) {
375 bondColor = _listeBases.get(bp.getPartner5().getIndex())
376 .getStyleBase().getBaseInnerColor();
379 bondColor = bp.getStyle().getColor(bondColor);
384 public double getBasePairThickness(ModeleBP bp, VARNAConfig conf) {
385 double thickness = bp.getStyle().getThickness(conf._bpThickness);
389 private void drawSymbol(SecStrDrawingProducer out, double posx,
390 double posy, double normx, double normy, double radius,
391 boolean isCIS, ModeleBP.Edge e, double thickness) {
392 Color bck = out.getCurrentColor();
396 out.fillCircle(posx, posy, (radius / 2.0), thickness, bck);
398 out.fillCircle(posx, posy, (radius / 2.0), thickness,
401 out.drawCircle(posx, posy, (radius / 2.0), thickness);
405 double xtab[] = new double[4];
406 double ytab[] = new double[4];
407 xtab[0] = posx - radius * normx / 2.0 - radius * normy / 2.0;
408 ytab[0] = posy - radius * normy / 2.0 + radius * normx / 2.0;
409 xtab[1] = posx + radius * normx / 2.0 - radius * normy / 2.0;
410 ytab[1] = posy + radius * normy / 2.0 + radius * normx / 2.0;
411 xtab[2] = posx + radius * normx / 2.0 + radius * normy / 2.0;
412 ytab[2] = posy + radius * normy / 2.0 - radius * normx / 2.0;
413 xtab[3] = posx - radius * normx / 2.0 + radius * normy / 2.0;
414 ytab[3] = posy - radius * normy / 2.0 - radius * normx / 2.0;
416 out.fillPolygon(xtab, ytab, bck);
418 out.fillPolygon(xtab, ytab, Color.white);
420 out.drawPolygon(xtab, ytab, thickness);
425 double ix = radius * normx / 2.0;
426 double iy = radius * normy / 2.0;
427 double jx = radius * normy / 2.0;
428 double jy = -radius * normx / 2.0;
429 double xtab[] = new double[3];
430 double ytab[] = new double[3];
431 xtab[0] = posx - ix + jx;
432 ytab[0] = posy - iy + jy;
433 xtab[1] = posx + ix + jx;
434 ytab[1] = posy + iy + jy;
439 out.fillPolygon(xtab, ytab, bck);
441 out.fillPolygon(xtab, ytab, Color.white);
443 out.drawPolygon(xtab, ytab, thickness);
451 private void drawBasePairArc(SecStrDrawingProducer out, int i, int j,
452 Point2D.Double orig, Point2D.Double dest, ModeleBP style,
456 Point2D.Double center = new Point2D.Double((orig.x + dest.x)/2., (orig.y + dest.y)/2. + BASE_RADIUS);
458 coef = _bpHeightIncrement * 2;
460 coef = _bpHeightIncrement * 1;
461 distance = (int) Math.round(dest.x - orig.x);
462 if (conf._mainBPStyle != BP_STYLE.LW) {
463 out.drawArc(center, distance, distance * coef, 180, 0);
465 double thickness = getBasePairThickness(style, conf);
466 double radiusCircle = ((BASE_PAIR_DISTANCE - BASE_RADIUS) / 5.0);
468 if (style.isCanonical()) {
469 if (style.isCanonicalGC()) {
470 if ((orig.x != dest.x) || (orig.y != dest.y)) {
471 out.drawArc(center, distance - BASE_RADIUS / 2.,
472 distance * coef - BASE_RADIUS / 2, 180, 0);
473 out.drawArc(center, distance + BASE_RADIUS / 2.,
474 distance * coef + BASE_RADIUS / 2, 180, 0);
476 } else if (!style.isWobbleUG()) {
477 out.drawArc(center, distance, distance * coef, 180, 0);
478 drawSymbol(out, center.x, center.y + distance * coef / 2., 180., 0,
479 radiusCircle, style.isCIS(),
480 style.getEdgePartner5(), thickness);
482 out.drawArc(orig, distance, distance * coef, 180, 0);
485 ModeleBP.Edge p1 = style.getEdgePartner5();
486 ModeleBP.Edge p2 = style.getEdgePartner3();
487 out.drawArc(center, distance, distance * coef, 180, 0);
489 drawSymbol(out, center.x, center.y + distance * coef / 2., 1., 0,
490 radiusCircle, style.isCIS(),
491 style.getEdgePartner5(), thickness);
493 drawSymbol(out, center.x - BASE_RADIUS,
494 center.y + distance * coef / 2., 1., 0, radiusCircle,
495 style.isCIS(), p1, thickness);
496 drawSymbol(out, center.x + BASE_RADIUS,
497 center.y + distance * coef / 2., 1., 0, radiusCircle,
498 style.isCIS(), p2, thickness);
504 private void drawBasePair(SecStrDrawingProducer out, Point2D.Double orig,
505 Point2D.Double dest, ModeleBP style, VARNAConfig conf) {
506 double dx = dest.x - orig.x;
507 double dy = dest.y - orig.y;
508 double dist = Math.sqrt((dest.x - orig.x) * (dest.x - orig.x)
509 + (dest.y - orig.y) * (dest.y - orig.y));
514 orig = new Point2D.Double(orig.x + BASE_RADIUS * dx, orig.y
516 dest = new Point2D.Double(dest.x - BASE_RADIUS * dx, dest.y
518 if (conf._mainBPStyle == VARNAConfig.BP_STYLE.LW) {
519 double thickness = getBasePairThickness(style, conf);
520 double radiusCircle = ((BASE_PAIR_DISTANCE - BASE_RADIUS) / 5.0);
522 if (style.isCanonical()) {
523 if (style.isCanonicalGC()) {
524 if ((orig.x != dest.x) || (orig.y != dest.y)) {
525 nx *= BASE_RADIUS / 4.0;
526 ny *= BASE_RADIUS / 4.0;
527 out.drawLine((orig.x + nx), (orig.y + ny),
528 (dest.x + nx), (dest.y + ny), conf._bpThickness);
529 out.drawLine((orig.x - nx), (orig.y - ny),
530 (dest.x - nx), (dest.y - ny), conf._bpThickness);
532 } else if (style.isCanonicalAU()) {
533 out.drawLine(orig.x, orig.y, dest.x, dest.y,
535 } else if (style.isWobbleUG()) {
536 double cx = (dest.x + orig.x) / 2.0;
537 double cy = (dest.y + orig.y) / 2.0;
538 out.drawLine(orig.x, orig.y, dest.x, dest.y,
540 drawSymbol(out, cx, cy, nx, ny, radiusCircle, false,
541 ModeleBP.Edge.WC, thickness);
545 double cx = (dest.x + orig.x) / 2.0;
546 double cy = (dest.y + orig.y) / 2.0;
547 out.drawLine(orig.x, orig.y, dest.x, dest.y,
549 drawSymbol(out, cx, cy, nx, ny, radiusCircle,
550 style.isCIS(), style.getEdgePartner5(), thickness);
553 ModeleBP.Edge p1 = style.getEdgePartner5();
554 ModeleBP.Edge p2 = style.getEdgePartner3();
555 double cx = (dest.x + orig.x) / 2.0;
556 double cy = (dest.y + orig.y) / 2.0;
557 out.drawLine(orig.x, orig.y, dest.x, dest.y, conf._bpThickness);
559 drawSymbol(out, cx, cy, nx, ny, radiusCircle,
560 style.isCIS(), p1, thickness);
562 double vdx = (dest.x - orig.x);
563 double vdy = (dest.y - orig.y);
566 drawSymbol(out, cx + vdx, cy + vdy, nx, ny, radiusCircle,
567 style.isCIS(), p2, thickness);
568 drawSymbol(out, cx - vdx, cy - vdy, nx, ny, radiusCircle,
569 style.isCIS(), p1, thickness);
572 } else if (conf._mainBPStyle == VARNAConfig.BP_STYLE.RNAVIZ) {
573 double xcenter = (orig.x + dest.x) / 2.0;
574 double ycenter = (orig.y + dest.y) / 2.0;
575 out.fillCircle(xcenter, ycenter, 3.0 * conf._bpThickness,
576 conf._bpThickness, out.getCurrentColor());
577 } else if (conf._mainBPStyle == VARNAConfig.BP_STYLE.SIMPLE) {
578 out.drawLine(orig.x, orig.y, dest.x, dest.y, conf._bpThickness);
582 private void drawColorMap(VARNAConfig _conf, SecStrDrawingProducer out) {
583 double v1 = _conf._cm.getMinValue();
584 double v2 = _conf._cm.getMaxValue();
586 double xSpaceAvail = 0;
587 double ySpaceAvail = 0;
588 double thickness = 1.0;
591 * Math.min((getHeight()-rnabbox.height*scaleFactor-getTitleHeight
592 * ())/2.0,scaleFactor*(_conf._colorMapHeight+VARNAConfig.
593 * DEFAULT_COLOR_MAP_FONT_SIZE)); if ((int)ySpaceAvail==0) { xSpaceAvail
595 * Math.min((getWidth()-rnabbox.width*scaleFactor)/2,scaleFactor*(_conf
596 * ._colorMapWidth)+VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH); }
598 Rectangle2D.Double currentBBox = out.getBoundingBox();
600 double xBase = (currentBBox.getMaxX() - _conf._colorMapWidth - _conf._colorMapXOffset);
601 // double yBase = (minY - _conf._colorMapHeight +
602 // _conf._colorMapYOffset);
603 double yBase = (currentBBox.getMinY() - _conf._colorMapHeight - VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE);
605 for (int i = 0; i < _conf._colorMapWidth; i++) {
606 double ratio = (((double) i) / ((double) _conf._colorMapWidth - 1));
607 double val = v1 + (v2 - v1) * ratio;
608 Color c = _conf._cm.getColorForValue(val);
609 x = (int) (xBase + i);
611 out.fillRectangle(x, y, VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH,
612 _conf._colorMapHeight, c);
614 out.setColor(VARNAConfig.DEFAULT_COLOR_MAP_OUTLINE);
615 out.drawRectangle(xBase, yBase, (double) _conf._colorMapWidth
616 + VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH - 1,
617 _conf._colorMapHeight, thickness);
619 out.setColor(VARNAConfig.DEFAULT_COLOR_MAP_FONT_COLOR);
620 out.setFont(out.getCurrentFont(),
621 VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.5);
622 out.drawText(xBase, yBase + _conf._colorMapHeight
623 + VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7,
624 "" + _conf._cm.getMinValue());
625 out.drawText(xBase + VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH
626 + _conf._colorMapWidth, yBase + _conf._colorMapHeight
627 + VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7,
628 "" + _conf._cm.getMaxValue());
631 + (VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH + _conf._colorMapWidth)
633 - (VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7),
634 _conf._colorMapCaption);
638 private void renderRegionHighlights(SecStrDrawingProducer out,
639 Point2D.Double[] realCoords, Point2D.Double[] realCenters) {
640 for (HighlightRegionAnnotation r : _listeRegionHighlights) {
641 GeneralPath s = r.getShape(realCoords, realCenters, 1.0);
642 out.setColor(r.getFillColor());
643 out.fillPolygon(s, r.getFillColor());
644 out.setColor(r.getOutlineColor());
645 out.drawPolygon(s, 1l);
650 private void saveRNA(String path, VARNAConfig conf, double scale,
651 SecStrDrawingProducer out) throws ExceptionWritingForbidden {
653 // Computing bounding boxes
654 double EPSMargin = 40;
655 double minX = Double.MAX_VALUE;
656 double maxX = Double.MIN_VALUE;
657 double minY = Double.MAX_VALUE;
658 double maxY = Double.MIN_VALUE;
660 double x0, y0, x1, y1, xc, yc, xp, yp, dx, dy, norm;
662 for (int i = 0; i < _listeBases.size(); i++) {
663 minX = Math.min(minX, (_listeBases.get(i).getCoords().getX()
664 - BASE_RADIUS - EPSMargin));
665 minY = Math.min(minY, -(_listeBases.get(i).getCoords().getY()
666 - BASE_RADIUS - EPSMargin));
667 maxX = Math.max(maxX, (_listeBases.get(i).getCoords().getX()
668 + BASE_RADIUS + EPSMargin));
669 maxY = Math.max(maxY, -(_listeBases.get(i).getCoords().getY()
670 + BASE_RADIUS + EPSMargin));
673 // Rescaling everything
674 Point2D.Double[] coords = new Point2D.Double[_listeBases.size()];
675 Point2D.Double[] centers = new Point2D.Double[_listeBases.size()];
676 for (int i = 0; i < _listeBases.size(); i++) {
677 xp = (_listeBases.get(i).getCoords().getX() - minX);
678 yp = -(_listeBases.get(i).getCoords().getY() - minY);
679 coords[i] = new Point2D.Double(xp, yp);
681 Point2D.Double centerBck = getCenter(i);
682 if (get_drawMode() == RNA.DRAW_MODE_NAVIEW
683 || get_drawMode() == RNA.DRAW_MODE_RADIATE) {
684 if ((_listeBases.get(i).getElementStructure() != -1)
685 && i < _listeBases.size() - 1 && i > 1) {
686 ModeleBase b1 = get_listeBases().get(i - 1);
687 ModeleBase b2 = get_listeBases().get(i + 1);
688 int j1 = b1.getElementStructure();
689 int j2 = b2.getElementStructure();
690 if ((j1 == -1) ^ (j2 == -1)) {
691 // alors la position du nombre associé doit etre
693 Point2D.Double a1 = b1.getCoords();
694 Point2D.Double a2 = b2.getCoords();
695 Point2D.Double c1 = b1.getCenter();
696 Point2D.Double c2 = b2.getCenter();
698 centerBck.x = _listeBases.get(i).getCoords().x
699 + (c1.x - a1.x) / c1.distance(a1)
700 + (c2.x - a2.x) / c2.distance(a2);
701 centerBck.y = _listeBases.get(i).getCoords().y
702 + (c1.y - a1.y) / c1.distance(a1)
703 + (c2.y - a2.y) / c2.distance(a2);
707 xc = (centerBck.getX() - minX);
708 yc = -(centerBck.getY() - minY);
709 centers[i] = new Point2D.Double(xc, yc);
712 // Drawing background
713 if (conf._drawBackground)
714 out.setBackgroundColor(conf._backgroundColor);
716 // Drawing region highlights
717 renderRegionHighlights(out, coords, centers);
720 if (conf._drawBackbone)
722 for (int i = 1; i < _listeBases.size(); i++) {
723 Point2D.Double p1 = coords[i - 1];
724 Point2D.Double p2 = coords[i];
729 Point2D.Double vn = new Point2D.Double();
730 double dist = p1.distance(p2);
731 int a = _listeBases.get(i - 1).getElementStructure();
732 int b = _listeBases.get(i).getElementStructure();
733 BackboneType bt = _backbone.getTypeBefore(i);
734 boolean consecutivePair = (a == i) && (b == i - 1);
737 if (bt != BackboneType.DISCONTINUOUS_TYPE) {
738 Color c = _backbone.getColorBefore(i, conf._backboneColor);
739 if (bt == BackboneType.MISSING_PART_TYPE) {
744 vn.x = (x1 - x0) / dist;
745 vn.y = (y1 - y0) / dist;
747 &&(getDrawMode() != RNA.DRAW_MODE_LINEAR)
748 && (getDrawMode() != RNA.DRAW_MODE_CIRCULAR)) {
750 if (i + 1 < coords.length) {
751 dir = (testDirectionality(i - 1, i, i + 1) ? 1 : -1);
752 } else if (i - 2 >= 0) {
753 dir = (testDirectionality(i - 2, i - 1, i) ? 1 : -1);
755 Point2D.Double centerSeg = new Point2D.Double(
756 (p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0);
757 double centerDist = RNA.VIRTUAL_LOOP_RADIUS * scale;
758 Point2D.Double centerLoop = new Point2D.Double(
759 centerSeg.x + centerDist * dir * vn.y,
760 centerSeg.y - centerDist * dir * vn.x);
762 //out.drawLine(centerLoop.x - 5, centerLoop.y,
763 // centerLoop.x + 5, centerLoop.y, 2.0);
764 //out.drawLine(centerLoop.x, centerLoop.y - 5,
765 // centerLoop.x, centerLoop.y + 5, 2.0);
767 double radius = centerLoop.distance(p1);
769 * (Math.atan2(p1.y - centerLoop.y, p1.x - centerLoop.x))
772 * (Math.atan2(p2.y - centerLoop.y, p2.x - centerLoop.x))
786 out.drawArc(centerLoop, 2. * radius, 2. * radius, a1,
789 out.drawLine((x0 + BASE_RADIUS * vn.x),
790 (y0 + BASE_RADIUS * vn.y), (x1 - BASE_RADIUS
791 * vn.x), (y1 - BASE_RADIUS * vn.y), 1.0);
799 for (int i = 0; i < _listeBases.size(); i++) {
800 if (_listeBases.get(i).getElementStructure() > i) {
801 ModeleBP style = _listeBases.get(i).getStyleBP();
802 if (style.isCanonical() || conf._drawnNonCanonicalBP) {
803 Color bpcol = getBasePairColor(style, conf);
806 int j = _listeBases.get(i).getElementStructure();
813 norm = Math.sqrt(dx * dx + dy * dy);
817 if (_drawMode == DRAW_MODE_CIRCULAR
818 || _drawMode == DRAW_MODE_RADIATE
819 || _drawMode == DRAW_MODE_NAVIEW) {
820 drawBasePair(out, new Point2D.Double(x0, y0),
821 new Point2D.Double(x1, y1), style, conf);
822 } else if (_drawMode == DRAW_MODE_LINEAR) {
823 drawBasePairArc(out, i, j, new Point2D.Double(x0, y0),
824 new Point2D.Double(x1, y1), style, conf);
830 // Drawing additional bonds
831 if (conf._drawnNonPlanarBP) {
832 for (int i = 0; i < _structureAux.size(); i++) {
833 ModeleBP bp = _structureAux.get(i);
834 out.setColor(getBasePairColor(bp, conf));
836 int a = bp.getPartner5().getIndex();
837 int b = bp.getPartner3().getIndex();
839 if (bp.isCanonical() || conf._drawnNonCanonicalBP) {
846 norm = Math.sqrt(dx * dx + dy * dy);
849 if ((_drawMode == DRAW_MODE_CIRCULAR)
850 || (_drawMode == DRAW_MODE_RADIATE)
851 || _drawMode == DRAW_MODE_NAVIEW) {
852 drawBasePair(out, new Point2D.Double(x0, y0),
853 new Point2D.Double(x1, y1), bp, conf);
854 } else if (_drawMode == DRAW_MODE_LINEAR) {
855 drawBasePairArc(out, a, b, new Point2D.Double(x0, y0),
856 new Point2D.Double(x1, y1), bp, conf);
863 double baseFontSize = (1.5 * BASE_RADIUS);
864 out.setFont(PSExport.FONT_HELVETICA_BOLD, baseFontSize);
866 for (int i = 0; i < _listeBases.size(); i++) {
870 Color baseInnerColor = getBaseInnerColor(i, conf);
871 Color baseOuterColor = getBaseOuterColor(i, conf);
872 Color baseNameColor = getBaseNameColor(i, conf);
873 if ( RNA.whiteLabelPreferrable(baseInnerColor))
875 baseNameColor=Color.white;
879 if (_listeBases.get(i) instanceof ModeleBasesComparison) {
880 ModeleBasesComparison mb = (ModeleBasesComparison) _listeBases
882 if (conf._fillBases) {
883 out.fillRectangle(x0 - 1.5 * BASE_RADIUS, y0 - BASE_RADIUS,
884 3 * BASE_RADIUS, 2 * BASE_RADIUS,
887 if (conf._drawOutlineBases) {
888 out.setColor(baseOuterColor);
889 out.drawRectangle(x0 - 1.5 * BASE_RADIUS, y0 - BASE_RADIUS,
890 3 * BASE_RADIUS, 2 * BASE_RADIUS, 1l);
891 out.drawLine(x0, y0 - BASE_RADIUS, x0, y0 + BASE_RADIUS, 1l);
894 out.setColor(baseNameColor);
895 out.drawText(x0 - .75 * BASE_RADIUS, y0, "" + mb.getBase1());
896 out.drawText(x0 + .75 * BASE_RADIUS, y0, "" + mb.getBase2());
897 } else if (_listeBases.get(i) instanceof ModeleBaseNucleotide) {
898 if (conf._fillBases) {
899 out.fillCircle(x0, y0, BASE_RADIUS, 1l,
902 if (conf._drawOutlineBases) {
903 out.setColor(baseOuterColor);
904 out.drawCircle(x0, y0, BASE_RADIUS, 1l);
906 out.setColor(baseNameColor);
907 out.drawText(x0, y0, _listeBases.get(i).getContent());
912 // Drawing base numbers
913 double numFontSize = (double) (1.5 * BASE_RADIUS);
914 out.setFont(PSExport.FONT_HELVETICA_BOLD, numFontSize);
916 for (int i = 0; i < _listeBases.size(); i++) {
917 int basenum = _listeBases.get(i).getBaseNumber();
921 ModeleBase mb = _listeBases.get(i);
922 if (this.isNumberDrawn(mb, conf._numPeriod)) {
923 out.setColor(mb.getStyleBase()
924 .getBaseNumberColor());
931 norm = Math.sqrt(dx * dx + dy * dy);
934 Point2D.Double vn = VARNAPanel.computeExcentricUnitVector(i,coords,centers);
936 out.drawLine((x0 + 1.5 * BASE_RADIUS * vn.x), (y0 + 1.5
937 * BASE_RADIUS * vn.y), (x0 + 2.5 * BASE_RADIUS * vn.x),
938 (y0 + 2.5 * BASE_RADIUS * vn.y), 1);
940 (x0 + (conf._distNumbers + 1.0) * BASE_RADIUS * vn.x),
941 (y0 + (conf._distNumbers + 1.0) * BASE_RADIUS * vn.y), mb.getLabel());
944 renderAnnotations(out, minX, minY, conf);
947 if (conf._drawColorMap) {
948 drawColorMap(conf, out);
952 Rectangle2D.Double currentBBox = out.getBoundingBox();
953 double titleFontSize = (2.0 * conf._titleFont.getSize());
954 out.setColor(conf._titleColor);
955 out.setFont(PSExport.FONT_HELVETICA, titleFontSize);
956 double yTitle = currentBBox.y - titleFontSize / 2.0;
957 if (!getName().equals("")) {
958 out.drawText((maxX - minX) / 2.0, yTitle, getName());
961 OutputStreamWriter fout;
964 fout = new OutputStreamWriter(new FileOutputStream(path), "UTF-8");
966 fout.write(out.export());
968 } catch (IOException e) {
969 throw new ExceptionWritingForbidden(e.getMessage());
973 Point2D.Double buildCaptionPosition(ModeleBase mb, double heightEstimate,
976 if (isNumberDrawn(mb, conf._numPeriod)) {
977 radius += (conf._distNumbers + 1.0);
979 Point2D.Double center = mb.getCenter();
980 Point2D.Double p = mb.getCoords();
981 double realDistance = BASE_RADIUS * radius + heightEstimate;
982 return new Point2D.Double(center.getX() + (p.getX() - center.getX())
983 * ((p.distance(center) + realDistance) / p.distance(center)),
985 + (p.getY() - center.getY())
986 * ((p.distance(center) + realDistance) / p
990 public double getBPHeightIncrement() {
991 return this._bpHeightIncrement;
994 public void setBPHeightIncrement(double d) {
995 _bpHeightIncrement = d;
998 private void drawChemProbAnnotation(SecStrDrawingProducer out,
999 ChemProbAnnotation cpa, Point2D.Double anchor, double minX,
1001 out.setColor(cpa.getColor());
1002 Point2D.Double v = cpa.getDirVector();
1003 Point2D.Double vn = cpa.getNormalVector();
1004 Point2D.Double base = new Point2D.Double((anchor.x + CHEM_PROB_DIST
1005 * v.x), (anchor.y + CHEM_PROB_DIST * v.y));
1006 Point2D.Double edge = new Point2D.Double(
1007 (base.x + CHEM_PROB_BASE_LENGTH * cpa.getIntensity() * v.x),
1008 (base.y + CHEM_PROB_BASE_LENGTH * cpa.getIntensity() * v.y));
1009 double thickness = CHEM_PROB_ARROW_THICKNESS * cpa.getIntensity();
1010 switch (cpa.getType()) {
1012 Point2D.Double arrowTip1 = new Point2D.Double(
1013 (base.x + cpa.getIntensity()
1014 * (CHEM_PROB_ARROW_WIDTH * vn.x + CHEM_PROB_ARROW_HEIGHT
1016 (base.y + cpa.getIntensity()
1017 * (CHEM_PROB_ARROW_WIDTH * vn.y + CHEM_PROB_ARROW_HEIGHT
1019 Point2D.Double arrowTip2 = new Point2D.Double(
1020 (base.x + cpa.getIntensity()
1021 * (-CHEM_PROB_ARROW_WIDTH * vn.x + CHEM_PROB_ARROW_HEIGHT
1023 (base.y + cpa.getIntensity()
1024 * (-CHEM_PROB_ARROW_WIDTH * vn.y + CHEM_PROB_ARROW_HEIGHT
1026 out.drawLine(base.x - minX, minY - base.y, edge.x - minX, minY
1027 - edge.y, thickness);
1028 out.drawLine(base.x - minX, minY - base.y, arrowTip1.x - minX, minY
1029 - arrowTip1.y, thickness);
1030 out.drawLine(base.x - minX, minY - base.y, arrowTip2.x - minX, minY
1031 - arrowTip2.y, thickness);
1035 Point2D.Double side1 = new Point2D.Double(
1036 (edge.x - cpa.getIntensity()
1037 * (CHEM_PROB_PIN_SEMIDIAG * v.x)),
1038 (edge.y - cpa.getIntensity()
1039 * (CHEM_PROB_PIN_SEMIDIAG * v.y)));
1040 Point2D.Double side2 = new Point2D.Double(
1041 (edge.x - cpa.getIntensity()
1042 * (CHEM_PROB_PIN_SEMIDIAG * vn.x)),
1043 (edge.y - cpa.getIntensity()
1044 * (CHEM_PROB_PIN_SEMIDIAG * vn.y)));
1045 Point2D.Double side3 = new Point2D.Double(
1046 (edge.x + cpa.getIntensity()
1047 * (CHEM_PROB_PIN_SEMIDIAG * v.x)),
1048 (edge.y + cpa.getIntensity()
1049 * (CHEM_PROB_PIN_SEMIDIAG * v.y)));
1050 Point2D.Double side4 = new Point2D.Double(
1051 (edge.x + cpa.getIntensity()
1052 * (CHEM_PROB_PIN_SEMIDIAG * vn.x)),
1053 (edge.y + cpa.getIntensity()
1054 * (CHEM_PROB_PIN_SEMIDIAG * vn.y)));
1055 GeneralPath p2 = new GeneralPath();
1056 p2.moveTo((float) (side1.x - minX), (float) (minY - side1.y));
1057 p2.lineTo((float) (side2.x - minX), (float) (minY - side2.y));
1058 p2.lineTo((float) (side3.x - minX), (float) (minY - side3.y));
1059 p2.lineTo((float) (side4.x - minX), (float) (minY - side4.y));
1061 out.fillPolygon(p2, cpa.getColor());
1062 out.drawLine(base.x - minX, minY - base.y, edge.x - minX, minY
1063 - edge.y, thickness);
1067 Point2D.Double arrowTip1 = new Point2D.Double(
1068 (edge.x + cpa.getIntensity()
1069 * (CHEM_PROB_TRIANGLE_WIDTH * vn.x)),
1070 (edge.y + cpa.getIntensity()
1071 * (CHEM_PROB_TRIANGLE_WIDTH * vn.y)));
1072 Point2D.Double arrowTip2 = new Point2D.Double(
1073 (edge.x + cpa.getIntensity()
1074 * (-CHEM_PROB_TRIANGLE_WIDTH * vn.x)),
1075 (edge.y + cpa.getIntensity()
1076 * (-CHEM_PROB_TRIANGLE_WIDTH * vn.y)));
1077 GeneralPath p2 = new GeneralPath();
1078 p2.moveTo((float) (base.x - minX), (float) (minY - base.y));
1079 p2.lineTo((float) (arrowTip1.x - minX),
1080 (float) (minY - arrowTip1.y));
1081 p2.lineTo((float) (arrowTip2.x - minX),
1082 (float) (minY - arrowTip2.y));
1084 out.fillPolygon(p2, cpa.getColor());
1088 Double radius = CHEM_PROB_DOT_RADIUS * cpa.getIntensity();
1089 Point2D.Double center = new Point2D.Double((base.x + radius * v.x)
1090 - minX, minY - (base.y + radius * v.y));
1091 out.fillCircle(center.x, center.y, radius, thickness,
1098 private void renderAnnotations(SecStrDrawingProducer out, double minX,
1099 double minY, VARNAConfig conf) {
1100 for (TextAnnotation textAnnotation : getAnnotations()) {
1101 out.setColor(textAnnotation.getColor());
1102 out.setFont(PSExport.FONT_HELVETICA_BOLD, 2.0 * textAnnotation
1103 .getFont().getSize());
1104 Point2D.Double position = textAnnotation.getCenterPosition();
1105 if (textAnnotation.getType() == TextAnnotation.AnchorType.BASE) {
1106 ModeleBase mb = (ModeleBase) textAnnotation.getAncrage();
1107 double fontHeight = Math.ceil(textAnnotation.getFont()
1109 position = buildCaptionPosition(mb, fontHeight, conf);
1112 out.drawText(position.x - minX, -(position.y - minY),
1113 textAnnotation.getTexte());
1115 for (ChemProbAnnotation cpa : getChemProbAnnotations()) {
1116 Point2D.Double anchor = cpa.getAnchorPosition();
1117 drawChemProbAnnotation(out, cpa, anchor, minX, minY);
1121 public boolean isNumberDrawn(ModeleBase mb, int numPeriod) {
1124 return ((mb.getIndex() == 0) || ((mb.getBaseNumber()) % numPeriod == 0) || (mb
1125 .getIndex() == get_listeBases().size() - 1));
1128 public void saveRNAEPS(String path, VARNAConfig conf)
1129 throws ExceptionWritingForbidden {
1130 PSExport out = new PSExport();
1131 saveRNA(path, conf, 0.4, out);
1134 public void saveRNAXFIG(String path, VARNAConfig conf)
1135 throws ExceptionWritingForbidden {
1136 XFIGExport out = new XFIGExport();
1137 saveRNA(path, conf, 20, out);
1140 public void saveRNATIKZ(String path, VARNAConfig conf)
1141 throws ExceptionWritingForbidden {
1142 TikzExport out = new TikzExport();
1143 saveRNA(path, conf, 0.15, out);
1146 public void saveRNASVG(String path, VARNAConfig conf)
1147 throws ExceptionWritingForbidden {
1148 SVGExport out = new SVGExport();
1149 saveRNA(path, conf, 0.5, out);
1152 public Rectangle2D.Double getBBox() {
1153 Rectangle2D.Double result = new Rectangle2D.Double(10, 10, 10, 10);
1154 double minx, maxx, miny, maxy;
1155 minx = Double.MAX_VALUE;
1156 miny = Double.MAX_VALUE;
1157 maxx = -Double.MAX_VALUE;
1158 maxy = -Double.MAX_VALUE;
1159 for (int i = 0; i < _listeBases.size(); i++) {
1161 _listeBases.get(i).getCoords().getX() - BASE_RADIUS, minx);
1163 _listeBases.get(i).getCoords().getY() - BASE_RADIUS, miny);
1165 _listeBases.get(i).getCoords().getX() + BASE_RADIUS, maxx);
1167 _listeBases.get(i).getCoords().getY() + BASE_RADIUS, maxy);
1171 result.width = Math.max(maxx - minx, 1);
1172 result.height = Math.max(maxy - miny, 1);
1173 if (_drawMode == RNA.DRAW_MODE_LINEAR) {
1174 double realHeight = _bpHeightIncrement * result.width / 2.0;
1175 result.height += realHeight;
1176 result.y -= realHeight;
1181 public void setCoord(int index, Point2D.Double p) {
1182 setCoord(index, p.x, p.y);
1185 public void setCoord(int index, double x, double y) {
1186 if (index < _listeBases.size()) {
1187 _listeBases.get(index).setCoords(new Point2D.Double(x, y));
1191 public Point2D.Double getCoords(int i) {
1192 if (i < _listeBases.size() && i >= 0) {
1193 return _listeBases.get(i).getCoords();
1195 return new Point2D.Double();
1198 public String getBaseContent(int i) {
1199 if ((i >= 0) && (i < _listeBases.size())) {
1200 return _listeBases.get(i).getContent();
1205 public int getBaseNumber(int i) {
1206 if ((i >= 0) && (i < _listeBases.size())) {
1207 return _listeBases.get(i).getBaseNumber();
1212 public Point2D.Double getCenter(int i) {
1213 if (i < _listeBases.size()) {
1214 return _listeBases.get(i).getCenter();
1217 return new Point2D.Double();
1220 public void setCenter(int i, double x, double y) {
1221 setCenter(i, new Point2D.Double(x, y));
1224 public void setCenter(int i, Point2D.Double p) {
1225 if (i < _listeBases.size()) {
1226 _listeBases.get(i).setCenter(p);
1230 public void drawRNACircle(VARNAConfig conf) {
1232 _drawMode = DRAW_MODE_CIRCULAR;
1233 int radius = (int) ((3 * (_listeBases.size() + 1) * BASE_RADIUS) / (2 * Math.PI));
1235 for (int i = 0; i < _listeBases.size(); i++) {
1236 angle = -((((double) -(i + 1)) * 2.0 * Math.PI)
1237 / ((double) (_listeBases.size() + 1)) - Math.PI / 2.0);
1242 (radius * Math.cos(angle) * conf._spaceBetweenBases),
1243 (radius * Math.sin(angle) * conf._spaceBetweenBases)));
1244 _listeBases.get(i).setCenter(new Point2D.Double(0, 0));
1248 public void drawRNAVARNAView(VARNAConfig conf) {
1250 _drawMode = DRAW_MODE_VARNA_VIEW;
1251 VARNASecDraw vs = new VARNASecDraw();
1252 vs.drawRNA(1, this);
1255 public void drawRNALine(VARNAConfig conf) {
1257 _drawMode = DRAW_MODE_LINEAR;
1258 for (int i = 0; i < get_listeBases().size(); i++) {
1259 get_listeBases().get(i).setCoords(
1260 new Point2D.Double(i * conf._spaceBetweenBases * 20, 0));
1261 get_listeBases().get(i).setCenter(
1262 new Point2D.Double(i * conf._spaceBetweenBases * 20, -10));
1266 public RNATemplateMapping drawRNATemplate(RNATemplate template, boolean straightBulges,
1267 VARNAConfig conf) throws RNATemplateDrawingAlgorithmException {
1268 return drawRNATemplate(template, conf,
1269 DrawRNATemplateMethod.getDefault(),
1270 DrawRNATemplateCurveMethod.getDefault(), straightBulges);
1273 public RNATemplateMapping drawRNATemplate(RNATemplate template,
1274 VARNAConfig conf, DrawRNATemplateMethod helixLengthAdjustmentMethod,
1275 boolean straightBulges)
1276 throws RNATemplateDrawingAlgorithmException {
1277 return drawRNATemplate(template, conf, helixLengthAdjustmentMethod,
1278 DrawRNATemplateCurveMethod.getDefault(),straightBulges);
1281 public RNATemplateMapping drawRNATemplate(RNATemplate template,
1283 DrawRNATemplateMethod helixLengthAdjustmentMethod,
1284 DrawRNATemplateCurveMethod curveMethod,
1285 boolean straightBulges)
1286 throws RNATemplateDrawingAlgorithmException {
1288 _drawMode = DRAW_MODE_TEMPLATE;
1290 DrawRNATemplate drawRNATemplate = new DrawRNATemplate(this);
1291 drawRNATemplate.drawRNATemplate(template, conf,
1292 helixLengthAdjustmentMethod, curveMethod,
1294 return drawRNATemplate.getMapping();
1297 private static double objFun(int n1, int n2, double r, double bpdist,
1299 return (((double) n1) * 2.0 * Math.asin(((double) bpdist) / (2.0 * r))
1300 + ((double) n2) * 2.0
1301 * Math.asin(((double) multidist) / (2.0 * r)) - (2.0 * Math.PI));
1304 public double determineRadius(int nbHel, int nbUnpaired, double startRadius) {
1305 return determineRadius(nbHel, nbUnpaired, startRadius,
1306 BASE_PAIR_DISTANCE, MULTILOOP_DISTANCE);
1309 public static double determineRadius(int nbHel, int nbUnpaired,
1310 double startRadius, double bpdist, double multidist) {
1311 double xmin = bpdist / 2.0;
1312 double xmax = 3.0 * multidist + 1;
1313 double x = (xmin + xmax) / 2.0;
1315 double ymin = -1000.0;
1316 double ymax = 1000.0;
1318 double precision = 0.00001;
1319 while ((Math.abs(y) > precision) && (numIt < 10000)) {
1320 x = (xmin + xmax) / 2.0;
1321 y = objFun(nbHel, nbUnpaired, x, bpdist, multidist);
1322 ymin = objFun(nbHel, nbUnpaired, xmax, bpdist, multidist);
1323 ymax = objFun(nbHel, nbUnpaired, xmin, bpdist, multidist);
1325 xmax = xmax + (xmax - xmin);
1326 } else if ((y <= 0.0) && (ymax > 0.0)) {
1328 } else if ((y >= 0.0) && (ymin < 0.0)) {
1330 } else if (ymax < 0.0) {
1331 xmin = Math.max(xmin - (x - xmin),
1332 Math.max(bpdist / 2.0, multidist / 2.0));
1340 public void drawRNA(VARNAConfig conf) throws ExceptionNAViewAlgorithm {
1341 drawRNA(RNA.DEFAULT_DRAW_MODE, conf);
1344 public void drawRNA(int mode, VARNAConfig conf)
1345 throws ExceptionNAViewAlgorithm {
1347 switch (get_drawMode()) {
1348 case RNA.DRAW_MODE_RADIATE:
1349 drawRNARadiate(conf);
1351 case RNA.DRAW_MODE_LINEAR:
1354 case RNA.DRAW_MODE_CIRCULAR:
1355 drawRNACircle(conf);
1357 case RNA.DRAW_MODE_NAVIEW:
1358 drawRNANAView(conf);
1360 case RNA.DRAW_MODE_VARNA_VIEW:
1361 drawRNAVARNAView(conf);
1369 public int getDrawMode() {
1373 public static double HYSTERESIS_EPSILON = .15;
1374 public static final double[] HYSTERESIS_ATTRACTORS = {0.,Math.PI/4.,Math.PI/2.,3.*Math.PI/4.,Math.PI,5.*(Math.PI)/4.,3.*(Math.PI)/2,7.*(Math.PI)/4.};
1376 public static double normalizeAngle(double angle)
1378 return normalizeAngle(angle,0.);
1381 public static double normalizeAngle(double angle, double fromVal)
1383 double toVal = fromVal +2.*Math.PI;
1384 double result = angle;
1385 while(result<fromVal)
1387 result += 2.*Math.PI;
1389 while(result >= toVal)
1391 result -= 2.*Math.PI;
1396 public static double correctHysteresis(double angle)
1398 double result = normalizeAngle(angle);
1400 for (int i=0;i<HYSTERESIS_ATTRACTORS.length;i++)
1402 double att = HYSTERESIS_ATTRACTORS[i];
1403 if (Math.abs(normalizeAngle(att-result,-Math.PI))<HYSTERESIS_EPSILON)
1413 private void distributeUnpaired(
1418 Point2D.Double center,
1419 Vector<Integer> bases)
1421 double mydist = Math.abs(radius*(angle / (bases.size() + 1)));
1422 double addedRadius= 0.;
1423 Point2D.Double PA = new Point2D.Double(center.x + radius * Math.cos(base + pHel),
1424 center.y + radius * Math.sin(base + pHel));
1425 Point2D.Double PB = new Point2D.Double(center.x + radius * Math.cos(base + pHel+angle),
1426 center.y + radius * Math.sin(base + pHel+angle));
1427 double dist = PA.distance(PB);
1428 Point2D.Double VN = new Point2D.Double((PB.y-PA.y)/dist,(-PB.x+PA.x)/dist);
1429 if (mydist<2*BASE_RADIUS)
1431 addedRadius=Math.min(1.0,(2*BASE_RADIUS-mydist)/4)*computeRadius(mydist, 2.29*(bases.size() + 1)*BASE_RADIUS-mydist);
1435 ArrayList<Point2D.Double> pos = computeNewAngles(bases.size(),center,VN, angle,base + pHel,radius,addedRadius);
1436 for (int i = 0; i < bases.size(); i++)
1438 int k = bases.get(i);
1439 setCoord(k, pos.get(i));
1444 private double computeRadius(double b, double pobj)
1446 double a=b, aL=a, aU=Double.POSITIVE_INFINITY;
1447 double h = (a-b)*(a-b)/((a+b)*(a+b));
1448 double p = Math.PI*(a+b)*(1+h/4.+h*h/64.+h*h*h/256.+25.*h*h*h*h/16384.)/2.0;
1450 while ((Math.abs(p-pobj)>10e-4)&&(aold!=a)){
1455 if (aU==Double.POSITIVE_INFINITY)
1465 h = (a-b)*(a-b)/((a+b)*(a+b));
1466 p = (Math.PI*(a+b)*(1+h/4.+h*h/64.+h*h*h/256.+25.*h*h*h*h/16384.))/2.0;
1471 public static double computeAngle(Point2D.Double center, Point2D.Double p) {
1472 double dist = center.distance(p);
1473 double angle = Math.asin((p.y - center.y) / dist);
1474 if (p.x - center.x < 0) {
1475 angle = Math.PI - angle;
1480 private Point2D.Double rotatePoint(Point2D.Double center, Point2D.Double p,
1482 double dist = p.distance(center);
1483 double oldAngle = Math.asin((p.y - center.y) / dist);
1485 if (p.x - center.x < 0) {
1486 oldAngle = Math.PI - oldAngle;
1489 double newX = (center.x + dist * Math.cos(oldAngle + angle));
1490 double newY = (center.y + dist * Math.sin(oldAngle + angle));
1492 return new Point2D.Double(newX, newY);
1497 private void rotateHelix(Point2D.Double center, int i, int j, double angle) {
1498 for (int k = i; k <= j; k++) {
1499 Point2D.Double oldp = getCoords(k);
1500 Point2D.Double newp = rotatePoint(center, oldp, angle);
1502 if ((k != i) && (k != j)) {
1504 Point2D.Double oldc = get_listeBases().get(k)
1506 Point2D.Double newc = rotatePoint(center, oldc, angle);
1514 private void fixUnpairedPositions(boolean isDirect,
1515 double angleRightPartner,
1516 double angleLimitLeft, double angleLimitRight, double angleLeftPartner,
1517 double radius, double base, Point2D.Double center,Vector<Integer> prevBases,Vector<Integer> nextBases)
1520 double anglePrev = normalizeAngle(angleLimitLeft - angleRightPartner);
1521 double angleNext = normalizeAngle(angleLeftPartner - angleLimitRight);
1522 distributeUnpaired(radius,anglePrev, angleRightPartner, base,
1524 distributeUnpaired(radius,-angleNext, angleLeftPartner, base,
1527 double anglePrev = normalizeAngle(angleLeftPartner - angleLimitRight);
1528 double angleNext = normalizeAngle(angleLimitLeft - angleRightPartner);
1529 distributeUnpaired(radius,-anglePrev, angleLeftPartner, base,
1531 distributeUnpaired(radius,angleNext, angleRightPartner, base,
1537 private static Point2D.Double getPoint(double angleLine, double angleBulge, Point2D.Double center,
1538 Point2D.Double VN,double radius, double addedRadius, double dirBulge)
1540 return new Point2D.Double(
1541 center.x + radius * Math.cos(angleLine)+
1542 dirBulge*addedRadius*Math.sin(angleBulge)*VN.x,
1543 center.y + radius * Math.sin(angleLine)+
1544 dirBulge*addedRadius*Math.sin(angleBulge)*VN.y);
1548 private ArrayList<Point2D.Double> computeNewAngles(int numPoints, Point2D.Double center,
1549 Point2D.Double VN, double angle, double angleBase, double radius, double addedRadius)
1551 ArrayList<Point2D.Double> result = new ArrayList<Point2D.Double>();
1554 ArrayList<Double> factors = new ArrayList<Double>();
1557 Point2D.Double prevP = new Point2D.Double(
1558 center.x + radius * Math.cos(angleBase),
1559 center.y + radius * Math.sin(angleBase));
1564 double angleBulge = 0.;
1565 double dirBulge = (angle<0)?-1.:1.;
1566 double dtarget =2.*BASE_RADIUS;
1568 for (int i = 0; i < numPoints; i++)
1570 double lbound = fact;
1571 double ubound = 1.0;
1572 double angleLine = angleBase + angle*fact;
1573 angleBulge = Math.PI*fact;
1574 Point2D.Double currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge);
1577 while ((Math.abs(currP.distance(prevP)-dtarget)>0.01)&& (numIter<100))
1579 if (currP.distance(prevP)> dtarget)
1582 fact = (fact+lbound)/2.0;
1587 fact = (fact+ubound)/2.0;
1589 angleLine = angleBase + angle*fact;
1590 angleBulge = Math.PI*fact;
1591 currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge);
1599 double rescale = 1.0/(factors.get(factors.size()-1)+factors.get(0));
1601 for(int j=0;j<factors.size();j++)
1603 factors.set(j,factors.get(j)*rescale);
1609 prevP = getPoint(angleBase, 0, center,VN,radius, addedRadius, dirBulge);
1610 double totDist = 0.0;
1611 for(int j=0;j<factors.size();j++)
1613 double newfact = factors.get(j);
1614 double angleLine = angleBase + angle*newfact;
1615 angleBulge = Math.PI*newfact;
1616 Point2D.Double currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge);
1617 totDist += currP.distance(prevP);
1620 totDist += getPoint(angleBase+angle, Math.PI, center,VN,radius, addedRadius, dirBulge).distance(prevP);
1621 dtarget = totDist/(numPoints+1);
1623 factors=new ArrayList<Double>();
1624 prevP = new Point2D.Double(
1625 center.x + radius * Math.cos(angleBase),
1626 center.y + radius * Math.sin(angleBase));
1627 for (int i = 0; i < numPoints; i++)
1629 double lbound = fact;
1630 double ubound = 1.5;
1631 double angleLine = angleBase + angle*fact;
1632 angleBulge = Math.PI*fact;
1633 Point2D.Double currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge);
1636 while ((Math.abs(currP.distance(prevP)-dtarget)>0.01)&& (numIter<100))
1638 if (currP.distance(prevP)> dtarget)
1641 fact = (fact+lbound)/2.0;
1646 fact = (fact+ubound)/2.0;
1648 angleLine = angleBase + angle*fact;
1649 angleBulge = Math.PI*fact;
1650 currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge);
1656 rescale = 1.0/(factors.get(factors.size()-1)+factors.get(0));
1657 for(int j=0;j<factors.size();j++)
1659 factors.set(j,factors.get(j)*rescale);
1663 for(int j=0;j<factors.size();j++)
1665 double newfact = factors.get(j);
1666 double angleLine = angleBase + angle*newfact;
1667 angleBulge = Math.PI*newfact;
1668 result.add(getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge));
1676 void drawLoop(int i, int j, double x, double y, double dirAngle,
1677 Point2D.Double[] coords, Point2D.Double[] centers, double[] angles,
1678 boolean straightBulges) {
1684 if (_listeBases.get(i).getElementStructure() == j) {
1685 double normalAngle = Math.PI / 2.0;
1686 centers[i] = new Point2D.Double(x, y);
1687 centers[j] = new Point2D.Double(x, y);
1688 coords[i].x = (x + BASE_PAIR_DISTANCE
1689 * Math.cos(dirAngle - normalAngle) / 2.0);
1690 coords[i].y = (y + BASE_PAIR_DISTANCE
1691 * Math.sin(dirAngle - normalAngle) / 2.0);
1692 coords[j].x = (x + BASE_PAIR_DISTANCE
1693 * Math.cos(dirAngle + normalAngle) / 2.0);
1694 coords[j].y = (y + BASE_PAIR_DISTANCE
1695 * Math.sin(dirAngle + normalAngle) / 2.0);
1696 drawLoop(i + 1, j - 1, x + LOOP_DISTANCE * Math.cos(dirAngle), y
1697 + LOOP_DISTANCE * Math.sin(dirAngle), dirAngle, coords,
1698 centers, angles, straightBulges);
1701 Vector<Integer> basesMultiLoop = new Vector<Integer>();
1702 Vector<Integer> helices = new Vector<Integer>();
1705 l = _listeBases.get(k).getElementStructure();
1707 basesMultiLoop.add(new Integer(k));
1708 basesMultiLoop.add(new Integer(l));
1709 helices.add(new Integer(k));
1712 basesMultiLoop.add(new Integer(k));
1716 int mlSize = basesMultiLoop.size() + 2;
1717 int numHelices = helices.size() + 1;
1718 double totalLength = MULTILOOP_DISTANCE * (mlSize - numHelices)
1719 + BASE_PAIR_DISTANCE * numHelices;
1720 double multiLoopRadius;
1721 double angleIncrementML;
1722 double angleIncrementBP;
1724 multiLoopRadius = determineRadius(numHelices, mlSize
1725 - numHelices, (totalLength) / (2.0 * Math.PI),
1726 BASE_PAIR_DISTANCE, MULTILOOP_DISTANCE);
1727 angleIncrementML = -2.0
1728 * Math.asin(((float) MULTILOOP_DISTANCE)
1729 / (2.0 * multiLoopRadius));
1730 angleIncrementBP = -2.0
1731 * Math.asin(((float) BASE_PAIR_DISTANCE)
1732 / (2.0 * multiLoopRadius));
1735 multiLoopRadius = 35.0;
1736 angleIncrementBP = -2.0
1737 * Math.asin(((float) BASE_PAIR_DISTANCE)
1738 / (2.0 * multiLoopRadius));
1739 angleIncrementML = (-2.0 * Math.PI - angleIncrementBP) / 2.0;
1741 // System.out.println("MLr:"+multiLoopRadius+" iBP:"+angleIncrementBP+" iML:"+angleIncrementML);
1743 double centerDist = Math.sqrt(Math.max(Math.pow(multiLoopRadius, 2)
1744 - Math.pow(BASE_PAIR_DISTANCE / 2.0, 2), 0.0))
1746 Point2D.Double mlCenter = new Point2D.Double(
1747 (x + (centerDist * Math.cos(dirAngle))),
1748 (y + (centerDist * Math.sin(dirAngle))));
1750 // Base directing angle for (multi|hairpin) loop, from the center's
1752 double baseAngle = dirAngle
1755 // Account for already drawn supporting base-pair
1756 + 0.5 * angleIncrementBP
1757 // Base cannot be paired twice, so next base is at
1758 // "unpaired base distance"
1759 + 1.0 * angleIncrementML;
1761 ArrayList<Integer> currUnpaired = new ArrayList<Integer>();
1762 Couple<Double,Double> currInterval = new Couple<Double,Double>(0.,baseAngle-1.0 * angleIncrementML);
1763 ArrayList<Couple<ArrayList<Integer>,Couple<Double,Double>>> intervals = new ArrayList<Couple<ArrayList<Integer>,Couple<Double,Double>>>();
1765 for (k = basesMultiLoop.size() - 1; k >= 0; k--) {
1766 l = basesMultiLoop.get(k).intValue();
1767 //System.out.println(l+" ");
1768 centers[l] = mlCenter;
1769 boolean isPaired = (_listeBases.get(l).getElementStructure() != -1);
1770 boolean isPaired3 = isPaired && (_listeBases.get(l).getElementStructure() < l);
1771 boolean isPaired5 = isPaired && !isPaired3;
1773 if ((numHelices == 2) && straightBulges)
1775 baseAngle = dirAngle-angleIncrementBP/2.;
1779 baseAngle = correctHysteresis(baseAngle+angleIncrementBP/2.)-angleIncrementBP/2.;
1781 currInterval.first = baseAngle;
1782 intervals.add(new Couple<ArrayList<Integer>,Couple<Double,Double>>(currUnpaired,currInterval));
1783 currInterval = new Couple<Double,Double>(-1.,-1.);
1784 currUnpaired = new ArrayList<Integer>();
1788 currInterval.second = baseAngle;
1792 currUnpaired.add(l);
1795 angles[l] = baseAngle;
1798 baseAngle += angleIncrementBP;
1801 baseAngle += angleIncrementML;
1804 currInterval.first = dirAngle
1806 - 0.5 * angleIncrementBP;
1807 intervals.add(new Couple<ArrayList<Integer>,Couple<Double,Double>>(currUnpaired,currInterval));
1808 //System.out.println("Inc. ML:"+angleIncrementML+" BP:"+angleIncrementBP);
1810 for(Couple<ArrayList<Integer>,Couple<Double,Double>> inter: intervals)
1812 //double mid = inter.second.second;
1813 double mina = inter.second.first;
1814 double maxa = normalizeAngle(inter.second.second,mina);
1815 //System.out.println(""+mina+" " +maxa);
1817 for (int n=0;n<inter.first.size();n++)
1819 double ratio = (1.+n)/(1.+inter.first.size());
1820 int b = inter.first.get(n);
1821 angles[b] = mina + (1.-ratio)*(maxa-mina);
1826 for (k = basesMultiLoop.size() - 1; k >= 0; k--) {
1827 l = basesMultiLoop.get(k).intValue();
1828 coords[l].x = mlCenter.x + multiLoopRadius
1829 * Math.cos(angles[l]);
1830 coords[l].y = mlCenter.y + multiLoopRadius
1831 * Math.sin(angles[l]);
1834 // System.out.println("n1:"+n1+" n2:"+n2);
1837 for (k = 0; k < helices.size(); k++) {
1838 m = helices.get(k).intValue();
1839 n = _listeBases.get(m).getElementStructure();
1840 newAngle = (angles[m] + angles[n]) / 2.0;
1841 drawLoop(m + 1, n - 1, (LOOP_DISTANCE * Math.cos(newAngle))
1842 + (coords[m].x + coords[n].x) / 2.0,
1843 (LOOP_DISTANCE * Math.sin(newAngle))
1844 + (coords[m].y + coords[n].y) / 2.0, newAngle,
1845 coords, centers, angles, straightBulges);
1850 private Vector<Integer> getPreviousUnpaired(Point h)
1852 Vector<Integer> prevBases = new Vector<Integer>();
1853 boolean over = false;
1856 if (i >=get_listeBases().size()) {
1859 if (get_listeBases().get(i)
1860 .getElementStructure() == -1) {
1861 prevBases.add(new Integer(i));
1871 private Vector<Integer> getNextUnpaired(Point h)
1873 boolean over = false;
1875 Vector<Integer> nextBases = new Vector<Integer>();
1880 if (get_listeBases().get(i)
1881 .getElementStructure() == -1) {
1882 nextBases.add(new Integer(i));
1893 public void rotateEverything(double delta, double base, double pLimL, double pLimR, Point h, Point ml, Hashtable<Integer,Point2D.Double> backupPos)
1895 boolean isDirect = testDirectionality(ml.x, ml.y, h.x);
1896 Point2D.Double center = get_listeBases().get(h.x).getCenter();
1897 for(int k=h.x;k<=h.y;k++)
1898 { backupPos.put(k, getBaseAt(k).getCoords()); }
1899 rotateHelix(center, h.x, h.y, delta);
1901 // Re-assigns unpaired atoms
1902 Point2D.Double helixStart = getCoords(h.x);
1903 Point2D.Double helixStop = getCoords(h.y);
1906 pHelR = computeAngle(center, helixStop) - base;
1907 pHelL = computeAngle(center, helixStart) - base;
1909 pHelL = computeAngle(center, helixStop) - base;
1910 pHelR = computeAngle(center, helixStart) - base;
1913 Vector<Integer> prevBases = getPreviousUnpaired(h);
1914 Vector<Integer> nextBases = getNextUnpaired(h);
1916 double radius = center.distance(helixStart);
1918 for (int j = 0; j < prevBases.size(); j++)
1920 int k = prevBases.get(j);
1921 backupPos.put(k, getCoords(k));
1923 for (int j = 0; j < nextBases.size(); j++)
1925 int k = nextBases.get(j);
1926 backupPos.put(k, getCoords(k));
1928 fixUnpairedPositions(isDirect, pHelR, pLimL, pLimR, pHelL, radius, base,center,prevBases,nextBases);
1933 public void drawRNARadiate() {
1934 drawRNARadiate(-1.0, VARNAConfig.DEFAULT_SPACE_BETWEEN_BASES, true, true);
1937 public void drawRNARadiate(VARNAConfig conf) {
1938 drawRNARadiate(-1.0, conf._spaceBetweenBases, conf._flatExteriorLoop, false);
1941 public static final double FLAT_RECURSIVE_INCREMENT = 20.;
1943 public void drawRNARadiate(double dirAngle, double _spaceBetweenBases,
1944 boolean flatExteriorLoop, boolean straightBulges) {
1946 straightBulges = true;
1947 _drawMode = DRAW_MODE_RADIATE;
1948 Point2D.Double[] coords = new Point2D.Double[_listeBases.size()];
1949 Point2D.Double[] centers = new Point2D.Double[_listeBases.size()];
1950 double[] angles = new double[_listeBases.size()];
1951 for (int i = 0; i < _listeBases.size(); i++) {
1952 coords[i] = new Point2D.Double(0, 0);
1953 centers[i] = new Point2D.Double(0, 0);
1955 if (flatExteriorLoop) {
1956 dirAngle += 1.0 - Math.PI / 2.0;
1960 double vx = -Math.sin(dirAngle);
1961 double vy = Math.cos(dirAngle);
1962 while (i < _listeBases.size()) {
1965 centers[i].x = x + BASE_PAIR_DISTANCE * vy;
1966 centers[i].y = y - BASE_PAIR_DISTANCE * vx;
1967 int j = _listeBases.get(i).getElementStructure();
1969 double increment = 0.;
1970 if (i+1<_listeBases.size())
1972 if (_listeBases.get(i+1).getElementStructure()==-1)
1974 //increment = -FLAT_RECURSIVE_INCREMENT;
1977 drawLoop(i, j, x + (BASE_PAIR_DISTANCE * vx / 2.0), y
1978 + (BASE_PAIR_DISTANCE * vy / 2.0)+increment, dirAngle,
1979 coords, centers, angles, straightBulges);
1980 centers[i].x = coords[i].x + BASE_PAIR_DISTANCE * vy;
1981 centers[i].y = y - BASE_PAIR_DISTANCE * vx;
1983 x += BASE_PAIR_DISTANCE * vx;
1984 y += BASE_PAIR_DISTANCE * vy;
1985 centers[i].x = coords[i].x + BASE_PAIR_DISTANCE * vy;
1986 centers[i].y = y - BASE_PAIR_DISTANCE * vx;
1988 x += MULTILOOP_DISTANCE * vx;
1989 y += MULTILOOP_DISTANCE * vy;
1993 drawLoop(0, _listeBases.size() - 1, 0, 0, dirAngle, coords, centers, angles, straightBulges);
1995 for (int i = 0; i < _listeBases.size(); i++) {
1996 _listeBases.get(i).setCoords(
1997 new Point2D.Double(coords[i].x * _spaceBetweenBases,
1998 coords[i].y * _spaceBetweenBases));
1999 _listeBases.get(i).setCenter(
2000 new Point2D.Double(centers[i].x * _spaceBetweenBases,
2001 centers[i].y * _spaceBetweenBases));
2005 // change les centres des bases de la premiere helice vers la boucle la
2009 public void drawRNANAView(VARNAConfig conf) throws ExceptionNAViewAlgorithm {
2010 _drawMode = DRAW_MODE_NAVIEW;
2013 ArrayList<Double> X = new ArrayList<Double>(_listeBases.size());
2014 ArrayList<Double> Y = new ArrayList<Double>(_listeBases.size());
2015 ArrayList<Short> pair_table = new ArrayList<Short>(_listeBases.size());
2017 for (int i = 0; i < _listeBases.size(); i++) {
2018 pair_table.add(Short.valueOf(String.valueOf(_listeBases.get(i)
2019 .getElementStructure())));
2021 NAView naView = new NAView();
2022 naView.naview_xy_coordinates(pair_table, X, Y);
2024 // Updating individual base positions
2025 for (int i = 0; i < _listeBases.size(); i++) {
2026 _listeBases.get(i).setCoords(
2028 X.get(i) * 2.5 * conf._spaceBetweenBases, Y.get(i)
2029 * 2.5 * conf._spaceBetweenBases));
2033 for (int i = 0; i < _listeBases.size(); i++) {
2034 int indicePartner = _listeBases.get(i).getElementStructure();
2035 if (indicePartner != -1) {
2036 Point2D.Double base = _listeBases.get(i).getCoords();
2037 Point2D.Double partner = _listeBases.get(indicePartner)
2039 _listeBases.get(i).setCenter(
2040 new Point2D.Double((base.x + partner.x) / 2.0,
2041 (base.y + partner.y) / 2.0));
2043 Vector<Integer> loop = getLoopBases(i);
2046 for (int j = 0; j < loop.size(); j++) {
2047 int partner = loop.elementAt(j);
2048 Point2D.Double loopmember = _listeBases.get(partner)
2050 tmpx += loopmember.x;
2051 tmpy += loopmember.y;
2053 _listeBases.get(i).setCenter(
2054 new Point2D.Double(tmpx / loop.size(), tmpy
2061 * public void drawMOTIFView() { _drawn = true; _drawMode =
2062 * DRAW_MODE_MOTIFVIEW; int spaceBetweenStrand =0; Motif motif = new
2063 * Motif(this,get_listeBases()); motif.listStrand(); for (int i = 0; i <
2064 * motif.getListStrand().sizeStruct(); i++ ){ for (int j = 0; j <
2065 * motif.getListStrand().getStrand(i).sizeStrand(); j++ ){ int indice =
2066 * motif.getListStrand().getStrand(i).getMB(j).getIndex();
2067 * get_listeBases().get(indice).setCoords( new Point2D.Double(0,0));
2068 * get_listeBases().get(indice).setCenter( new Point2D.Double(0, 0));
2070 * } } //Recherche du brin central int centralStrand =
2071 * motif.getCentralStrand();
2073 * //Cas o? l'on a un motif en ?toile if(centralStrand!=-1){ //On positionne
2074 * le brin central motif.positionneSpecificStrand(centralStrand,
2075 * spaceBetweenStrand);
2077 * //On place les autres brins par rapport a ce brin central
2078 * motif.orderStrands(centralStrand); }
2080 * else { centralStrand = 0; motif.positionneStrand(); motif.ajusteStrand();
2081 * } motif.reajustement(); motif.deviationBasePair();
2082 * motif.setCenterMotif(); }
2085 public ArrayList<ModeleBase> getAllPartners(int indice) {
2086 ArrayList<ModeleBase> result = new ArrayList<ModeleBase>();
2087 ModeleBase me = this.getBaseAt(indice);
2088 int i = me.getElementStructure();
2090 result.add(getBaseAt(i));
2092 ArrayList<ModeleBP> msbps = getAuxBPs(indice);
2093 for (ModeleBP m : msbps) {
2094 result.add(m.getPartner(me));
2099 public int get_drawMode() {
2103 public void setDrawMode(int drawMode) {
2104 _drawMode = drawMode;
2107 public Set<Integer> getSeparatorPositions(String s) {
2108 HashSet<Integer> result = new HashSet<Integer>();
2109 int index = s.indexOf(DBNStrandSep);
2110 while (index >= 0) {
2112 index = s.indexOf(DBNStrandSep, index + 1);
2117 public static String DBNStrandSep = "&";
2119 public void setRNA(String seq, String str)
2120 throws ExceptionFileFormatOrSyntax,
2121 ExceptionUnmatchedClosingParentheses {
2122 ArrayList<String> al = RNA.explodeSequence(seq);
2123 Set<Integer> sepPos = getSeparatorPositions(str);
2124 ArrayList<String> alRes = new ArrayList<String>();
2125 Set<Integer> resSepPos = new HashSet<Integer>();
2127 for (int i = 0; i < al.size(); i++) {
2128 if (sepPos.contains(i) && al.get(i).equals(DBNStrandSep)) {
2129 resSepPos.add(alRes.size() - 1);
2131 alRes.add(al.get(i));
2134 strRes += str.charAt(i);
2142 for (int i = al.size(); i < str.length(); i++) {
2144 strRes += str.charAt(i);
2146 setRNA(alRes, strRes);
2147 for (int i : resSepPos) {
2148 _backbone.addElement(new ModeleBackboneElement(i,
2149 BackboneType.DISCONTINUOUS_TYPE));
2153 public void setRNA(String seq) {
2154 ArrayList<String> s = RNA.explodeSequence(seq);
2155 int[] str = new int[s.size()];
2156 for (int i = 0; i < str.length; i++) {
2161 } catch (ExceptionFileFormatOrSyntax e) {
2162 // TODO Auto-generated catch block
2163 e.printStackTrace();
2167 public void setRNA(String seq, int[] str)
2168 throws ExceptionFileFormatOrSyntax,
2169 ExceptionUnmatchedClosingParentheses {
2170 setRNA(RNA.explodeSequence(seq), str);
2173 public void setRNA(String[] seq, int[] str)
2174 throws ExceptionFileFormatOrSyntax {
2175 setRNA(seq, str, 1);
2178 public void setRNA(List<String> seq, int[] str)
2179 throws ExceptionFileFormatOrSyntax {
2180 setRNA(seq.toArray(new String[seq.size()]), str, 1);
2183 public void setRNA(List<String> seq, int[] str, int baseIndex)
2184 throws ExceptionFileFormatOrSyntax {
2185 setRNA(seq.toArray(new String[seq.size()]), str, baseIndex);
2188 public void setRNA(String[] seq, int[] str, int baseIndex)
2189 throws ExceptionFileFormatOrSyntax {
2191 _listeBases = new ArrayList<ModeleBase>();
2192 if (seq.length != str.length) {
2193 warningEmition("Sequence length " + seq.length
2194 + " differs from that of secondary structure " + str.length
2195 + ". \nAdapting sequence length ...");
2196 if (seq.length < str.length) {
2197 String[] nseq = new String[str.length];
2198 for (int i = 0; i < seq.length; i++) {
2201 for (int i = seq.length; i < nseq.length; i++) {
2206 String[] seqTmp = new String[str.length];
2207 for (int i = 0; i < str.length; i++) {
2213 for (int i = 0; i < str.length; i++) {
2214 _listeBases.add(new ModeleBaseNucleotide(seq[i], i, baseIndex + i));
2220 * Sets the RNA to be drawn. Uses when comparison mode is on. Will draw the
2221 * super-structure passed in parameters and apply specials styles to the
2222 * bases owning by each RNA alignment and both.
2225 * - The sequence of the super-structure This sequence shall be
2226 * designed like this:
2227 * <code>firstRNA1stBaseSecondRNA1stBaseFirstRNA2ndBaseSecondRNA2ndBase [...]</code>
2229 * <b>Example:</b> <code>AAC-GUAGA--UGG</code>
2231 * - The super-structure
2233 * - The RNA owning bases array (each index will be:0 when common
2234 * base, 1 when first RNA alignment base, 2 when second RNA
2236 * @throws ExceptionUnmatchedClosingParentheses
2237 * @throws ExceptionFileFormatOrSyntax
2239 public void setRNA(String seq, String struct, ArrayList<Integer> basesOwn)
2240 throws ExceptionUnmatchedClosingParentheses,
2241 ExceptionFileFormatOrSyntax {
2243 _listeBases = new ArrayList<ModeleBase>();
2244 // On "parse" la structure (repérage des points, tiret et couples
2245 // parentheses ouvrante/fermante)
2246 int[] array_struct = parseStruct(struct);
2247 int size = struct.length();
2249 for (int i = 0; i < size; i++) {
2251 if (seq.charAt(j) != seq.charAt(j + 1)) {
2252 ModeleBasesComparison mbc = new ModeleBasesComparison(
2253 seq.charAt(j), seq.charAt(j + 1), i);
2254 mbc.set_appartenance(basesOwn.get(i));
2255 mbc.setBaseNumber(i + 1);
2258 mb = new ModeleBaseNucleotide("" + seq.charAt(j), i, i + 1);
2261 _listeBases.add(mb);
2264 for (int i = 0; i < size; i++) {
2265 if (array_struct[i] != -1) {
2266 this.addBPNow(i, array_struct[i]);
2273 public void setRNA(List<String> seq, String dbnStr)
2274 throws ExceptionUnmatchedClosingParentheses,
2275 ExceptionFileFormatOrSyntax {
2277 int[] finStr = RNAFactory.parseSecStr(dbnStr);
2278 setRNA(seq, finStr);
2281 public static ArrayList<String> explodeSequence(String seq) {
2282 ArrayList<String> analyzedSeq = new ArrayList<String>();
2284 while (i < seq.length()) {
2285 if (seq.charAt(i) == '{') {
2286 boolean found = false;
2289 while (!found & (i < seq.length())) {
2290 if (seq.charAt(i) != '}') {
2291 buf += seq.charAt(i);
2297 analyzedSeq.add(buf);
2299 analyzedSeq.add("" + seq.charAt(i));
2306 public int[] parseStruct(String str)
2307 throws ExceptionUnmatchedClosingParentheses,
2308 ExceptionFileFormatOrSyntax {
2309 int[] result = new int[str.length()];
2310 int unexpectedChar = -1;
2311 Stack<Integer> p = new Stack<Integer>();
2312 for (int i = 0; i < str.length(); i++) {
2313 char c = str.charAt(i);
2315 p.push(new Integer(i));
2316 } else if (c == '.' || c == '-' || c == ':') {
2318 } else if (c == ')') {
2319 if (p.size() == 0) {
2320 throw new ExceptionUnmatchedClosingParentheses(i + 1);
2322 int j = p.pop().intValue();
2326 if (unexpectedChar == -1)
2332 if (unexpectedChar != -1) {
2333 // warningEmition("Unexpected Character at index:" +
2337 if (p.size() != 0) {
2338 throw new ExceptionUnmatchedClosingParentheses(
2339 p.pop().intValue() + 1);
2345 public Point getHelixInterval(int index) {
2346 if ((index < 0) || (index >= _listeBases.size())) {
2347 return new Point(index, index);
2349 int j = _listeBases.get(index).getElementStructure();
2358 boolean over = false;
2360 if ((minH < 0) || (maxH >= _listeBases.size())) {
2363 if (_listeBases.get(minH).getElementStructure() == maxH) {
2373 return new Point(minH, maxH);
2375 return new Point(0, 0);
2378 public Point getExteriorHelix(int index) {
2379 Point h = getHelixInterval(index);
2386 h = getHelixInterval(a-1);
2388 return new Point(a, b);
2392 public ArrayList<Integer> getHelix(int index) {
2393 ArrayList<Integer> result = new ArrayList<Integer>();
2394 if ((index < 0) || (index >= _listeBases.size())) {
2397 Point p = getHelixInterval(index);
2398 for (int i = p.x; i <= p.y; i++) {
2400 result.add(this._listeBases.get(i).getElementStructure());
2405 public Point getMultiLoop(int index) {
2406 if ((index < 0) || (index >= _listeBases.size())) {
2407 return new Point(index, index);
2409 Point h = getHelixInterval(index);
2412 boolean over = false;
2418 if (_listeBases.get(minH).getElementStructure() == -1) {
2420 } else if (_listeBases.get(minH).getElementStructure() < minH) {
2421 minH = _listeBases.get(minH).getElementStructure() - 1;
2429 if (maxH > _listeBases.size() - 1) {
2431 maxH = _listeBases.size() - 1;
2433 if (_listeBases.get(maxH).getElementStructure() == -1) {
2435 } else if (_listeBases.get(maxH).getElementStructure() > maxH) {
2436 maxH = _listeBases.get(maxH).getElementStructure() + 1;
2442 return new Point(minH, maxH);
2445 public Vector<Integer> getLoopBases(int startIndex) {
2446 Vector<Integer> result = new Vector<Integer>();
2448 if ((startIndex < 0) || (startIndex >= _listeBases.size())) {
2451 int index = startIndex;
2452 result.add(startIndex);
2453 if (_listeBases.get(index).getElementStructure() <= index) {
2454 index = (index + 1) % _listeBases.size();
2456 index = _listeBases.get(index).getElementStructure();
2458 index = (index + 1) % _listeBases.size();
2461 while (index != startIndex) {
2463 if (_listeBases.get(index).getElementStructure() == -1) {
2464 index = (index + 1) % _listeBases.size();
2466 index = _listeBases.get(index).getElementStructure();
2468 index = (index + 1) % _listeBases.size();
2475 * Returns the RNA secondary structure displayed by this panel as a
2476 * well-parenthesized word, accordingly to the DBN format
2478 * @return This panel's secondary structure
2480 public String getStructDBN() {
2482 for (int i = 0; i < _listeBases.size(); i++) {
2483 int j = _listeBases.get(i).getElementStructure();
2492 return addStrandSeparators(result);
2495 private ArrayList<ModeleBP> getNonCrossingSubset(
2496 ArrayList<ArrayList<ModeleBP>> rankedBPs) {
2497 ArrayList<ModeleBP> currentBPs = new ArrayList<ModeleBP>();
2498 Stack<Integer> pile = new Stack<Integer>();
2499 for (int i = 0; i < rankedBPs.size(); i++) {
2500 ArrayList<ModeleBP> lbp = rankedBPs.get(i);
2501 if (!lbp.isEmpty()) {
2502 ModeleBP bp = lbp.get(0);
2504 if (!pile.empty()) {
2505 int x = pile.peek();
2506 if ((bp.getIndex3() >= x)) {
2513 pile.add(bp.getIndex3());
2516 if (!pile.empty() && (i == pile.peek())) {
2523 public ArrayList<int[]> paginateStructure() {
2524 ArrayList<int[]> result = new ArrayList<int[]>();
2525 // Mumbo jumbo to sort the basepair list
2526 ArrayList<ModeleBP> bps = this.getAllBPs();
2527 ModeleBP[] mt = new ModeleBP[bps.size()];
2529 Arrays.sort(mt, new Comparator<ModeleBP>() {
2530 public int compare(ModeleBP arg0, ModeleBP arg1) {
2531 if (arg0.getIndex5() != arg1.getIndex5())
2532 return arg0.getIndex5() - arg1.getIndex5();
2534 return arg0.getIndex3() - arg1.getIndex3();
2538 ArrayList<ArrayList<ModeleBP>> rankedBps = new ArrayList<ArrayList<ModeleBP>>();
2539 for (int i = 0; i < getSize(); i++) {
2540 rankedBps.add(new ArrayList<ModeleBP>());
2542 for (int i = 0; i < mt.length; i++) {
2543 rankedBps.get(mt[i].getIndex5()).add(mt[i]);
2546 while (!bps.isEmpty()) {
2547 //System.out.println("Page: " + result.size());
2548 ArrayList<ModeleBP> currentBPs = getNonCrossingSubset(rankedBps);
2549 int[] ss = new int[this.getSize()];
2550 for (int i = 0; i < ss.length; i++) {
2554 for (int i = 0; i < currentBPs.size(); i++) {
2555 ModeleBP mbp = currentBPs.get(i);
2556 ss[mbp.getIndex3()] = mbp.getIndex5();
2557 ss[mbp.getIndex5()] = mbp.getIndex3();
2559 bps.removeAll(currentBPs);
2565 private void showBasic(int[] res) {
2566 for (int i = 0; i < res.length; i++) {
2567 System.out.print(res[i] + ",");
2569 System.out.println();
2573 public int[] getStrandShifts()
2575 int[] result = new int[getSize()];
2577 for (int i=0;i<getSize();i++)
2579 if (_backbone.getTypeBefore(i)==BackboneType.DISCONTINUOUS_TYPE)
2589 public String addStrandSeparators(String s)
2592 for (int i=0;i<s.length();i++)
2595 if (_backbone.getTypeAfter(i)==BackboneType.DISCONTINUOUS_TYPE)
2597 res += DBNStrandSep;
2604 public String getStructDBN(boolean includeMostPKs) {
2605 String result = getStructDBN();
2606 if (includeMostPKs) {
2607 ArrayList<int[]> pages = paginateStructure();
2608 char[] res = new char[getSize()];
2609 for (int i = 0; i < res.length; i++) {
2612 char[] open = { '(', '[', '{', '<', 'A', 'B', 'C', 'D', 'E', 'F',
2613 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
2614 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
2616 char[] close = new char[open.length];
2621 for (int i=4; i<open.length;i++)
2623 close[i] = Character.toLowerCase(open[i]);
2626 for (int p = 0; p < Math.min(pages.size(), open.length); p++) {
2627 int[] page = pages.get(p);
2629 for (int i = 0; i < res.length; i++) {
2630 if (page[i] != -1 && page[i] > i && res[i] == '.'
2631 && res[page[i]] == '.') {
2633 res[page[i]] = close[p];
2638 for (int i = 0; i < res.length; i++) {
2643 return addStrandSeparators(result);
2647 public String getStructDBN(int[] str) {
2649 for (int i = 0; i < str.length; i++) {
2652 } else if (str[i] > i) {
2658 return addStrandSeparators(result);
2662 * Returns the raw nucleotides sequence for the displayed RNA
2664 * @return The RNA sequence
2666 public String getSeq() {
2668 for (int i = 0; i < _listeBases.size(); i++) {
2669 result += ((ModeleBase) _listeBases.get(i)).getContent();
2671 return addStrandSeparators(result);
2674 public String getStructBPSEQ() {
2676 int[] str = getNonOverlappingStruct();
2677 for (int i = 0; i < _listeBases.size(); i++) {
2678 result += (i + 1) + " "
2679 + ((ModeleBaseNucleotide) _listeBases.get(i)).getContent()
2680 + " " + (str[i] + 1) + "\n";
2685 public int[] getNonCrossingStruct() {
2686 int[] result = new int[_listeBases.size()];
2687 // Adding "planar" base-pairs
2688 for (int i = 0; i < _listeBases.size(); i++) {
2689 result[i] = _listeBases.get(i).getElementStructure();
2694 public int[] getNonOverlappingStruct() {
2695 int[] result = getNonCrossingStruct();
2696 // Adding additional base pairs when possible (No more than one
2697 // base-pair per base)
2698 for (int i = 0; i < _structureAux.size(); i++) {
2699 ModeleBP msbp = _structureAux.get(i);
2700 ModeleBase mb5 = msbp.getPartner5();
2701 ModeleBase mb3 = msbp.getPartner3();
2702 int j5 = mb5.getIndex();
2703 int j3 = mb3.getIndex();
2704 if ((result[j3] == -1) && (result[j5] == -1)) {
2712 public String getStructCT() {
2714 for (int i = 0; i < _listeBases.size(); i++) {
2715 result += (i + 1) + " "
2716 + ((ModeleBase) _listeBases.get(i)).getContent() + " " + i
2717 + " " + (i + 2) + " "
2718 + (_listeBases.get(i).getElementStructure() + 1) + " "
2724 public void saveAsBPSEQ(String path, String title)
2725 throws ExceptionExportFailed, ExceptionPermissionDenied {
2727 FileWriter f = new FileWriter(path);
2728 f.write("# " + title + "\n");
2729 f.write(this.getStructBPSEQ() + "\n");
2731 } catch (IOException e) {
2732 throw new ExceptionExportFailed(e.getMessage(), path);
2736 public void saveAsCT(String path, String title)
2737 throws ExceptionExportFailed, ExceptionPermissionDenied {
2739 FileWriter f = new FileWriter(path);
2740 f.write("" + _listeBases.size() + " " + title + "\n");
2741 f.write(this.getStructCT() + "\n");
2743 } catch (IOException e) {
2744 throw new ExceptionExportFailed(e.getMessage(), path);
2748 public void saveAsDBN(String path, String title)
2749 throws ExceptionExportFailed, ExceptionPermissionDenied {
2751 FileWriter f = new FileWriter(path);
2752 f.write("> " + title + "\n");
2753 f.write(getListeBasesToString() + "\n");
2754 f.write(getStructDBN() + "\n");
2756 } catch (IOException e) {
2757 throw new ExceptionExportFailed(e.getMessage(), path);
2761 public String getListeBasesToString() {
2762 String s = new String();
2763 for (int i = 0; i < _listeBases.size(); i++) {
2764 s += ((ModeleBaseNucleotide) _listeBases.get(i)).getContent();
2766 return addStrandSeparators(s);
2769 public void applyBPs(ArrayList<ModeleBP> allbps) {
2770 ArrayList<ModeleBP> planar = new ArrayList<ModeleBP>();
2771 ArrayList<ModeleBP> others = new ArrayList<ModeleBP>();
2772 // System.err.println("Sequence: "+this.getSeq());
2773 RNAMLParser.planarize(allbps, planar, others, getSize());
2774 // System.err.println("All:"+allbps);
2775 // System.err.println("=> Planar: "+planar);
2776 // System.err.println("=> Others: "+others);
2778 for (ModeleBP mb : planar) {
2779 addBPnow(mb.getPartner5().getIndex(), mb.getPartner3().getIndex(),
2783 for (ModeleBP mb : others) {
2784 addBPAux(mb.getPartner5().getIndex(), mb.getPartner3().getIndex(),
2789 public void set_listeBases(ArrayList<ModeleBase> _liste) {
2790 this._listeBases = _liste;
2793 public void addVARNAListener(InterfaceVARNAListener rl) {
2794 _listeVARNAListener.add(rl);
2797 public void warningEmition(String warningMessage) {
2798 for (int i = 0; i < _listeVARNAListener.size(); i++) {
2799 _listeVARNAListener.get(i).onWarningEmitted(warningMessage);
2803 public void applyStyleOnBases(ArrayList<Integer> basesList,
2804 ModelBaseStyle style) {
2805 for (int i = 1; i < basesList.size(); i++) {
2806 _listeBases.get(basesList.get(i)).setStyleBase(style);
2810 private int[] correctReciprocity(int[] str) {
2811 int[] result = new int[str.length];
2812 for (int i = 0; i < str.length; i++) {
2814 if (i == str[str[i]]) {
2826 private void applyStruct(int[] str) throws ExceptionFileFormatOrSyntax {
2827 str = correctReciprocity(str);
2829 int[] planarSubset = RNAMLParser.planarize(str);
2830 _structureAux.clear();
2832 for (int i = 0; i < planarSubset.length; i++) {
2834 if (planarSubset[i] > i) {
2835 addBPNow(i, planarSubset[i]);
2836 } else if ((planarSubset[i] != str[i])) {
2837 addBPAux(i, str[i]);
2844 public ArrayList<ModeleBase> get_listeBases() {
2848 public int getSize() {
2849 return _listeBases.size();
2852 public ArrayList<Integer> findAll() {
2853 ArrayList<Integer> listAll = new ArrayList<Integer>();
2854 for (int i = 0; i < get_listeBases().size(); i++) {
2860 public ArrayList<Integer> findBulge(int index) {
2861 ArrayList<Integer> listUp = new ArrayList<Integer>();
2862 if (get_listeBases().get(index).getElementStructure() == -1) {
2864 boolean over = false;
2865 while ((i < get_listeBases().size()) && !over) {
2866 int j = get_listeBases().get(i).getElementStructure();
2876 while ((i >= 0) && !over) {
2877 int j = get_listeBases().get(i).getElementStructure();
2889 public ArrayList<Integer> findStem(int index) {
2890 ArrayList<Integer> listUp = new ArrayList<Integer>();
2894 int j = get_listeBases().get(i).getElementStructure();
2896 i = (i + 1) % getSize();
2898 if ((j < i) && (index <= i) && (j <= index)) {
2901 i = (i + 1) % getSize();
2904 } while (i != index);
2908 public int getHelixCountOnLoop(int indice) {
2910 if (indice < 0 || indice >= get_listeBases().size())
2913 int j = get_listeBases().get(i).getElementStructure();
2914 // Only way to distinguish "supporting base-pair" from others
2915 boolean justJumped = false;
2916 if ((j != -1) && (j < i)) {
2921 j = get_listeBases().get(i).getElementStructure();
2922 if ((j != -1) && (!justJumped)) {
2927 i = (i + 1) % get_listeBases().size();
2930 } while (i != indice);
2934 public ArrayList<Integer> findLoop(int indice) {
2935 return findLoopForward(indice);
2938 public ArrayList<Integer> findLoopForward(int indice) {
2939 ArrayList<Integer> base = new ArrayList<Integer>();
2940 if (indice < 0 || indice >= get_listeBases().size())
2943 int j = get_listeBases().get(i).getElementStructure();
2944 // Only way to distinguish "supporting base-pair" from others
2945 boolean justJumped = false;
2947 i = Math.min(i, j) + 1;
2952 j = get_listeBases().get(i).getElementStructure();
2953 if ((j != -1) && (!justJumped)) {
2957 i = (i + 1) % get_listeBases().size();
2960 } while (i != indice);
2964 public ArrayList<Integer> findPair(int indice) {
2965 ArrayList<Integer> base = new ArrayList<Integer>();
2966 int j = get_listeBases().get(indice).getElementStructure();
2968 base.add(Math.min(indice, j));
2969 base.add(Math.max(indice, j));
2976 public ArrayList<Integer> findLoopBackward(int indice) {
2977 ArrayList<Integer> base = new ArrayList<Integer>();
2978 if (indice < 0 || indice >= get_listeBases().size())
2981 int j = get_listeBases().get(i).getElementStructure();
2982 // Only way to distinguish "supporting base-pair" from others
2983 boolean justJumped = false;
2985 i = Math.min(i, j) - 1;
2993 j = get_listeBases().get(i).getElementStructure();
2994 if ((j != -1) && (!justJumped)) {
2998 i = (i + get_listeBases().size() - 1) % get_listeBases().size();
3001 } while (i != indice);
3005 public ArrayList<Integer> findHelix(int indice) {
3006 ArrayList<Integer> list = new ArrayList<Integer>();
3007 if (get_listeBases().get(indice).getElementStructure() != -1) {
3009 list.add(get_listeBases().get(indice).getElementStructure());
3010 int i = 1, prec = get_listeBases().get(indice)
3011 .getElementStructure();
3012 while (indice + i < get_listeBases().size()
3013 && get_listeBases().get(indice + i).getElementStructure() != -1
3014 && get_listeBases().get(indice + i).getElementStructure() == prec - 1) {
3015 list.add(indice + i);
3016 list.add(get_listeBases().get(indice + i).getElementStructure());
3017 prec = get_listeBases().get(indice + i).getElementStructure();
3021 prec = get_listeBases().get(indice).getElementStructure();
3022 while (indice + i >= 0
3023 && get_listeBases().get(indice + i).getElementStructure() != -1
3024 && get_listeBases().get(indice + i).getElementStructure() == prec + 1) {
3025 list.add(indice + i);
3026 list.add(get_listeBases().get(indice + i).getElementStructure());
3027 prec = get_listeBases().get(indice + i).getElementStructure();
3034 public ArrayList<Integer> find3Prime(int indice) {
3035 ArrayList<Integer> list = new ArrayList<Integer>();
3036 boolean over = false;
3037 while ((indice >= 0) && !over) {
3038 over = (get_listeBases().get(indice).getElementStructure() != -1);
3045 for (int i = indice; i < get_listeBases().size(); i++) {
3047 if (get_listeBases().get(i).getElementStructure() != -1) {
3048 return new ArrayList<Integer>();
3054 public ArrayList<Integer> find5Prime(int indice) {
3055 ArrayList<Integer> list = new ArrayList<Integer>();
3056 for (int i = 0; i <= indice; i++) {
3058 if (get_listeBases().get(i).getElementStructure() != -1) {
3059 return new ArrayList<Integer>();
3065 public static Double angle(Point2D.Double p1, Point2D.Double p2,
3066 Point2D.Double p3) {
3067 Double alpha = Math.atan2(p1.y - p2.y, p1.x - p2.x);
3068 Double beta = Math.atan2(p3.y - p2.y, p3.x - p2.x);
3069 Double angle = (beta - alpha);
3071 // Correction de l'angle pour le resituer entre 0 et 2PI
3072 while (angle < 0.0 || angle > 2 * Math.PI) {
3074 angle += 2 * Math.PI;
3075 else if (angle > 2 * Math.PI)
3076 angle -= 2 * Math.PI;
3081 public ArrayList<Integer> findNonPairedBaseGroup(Integer get_nearestBase) {
3082 // detection 3', 5', bulge
3083 ArrayList<Integer> list = new ArrayList<Integer>();
3084 int indice = get_nearestBase;
3085 boolean nonpairedUp = true, nonpairedDown = true;
3086 while (indice < get_listeBases().size() && nonpairedUp) {
3087 if (get_listeBases().get(indice).getElementStructure() == -1) {
3091 nonpairedUp = false;
3094 indice = get_nearestBase - 1;
3095 while (indice >= 0 && nonpairedDown) {
3096 if (get_listeBases().get(indice).getElementStructure() == -1) {
3100 nonpairedDown = false;
3107 * public boolean getDrawn() { return _drawn; }
3110 public ArrayList<ModeleBP> getStructureAux() {
3111 return _structureAux;
3115 * Translates a base number into its corresponding index. Although both
3116 * should be unique, base numbers are not necessarily contiguous, and
3117 * indices should be preferred for any reasonably complex algorithmic
3122 * @return The first index whose associated Base model has base number
3123 * <code>num</code>, <code>-1</code> of no such base model exists.
3126 public int getIndexFromBaseNumber(int num) {
3127 for (int i = 0; i < this._listeBases.size(); i++) {
3128 if (_listeBases.get(i).getBaseNumber() == num) {
3136 * Adds a base pair to this RNA's structure. Tries to add it to the
3137 * secondary structure first, eventually adding it to the 'tertiary'
3138 * interactions if it clashes with the current secondary structure.
3140 * @param baseNumber5
3141 * - Base number of the origin of this base pair
3142 * @param baseNumber3
3143 * - Base number of the destination of this base pair
3146 public void addBPToStructureUsingNumbers(int baseNumber5, int baseNumber3) {
3147 int i = getIndexFromBaseNumber(baseNumber5);
3148 int j = getIndexFromBaseNumber(baseNumber3);
3153 * Adds a base pair to this RNA's structure. Tries to add it to the
3154 * secondary structure first, possibly adding it to the 'tertiary'
3155 * interactions if it clashes with the current secondary structure.
3158 * - Base number of the origin of this base pair
3160 * - Base number of the destination of this base pair
3163 public void addBPToStructureUsingNumbers(int number5, int number3,
3165 addBP(getIndexFromBaseNumber(number5), getIndexFromBaseNumber(number3),
3169 public void addBP(int index5, int index3) {
3172 ModeleBase part5 = _listeBases.get(i);
3173 ModeleBase part3 = _listeBases.get(j);
3174 ModeleBP msbp = new ModeleBP(part5, part3);
3178 public void addBP(int index5, int index3, ModeleBP msbp) {
3188 for (int k = i; k <= j; k++) {
3189 ModeleBase tmp = _listeBases.get(k);
3190 int l = tmp.getElementStructure();
3192 if ((l <= i) || (l >= j)) {
3193 addBPAux(i, j, msbp);
3198 addBPnow(i, j, msbp);
3202 public void removeBP(ModeleBP ms) {
3203 if (_structureAux.contains(ms)) {
3204 _structureAux.remove(ms);
3206 ModeleBase m5 = ms.getPartner5();
3207 ModeleBase m3 = ms.getPartner3();
3208 int i = m5.getIndex();
3209 int j = m3.getIndex();
3210 if ((m5.getElementStructure() == m3.getIndex())
3211 && (m3.getElementStructure() == m5.getIndex())) {
3212 m5.removeElementStructure();
3213 m3.removeElementStructure();
3219 * Register base-pair, no question asked. More precisely, this function will
3220 * not try to determine if the base-pairs crosses any other.
3226 private void addBPNow(int i, int j) {
3233 ModeleBase part5 = _listeBases.get(i);
3234 ModeleBase part3 = _listeBases.get(j);
3235 ModeleBP msbp = new ModeleBP(part5, part3);
3236 addBPnow(i, j, msbp);
3240 * Register base-pair, no question asked. More precisely, this function will
3241 * not try to determine if the base-pairs crosses any other.
3247 private void addBPnow(int i, int j, ModeleBP msbp) {
3253 ModeleBase part5 = _listeBases.get(i);
3254 ModeleBase part3 = _listeBases.get(j);
3255 msbp.setPartner5(part5);
3256 msbp.setPartner3(part3);
3257 part5.setElementStructure(j, msbp);
3258 part3.setElementStructure(i, msbp);
3261 public void addBPAux(int i, int j) {
3262 ModeleBase part5 = _listeBases.get(i);
3263 ModeleBase part3 = _listeBases.get(j);
3264 ModeleBP msbp = new ModeleBP(part5, part3);
3265 addBPAux(i, j, msbp);
3268 public void addBPAux(int i, int j, ModeleBP msbp) {
3274 ModeleBase part5 = _listeBases.get(i);
3275 ModeleBase part3 = _listeBases.get(j);
3276 msbp.setPartner5(part5);
3277 msbp.setPartner3(part3);
3278 _structureAux.add(msbp);
3281 public ArrayList<ModeleBP> getBPsAt(int i) {
3282 ArrayList<ModeleBP> result = new ArrayList<ModeleBP>();
3283 if (_listeBases.get(i).getElementStructure() != -1) {
3284 result.add(_listeBases.get(i).getStyleBP());
3286 for (int k = 0; k < _structureAux.size(); k++) {
3287 ModeleBP bp = _structureAux.get(k);
3288 if ((bp.getPartner5().getIndex() == i)
3289 || (bp.getPartner3().getIndex() == i)) {
3297 public ModeleBP getBPStyle(int i, int j) {
3298 ModeleBP result = null;
3304 if (_listeBases.get(i).getElementStructure() == j) {
3305 result = _listeBases.get(i).getStyleBP();
3307 for (int k = 0; k < _structureAux.size(); k++) {
3308 ModeleBP bp = _structureAux.get(k);
3309 if ((bp.getPartner5().getIndex() == i)
3310 && (bp.getPartner3().getIndex() == j)) {
3317 public ArrayList<ModeleBP> getSecStrBPs() {
3318 ArrayList<ModeleBP> result = new ArrayList<ModeleBP>();
3319 for (int i = 0; i < this.getSize(); i++) {
3320 ModeleBase mb = _listeBases.get(i);
3321 int k = mb.getElementStructure();
3322 if ((k != -1) && (k > i)) {
3323 result.add(mb.getStyleBP());
3329 public ArrayList<ModeleBP> getAuxBPs() {
3330 ArrayList<ModeleBP> result = new ArrayList<ModeleBP>();
3331 for (ModeleBP bp : _structureAux) {
3337 public ArrayList<ModeleBP> getAllBPs() {
3338 ArrayList<ModeleBP> result = new ArrayList<ModeleBP>();
3339 result.addAll(getSecStrBPs());
3340 result.addAll(getAuxBPs());
3344 public ArrayList<ModeleBP> getAuxBPs(int i) {
3345 ArrayList<ModeleBP> result = new ArrayList<ModeleBP>();
3346 for (ModeleBP bp : _structureAux) {
3347 if ((bp.getPartner5().getIndex() == i)
3348 || (bp.getPartner3().getIndex() == i)) {
3355 public void setBaseInnerColor(Color c) {
3356 for (int i = 0; i < _listeBases.size(); i++) {
3357 ModeleBase mb = _listeBases.get(i);
3358 mb.getStyleBase().setBaseInnerColor(c);
3362 public void setBaseNumbersColor(Color c) {
3363 for (int i = 0; i < _listeBases.size(); i++) {
3364 ModeleBase mb = _listeBases.get(i);
3365 mb.getStyleBase().setBaseNumberColor(c);
3369 public void setBaseNameColor(Color c) {
3370 for (int i = 0; i < _listeBases.size(); i++) {
3371 ModeleBase mb = _listeBases.get(i);
3372 mb.getStyleBase().setBaseNameColor(c);
3376 public void setBaseOutlineColor(Color c) {
3377 for (int i = 0; i < _listeBases.size(); i++) {
3378 ModeleBase mb = _listeBases.get(i);
3379 mb.getStyleBase().setBaseOutlineColor(c);
3383 public String getName() {
3387 public void setName(String n) {
3391 public ArrayList<TextAnnotation> getAnnotations() {
3392 return _listeAnnotations;
3395 public boolean removeAnnotation(TextAnnotation t) {
3396 return _listeAnnotations.remove(t);
3399 public void addAnnotation(TextAnnotation t) {
3400 _listeAnnotations.add(t);
3403 public void removeAnnotation(String filter) {
3404 ArrayList<TextAnnotation> condamne = new ArrayList<TextAnnotation>();
3405 for (TextAnnotation t : _listeAnnotations) {
3406 if (t.getTexte().contains(filter)) {
3410 for (TextAnnotation t : condamne) {
3411 _listeAnnotations.remove(t);
3415 public void clearAnnotations() {
3416 _listeAnnotations.clear();
3419 private boolean _strandEndsAnnotated = false;
3421 public void autoAnnotateStrandEnds() {
3422 if (!_strandEndsAnnotated) {
3423 int tailleListBases = _listeBases.size();
3424 boolean endAnnotate = false;
3425 addAnnotation(new TextAnnotation("5'", _listeBases.get(0)));
3426 for (int i = 0; i < _listeBases.size() - 1; i++) {
3427 int realposA = _listeBases.get(i).getBaseNumber();
3428 int realposB = _listeBases.get(i + 1).getBaseNumber();
3429 if (realposB - realposA != 1) {
3430 addAnnotation(new TextAnnotation("3'", _listeBases.get(i)));
3431 addAnnotation(new TextAnnotation("5'",
3432 _listeBases.get(i + 1)));
3433 if (i + 1 == _listeBases.size() - 1) {
3439 addAnnotation(new TextAnnotation("3'",
3440 _listeBases.get(tailleListBases - 1)));
3442 _strandEndsAnnotated = true;
3444 removeAnnotation("3'");
3445 removeAnnotation("5'");
3446 _strandEndsAnnotated = false;
3450 public void autoAnnotateHelices() {
3451 Stack<Integer> p = new Stack<Integer>();
3454 while (!p.empty()) {
3456 if (i < _listeBases.size()) {
3457 ModeleBase mb = _listeBases.get(i);
3458 int j = mb.getElementStructure();
3463 ModeleBase mbp = _listeBases.get(j);
3465 ArrayList<ModeleBase> h = new ArrayList<ModeleBase>();
3467 while (mb.getElementStructure() == mbp.getIndex()) {
3470 mb = _listeBases.get(i + k);
3471 mbp = _listeBases.get(j - k);
3476 addAnnotation(new TextAnnotation("H" + nbH++, h,
3477 TextAnnotation.AnchorType.HELIX));
3478 } catch (Exception e) {
3479 e.printStackTrace();
3488 public void autoAnnotateTerminalLoops() {
3489 Stack<Integer> p = new Stack<Integer>();
3492 while (!p.empty()) {
3494 if (i < _listeBases.size()) {
3495 ModeleBase mb = _listeBases.get(i);
3496 int j = mb.getElementStructure();
3499 ArrayList<ModeleBase> t = new ArrayList<ModeleBase>();
3500 while ((i + k < getSize())
3501 && (mb.getElementStructure() == -1)) {
3503 mb = _listeBases.get(i + k);
3506 if (mb.getElementStructure() != -1) {
3507 if (mb.getElementStructure() == i - 1) {
3509 t.add(_listeBases.get(i - 1));
3510 t.add(_listeBases.get(i + k - 1));
3511 addAnnotation(new TextAnnotation("T" + nbT++,
3512 t, TextAnnotation.AnchorType.LOOP));
3513 } catch (Exception e) {
3514 e.printStackTrace();
3530 public void autoAnnotateInteriorLoops() {
3531 Stack<Integer> p = new Stack<Integer>();
3534 while (!p.empty()) {
3536 if (i < _listeBases.size()) {
3537 ModeleBase mb = _listeBases.get(i);
3538 int j = mb.getElementStructure();
3541 ArrayList<ModeleBase> t = new ArrayList<ModeleBase>();
3542 boolean terminal = true;
3543 while ((k < getSize())
3544 && ((mb.getElementStructure() >= i) || (mb
3545 .getElementStructure() == -1))) {
3547 mb = _listeBases.get(k);
3548 if ((mb.getElementStructure() == -1)
3549 || (mb.getElementStructure() < k))
3554 k = mb.getElementStructure();
3557 if (mb.getElementStructure() != -1) {
3558 if ((mb.getElementStructure() == i - 1) && !terminal) {
3560 t.add(_listeBases.get(i - 1));
3561 t.add(_listeBases.get(k - 1));
3562 addAnnotation(new TextAnnotation("I" + nbT++,
3563 t, TextAnnotation.AnchorType.LOOP));
3564 } catch (Exception e) {
3565 e.printStackTrace();
3579 @SuppressWarnings("unchecked")
3580 public TextAnnotation getAnnotation(TextAnnotation.AnchorType type,
3582 TextAnnotation result = null;
3583 for (TextAnnotation t : _listeAnnotations) {
3584 if (t.getType() == type) {
3587 if (base == (ModeleBase) t.getAncrage())
3592 ArrayList<ModeleBase> mbl = (ArrayList<ModeleBase>) t
3594 if (mbl.contains(base))
3604 public void addChemProbAnnotation(ChemProbAnnotation cpa) {
3605 //System.err.println(cpa.isOut());
3606 _chemProbAnnotations.add(cpa);
3609 public ArrayList<ChemProbAnnotation> getChemProbAnnotations() {
3610 return _chemProbAnnotations;
3613 public void setColorMapValues(Double[] values, ModeleColorMap cm) {
3614 setColorMapValues(values, cm, false);
3617 public void adaptColorMapToValues(ModeleColorMap cm) {
3618 double min = Double.MAX_VALUE;
3619 double max = Double.MIN_VALUE;
3620 for (int i = 0; i < Math.min(_listeBases.size(), _listeBases.size()); i++) {
3621 ModeleBase mb = _listeBases.get(i);
3622 max = Math.max(max, mb.getValue());
3623 min = Math.min(min, mb.getValue());
3625 cm.rescale(min, max);
3629 private ArrayList<Double> loadDotPlot(StreamTokenizer st)
3631 ArrayList<Double> result = new ArrayList<Double>();
3633 boolean inSeq = false;
3634 String sequence = "";
3635 ArrayList<Double> accumulator = new ArrayList<Double>();
3636 int type = st.nextToken();
3637 Hashtable<Couple<Integer,Integer>,Double> BP = new Hashtable<Couple<Integer,Integer>,Double>();
3638 while (type != StreamTokenizer.TT_EOF) {
3640 case (StreamTokenizer.TT_NUMBER):
3641 accumulator.add(st.nval);
3643 case (StreamTokenizer.TT_EOL):
3645 case (StreamTokenizer.TT_WORD):
3646 if (st.sval.equals("/sequence"))
3650 else if (st.sval.equals("ubox"))
3652 int i = accumulator.get(accumulator.size()-3).intValue()-1;
3653 int j = accumulator.get(accumulator.size()-2).intValue()-1;
3654 double val = accumulator.get(accumulator.size()-1);
3655 //System.err.println((char) type);
3656 BP.put(new Couple<Integer, Integer>(Math.min(i, j), Math.max(i, j)),val*val);
3657 accumulator.clear();
3661 sequence += st.sval;
3668 type = st.nextToken();
3670 for (int i = 0; i < getSize(); i++) {
3671 int j = getBaseAt(i).getElementStructure();
3673 Couple<Integer, Integer> coor = new Couple<Integer, Integer>(
3674 Math.min(i, j), Math.max(i, j));
3675 if (BP.containsKey(coor)) {
3676 result.add(BP.get(coor));
3682 for (int k = 0; k < getSize(); k++) {
3683 Couple<Integer, Integer> coor = new Couple<Integer, Integer>(
3684 Math.min(i, k), Math.max(i, k));
3685 if (BP.containsKey(coor)) {
3686 acc -= BP.get(coor);
3692 } catch (IOException e) {
3693 // TODO Auto-generated catch block
3694 e.printStackTrace();
3699 public void readValues(Reader r, ModeleColorMap cm) {
3701 StreamTokenizer st = new StreamTokenizer(r);
3702 st.eolIsSignificant(true);
3703 st.wordChars('/', '/');
3705 ArrayList<Double> vals = new ArrayList<Double>();
3706 ArrayList<Double> curVals = new ArrayList<Double>();
3707 int type = st.nextToken();
3708 boolean isDotPlot = false;
3711 vals = loadDotPlot(st);
3716 while (type != StreamTokenizer.TT_EOF) {
3718 case (StreamTokenizer.TT_NUMBER):
3719 curVals.add(st.nval);
3721 case (StreamTokenizer.TT_EOL):
3722 if (curVals.size() > 0) {
3723 vals.add(curVals.get(curVals.size()-1));
3724 curVals = new ArrayList<Double>();
3728 type = st.nextToken();
3730 if (curVals.size() > 0)
3731 vals.add(curVals.get(curVals.size()-1));
3734 Double[] v = new Double[vals.size()];
3735 for (int i = 0; i < Math.min(vals.size(), getSize()); i++) {
3738 setColorMapValues(v, cm, true);
3741 cm.setMinValue(0.0);
3742 cm.setMaxValue(1.0);
3744 } catch (IOException e) {
3745 e.printStackTrace();
3749 public void setColorMapValues(Double[] values, ModeleColorMap cm,
3750 boolean rescaleColorMap) {
3751 if (values.length > 0) {
3752 for (int i = 0; i < Math.min(values.length, _listeBases.size()); i++) {
3753 ModeleBase mb = _listeBases.get(i);
3754 mb.setValue(values[i]);
3756 if (rescaleColorMap) {
3757 adaptColorMapToValues(cm);
3762 public Double[] getColorMapValues() {
3763 Double[] values = new Double[_listeBases.size()];
3764 for (int i = 0; i < _listeBases.size(); i++) {
3765 values[i] = _listeBases.get(i).getValue();
3770 public void rescaleColorMap(ModeleColorMap cm) {
3771 Double max = Double.MIN_VALUE;
3772 Double min = Double.MAX_VALUE;
3773 for (int i = 0; i < _listeBases.size(); i++) {
3774 Double value = _listeBases.get(i).getValue();
3775 max = Math.max(max, value);
3776 min = Math.min(min, value);
3778 cm.rescale(min, max);
3781 public void addBase(ModeleBase mb) {
3782 _listeBases.add(mb);
3785 public void setSequence(String s) {
3786 setSequence(RNA.explodeSequence(s));
3789 public void setSequence(List<String> s) {
3792 while ((i < s.size()) && (j < _listeBases.size())) {
3793 ModeleBase mb = _listeBases.get(j);
3794 if (mb instanceof ModeleBaseNucleotide) {
3795 ((ModeleBaseNucleotide) mb).setBase(s.get(i));
3798 } else if (mb instanceof ModeleBasesComparison) {
3799 ((ModeleBasesComparison) mb)
3800 .setBase1(((s.get(i).length() > 0) ? s.get(i).charAt(0)
3802 ((ModeleBasesComparison) mb)
3803 .setBase2(((s.get(i + 1).length() > 0) ? s.get(i + 1)
3810 for (i = _listeBases.size(); i < s.size(); i++) {
3811 _listeBases.add(new ModeleBaseNucleotide(s.get(i), i));
3815 public void eraseSequence() {
3817 while ((j < _listeBases.size())) {
3818 ModeleBase mb = _listeBases.get(j);
3819 if (mb instanceof ModeleBaseNucleotide) {
3820 ((ModeleBaseNucleotide) mb).setBase("");
3822 } else if (mb instanceof ModeleBasesComparison) {
3823 ((ModeleBasesComparison) mb).setBase1(' ');
3824 ((ModeleBasesComparison) mb).setBase2(' ');
3831 public RNA clone() {
3833 ByteArrayOutputStream out = new ByteArrayOutputStream();
3834 ObjectOutputStream oout = new ObjectOutputStream(out);
3835 oout.writeObject(this);
3837 ObjectInputStream in = new ObjectInputStream(
3838 new ByteArrayInputStream(out.toByteArray()));
3839 return (RNA) in.readObject();
3840 } catch (Exception e) {
3841 throw new RuntimeException("cannot clone class ["
3842 + this.getClass().getName() + "] via serialization: "
3848 * Returns the base at index <code>index</code>. Indices are contiguous in
3849 * the sequence over an interval <code>[0,this.getSize()-1]</code>, where
3850 * <code>n</code> is the length of the sequence.
3853 * The index, <code>0 ≤ index < this.getSize()</code>, of the
3855 * @return The base model of index <code>index</code>
3857 public ModeleBase getBaseAt(int index) {
3858 return this._listeBases.get(index);
3862 * Returns the set of bases of indices in <code>indices</code>. Indices are
3863 * contiguous in the sequence, and belong to an interval
3864 * <code>[0,n-1]</code>, where <code>n</code> is the length of the sequence.
3867 * A Collection of indices <code>i</code>,
3868 * <code>0 ≤ index < this.getSize()</code>, where some base
3870 * @return A list of base model of indices in <code>indices</code>
3872 public ArrayList<ModeleBase> getBasesAt(
3873 Collection<? extends Integer> indices) {
3874 ArrayList<ModeleBase> mbs = new ArrayList<ModeleBase>();
3875 for (int i : indices) {
3876 mbs.add(getBaseAt(i));
3881 public ArrayList<ModeleBase> getBasesBetween(int from, int to) {
3882 ArrayList<ModeleBase> mbs = new ArrayList<ModeleBase>();
3883 int bck = Math.min(from, to);
3884 to = Math.max(from, to);
3886 for (int i = from; i <= to; i++) {
3887 mbs.add(getBaseAt(i));
3892 public void addHighlightRegion(HighlightRegionAnnotation n) {
3893 _listeRegionHighlights.add(n);
3896 public void removeHighlightRegion(HighlightRegionAnnotation n) {
3897 _listeRegionHighlights.remove(n);
3900 public void removeChemProbAnnotation(ChemProbAnnotation a) {
3901 _chemProbAnnotations.remove(a);
3904 public void clearChemProbAnnotations() {
3905 _chemProbAnnotations.clear();
3908 public void addHighlightRegion(int from, int to, Color fill, Color outline,
3910 _listeRegionHighlights.add(new HighlightRegionAnnotation(
3911 getBasesBetween(from, to), fill, outline, radius));
3914 public void addHighlightRegion(int from, int to) {
3915 _listeRegionHighlights.add(new HighlightRegionAnnotation(
3916 getBasesBetween(from, to)));
3919 public ArrayList<HighlightRegionAnnotation> getHighlightRegion() {
3920 return _listeRegionHighlights;
3924 * Rotates the RNA coordinates by a certain angle
3926 * @param angleDegres
3927 * Rotation angle, in degrees
3929 public void globalRotation(Double angleDegres) {
3930 if (_listeBases.size() > 0) {
3933 Double angle = angleDegres * Math.PI / 180;
3935 // initialisation du minimum et dumaximum
3936 Double maxX = _listeBases.get(0).getCoords().x;
3937 Double maxY = _listeBases.get(0).getCoords().y;
3938 Double minX = _listeBases.get(0).getCoords().x;
3939 Double minY = _listeBases.get(0).getCoords().y;
3940 // mise a jour du minimum et du maximum
3941 for (int i = 0; i < _listeBases.size(); i++) {
3942 if (_listeBases.get(i).getCoords().getX() < minX)
3943 minX = _listeBases.get(i).getCoords().getX();
3944 if (_listeBases.get(i).getCoords().getY() < minY)
3945 minY = _listeBases.get(i).getCoords().getY();
3946 if (_listeBases.get(i).getCoords().getX() > maxX)
3947 maxX = _listeBases.get(i).getCoords().getX();
3948 if (_listeBases.get(i).getCoords().getX() > maxY)
3949 maxY = _listeBases.get(i).getCoords().getY();
3951 // creation du point central
3952 Point2D.Double centre = new Point2D.Double((maxX - minX) / 2,
3955 for (int i = 0; i < _listeBases.size(); i++) {
3956 // application de la rotation au centre de chaque base
3957 // x' = cos(theta)*(x-xc) - sin(theta)*(y-yc) + xc
3959 * (_listeBases.get(i).getCenter().getX() - centre.x)
3961 * (_listeBases.get(i).getCenter().getY() - centre.y)
3963 // y' = sin(theta)*(x-xc) + cos(theta)*(y-yc) + yc
3965 * (_listeBases.get(i).getCenter().getX() - centre.x)
3967 * (_listeBases.get(i).getCenter().getY() - centre.y)
3969 _listeBases.get(i).setCenter(new Point2D.Double(x, y));
3971 // application de la rotation au coordonnees de chaque
3973 // x' = cos(theta)*(x-xc) - sin(theta)*(y-yc) + xc
3975 * (_listeBases.get(i).getCoords().getX() - centre.x)
3977 * (_listeBases.get(i).getCoords().getY() - centre.y)
3979 // y' = sin(theta)*(x-xc) + cos(theta)*(y-yc) + yc
3981 * (_listeBases.get(i).getCoords().getX() - centre.x)
3983 * (_listeBases.get(i).getCoords().getY() - centre.y)
3985 _listeBases.get(i).setCoords(new Point2D.Double(x, y));
3990 private static double MIN_DISTANCE = 10.;
3994 * Flip an helix around its supporting base
3996 public void flipHelix(Point h) {
3997 if (h.x!=-1 && h.y!=-1 && h.x!=h.y)
4001 Point2D.Double A = getCoords(hBeg);
4002 Point2D.Double B = getCoords(hEnd);
4003 Point2D.Double AB = new Point2D.Double(B.x - A.x, B.y - A.y);
4004 double normAB = Math.sqrt(AB.x * AB.x + AB.y * AB.y);
4005 // Creating a coordinate system centered on A and having
4006 // unit x-vector Ox.
4007 Point2D.Double O = A;
4008 Point2D.Double Ox = new Point2D.Double(AB.x / normAB, AB.y / normAB);
4009 Hashtable<Integer,Point2D.Double> old = new Hashtable<Integer,Point2D.Double>();
4010 for (int i = hBeg + 1; i < hEnd; i++) {
4011 Point2D.Double P = getCoords(i);
4012 Point2D.Double nP = project(O, Ox, P);
4015 Point2D.Double Center = getCenter(i);
4016 setCenter(i, project(O, Ox, Center));
4021 public static Point2D.Double project(Point2D.Double O, Point2D.Double Ox,
4023 Point2D.Double OC = new Point2D.Double(C.x - O.x, C.y - O.y);
4024 // Projection of OC on OI => OX
4025 double normOX = (Ox.x * OC.x + Ox.y * OC.y);
4026 Point2D.Double OX = new Point2D.Double((normOX * Ox.x), (normOX * Ox.y));
4027 // Portion of OC orthogonal to Ox => XC
4028 Point2D.Double XC = new Point2D.Double(OC.x - OX.x, OC.y - OX.y);
4029 // Reflexive image of C with respect to Ox => CP
4030 Point2D.Double OCP = new Point2D.Double(OX.x - XC.x, OX.y - XC.y);
4031 Point2D.Double CP = new Point2D.Double(O.x + OCP.x, O.y + OCP.y);
4036 public boolean testDirectionality(int i, int j, int k) {
4038 // Which direction are we heading toward?
4039 Point2D.Double pi = getCoords(i);
4040 Point2D.Double pj = getCoords(j);
4041 Point2D.Double pk = getCoords(k);
4042 return testDirectionality(pi, pj, pk);
4045 public static boolean testDirectionality(Point2D.Double pi,
4046 Point2D.Double pj, Point2D.Double pk) {
4048 // Which direction are we heading toward?
4049 double test = (pj.x - pi.x) * (pk.y - pj.y) - (pj.y - pi.y)
4054 public double getOrientation() {
4055 double maxDist = Double.MIN_VALUE;
4057 for (int i = 0; i < _listeBases.size(); i++) {
4058 ModeleBase b1 = _listeBases.get(i);
4059 for (int j = i + 1; j < _listeBases.size(); j++) {
4060 ModeleBase b2 = _listeBases.get(j);
4061 Point2D.Double p1 = b1._coords.toPoint2D();
4062 Point2D.Double p2 = b2._coords.toPoint2D();
4063 double dist = p1.distance(p2);
4064 if (dist > maxDist) {
4066 angle = computeAngle(p1, p2);
4073 public boolean hasVirtualLoops() {
4074 boolean consecutiveBPs = false;
4075 for (int i = 0; i < _listeBases.size(); i++) {
4076 int j = _listeBases.get(i).getElementStructure();
4078 consecutiveBPs = true;
4082 return ((_drawMode != DRAW_MODE_LINEAR)
4083 && (_drawMode != DRAW_MODE_CIRCULAR) && (consecutiveBPs));
4086 public String getHTMLDescription() {
4087 String result = "<table>";
4088 result += "<tr><td><b>Name:</b></td><td>" + this._name + "</td></tr>";
4089 result += "<tr><td><b>Length:</b></td><td>" + this.getSize()
4091 result += "<tr><td><b>Base-pairs:</b></td><td>"
4092 + this.getAllBPs().size() + " </td></tr>";
4093 return result + "</table>";
4096 public String getID() {
4100 public void setID(String id) {
4104 public static ArrayList<Integer> getGapPositions(String gapString) {
4105 ArrayList<Integer> result = new ArrayList<Integer>();
4106 for (int i = 0; i < gapString.length(); i++) {
4107 char c = gapString.charAt(i);
4108 if (c == '.' || c == ':') {
4115 public RNA restrictTo(String gapString) {
4116 return restrictTo(getGapPositions(gapString));
4119 public RNA restrictTo(ArrayList<Integer> positions) {
4120 RNA result = new RNA();
4121 String oldSeq = this.getSeq();
4123 HashSet<Integer> removedPos = new HashSet<Integer>(positions);
4124 int[] matching = new int[oldSeq.length()];
4126 for (int i = 0; i < oldSeq.length(); i++) {
4128 if (!removedPos.contains(i)) {
4129 newSeq += oldSeq.charAt(i);
4133 result.setRNA(newSeq);
4134 for (ModeleBP m : getAllBPs()) {
4135 if (removedPos.contains(m.getIndex5())
4136 || removedPos.contains(m.getIndex3())) {
4137 int i5 = matching[m.getIndex5()];
4138 int i3 = matching[m.getIndex3()];
4139 ModeleBP msbp = new ModeleBP(result.getBaseAt(i5),
4140 result.getBaseAt(i3), m.getEdgePartner5(),
4141 m.getEdgePartner3(), m.getStericity());
4142 result.addBP(i5, i3, msbp);
4148 public void rescale(double d) {
4149 for (ModeleBase mb : _listeBases) {
4158 * Necessary for DrawRNATemplate (which is why the method is
4161 ArrayList<ModeleBase> getListeBases() {