X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src2%2Ffr%2Forsay%2Flri%2Fvarna%2Fmodels%2Frna%2FRNA.java;fp=src2%2Ffr%2Forsay%2Flri%2Fvarna%2Fmodels%2Frna%2FRNA.java;h=4b530e0b70fefbb852e69bbbfcd10385aa2fd6f7;hb=9f55415c9f8005e9dcd8243453883ff853fd5b76;hp=0000000000000000000000000000000000000000;hpb=d8e8c742b864e58406d13e21d124699a26b6492f;p=jalview.git diff --git a/src2/fr/orsay/lri/varna/models/rna/RNA.java b/src2/fr/orsay/lri/varna/models/rna/RNA.java new file mode 100644 index 0000000..4b530e0 --- /dev/null +++ b/src2/fr/orsay/lri/varna/models/rna/RNA.java @@ -0,0 +1,4164 @@ +/* + 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. + Copyright (C) 2008 Kevin Darty, Alain Denise and Yann Ponty. + electronic mail : Yann.Ponty@lri.fr + paper mail : LRI, bat 490 Université Paris-Sud 91405 Orsay Cedex France + + This file is part of VARNA version 3.1. + VARNA version 3.1 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + + VARNA version 3.1 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with VARNA version 3.1. + If not, see http://www.gnu.org/licenses. + */ +package fr.orsay.lri.varna.models.rna; + +import java.awt.Color; +import java.awt.Point; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Serializable; +import java.io.StreamTokenizer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.List; +import java.util.Set; +import java.util.Stack; +import java.util.Vector; + +import javax.xml.transform.sax.TransformerHandler; + +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import fr.orsay.lri.varna.VARNAPanel; +import fr.orsay.lri.varna.applications.templateEditor.Couple; +import fr.orsay.lri.varna.exceptions.ExceptionExportFailed; +import fr.orsay.lri.varna.exceptions.ExceptionFileFormatOrSyntax; +import fr.orsay.lri.varna.exceptions.ExceptionNAViewAlgorithm; +import fr.orsay.lri.varna.exceptions.ExceptionPermissionDenied; +import fr.orsay.lri.varna.exceptions.ExceptionUnmatchedClosingParentheses; +import fr.orsay.lri.varna.exceptions.ExceptionWritingForbidden; +import fr.orsay.lri.varna.factories.RNAFactory; +import fr.orsay.lri.varna.interfaces.InterfaceVARNAListener; +import fr.orsay.lri.varna.interfaces.InterfaceVARNAObservable; +import fr.orsay.lri.varna.models.VARNAConfig; +import fr.orsay.lri.varna.models.VARNAConfig.BP_STYLE; +import fr.orsay.lri.varna.models.annotations.ChemProbAnnotation; +import fr.orsay.lri.varna.models.annotations.HighlightRegionAnnotation; +import fr.orsay.lri.varna.models.annotations.TextAnnotation; +import fr.orsay.lri.varna.models.export.PSExport; +import fr.orsay.lri.varna.models.export.SVGExport; +import fr.orsay.lri.varna.models.export.SecStrDrawingProducer; +import fr.orsay.lri.varna.models.export.TikzExport; +import fr.orsay.lri.varna.models.export.XFIGExport; +import fr.orsay.lri.varna.models.naView.NAView; +import fr.orsay.lri.varna.models.rna.ModeleBackboneElement.BackboneType; +import fr.orsay.lri.varna.models.templates.DrawRNATemplateCurveMethod; +import fr.orsay.lri.varna.models.templates.DrawRNATemplateMethod; +import fr.orsay.lri.varna.models.templates.RNATemplate; +import fr.orsay.lri.varna.models.templates.RNATemplateDrawingAlgorithmException; +import fr.orsay.lri.varna.models.templates.RNATemplateMapping; +import fr.orsay.lri.varna.utils.RNAMLParser; +import fr.orsay.lri.varna.utils.XMLUtils; +import fr.orsay.lri.varna.views.VueUI; + +/** + * The RNA model which contain the base list and the draw algorithm mode + * + * @author darty + * + */ +public class RNA extends InterfaceVARNAObservable implements Serializable { + /** + * + */ + private static final long serialVersionUID = 7541274455751497303L; + + /** + * Selects the "Feynman diagram" drawing algorithm that places the bases on + * a circle and draws the base-pairings as chords of the circle graph. + */ + + public static final int DRAW_MODE_CIRCULAR = 1; + /** + * Selects the "tree drawing" algorithm. Draws each loop on a circle whose + * radius depends on the number of bases involved in the loop. As some + * helices can be overlapping in the result, basic interaction is provided + * so that the user can "disentangle" the drawing by spinning the helices + * around the axis defined by their multiloop (bulge or internal loop) + * origin. This is roughly the initial placement strategy of RNAViz. + * + * @see RNAViz + */ + public static final int DRAW_MODE_RADIATE = 2; + + /** + * Selects the NAView algorithm. + */ + public static final int DRAW_MODE_NAVIEW = 3; + /** + * Selects the linear algorithm. + */ + public static final int DRAW_MODE_LINEAR = 4; + + public static final int DRAW_MODE_VARNA_VIEW = 5; + + /** + * Selects the RNAView algorithm. + */ + public static final int DRAW_MODE_MOTIFVIEW = 6; + + public static final int DRAW_MODE_TEMPLATE = 7; + + public static final int DEFAULT_DRAW_MODE = DRAW_MODE_RADIATE; + + public int BASE_RADIUS = 10; + public static final double LOOP_DISTANCE = 40.0; // distance between base + // pairs in an helix + public static final double BASE_PAIR_DISTANCE = 65.0; // distance between + // the two bases of + // a pair + public static final double MULTILOOP_DISTANCE = 35.0; + public static final double VIRTUAL_LOOP_RADIUS = 40.0; + + public double CHEM_PROB_DIST = 14; + public double CHEM_PROB_BASE_LENGTH = 30; + public double CHEM_PROB_ARROW_HEIGHT = 10; + public double CHEM_PROB_ARROW_WIDTH = 5; + public double CHEM_PROB_TRIANGLE_WIDTH = 2.5; + public double CHEM_PROB_PIN_SEMIDIAG = 6; + public double CHEM_PROB_DOT_RADIUS = 6.; + public static double CHEM_PROB_ARROW_THICKNESS = 2.0; + + public static ArrayList NormalBases = new ArrayList(); + { + NormalBases.add("a"); + NormalBases.add("c"); + NormalBases.add("g"); + NormalBases.add("u"); + NormalBases.add("t"); + } + + public GeneralPath _debugShape = null; + + /** + * The draw algorithm mode + */ + private int _drawMode = DRAW_MODE_RADIATE; + private boolean _drawn = false; + private String _name = ""; + private String _id = ""; + public double _bpHeightIncrement = VARNAConfig.DEFAULT_BP_INCREMENT; + /** + * the base list + */ + private ArrayList _listeBases; + /** + * the strand list + */ + StructureTemp _listStrands = new StructureTemp(); + /** + * Additional bonds and info can be specified here. + */ + private ArrayList _structureAux = new ArrayList(); + private ArrayList _listeAnnotations = new ArrayList(); + private ArrayList _listeRegionHighlights = new ArrayList(); + private ArrayList _chemProbAnnotations = new ArrayList(); + private ModeleBackbone _backbone = new ModeleBackbone(); + + public static String XML_ELEMENT_NAME = "RNA"; + public static String XML_VAR_BASE_SPACING_NAME = "spacing"; + public static String XML_VAR_DRAWN_NAME = "drawn"; + public static String XML_VAR_NAME_NAME = "name"; + public static String XML_VAR_DRAWN_MODE_NAME = "mode"; + public static String XML_VAR_ID_NAME = "id"; + public static String XML_VAR_BP_HEIGHT_NAME = "delta"; + public static String XML_VAR_BASES_NAME = "bases"; + public static String XML_VAR_BASEPAIRS_NAME = "BPs"; + public static String XML_VAR_ANNOTATIONS_NAME = "annotations"; + public static String XML_VAR_BACKBONE_NAME = "backbone"; + + public void toXML(TransformerHandler hd) throws SAXException { + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute("", "", XML_VAR_DRAWN_NAME, "CDATA", "" + _drawn); + atts.addAttribute("", "", XML_VAR_DRAWN_MODE_NAME, "CDATA", "" + + _drawMode); + atts.addAttribute("", "", XML_VAR_ID_NAME, "CDATA", "" + _id); + atts.addAttribute("", "", XML_VAR_BP_HEIGHT_NAME, "CDATA", "" + + _bpHeightIncrement); + hd.startElement("", "", XML_ELEMENT_NAME, atts); + + atts.clear(); + hd.startElement("", "", XML_VAR_NAME_NAME, atts); + XMLUtils.exportCDATAString(hd, "" + _name); + hd.endElement("", "", XML_VAR_NAME_NAME); + + atts.clear(); + hd.startElement("", "", XML_VAR_BASES_NAME, atts); + for (ModeleBase mb : _listeBases) { + mb.toXML(hd); + } + hd.endElement("", "", XML_VAR_BASES_NAME); + atts.clear(); + + hd.startElement("", "", XML_VAR_BASEPAIRS_NAME, atts); + for (ModeleBP mbp : getSecStrBPs()) { + mbp.toXML(hd, true); + } + for (ModeleBP mbp : _structureAux) { + mbp.toXML(hd, false); + } + hd.endElement("", "", XML_VAR_BASEPAIRS_NAME); + atts.clear(); + + getBackbone().toXML(hd); + atts.clear(); + + hd.startElement("", "", XML_VAR_ANNOTATIONS_NAME, atts); + for (TextAnnotation ta : _listeAnnotations) { + ta.toXML(hd); + } + for (HighlightRegionAnnotation hra : _listeRegionHighlights) { + hra.toXML(hd); + } + for (ChemProbAnnotation cpa : _chemProbAnnotations) { + cpa.toXML(hd); + } + hd.endElement("", "", XML_VAR_ANNOTATIONS_NAME); + hd.endElement("", "", XML_ELEMENT_NAME); + } + + public ModeleBackbone getBackbone() { + return _backbone; + } + + public void setBackbone(ModeleBackbone b) { + _backbone = b; + } + + transient private ArrayList _listeVARNAListener = new ArrayList(); + + public RNA() { + this(""); + } + + public RNA(String name) { + _name = name; + _listeBases = new ArrayList(); + _drawn = false; + init(); + } + + public String toString() { + if (_name.equals("")) { + return getStructDBN(); + } else { + return _name; + } + } + + public RNA(RNA r) { + _drawMode = r._drawMode; + _listeBases.addAll(r._listeBases); + _listeVARNAListener = (ArrayList) r._listeVARNAListener; + _drawn = r._drawn; + init(); + } + + public void init() { + } + + public void saveRNADBN(String path, String title) + throws ExceptionWritingForbidden { + try { + FileWriter out = new FileWriter(path); + if (!title.equals("")) { + out.write("> " + title + "\n"); + } + out.write(getListeBasesToString()); + out.write('\n'); + String str = ""; + for (int i = 0; i < _listeBases.size(); i++) { + if (_listeBases.get(i).getElementStructure() == -1) { + str += '.'; + } else { + if (_listeBases.get(i).getElementStructure() > i) { + str += '('; + } else { + str += ')'; + } + } + } + out.write(str); + out.write('\n'); + out.close(); + } catch (IOException e) { + throw new ExceptionWritingForbidden(e.getMessage()); + } + } + + public Color getBaseInnerColor(int i, VARNAConfig conf) { + Color result = _listeBases.get(i).getStyleBase().getBaseInnerColor(); + String res = _listeBases.get(i).getContent(); + if (conf._drawColorMap) { + result = conf._cm.getColorForValue(_listeBases.get(i).getValue()); + } else if ((conf._colorDashBases && (res.contains("-")))) { + result = conf._dashBasesColor; + } else if ((conf._colorSpecialBases && !NormalBases.contains(res + .toLowerCase()))) { + result = conf._specialBasesColor; + } + return result; + } + + public Color getBaseOuterColor(int i, VARNAConfig conf) { + Color result = _listeBases.get(i).getStyleBase() + .getBaseOutlineColor(); + return result; + } + + private static double correctComponent(double c) + { + c = c / 255.0; + if (c <= 0.03928) + c = c/12.92; + else + c = Math.pow(((c+0.055)/1.055) , 2.4); + return c; + } + public static double getLuminance(Color c) + { + return 0.2126 * correctComponent(c.getRed()) + 0.7152 * correctComponent(c.getGreen()) + 0.0722 * correctComponent(c.getBlue()); + } + + public static boolean whiteLabelPreferrable(Color c) + { + if (getLuminance(c) > 0.32) + return false; + return true; + } + + + + public Color getBaseNameColor(int i, VARNAConfig conf) { + Color result = _listeBases.get(i).getStyleBase().getBaseNameColor(); + if ( RNA.whiteLabelPreferrable(getBaseInnerColor(i, conf))) + { + result=Color.white; + } + + return result; + } + + public Color getBasePairColor(ModeleBP bp, VARNAConfig conf) { + Color bondColor = conf._bondColor; + if (conf._useBaseColorsForBPs) { + bondColor = _listeBases.get(bp.getPartner5().getIndex()) + .getStyleBase().getBaseInnerColor(); + } + if (bp != null) { + bondColor = bp.getStyle().getColor(bondColor); + } + return bondColor; + } + + public double getBasePairThickness(ModeleBP bp, VARNAConfig conf) { + double thickness = bp.getStyle().getThickness(conf._bpThickness); + return thickness; + } + + private void drawSymbol(SecStrDrawingProducer out, double posx, + double posy, double normx, double normy, double radius, + boolean isCIS, ModeleBP.Edge e, double thickness) { + Color bck = out.getCurrentColor(); + switch (e) { + case WC: + if (isCIS) { + out.fillCircle(posx, posy, (radius / 2.0), thickness, bck); + } else { + out.fillCircle(posx, posy, (radius / 2.0), thickness, + Color.white); + out.setColor(bck); + out.drawCircle(posx, posy, (radius / 2.0), thickness); + } + break; + case HOOGSTEEN: { + double xtab[] = new double[4]; + double ytab[] = new double[4]; + xtab[0] = posx - radius * normx / 2.0 - radius * normy / 2.0; + ytab[0] = posy - radius * normy / 2.0 + radius * normx / 2.0; + xtab[1] = posx + radius * normx / 2.0 - radius * normy / 2.0; + ytab[1] = posy + radius * normy / 2.0 + radius * normx / 2.0; + xtab[2] = posx + radius * normx / 2.0 + radius * normy / 2.0; + ytab[2] = posy + radius * normy / 2.0 - radius * normx / 2.0; + xtab[3] = posx - radius * normx / 2.0 + radius * normy / 2.0; + ytab[3] = posy - radius * normy / 2.0 - radius * normx / 2.0; + if (isCIS) { + out.fillPolygon(xtab, ytab, bck); + } else { + out.fillPolygon(xtab, ytab, Color.white); + out.setColor(bck); + out.drawPolygon(xtab, ytab, thickness); + } + } + break; + case SUGAR: { + double ix = radius * normx / 2.0; + double iy = radius * normy / 2.0; + double jx = radius * normy / 2.0; + double jy = -radius * normx / 2.0; + double xtab[] = new double[3]; + double ytab[] = new double[3]; + xtab[0] = posx - ix + jx; + ytab[0] = posy - iy + jy; + xtab[1] = posx + ix + jx; + ytab[1] = posy + iy + jy; + xtab[2] = posx - jx; + ytab[2] = posy - jy; + + if (isCIS) { + out.fillPolygon(xtab, ytab, bck); + } else { + out.fillPolygon(xtab, ytab, Color.white); + out.setColor(bck); + out.drawPolygon(xtab, ytab, thickness); + } + } + break; + } + out.setColor(bck); + } + + private void drawBasePairArc(SecStrDrawingProducer out, int i, int j, + Point2D.Double orig, Point2D.Double dest, ModeleBP style, + VARNAConfig conf) { + double coef; + double distance; + Point2D.Double center = new Point2D.Double((orig.x + dest.x)/2., (orig.y + dest.y)/2. + BASE_RADIUS); + if (j - i == 1) + coef = _bpHeightIncrement * 2; + else + coef = _bpHeightIncrement * 1; + distance = (int) Math.round(dest.x - orig.x); + if (conf._mainBPStyle != BP_STYLE.LW) { + out.drawArc(center, distance, distance * coef, 180, 0); + } else { + double thickness = getBasePairThickness(style, conf); + double radiusCircle = ((BASE_PAIR_DISTANCE - BASE_RADIUS) / 5.0); + + if (style.isCanonical()) { + if (style.isCanonicalGC()) { + if ((orig.x != dest.x) || (orig.y != dest.y)) { + out.drawArc(center, distance - BASE_RADIUS / 2., + distance * coef - BASE_RADIUS / 2, 180, 0); + out.drawArc(center, distance + BASE_RADIUS / 2., + distance * coef + BASE_RADIUS / 2, 180, 0); + } + } else if (!style.isWobbleUG()) { + out.drawArc(center, distance, distance * coef, 180, 0); + drawSymbol(out, center.x, center.y + distance * coef / 2., 180., 0, + radiusCircle, style.isCIS(), + style.getEdgePartner5(), thickness); + } else { + out.drawArc(orig, distance, distance * coef, 180, 0); + } + } else { + ModeleBP.Edge p1 = style.getEdgePartner5(); + ModeleBP.Edge p2 = style.getEdgePartner3(); + out.drawArc(center, distance, distance * coef, 180, 0); + if (p1 == p2) { + drawSymbol(out, center.x, center.y + distance * coef / 2., 1., 0, + radiusCircle, style.isCIS(), + style.getEdgePartner5(), thickness); + } else { + drawSymbol(out, center.x - BASE_RADIUS, + center.y + distance * coef / 2., 1., 0, radiusCircle, + style.isCIS(), p1, thickness); + drawSymbol(out, center.x + BASE_RADIUS, + center.y + distance * coef / 2., 1., 0, radiusCircle, + style.isCIS(), p2, thickness); + } + } + } + } + + private void drawBasePair(SecStrDrawingProducer out, Point2D.Double orig, + Point2D.Double dest, ModeleBP style, VARNAConfig conf) { + double dx = dest.x - orig.x; + double dy = dest.y - orig.y; + double dist = Math.sqrt((dest.x - orig.x) * (dest.x - orig.x) + + (dest.y - orig.y) * (dest.y - orig.y)); + dx /= dist; + dy /= dist; + double nx = -dy; + double ny = dx; + orig = new Point2D.Double(orig.x + BASE_RADIUS * dx, orig.y + + BASE_RADIUS * dy); + dest = new Point2D.Double(dest.x - BASE_RADIUS * dx, dest.y + - BASE_RADIUS * dy); + if (conf._mainBPStyle == VARNAConfig.BP_STYLE.LW) { + double thickness = getBasePairThickness(style, conf); + double radiusCircle = ((BASE_PAIR_DISTANCE - BASE_RADIUS) / 5.0); + + if (style.isCanonical()) { + if (style.isCanonicalGC()) { + if ((orig.x != dest.x) || (orig.y != dest.y)) { + nx *= BASE_RADIUS / 4.0; + ny *= BASE_RADIUS / 4.0; + out.drawLine((orig.x + nx), (orig.y + ny), + (dest.x + nx), (dest.y + ny), conf._bpThickness); + out.drawLine((orig.x - nx), (orig.y - ny), + (dest.x - nx), (dest.y - ny), conf._bpThickness); + } + } else if (style.isCanonicalAU()) { + out.drawLine(orig.x, orig.y, dest.x, dest.y, + conf._bpThickness); + } else if (style.isWobbleUG()) { + double cx = (dest.x + orig.x) / 2.0; + double cy = (dest.y + orig.y) / 2.0; + out.drawLine(orig.x, orig.y, dest.x, dest.y, + conf._bpThickness); + drawSymbol(out, cx, cy, nx, ny, radiusCircle, false, + ModeleBP.Edge.WC, thickness); + } + + else { + double cx = (dest.x + orig.x) / 2.0; + double cy = (dest.y + orig.y) / 2.0; + out.drawLine(orig.x, orig.y, dest.x, dest.y, + conf._bpThickness); + drawSymbol(out, cx, cy, nx, ny, radiusCircle, + style.isCIS(), style.getEdgePartner5(), thickness); + } + } else { + ModeleBP.Edge p1 = style.getEdgePartner5(); + ModeleBP.Edge p2 = style.getEdgePartner3(); + double cx = (dest.x + orig.x) / 2.0; + double cy = (dest.y + orig.y) / 2.0; + out.drawLine(orig.x, orig.y, dest.x, dest.y, conf._bpThickness); + if (p1 == p2) { + drawSymbol(out, cx, cy, nx, ny, radiusCircle, + style.isCIS(), p1, thickness); + } else { + double vdx = (dest.x - orig.x); + double vdy = (dest.y - orig.y); + vdx /= 6.0; + vdy /= 6.0; + drawSymbol(out, cx + vdx, cy + vdy, nx, ny, radiusCircle, + style.isCIS(), p2, thickness); + drawSymbol(out, cx - vdx, cy - vdy, nx, ny, radiusCircle, + style.isCIS(), p1, thickness); + } + } + } else if (conf._mainBPStyle == VARNAConfig.BP_STYLE.RNAVIZ) { + double xcenter = (orig.x + dest.x) / 2.0; + double ycenter = (orig.y + dest.y) / 2.0; + out.fillCircle(xcenter, ycenter, 3.0 * conf._bpThickness, + conf._bpThickness, out.getCurrentColor()); + } else if (conf._mainBPStyle == VARNAConfig.BP_STYLE.SIMPLE) { + out.drawLine(orig.x, orig.y, dest.x, dest.y, conf._bpThickness); + } + } + + private void drawColorMap(VARNAConfig _conf, SecStrDrawingProducer out) { + double v1 = _conf._cm.getMinValue(); + double v2 = _conf._cm.getMaxValue(); + int x, y; + double xSpaceAvail = 0; + double ySpaceAvail = 0; + double thickness = 1.0; + /* + * ySpaceAvail = + * Math.min((getHeight()-rnabbox.height*scaleFactor-getTitleHeight + * ())/2.0,scaleFactor*(_conf._colorMapHeight+VARNAConfig. + * DEFAULT_COLOR_MAP_FONT_SIZE)); if ((int)ySpaceAvail==0) { xSpaceAvail + * = + * Math.min((getWidth()-rnabbox.width*scaleFactor)/2,scaleFactor*(_conf + * ._colorMapWidth)+VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH); } + */ + Rectangle2D.Double currentBBox = out.getBoundingBox(); + + double xBase = (currentBBox.getMaxX() - _conf._colorMapWidth - _conf._colorMapXOffset); + // double yBase = (minY - _conf._colorMapHeight + + // _conf._colorMapYOffset); + double yBase = (currentBBox.getMinY() - _conf._colorMapHeight - VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE); + + for (int i = 0; i < _conf._colorMapWidth; i++) { + double ratio = (((double) i) / ((double) _conf._colorMapWidth - 1)); + double val = v1 + (v2 - v1) * ratio; + Color c = _conf._cm.getColorForValue(val); + x = (int) (xBase + i); + y = (int) yBase; + out.fillRectangle(x, y, VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH, + _conf._colorMapHeight, c); + } + out.setColor(VARNAConfig.DEFAULT_COLOR_MAP_OUTLINE); + out.drawRectangle(xBase, yBase, (double) _conf._colorMapWidth + + VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH - 1, + _conf._colorMapHeight, thickness); + + out.setColor(VARNAConfig.DEFAULT_COLOR_MAP_FONT_COLOR); + out.setFont(out.getCurrentFont(), + VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.5); + out.drawText(xBase, yBase + _conf._colorMapHeight + + VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7, + "" + _conf._cm.getMinValue()); + out.drawText(xBase + VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH + + _conf._colorMapWidth, yBase + _conf._colorMapHeight + + VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7, + "" + _conf._cm.getMaxValue()); + out.drawText( + xBase + + (VARNAConfig.DEFAULT_COLOR_MAP_STRIPE_WIDTH + _conf._colorMapWidth) + / 2.0, yBase + - (VARNAConfig.DEFAULT_COLOR_MAP_FONT_SIZE / 1.7), + _conf._colorMapCaption); + + } + + private void renderRegionHighlights(SecStrDrawingProducer out, + Point2D.Double[] realCoords, Point2D.Double[] realCenters) { + for (HighlightRegionAnnotation r : _listeRegionHighlights) { + GeneralPath s = r.getShape(realCoords, realCenters, 1.0); + out.setColor(r.getFillColor()); + out.fillPolygon(s, r.getFillColor()); + out.setColor(r.getOutlineColor()); + out.drawPolygon(s, 1l); + } + + } + + private void saveRNA(String path, VARNAConfig conf, double scale, + SecStrDrawingProducer out) throws ExceptionWritingForbidden { + out.setScale(scale); + // Computing bounding boxes + double EPSMargin = 40; + double minX = Double.MAX_VALUE; + double maxX = Double.MIN_VALUE; + double minY = Double.MAX_VALUE; + double maxY = Double.MIN_VALUE; + + double x0, y0, x1, y1, xc, yc, xp, yp, dx, dy, norm; + + for (int i = 0; i < _listeBases.size(); i++) { + minX = Math.min(minX, (_listeBases.get(i).getCoords().getX() + - BASE_RADIUS - EPSMargin)); + minY = Math.min(minY, -(_listeBases.get(i).getCoords().getY() + - BASE_RADIUS - EPSMargin)); + maxX = Math.max(maxX, (_listeBases.get(i).getCoords().getX() + + BASE_RADIUS + EPSMargin)); + maxY = Math.max(maxY, -(_listeBases.get(i).getCoords().getY() + + BASE_RADIUS + EPSMargin)); + } + + // Rescaling everything + Point2D.Double[] coords = new Point2D.Double[_listeBases.size()]; + Point2D.Double[] centers = new Point2D.Double[_listeBases.size()]; + for (int i = 0; i < _listeBases.size(); i++) { + xp = (_listeBases.get(i).getCoords().getX() - minX); + yp = -(_listeBases.get(i).getCoords().getY() - minY); + coords[i] = new Point2D.Double(xp, yp); + + Point2D.Double centerBck = getCenter(i); + if (get_drawMode() == RNA.DRAW_MODE_NAVIEW + || get_drawMode() == RNA.DRAW_MODE_RADIATE) { + if ((_listeBases.get(i).getElementStructure() != -1) + && i < _listeBases.size() - 1 && i > 1) { + ModeleBase b1 = get_listeBases().get(i - 1); + ModeleBase b2 = get_listeBases().get(i + 1); + int j1 = b1.getElementStructure(); + int j2 = b2.getElementStructure(); + if ((j1 == -1) ^ (j2 == -1)) { + // alors la position du nombre associé doit etre + // décalé + Point2D.Double a1 = b1.getCoords(); + Point2D.Double a2 = b2.getCoords(); + Point2D.Double c1 = b1.getCenter(); + Point2D.Double c2 = b2.getCenter(); + + centerBck.x = _listeBases.get(i).getCoords().x + + (c1.x - a1.x) / c1.distance(a1) + + (c2.x - a2.x) / c2.distance(a2); + centerBck.y = _listeBases.get(i).getCoords().y + + (c1.y - a1.y) / c1.distance(a1) + + (c2.y - a2.y) / c2.distance(a2); + } + } + } + xc = (centerBck.getX() - minX); + yc = -(centerBck.getY() - minY); + centers[i] = new Point2D.Double(xc, yc); + } + + // Drawing background + if (conf._drawBackground) + out.setBackgroundColor(conf._backgroundColor); + + // Drawing region highlights + renderRegionHighlights(out, coords, centers); + + // Drawing backbone + if (conf._drawBackbone) + { + for (int i = 1; i < _listeBases.size(); i++) { + Point2D.Double p1 = coords[i - 1]; + Point2D.Double p2 = coords[i]; + x0 = p1.x; + y0 = p1.y; + x1 = p2.x; + y1 = p2.y; + Point2D.Double vn = new Point2D.Double(); + double dist = p1.distance(p2); + int a = _listeBases.get(i - 1).getElementStructure(); + int b = _listeBases.get(i).getElementStructure(); + BackboneType bt = _backbone.getTypeBefore(i); + boolean consecutivePair = (a == i) && (b == i - 1); + + if (dist > 0) { + if (bt != BackboneType.DISCONTINUOUS_TYPE) { + Color c = _backbone.getColorBefore(i, conf._backboneColor); + if (bt == BackboneType.MISSING_PART_TYPE) { + c.brighter(); + } + out.setColor(c); + + vn.x = (x1 - x0) / dist; + vn.y = (y1 - y0) / dist; + if (consecutivePair + &&(getDrawMode() != RNA.DRAW_MODE_LINEAR) + && (getDrawMode() != RNA.DRAW_MODE_CIRCULAR)) { + int dir = 0; + if (i + 1 < coords.length) { + dir = (testDirectionality(i - 1, i, i + 1) ? 1 : -1); + } else if (i - 2 >= 0) { + dir = (testDirectionality(i - 2, i - 1, i) ? 1 : -1); + } + Point2D.Double centerSeg = new Point2D.Double( + (p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0); + double centerDist = RNA.VIRTUAL_LOOP_RADIUS * scale; + Point2D.Double centerLoop = new Point2D.Double( + centerSeg.x + centerDist * dir * vn.y, + centerSeg.y - centerDist * dir * vn.x); + // Debug crosshair + //out.drawLine(centerLoop.x - 5, centerLoop.y, + // centerLoop.x + 5, centerLoop.y, 2.0); + //out.drawLine(centerLoop.x, centerLoop.y - 5, + // centerLoop.x, centerLoop.y + 5, 2.0); + + double radius = centerLoop.distance(p1); + double a1 = 360. + * (Math.atan2(p1.y - centerLoop.y, p1.x - centerLoop.x)) + / (2. * Math.PI); + double a2 = 360. + * (Math.atan2(p2.y - centerLoop.y, p2.x - centerLoop.x)) + / (2. * Math.PI); + if (dir>0) + { + double tmp = a1; + a1 = a2; + a2 = tmp; + } + if (a1 < 0) { + a1 += 360.; + } + if (a2 < 0) { + a2 += 360.; + } + out.drawArc(centerLoop, 2. * radius, 2. * radius, a1, + a2); + } else { + out.drawLine((x0 + BASE_RADIUS * vn.x), + (y0 + BASE_RADIUS * vn.y), (x1 - BASE_RADIUS + * vn.x), (y1 - BASE_RADIUS * vn.y), 1.0); + } + } + } + } + } + + // Drawing bonds + for (int i = 0; i < _listeBases.size(); i++) { + if (_listeBases.get(i).getElementStructure() > i) { + ModeleBP style = _listeBases.get(i).getStyleBP(); + if (style.isCanonical() || conf._drawnNonCanonicalBP) { + Color bpcol = getBasePairColor(style, conf); + out.setColor(bpcol); + + int j = _listeBases.get(i).getElementStructure(); + x0 = coords[i].x; + y0 = coords[i].y; + x1 = coords[j].x; + y1 = coords[j].y; + dx = x1 - x0; + dy = y1 - y0; + norm = Math.sqrt(dx * dx + dy * dy); + dx /= norm; + dy /= norm; + + if (_drawMode == DRAW_MODE_CIRCULAR + || _drawMode == DRAW_MODE_RADIATE + || _drawMode == DRAW_MODE_NAVIEW) { + drawBasePair(out, new Point2D.Double(x0, y0), + new Point2D.Double(x1, y1), style, conf); + } else if (_drawMode == DRAW_MODE_LINEAR) { + drawBasePairArc(out, i, j, new Point2D.Double(x0, y0), + new Point2D.Double(x1, y1), style, conf); + } + } + } + } + + // Drawing additional bonds + if (conf._drawnNonPlanarBP) { + for (int i = 0; i < _structureAux.size(); i++) { + ModeleBP bp = _structureAux.get(i); + out.setColor(getBasePairColor(bp, conf)); + + int a = bp.getPartner5().getIndex(); + int b = bp.getPartner3().getIndex(); + + if (bp.isCanonical() || conf._drawnNonCanonicalBP) { + x0 = coords[a].x; + y0 = coords[a].y; + x1 = coords[b].x; + y1 = coords[b].y; + dx = x1 - x0; + dy = y1 - y0; + norm = Math.sqrt(dx * dx + dy * dy); + dx /= norm; + dy /= norm; + if ((_drawMode == DRAW_MODE_CIRCULAR) + || (_drawMode == DRAW_MODE_RADIATE) + || _drawMode == DRAW_MODE_NAVIEW) { + drawBasePair(out, new Point2D.Double(x0, y0), + new Point2D.Double(x1, y1), bp, conf); + } else if (_drawMode == DRAW_MODE_LINEAR) { + drawBasePairArc(out, a, b, new Point2D.Double(x0, y0), + new Point2D.Double(x1, y1), bp, conf); + } + } + } + } + + // Drawing Bases + double baseFontSize = (1.5 * BASE_RADIUS); + out.setFont(PSExport.FONT_HELVETICA_BOLD, baseFontSize); + + for (int i = 0; i < _listeBases.size(); i++) { + x0 = coords[i].x; + y0 = coords[i].y; + + Color baseInnerColor = getBaseInnerColor(i, conf); + Color baseOuterColor = getBaseOuterColor(i, conf); + Color baseNameColor = getBaseNameColor(i, conf); + if ( RNA.whiteLabelPreferrable(baseInnerColor)) + { + baseNameColor=Color.white; + } + + + if (_listeBases.get(i) instanceof ModeleBasesComparison) { + ModeleBasesComparison mb = (ModeleBasesComparison) _listeBases + .get(i); + if (conf._fillBases) { + out.fillRectangle(x0 - 1.5 * BASE_RADIUS, y0 - BASE_RADIUS, + 3 * BASE_RADIUS, 2 * BASE_RADIUS, + baseInnerColor); + } + if (conf._drawOutlineBases) { + out.setColor(baseOuterColor); + out.drawRectangle(x0 - 1.5 * BASE_RADIUS, y0 - BASE_RADIUS, + 3 * BASE_RADIUS, 2 * BASE_RADIUS, 1l); + out.drawLine(x0, y0 - BASE_RADIUS, x0, y0 + BASE_RADIUS, 1l); + } + + out.setColor(baseNameColor); + out.drawText(x0 - .75 * BASE_RADIUS, y0, "" + mb.getBase1()); + out.drawText(x0 + .75 * BASE_RADIUS, y0, "" + mb.getBase2()); + } else if (_listeBases.get(i) instanceof ModeleBaseNucleotide) { + if (conf._fillBases) { + out.fillCircle(x0, y0, BASE_RADIUS, 1l, + baseInnerColor); + } + if (conf._drawOutlineBases) { + out.setColor(baseOuterColor); + out.drawCircle(x0, y0, BASE_RADIUS, 1l); + } + out.setColor(baseNameColor); + out.drawText(x0, y0, _listeBases.get(i).getContent()); + + } + } + + // Drawing base numbers + double numFontSize = (double) (1.5 * BASE_RADIUS); + out.setFont(PSExport.FONT_HELVETICA_BOLD, numFontSize); + + for (int i = 0; i < _listeBases.size(); i++) { + int basenum = _listeBases.get(i).getBaseNumber(); + if (basenum == -1) { + basenum = i + 1; + } + ModeleBase mb = _listeBases.get(i); + if (this.isNumberDrawn(mb, conf._numPeriod)) { + out.setColor(mb.getStyleBase() + .getBaseNumberColor()); + x0 = coords[i].x; + y0 = coords[i].y; + x1 = centers[i].x; + y1 = centers[i].y; + dx = x1 - x0; + dy = y1 - y0; + norm = Math.sqrt(dx * dx + dy * dy); + dx /= norm; + dy /= norm; + Point2D.Double vn = VARNAPanel.computeExcentricUnitVector(i,coords,centers); + + out.drawLine((x0 + 1.5 * BASE_RADIUS * vn.x), (y0 + 1.5 + * BASE_RADIUS * vn.y), (x0 + 2.5 * BASE_RADIUS * vn.x), + (y0 + 2.5 * BASE_RADIUS * vn.y), 1); + out.drawText( + (x0 + (conf._distNumbers + 1.0) * BASE_RADIUS * vn.x), + (y0 + (conf._distNumbers + 1.0) * BASE_RADIUS * vn.y), mb.getLabel()); + } + } + renderAnnotations(out, minX, minY, conf); + + // Draw color map + if (conf._drawColorMap) { + drawColorMap(conf, out); + } + + // Drawing Title + Rectangle2D.Double currentBBox = out.getBoundingBox(); + double titleFontSize = (2.0 * conf._titleFont.getSize()); + out.setColor(conf._titleColor); + out.setFont(PSExport.FONT_HELVETICA, titleFontSize); + double yTitle = currentBBox.y - titleFontSize / 2.0; + if (!getName().equals("")) { + out.drawText((maxX - minX) / 2.0, yTitle, getName()); + } + + OutputStreamWriter fout; + + try { + fout = new OutputStreamWriter(new FileOutputStream(path), "UTF-8"); + + fout.write(out.export()); + fout.close(); + } catch (IOException e) { + throw new ExceptionWritingForbidden(e.getMessage()); + } + } + + Point2D.Double buildCaptionPosition(ModeleBase mb, double heightEstimate, + VARNAConfig conf) { + double radius = 2.0; + if (isNumberDrawn(mb, conf._numPeriod)) { + radius += (conf._distNumbers + 1.0); + } + Point2D.Double center = mb.getCenter(); + Point2D.Double p = mb.getCoords(); + double realDistance = BASE_RADIUS * radius + heightEstimate; + return new Point2D.Double(center.getX() + (p.getX() - center.getX()) + * ((p.distance(center) + realDistance) / p.distance(center)), + center.getY() + + (p.getY() - center.getY()) + * ((p.distance(center) + realDistance) / p + .distance(center))); + } + + public double getBPHeightIncrement() { + return this._bpHeightIncrement; + } + + public void setBPHeightIncrement(double d) { + _bpHeightIncrement = d; + } + + private void drawChemProbAnnotation(SecStrDrawingProducer out, + ChemProbAnnotation cpa, Point2D.Double anchor, double minX, + double minY) { + out.setColor(cpa.getColor()); + Point2D.Double v = cpa.getDirVector(); + Point2D.Double vn = cpa.getNormalVector(); + Point2D.Double base = new Point2D.Double((anchor.x + CHEM_PROB_DIST + * v.x), (anchor.y + CHEM_PROB_DIST * v.y)); + Point2D.Double edge = new Point2D.Double( + (base.x + CHEM_PROB_BASE_LENGTH * cpa.getIntensity() * v.x), + (base.y + CHEM_PROB_BASE_LENGTH * cpa.getIntensity() * v.y)); + double thickness = CHEM_PROB_ARROW_THICKNESS * cpa.getIntensity(); + switch (cpa.getType()) { + case ARROW: { + Point2D.Double arrowTip1 = new Point2D.Double( + (base.x + cpa.getIntensity() + * (CHEM_PROB_ARROW_WIDTH * vn.x + CHEM_PROB_ARROW_HEIGHT + * v.x)), + (base.y + cpa.getIntensity() + * (CHEM_PROB_ARROW_WIDTH * vn.y + CHEM_PROB_ARROW_HEIGHT + * v.y))); + Point2D.Double arrowTip2 = new Point2D.Double( + (base.x + cpa.getIntensity() + * (-CHEM_PROB_ARROW_WIDTH * vn.x + CHEM_PROB_ARROW_HEIGHT + * v.x)), + (base.y + cpa.getIntensity() + * (-CHEM_PROB_ARROW_WIDTH * vn.y + CHEM_PROB_ARROW_HEIGHT + * v.y))); + out.drawLine(base.x - minX, minY - base.y, edge.x - minX, minY + - edge.y, thickness); + out.drawLine(base.x - minX, minY - base.y, arrowTip1.x - minX, minY + - arrowTip1.y, thickness); + out.drawLine(base.x - minX, minY - base.y, arrowTip2.x - minX, minY + - arrowTip2.y, thickness); + } + break; + case PIN: { + Point2D.Double side1 = new Point2D.Double( + (edge.x - cpa.getIntensity() + * (CHEM_PROB_PIN_SEMIDIAG * v.x)), + (edge.y - cpa.getIntensity() + * (CHEM_PROB_PIN_SEMIDIAG * v.y))); + Point2D.Double side2 = new Point2D.Double( + (edge.x - cpa.getIntensity() + * (CHEM_PROB_PIN_SEMIDIAG * vn.x)), + (edge.y - cpa.getIntensity() + * (CHEM_PROB_PIN_SEMIDIAG * vn.y))); + Point2D.Double side3 = new Point2D.Double( + (edge.x + cpa.getIntensity() + * (CHEM_PROB_PIN_SEMIDIAG * v.x)), + (edge.y + cpa.getIntensity() + * (CHEM_PROB_PIN_SEMIDIAG * v.y))); + Point2D.Double side4 = new Point2D.Double( + (edge.x + cpa.getIntensity() + * (CHEM_PROB_PIN_SEMIDIAG * vn.x)), + (edge.y + cpa.getIntensity() + * (CHEM_PROB_PIN_SEMIDIAG * vn.y))); + GeneralPath p2 = new GeneralPath(); + p2.moveTo((float) (side1.x - minX), (float) (minY - side1.y)); + p2.lineTo((float) (side2.x - minX), (float) (minY - side2.y)); + p2.lineTo((float) (side3.x - minX), (float) (minY - side3.y)); + p2.lineTo((float) (side4.x - minX), (float) (minY - side4.y)); + p2.closePath(); + out.fillPolygon(p2, cpa.getColor()); + out.drawLine(base.x - minX, minY - base.y, edge.x - minX, minY + - edge.y, thickness); + } + break; + case TRIANGLE: { + Point2D.Double arrowTip1 = new Point2D.Double( + (edge.x + cpa.getIntensity() + * (CHEM_PROB_TRIANGLE_WIDTH * vn.x)), + (edge.y + cpa.getIntensity() + * (CHEM_PROB_TRIANGLE_WIDTH * vn.y))); + Point2D.Double arrowTip2 = new Point2D.Double( + (edge.x + cpa.getIntensity() + * (-CHEM_PROB_TRIANGLE_WIDTH * vn.x)), + (edge.y + cpa.getIntensity() + * (-CHEM_PROB_TRIANGLE_WIDTH * vn.y))); + GeneralPath p2 = new GeneralPath(); + p2.moveTo((float) (base.x - minX), (float) (minY - base.y)); + p2.lineTo((float) (arrowTip1.x - minX), + (float) (minY - arrowTip1.y)); + p2.lineTo((float) (arrowTip2.x - minX), + (float) (minY - arrowTip2.y)); + p2.closePath(); + out.fillPolygon(p2, cpa.getColor()); + } + break; + case DOT: { + Double radius = CHEM_PROB_DOT_RADIUS * cpa.getIntensity(); + Point2D.Double center = new Point2D.Double((base.x + radius * v.x) + - minX, minY - (base.y + radius * v.y)); + out.fillCircle(center.x, center.y, radius, thickness, + cpa.getColor()); + } + break; + } + } + + private void renderAnnotations(SecStrDrawingProducer out, double minX, + double minY, VARNAConfig conf) { + for (TextAnnotation textAnnotation : getAnnotations()) { + out.setColor(textAnnotation.getColor()); + out.setFont(PSExport.FONT_HELVETICA_BOLD, 2.0 * textAnnotation + .getFont().getSize()); + Point2D.Double position = textAnnotation.getCenterPosition(); + if (textAnnotation.getType() == TextAnnotation.AnchorType.BASE) { + ModeleBase mb = (ModeleBase) textAnnotation.getAncrage(); + double fontHeight = Math.ceil(textAnnotation.getFont() + .getSize()); + position = buildCaptionPosition(mb, fontHeight, conf); + + } + out.drawText(position.x - minX, -(position.y - minY), + textAnnotation.getTexte()); + } + for (ChemProbAnnotation cpa : getChemProbAnnotations()) { + Point2D.Double anchor = cpa.getAnchorPosition(); + drawChemProbAnnotation(out, cpa, anchor, minX, minY); + } + } + + public boolean isNumberDrawn(ModeleBase mb, int numPeriod) { + if (numPeriod <= 0) + return false; + return ((mb.getIndex() == 0) || ((mb.getBaseNumber()) % numPeriod == 0) || (mb + .getIndex() == get_listeBases().size() - 1)); + } + + public void saveRNAEPS(String path, VARNAConfig conf) + throws ExceptionWritingForbidden { + PSExport out = new PSExport(); + saveRNA(path, conf, 0.4, out); + } + + public void saveRNAXFIG(String path, VARNAConfig conf) + throws ExceptionWritingForbidden { + XFIGExport out = new XFIGExport(); + saveRNA(path, conf, 20, out); + } + + public void saveRNATIKZ(String path, VARNAConfig conf) + throws ExceptionWritingForbidden { + TikzExport out = new TikzExport(); + saveRNA(path, conf, 0.15, out); + } + + public void saveRNASVG(String path, VARNAConfig conf) + throws ExceptionWritingForbidden { + SVGExport out = new SVGExport(); + saveRNA(path, conf, 0.5, out); + } + + public Rectangle2D.Double getBBox() { + Rectangle2D.Double result = new Rectangle2D.Double(10, 10, 10, 10); + double minx, maxx, miny, maxy; + minx = Double.MAX_VALUE; + miny = Double.MAX_VALUE; + maxx = -Double.MAX_VALUE; + maxy = -Double.MAX_VALUE; + for (int i = 0; i < _listeBases.size(); i++) { + minx = Math.min( + _listeBases.get(i).getCoords().getX() - BASE_RADIUS, minx); + miny = Math.min( + _listeBases.get(i).getCoords().getY() - BASE_RADIUS, miny); + maxx = Math.max( + _listeBases.get(i).getCoords().getX() + BASE_RADIUS, maxx); + maxy = Math.max( + _listeBases.get(i).getCoords().getY() + BASE_RADIUS, maxy); + } + result.x = minx; + result.y = miny; + result.width = Math.max(maxx - minx, 1); + result.height = Math.max(maxy - miny, 1); + if (_drawMode == RNA.DRAW_MODE_LINEAR) { + double realHeight = _bpHeightIncrement * result.width / 2.0; + result.height += realHeight; + result.y -= realHeight; + } + return result; + } + + public void setCoord(int index, Point2D.Double p) { + setCoord(index, p.x, p.y); + } + + public void setCoord(int index, double x, double y) { + if (index < _listeBases.size()) { + _listeBases.get(index).setCoords(new Point2D.Double(x, y)); + } + } + + public Point2D.Double getCoords(int i) { + if (i < _listeBases.size() && i >= 0) { + return _listeBases.get(i).getCoords(); + } + return new Point2D.Double(); + } + + public String getBaseContent(int i) { + if ((i >= 0) && (i < _listeBases.size())) { + return _listeBases.get(i).getContent(); + } + return ""; + } + + public int getBaseNumber(int i) { + if ((i >= 0) && (i < _listeBases.size())) { + return _listeBases.get(i).getBaseNumber(); + } + return -1; + } + + public Point2D.Double getCenter(int i) { + if (i < _listeBases.size()) { + return _listeBases.get(i).getCenter(); + } + + return new Point2D.Double(); + } + + public void setCenter(int i, double x, double y) { + setCenter(i, new Point2D.Double(x, y)); + } + + public void setCenter(int i, Point2D.Double p) { + if (i < _listeBases.size()) { + _listeBases.get(i).setCenter(p); + } + } + + public void drawRNACircle(VARNAConfig conf) { + _drawn = true; + _drawMode = DRAW_MODE_CIRCULAR; + int radius = (int) ((3 * (_listeBases.size() + 1) * BASE_RADIUS) / (2 * Math.PI)); + double angle; + for (int i = 0; i < _listeBases.size(); i++) { + angle = -((((double) -(i + 1)) * 2.0 * Math.PI) + / ((double) (_listeBases.size() + 1)) - Math.PI / 2.0); + _listeBases + .get(i) + .setCoords( + new Point2D.Double( + (radius * Math.cos(angle) * conf._spaceBetweenBases), + (radius * Math.sin(angle) * conf._spaceBetweenBases))); + _listeBases.get(i).setCenter(new Point2D.Double(0, 0)); + } + } + + public void drawRNAVARNAView(VARNAConfig conf) { + _drawn = true; + _drawMode = DRAW_MODE_VARNA_VIEW; + VARNASecDraw vs = new VARNASecDraw(); + vs.drawRNA(1, this); + } + + public void drawRNALine(VARNAConfig conf) { + _drawn = true; + _drawMode = DRAW_MODE_LINEAR; + for (int i = 0; i < get_listeBases().size(); i++) { + get_listeBases().get(i).setCoords( + new Point2D.Double(i * conf._spaceBetweenBases * 20, 0)); + get_listeBases().get(i).setCenter( + new Point2D.Double(i * conf._spaceBetweenBases * 20, -10)); + } + } + + public RNATemplateMapping drawRNATemplate(RNATemplate template, boolean straightBulges, + VARNAConfig conf) throws RNATemplateDrawingAlgorithmException { + return drawRNATemplate(template, conf, + DrawRNATemplateMethod.getDefault(), + DrawRNATemplateCurveMethod.getDefault(), straightBulges); + } + + public RNATemplateMapping drawRNATemplate(RNATemplate template, + VARNAConfig conf, DrawRNATemplateMethod helixLengthAdjustmentMethod, + boolean straightBulges) + throws RNATemplateDrawingAlgorithmException { + return drawRNATemplate(template, conf, helixLengthAdjustmentMethod, + DrawRNATemplateCurveMethod.getDefault(),straightBulges); + } + + public RNATemplateMapping drawRNATemplate(RNATemplate template, + VARNAConfig conf, + DrawRNATemplateMethod helixLengthAdjustmentMethod, + DrawRNATemplateCurveMethod curveMethod, + boolean straightBulges) + throws RNATemplateDrawingAlgorithmException { + _drawn = true; + _drawMode = DRAW_MODE_TEMPLATE; + + DrawRNATemplate drawRNATemplate = new DrawRNATemplate(this); + drawRNATemplate.drawRNATemplate(template, conf, + helixLengthAdjustmentMethod, curveMethod, + straightBulges); + return drawRNATemplate.getMapping(); + } + + private static double objFun(int n1, int n2, double r, double bpdist, + double multidist) { + return (((double) n1) * 2.0 * Math.asin(((double) bpdist) / (2.0 * r)) + + ((double) n2) * 2.0 + * Math.asin(((double) multidist) / (2.0 * r)) - (2.0 * Math.PI)); + } + + public double determineRadius(int nbHel, int nbUnpaired, double startRadius) { + return determineRadius(nbHel, nbUnpaired, startRadius, + BASE_PAIR_DISTANCE, MULTILOOP_DISTANCE); + } + + public static double determineRadius(int nbHel, int nbUnpaired, + double startRadius, double bpdist, double multidist) { + double xmin = bpdist / 2.0; + double xmax = 3.0 * multidist + 1; + double x = (xmin + xmax) / 2.0; + double y = 10000.0; + double ymin = -1000.0; + double ymax = 1000.0; + int numIt = 0; + double precision = 0.00001; + while ((Math.abs(y) > precision) && (numIt < 10000)) { + x = (xmin + xmax) / 2.0; + y = objFun(nbHel, nbUnpaired, x, bpdist, multidist); + ymin = objFun(nbHel, nbUnpaired, xmax, bpdist, multidist); + ymax = objFun(nbHel, nbUnpaired, xmin, bpdist, multidist); + if (ymin > 0.0) { + xmax = xmax + (xmax - xmin); + } else if ((y <= 0.0) && (ymax > 0.0)) { + xmax = x; + } else if ((y >= 0.0) && (ymin < 0.0)) { + xmin = x; + } else if (ymax < 0.0) { + xmin = Math.max(xmin - (x - xmin), + Math.max(bpdist / 2.0, multidist / 2.0)); + xmax = x; + } + numIt++; + } + return x; + } + + public void drawRNA(VARNAConfig conf) throws ExceptionNAViewAlgorithm { + drawRNA(RNA.DEFAULT_DRAW_MODE, conf); + } + + public void drawRNA(int mode, VARNAConfig conf) + throws ExceptionNAViewAlgorithm { + _drawMode = mode; + switch (get_drawMode()) { + case RNA.DRAW_MODE_RADIATE: + drawRNARadiate(conf); + break; + case RNA.DRAW_MODE_LINEAR: + drawRNALine(conf); + break; + case RNA.DRAW_MODE_CIRCULAR: + drawRNACircle(conf); + break; + case RNA.DRAW_MODE_NAVIEW: + drawRNANAView(conf); + break; + case RNA.DRAW_MODE_VARNA_VIEW: + drawRNAVARNAView(conf); + break; + default: + break; + } + + } + + public int getDrawMode() { + return _drawMode; + } + + public static double HYSTERESIS_EPSILON = .15; + 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.}; + + public static double normalizeAngle(double angle) + { + return normalizeAngle(angle,0.); + } + + public static double normalizeAngle(double angle, double fromVal) + { + double toVal = fromVal +2.*Math.PI; + double result = angle; + while(result= toVal) + { + result -= 2.*Math.PI; + } + return result; + } + + public static double correctHysteresis(double angle) + { + double result = normalizeAngle(angle); + + for (int i=0;i bases) + { + double mydist = Math.abs(radius*(angle / (bases.size() + 1))); + double addedRadius= 0.; + Point2D.Double PA = new Point2D.Double(center.x + radius * Math.cos(base + pHel), + center.y + radius * Math.sin(base + pHel)); + Point2D.Double PB = new Point2D.Double(center.x + radius * Math.cos(base + pHel+angle), + center.y + radius * Math.sin(base + pHel+angle)); + double dist = PA.distance(PB); + Point2D.Double VN = new Point2D.Double((PB.y-PA.y)/dist,(-PB.x+PA.x)/dist); + if (mydist<2*BASE_RADIUS) + { + addedRadius=Math.min(1.0,(2*BASE_RADIUS-mydist)/4)*computeRadius(mydist, 2.29*(bases.size() + 1)*BASE_RADIUS-mydist); + } + + + ArrayList pos = computeNewAngles(bases.size(),center,VN, angle,base + pHel,radius,addedRadius); + for (int i = 0; i < bases.size(); i++) + { + int k = bases.get(i); + setCoord(k, pos.get(i)); + } + + } + + private double computeRadius(double b, double pobj) + { + double a=b, aL=a, aU=Double.POSITIVE_INFINITY; + double h = (a-b)*(a-b)/((a+b)*(a+b)); + double p = Math.PI*(a+b)*(1+h/4.+h*h/64.+h*h*h/256.+25.*h*h*h*h/16384.)/2.0; + double aold = a+1.; + while ((Math.abs(p-pobj)>10e-4)&&(aold!=a)){ + aold = a; + if (p prevBases,Vector nextBases) + { + if (isDirect) { + double anglePrev = normalizeAngle(angleLimitLeft - angleRightPartner); + double angleNext = normalizeAngle(angleLeftPartner - angleLimitRight); + distributeUnpaired(radius,anglePrev, angleRightPartner, base, + center,prevBases); + distributeUnpaired(radius,-angleNext, angleLeftPartner, base, + center,nextBases); + } else { + double anglePrev = normalizeAngle(angleLeftPartner - angleLimitRight); + double angleNext = normalizeAngle(angleLimitLeft - angleRightPartner); + distributeUnpaired(radius,-anglePrev, angleLeftPartner, base, + center,prevBases); + distributeUnpaired(radius,angleNext, angleRightPartner, base, + center,nextBases); + } + + } + + private static Point2D.Double getPoint(double angleLine, double angleBulge, Point2D.Double center, + Point2D.Double VN,double radius, double addedRadius, double dirBulge) + { + return new Point2D.Double( + center.x + radius * Math.cos(angleLine)+ + dirBulge*addedRadius*Math.sin(angleBulge)*VN.x, + center.y + radius * Math.sin(angleLine)+ + dirBulge*addedRadius*Math.sin(angleBulge)*VN.y); + } + + + private ArrayList computeNewAngles(int numPoints, Point2D.Double center, + Point2D.Double VN, double angle, double angleBase, double radius, double addedRadius) + { + ArrayList result = new ArrayList(); + if (numPoints>0) + { + ArrayList factors = new ArrayList(); + + + Point2D.Double prevP = new Point2D.Double( + center.x + radius * Math.cos(angleBase), + center.y + radius * Math.sin(angleBase)); + + + double fact = 0.; + + double angleBulge = 0.; + double dirBulge = (angle<0)?-1.:1.; + double dtarget =2.*BASE_RADIUS; + + for (int i = 0; i < numPoints; i++) + { + double lbound = fact; + double ubound = 1.0; + double angleLine = angleBase + angle*fact; + angleBulge = Math.PI*fact; + Point2D.Double currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge); + + int numIter = 0; + while ((Math.abs(currP.distance(prevP)-dtarget)>0.01)&& (numIter<100)) + { + if (currP.distance(prevP)> dtarget) + { + ubound = fact; + fact = (fact+lbound)/2.0; + } + else + { + lbound = fact; + fact = (fact+ubound)/2.0; + } + angleLine = angleBase + angle*fact; + angleBulge = Math.PI*fact; + currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge); + numIter++; + } + factors.add(fact); + prevP = currP; + } + + + double rescale = 1.0/(factors.get(factors.size()-1)+factors.get(0)); + + for(int j=0;j0) + { + prevP = getPoint(angleBase, 0, center,VN,radius, addedRadius, dirBulge); + double totDist = 0.0; + for(int j=0;j(); + prevP = new Point2D.Double( + center.x + radius * Math.cos(angleBase), + center.y + radius * Math.sin(angleBase)); + for (int i = 0; i < numPoints; i++) + { + double lbound = fact; + double ubound = 1.5; + double angleLine = angleBase + angle*fact; + angleBulge = Math.PI*fact; + Point2D.Double currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge); + + int numIter = 0; + while ((Math.abs(currP.distance(prevP)-dtarget)>0.01)&& (numIter<100)) + { + if (currP.distance(prevP)> dtarget) + { + ubound = fact; + fact = (fact+lbound)/2.0; + } + else + { + lbound = fact; + fact = (fact+ubound)/2.0; + } + angleLine = angleBase + angle*fact; + angleBulge = Math.PI*fact; + currP = getPoint(angleLine, angleBulge, center,VN,radius, addedRadius, dirBulge); + numIter++; + } + factors.add(fact); + prevP = currP; + } + rescale = 1.0/(factors.get(factors.size()-1)+factors.get(0)); + for(int j=0;j j) { + return; + } + + // BasePaired + if (_listeBases.get(i).getElementStructure() == j) { + double normalAngle = Math.PI / 2.0; + centers[i] = new Point2D.Double(x, y); + centers[j] = new Point2D.Double(x, y); + coords[i].x = (x + BASE_PAIR_DISTANCE + * Math.cos(dirAngle - normalAngle) / 2.0); + coords[i].y = (y + BASE_PAIR_DISTANCE + * Math.sin(dirAngle - normalAngle) / 2.0); + coords[j].x = (x + BASE_PAIR_DISTANCE + * Math.cos(dirAngle + normalAngle) / 2.0); + coords[j].y = (y + BASE_PAIR_DISTANCE + * Math.sin(dirAngle + normalAngle) / 2.0); + drawLoop(i + 1, j - 1, x + LOOP_DISTANCE * Math.cos(dirAngle), y + + LOOP_DISTANCE * Math.sin(dirAngle), dirAngle, coords, + centers, angles, straightBulges); + } else { + int k = i; + Vector basesMultiLoop = new Vector(); + Vector helices = new Vector(); + int l; + while (k <= j) { + l = _listeBases.get(k).getElementStructure(); + if (l > k) { + basesMultiLoop.add(new Integer(k)); + basesMultiLoop.add(new Integer(l)); + helices.add(new Integer(k)); + k = l + 1; + } else { + basesMultiLoop.add(new Integer(k)); + k++; + } + } + int mlSize = basesMultiLoop.size() + 2; + int numHelices = helices.size() + 1; + double totalLength = MULTILOOP_DISTANCE * (mlSize - numHelices) + + BASE_PAIR_DISTANCE * numHelices; + double multiLoopRadius; + double angleIncrementML; + double angleIncrementBP; + if (mlSize > 3) { + multiLoopRadius = determineRadius(numHelices, mlSize + - numHelices, (totalLength) / (2.0 * Math.PI), + BASE_PAIR_DISTANCE, MULTILOOP_DISTANCE); + angleIncrementML = -2.0 + * Math.asin(((float) MULTILOOP_DISTANCE) + / (2.0 * multiLoopRadius)); + angleIncrementBP = -2.0 + * Math.asin(((float) BASE_PAIR_DISTANCE) + / (2.0 * multiLoopRadius)); + } + else { + multiLoopRadius = 35.0; + angleIncrementBP = -2.0 + * Math.asin(((float) BASE_PAIR_DISTANCE) + / (2.0 * multiLoopRadius)); + angleIncrementML = (-2.0 * Math.PI - angleIncrementBP) / 2.0; + } + // System.out.println("MLr:"+multiLoopRadius+" iBP:"+angleIncrementBP+" iML:"+angleIncrementML); + + double centerDist = Math.sqrt(Math.max(Math.pow(multiLoopRadius, 2) + - Math.pow(BASE_PAIR_DISTANCE / 2.0, 2), 0.0)) + - LOOP_DISTANCE; + Point2D.Double mlCenter = new Point2D.Double( + (x + (centerDist * Math.cos(dirAngle))), + (y + (centerDist * Math.sin(dirAngle)))); + + // Base directing angle for (multi|hairpin) loop, from the center's + // perspective + double baseAngle = dirAngle + // U-turn + + Math.PI + // Account for already drawn supporting base-pair + + 0.5 * angleIncrementBP + // Base cannot be paired twice, so next base is at + // "unpaired base distance" + + 1.0 * angleIncrementML; + + ArrayList currUnpaired = new ArrayList(); + Couple currInterval = new Couple(0.,baseAngle-1.0 * angleIncrementML); + ArrayList,Couple>> intervals = new ArrayList,Couple>>(); + + for (k = basesMultiLoop.size() - 1; k >= 0; k--) { + l = basesMultiLoop.get(k).intValue(); + //System.out.println(l+" "); + centers[l] = mlCenter; + boolean isPaired = (_listeBases.get(l).getElementStructure() != -1); + boolean isPaired3 = isPaired && (_listeBases.get(l).getElementStructure() < l); + boolean isPaired5 = isPaired && !isPaired3; + if (isPaired3) { + if ((numHelices == 2) && straightBulges) + { + baseAngle = dirAngle-angleIncrementBP/2.; + } + else + { + baseAngle = correctHysteresis(baseAngle+angleIncrementBP/2.)-angleIncrementBP/2.; + } + currInterval.first = baseAngle; + intervals.add(new Couple,Couple>(currUnpaired,currInterval)); + currInterval = new Couple(-1.,-1.); + currUnpaired = new ArrayList(); + } + else if (isPaired5) + { + currInterval.second = baseAngle; + } + else + { + currUnpaired.add(l); + } + + angles[l] = baseAngle; + if (isPaired3) + { + baseAngle += angleIncrementBP; + } + else { + baseAngle += angleIncrementML; + } + } + currInterval.first = dirAngle + - Math.PI + - 0.5 * angleIncrementBP; + intervals.add(new Couple,Couple>(currUnpaired,currInterval)); + //System.out.println("Inc. ML:"+angleIncrementML+" BP:"+angleIncrementBP); + + for(Couple,Couple> inter: intervals) + { + //double mid = inter.second.second; + double mina = inter.second.first; + double maxa = normalizeAngle(inter.second.second,mina); + //System.out.println(""+mina+" " +maxa); + + for (int n=0;n= 0; k--) { + l = basesMultiLoop.get(k).intValue(); + coords[l].x = mlCenter.x + multiLoopRadius + * Math.cos(angles[l]); + coords[l].y = mlCenter.y + multiLoopRadius + * Math.sin(angles[l]); + } + + // System.out.println("n1:"+n1+" n2:"+n2); + double newAngle; + int m, n; + for (k = 0; k < helices.size(); k++) { + m = helices.get(k).intValue(); + n = _listeBases.get(m).getElementStructure(); + newAngle = (angles[m] + angles[n]) / 2.0; + drawLoop(m + 1, n - 1, (LOOP_DISTANCE * Math.cos(newAngle)) + + (coords[m].x + coords[n].x) / 2.0, + (LOOP_DISTANCE * Math.sin(newAngle)) + + (coords[m].y + coords[n].y) / 2.0, newAngle, + coords, centers, angles, straightBulges); + } + } + } + + private Vector getPreviousUnpaired(Point h) + { + Vector prevBases = new Vector(); + boolean over = false; + int i = h.y + 1; + while (!over) { + if (i >=get_listeBases().size()) { + over = true; + } else { + if (get_listeBases().get(i) + .getElementStructure() == -1) { + prevBases.add(new Integer(i)); + } else { + over = true; + } + } + i++; + } + return prevBases; + } + + private Vector getNextUnpaired(Point h) + { + boolean over = false; + int i = h.x - 1; + Vector nextBases = new Vector(); + while (!over) { + if (i < 0) { + over = true; + } else { + if (get_listeBases().get(i) + .getElementStructure() == -1) { + nextBases.add(new Integer(i)); + } else { + over = true; + } + } + i--; + } + return nextBases; + } + + + public void rotateEverything(double delta, double base, double pLimL, double pLimR, Point h, Point ml, Hashtable backupPos) + { + boolean isDirect = testDirectionality(ml.x, ml.y, h.x); + Point2D.Double center = get_listeBases().get(h.x).getCenter(); + for(int k=h.x;k<=h.y;k++) + { backupPos.put(k, getBaseAt(k).getCoords()); } + rotateHelix(center, h.x, h.y, delta); + + // Re-assigns unpaired atoms + Point2D.Double helixStart = getCoords(h.x); + Point2D.Double helixStop = getCoords(h.y); + double pHelR,pHelL; + if (isDirect) { + pHelR = computeAngle(center, helixStop) - base; + pHelL = computeAngle(center, helixStart) - base; + } else { + pHelL = computeAngle(center, helixStop) - base; + pHelR = computeAngle(center, helixStart) - base; + } + + Vector prevBases = getPreviousUnpaired(h); + Vector nextBases = getNextUnpaired(h); + + double radius = center.distance(helixStart); + + for (int j = 0; j < prevBases.size(); j++) + { + int k = prevBases.get(j); + backupPos.put(k, getCoords(k)); + } + for (int j = 0; j < nextBases.size(); j++) + { + int k = nextBases.get(j); + backupPos.put(k, getCoords(k)); + } + fixUnpairedPositions(isDirect, pHelR, pLimL, pLimR, pHelL, radius, base,center,prevBases,nextBases); + } + + + + public void drawRNARadiate() { + drawRNARadiate(-1.0, VARNAConfig.DEFAULT_SPACE_BETWEEN_BASES, true, true); + } + + public void drawRNARadiate(VARNAConfig conf) { + drawRNARadiate(-1.0, conf._spaceBetweenBases, conf._flatExteriorLoop, false); + } + + public static final double FLAT_RECURSIVE_INCREMENT = 20.; + + public void drawRNARadiate(double dirAngle, double _spaceBetweenBases, + boolean flatExteriorLoop, boolean straightBulges) { + _drawn = true; + straightBulges = true; + _drawMode = DRAW_MODE_RADIATE; + Point2D.Double[] coords = new Point2D.Double[_listeBases.size()]; + Point2D.Double[] centers = new Point2D.Double[_listeBases.size()]; + double[] angles = new double[_listeBases.size()]; + for (int i = 0; i < _listeBases.size(); i++) { + coords[i] = new Point2D.Double(0, 0); + centers[i] = new Point2D.Double(0, 0); + } + if (flatExteriorLoop) { + dirAngle += 1.0 - Math.PI / 2.0; + int i = 0; + double x = 0.0; + double y = 0.0; + double vx = -Math.sin(dirAngle); + double vy = Math.cos(dirAngle); + while (i < _listeBases.size()) { + coords[i].x = x; + coords[i].y = y; + centers[i].x = x + BASE_PAIR_DISTANCE * vy; + centers[i].y = y - BASE_PAIR_DISTANCE * vx; + int j = _listeBases.get(i).getElementStructure(); + if (j > i) { + double increment = 0.; + if (i+1<_listeBases.size()) + { + if (_listeBases.get(i+1).getElementStructure()==-1) + { + //increment = -FLAT_RECURSIVE_INCREMENT; + } + } + drawLoop(i, j, x + (BASE_PAIR_DISTANCE * vx / 2.0), y + + (BASE_PAIR_DISTANCE * vy / 2.0)+increment, dirAngle, + coords, centers, angles, straightBulges); + centers[i].x = coords[i].x + BASE_PAIR_DISTANCE * vy; + centers[i].y = y - BASE_PAIR_DISTANCE * vx; + i = j; + x += BASE_PAIR_DISTANCE * vx; + y += BASE_PAIR_DISTANCE * vy; + centers[i].x = coords[i].x + BASE_PAIR_DISTANCE * vy; + centers[i].y = y - BASE_PAIR_DISTANCE * vx; + } + x += MULTILOOP_DISTANCE * vx; + y += MULTILOOP_DISTANCE * vy; + i += 1; + } + } else { + drawLoop(0, _listeBases.size() - 1, 0, 0, dirAngle, coords, centers, angles, straightBulges); + } + for (int i = 0; i < _listeBases.size(); i++) { + _listeBases.get(i).setCoords( + new Point2D.Double(coords[i].x * _spaceBetweenBases, + coords[i].y * _spaceBetweenBases)); + _listeBases.get(i).setCenter( + new Point2D.Double(centers[i].x * _spaceBetweenBases, + centers[i].y * _spaceBetweenBases)); + } + + // TODO + // change les centres des bases de la premiere helice vers la boucle la + // plus proche + } + + public void drawRNANAView(VARNAConfig conf) throws ExceptionNAViewAlgorithm { + _drawMode = DRAW_MODE_NAVIEW; + _drawn = true; + + ArrayList X = new ArrayList(_listeBases.size()); + ArrayList Y = new ArrayList(_listeBases.size()); + ArrayList pair_table = new ArrayList(_listeBases.size()); + + for (int i = 0; i < _listeBases.size(); i++) { + pair_table.add(Short.valueOf(String.valueOf(_listeBases.get(i) + .getElementStructure()))); + } + NAView naView = new NAView(); + naView.naview_xy_coordinates(pair_table, X, Y); + + // Updating individual base positions + for (int i = 0; i < _listeBases.size(); i++) { + _listeBases.get(i).setCoords( + new Point2D.Double( + X.get(i) * 2.5 * conf._spaceBetweenBases, Y.get(i) + * 2.5 * conf._spaceBetweenBases)); + } + + // Updating centers + for (int i = 0; i < _listeBases.size(); i++) { + int indicePartner = _listeBases.get(i).getElementStructure(); + if (indicePartner != -1) { + Point2D.Double base = _listeBases.get(i).getCoords(); + Point2D.Double partner = _listeBases.get(indicePartner) + .getCoords(); + _listeBases.get(i).setCenter( + new Point2D.Double((base.x + partner.x) / 2.0, + (base.y + partner.y) / 2.0)); + } else { + Vector loop = getLoopBases(i); + double tmpx = 0.0; + double tmpy = 0.0; + for (int j = 0; j < loop.size(); j++) { + int partner = loop.elementAt(j); + Point2D.Double loopmember = _listeBases.get(partner) + .getCoords(); + tmpx += loopmember.x; + tmpy += loopmember.y; + } + _listeBases.get(i).setCenter( + new Point2D.Double(tmpx / loop.size(), tmpy + / loop.size())); + } + } + } + + /* + * public void drawMOTIFView() { _drawn = true; _drawMode = + * DRAW_MODE_MOTIFVIEW; int spaceBetweenStrand =0; Motif motif = new + * Motif(this,get_listeBases()); motif.listStrand(); for (int i = 0; i < + * motif.getListStrand().sizeStruct(); i++ ){ for (int j = 0; j < + * motif.getListStrand().getStrand(i).sizeStrand(); j++ ){ int indice = + * motif.getListStrand().getStrand(i).getMB(j).getIndex(); + * get_listeBases().get(indice).setCoords( new Point2D.Double(0,0)); + * get_listeBases().get(indice).setCenter( new Point2D.Double(0, 0)); + * + * } } //Recherche du brin central int centralStrand = + * motif.getCentralStrand(); + * + * //Cas o? l'on a un motif en ?toile if(centralStrand!=-1){ //On positionne + * le brin central motif.positionneSpecificStrand(centralStrand, + * spaceBetweenStrand); + * + * //On place les autres brins par rapport a ce brin central + * motif.orderStrands(centralStrand); } + * + * else { centralStrand = 0; motif.positionneStrand(); motif.ajusteStrand(); + * } motif.reajustement(); motif.deviationBasePair(); + * motif.setCenterMotif(); } + */ + + public ArrayList getAllPartners(int indice) { + ArrayList result = new ArrayList(); + ModeleBase me = this.getBaseAt(indice); + int i = me.getElementStructure(); + if (i != -1) { + result.add(getBaseAt(i)); + } + ArrayList msbps = getAuxBPs(indice); + for (ModeleBP m : msbps) { + result.add(m.getPartner(me)); + } + return result; + } + + public int get_drawMode() { + return _drawMode; + } + + public void setDrawMode(int drawMode) { + _drawMode = drawMode; + } + + public Set getSeparatorPositions(String s) { + HashSet result = new HashSet(); + int index = s.indexOf(DBNStrandSep); + while (index >= 0) { + result.add(index); + index = s.indexOf(DBNStrandSep, index + 1); + } + return result; + } + + public static String DBNStrandSep = "&"; + + public void setRNA(String seq, String str) + throws ExceptionFileFormatOrSyntax, + ExceptionUnmatchedClosingParentheses { + ArrayList al = RNA.explodeSequence(seq); + Set sepPos = getSeparatorPositions(str); + ArrayList alRes = new ArrayList(); + Set resSepPos = new HashSet(); + String strRes = ""; + for (int i = 0; i < al.size(); i++) { + if (sepPos.contains(i) && al.get(i).equals(DBNStrandSep)) { + resSepPos.add(alRes.size() - 1); + } else { + alRes.add(al.get(i)); + if (i s = RNA.explodeSequence(seq); + int[] str = new int[s.size()]; + for (int i = 0; i < str.length; i++) { + str[i] = -1; + } + try { + setRNA(s, str); + } catch (ExceptionFileFormatOrSyntax e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void setRNA(String seq, int[] str) + throws ExceptionFileFormatOrSyntax, + ExceptionUnmatchedClosingParentheses { + setRNA(RNA.explodeSequence(seq), str); + } + + public void setRNA(String[] seq, int[] str) + throws ExceptionFileFormatOrSyntax { + setRNA(seq, str, 1); + } + + public void setRNA(List seq, int[] str) + throws ExceptionFileFormatOrSyntax { + setRNA(seq.toArray(new String[seq.size()]), str, 1); + } + + public void setRNA(List seq, int[] str, int baseIndex) + throws ExceptionFileFormatOrSyntax { + setRNA(seq.toArray(new String[seq.size()]), str, baseIndex); + } + + public void setRNA(String[] seq, int[] str, int baseIndex) + throws ExceptionFileFormatOrSyntax { + clearAnnotations(); + _listeBases = new ArrayList(); + if (seq.length != str.length) { + warningEmition("Sequence length " + seq.length + + " differs from that of secondary structure " + str.length + + ". \nAdapting sequence length ..."); + if (seq.length < str.length) { + String[] nseq = new String[str.length]; + for (int i = 0; i < seq.length; i++) { + nseq[i] = seq[i]; + } + for (int i = seq.length; i < nseq.length; i++) { + nseq[i] = ""; + } + seq = nseq; + } else { + String[] seqTmp = new String[str.length]; + for (int i = 0; i < str.length; i++) { + seqTmp[i] = seq[i]; + } + seq = seqTmp; + } + } + for (int i = 0; i < str.length; i++) { + _listeBases.add(new ModeleBaseNucleotide(seq[i], i, baseIndex + i)); + } + applyStruct(str); + } + + /** + * Sets the RNA to be drawn. Uses when comparison mode is on. Will draw the + * super-structure passed in parameters and apply specials styles to the + * bases owning by each RNA alignment and both. + * + * @param seq + * - The sequence of the super-structure This sequence shall be + * designed like this: + * firstRNA1stBaseSecondRNA1stBaseFirstRNA2ndBaseSecondRNA2ndBase [...] + *
+ * Example: AAC-GUAGA--UGG + * @param struct + * - The super-structure + * @param basesOwn + * - The RNA owning bases array (each index will be:0 when common + * base, 1 when first RNA alignment base, 2 when second RNA + * alignment base) + * @throws ExceptionUnmatchedClosingParentheses + * @throws ExceptionFileFormatOrSyntax + */ + public void setRNA(String seq, String struct, ArrayList basesOwn) + throws ExceptionUnmatchedClosingParentheses, + ExceptionFileFormatOrSyntax { + clearAnnotations(); + _listeBases = new ArrayList(); + // On "parse" la structure (repérage des points, tiret et couples + // parentheses ouvrante/fermante) + int[] array_struct = parseStruct(struct); + int size = struct.length(); + int j = 0; + for (int i = 0; i < size; i++) { + ModeleBase mb; + if (seq.charAt(j) != seq.charAt(j + 1)) { + ModeleBasesComparison mbc = new ModeleBasesComparison( + seq.charAt(j), seq.charAt(j + 1), i); + mbc.set_appartenance(basesOwn.get(i)); + mbc.setBaseNumber(i + 1); + mb = mbc; + } else { + mb = new ModeleBaseNucleotide("" + seq.charAt(j), i, i + 1); + + } + _listeBases.add(mb); + j += 2; + } + for (int i = 0; i < size; i++) { + if (array_struct[i] != -1) { + this.addBPNow(i, array_struct[i]); + } + + j += 2; + } + } + + public void setRNA(List seq, String dbnStr) + throws ExceptionUnmatchedClosingParentheses, + ExceptionFileFormatOrSyntax { + clearAnnotations(); + int[] finStr = RNAFactory.parseSecStr(dbnStr); + setRNA(seq, finStr); + } + + public static ArrayList explodeSequence(String seq) { + ArrayList analyzedSeq = new ArrayList(); + int i = 0; + while (i < seq.length()) { + if (seq.charAt(i) == '{') { + boolean found = false; + String buf = ""; + i++; + while (!found & (i < seq.length())) { + if (seq.charAt(i) != '}') { + buf += seq.charAt(i); + i++; + } else { + found = true; + } + } + analyzedSeq.add(buf); + } else { + analyzedSeq.add("" + seq.charAt(i)); + } + i++; + } + return analyzedSeq; + } + + public int[] parseStruct(String str) + throws ExceptionUnmatchedClosingParentheses, + ExceptionFileFormatOrSyntax { + int[] result = new int[str.length()]; + int unexpectedChar = -1; + Stack p = new Stack(); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (c == '(') { + p.push(new Integer(i)); + } else if (c == '.' || c == '-' || c == ':') { + result[i] = -1; + } else if (c == ')') { + if (p.size() == 0) { + throw new ExceptionUnmatchedClosingParentheses(i + 1); + } + int j = p.pop().intValue(); + result[i] = j; + result[j] = i; + } else { + if (unexpectedChar == -1) + unexpectedChar = i; + break; + } + } + + if (unexpectedChar != -1) { + // warningEmition("Unexpected Character at index:" + + // unexpectedChar); + } + + if (p.size() != 0) { + throw new ExceptionUnmatchedClosingParentheses( + p.pop().intValue() + 1); + } + + return result; + } + + public Point getHelixInterval(int index) { + if ((index < 0) || (index >= _listeBases.size())) { + return new Point(index, index); + } + int j = _listeBases.get(index).getElementStructure(); + if (j != -1) { + int minH = index; + int maxH = index; + if (j > index) { + maxH = j; + } else { + minH = j; + } + boolean over = false; + while (!over) { + if ((minH < 0) || (maxH >= _listeBases.size())) { + over = true; + } else { + if (_listeBases.get(minH).getElementStructure() == maxH) { + minH--; + maxH++; + } else { + over = true; + } + } + } + minH++; + maxH--; + return new Point(minH, maxH); + } + return new Point(0, 0); + } + + public Point getExteriorHelix(int index) { + Point h = getHelixInterval(index); + int a = h.x; + int b = h.y; + while (!((h.x==0))) + { + a = h.x; + b = h.y; + h = getHelixInterval(a-1); + } + return new Point(a, b); + } + + + public ArrayList getHelix(int index) { + ArrayList result = new ArrayList(); + if ((index < 0) || (index >= _listeBases.size())) { + return result; + } + Point p = getHelixInterval(index); + for (int i = p.x; i <= p.y; i++) { + result.add(i); + result.add(this._listeBases.get(i).getElementStructure()); + } + return result; + } + + public Point getMultiLoop(int index) { + if ((index < 0) || (index >= _listeBases.size())) { + return new Point(index, index); + } + Point h = getHelixInterval(index); + int minH = h.x - 1; + int maxH = h.y + 1; + boolean over = false; + while (!over) { + if (minH < 0) { + over = true; + minH = 0; + } else { + if (_listeBases.get(minH).getElementStructure() == -1) { + minH--; + } else if (_listeBases.get(minH).getElementStructure() < minH) { + minH = _listeBases.get(minH).getElementStructure() - 1; + } else { + over = true; + } + } + } + over = false; + while (!over) { + if (maxH > _listeBases.size() - 1) { + over = true; + maxH = _listeBases.size() - 1; + } else { + if (_listeBases.get(maxH).getElementStructure() == -1) { + maxH++; + } else if (_listeBases.get(maxH).getElementStructure() > maxH) { + maxH = _listeBases.get(maxH).getElementStructure() + 1; + } else { + over = true; + } + } + } + return new Point(minH, maxH); + } + + public Vector getLoopBases(int startIndex) { + Vector result = new Vector(); + + if ((startIndex < 0) || (startIndex >= _listeBases.size())) { + return result; + } + int index = startIndex; + result.add(startIndex); + if (_listeBases.get(index).getElementStructure() <= index) { + index = (index + 1) % _listeBases.size(); + } else { + index = _listeBases.get(index).getElementStructure(); + result.add(index); + index = (index + 1) % _listeBases.size(); + } + + while (index != startIndex) { + result.add(index); + if (_listeBases.get(index).getElementStructure() == -1) { + index = (index + 1) % _listeBases.size(); + } else { + index = _listeBases.get(index).getElementStructure(); + result.add(index); + index = (index + 1) % _listeBases.size(); + } + } + return result; + } + + /** + * Returns the RNA secondary structure displayed by this panel as a + * well-parenthesized word, accordingly to the DBN format + * + * @return This panel's secondary structure + */ + public String getStructDBN() { + String result = ""; + for (int i = 0; i < _listeBases.size(); i++) { + int j = _listeBases.get(i).getElementStructure(); + if (j == -1) { + result += "."; + } else if (i > j) { + result += ")"; + } else { + result += "("; + } + } + return addStrandSeparators(result); + } + + private ArrayList getNonCrossingSubset( + ArrayList> rankedBPs) { + ArrayList currentBPs = new ArrayList(); + Stack pile = new Stack(); + for (int i = 0; i < rankedBPs.size(); i++) { + ArrayList lbp = rankedBPs.get(i); + if (!lbp.isEmpty()) { + ModeleBP bp = lbp.get(0); + boolean ok = true; + if (!pile.empty()) { + int x = pile.peek(); + if ((bp.getIndex3() >= x)) { + ok = false; + } + } + if (ok) { + lbp.remove(0); + currentBPs.add(bp); + pile.add(bp.getIndex3()); + } + } + if (!pile.empty() && (i == pile.peek())) { + pile.pop(); + } + } + return currentBPs; + } + + public ArrayList paginateStructure() { + ArrayList result = new ArrayList(); + // Mumbo jumbo to sort the basepair list + ArrayList bps = this.getAllBPs(); + ModeleBP[] mt = new ModeleBP[bps.size()]; + bps.toArray(mt); + Arrays.sort(mt, new Comparator() { + public int compare(ModeleBP arg0, ModeleBP arg1) { + if (arg0.getIndex5() != arg1.getIndex5()) + return arg0.getIndex5() - arg1.getIndex5(); + else + return arg0.getIndex3() - arg1.getIndex3(); + + } + }); + ArrayList> rankedBps = new ArrayList>(); + for (int i = 0; i < getSize(); i++) { + rankedBps.add(new ArrayList()); + } + for (int i = 0; i < mt.length; i++) { + rankedBps.get(mt[i].getIndex5()).add(mt[i]); + } + + while (!bps.isEmpty()) { + //System.out.println("Page: " + result.size()); + ArrayList currentBPs = getNonCrossingSubset(rankedBps); + int[] ss = new int[this.getSize()]; + for (int i = 0; i < ss.length; i++) { + ss[i] = -1; + } + + for (int i = 0; i < currentBPs.size(); i++) { + ModeleBP mbp = currentBPs.get(i); + ss[mbp.getIndex3()] = mbp.getIndex5(); + ss[mbp.getIndex5()] = mbp.getIndex3(); + } + bps.removeAll(currentBPs); + result.add(ss); + } + return result; + } + + private void showBasic(int[] res) { + for (int i = 0; i < res.length; i++) { + System.out.print(res[i] + ","); + } + System.out.println(); + + } + + public int[] getStrandShifts() + { + int[] result = new int[getSize()]; + int acc = 0; + for (int i=0;i pages = paginateStructure(); + char[] res = new char[getSize()]; + for (int i = 0; i < res.length; i++) { + res[i] = '.'; + } + char[] open = { '(', '[', '{', '<', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + + char[] close = new char[open.length]; + close[0] = ')'; + close[1] = ']'; + close[2] = '}'; + close[3] = '>'; + for (int i=4; i i && res[i] == '.' + && res[page[i]] == '.') { + res[i] = open[p]; + res[page[i]] = close[p]; + } + } + } + result = ""; + for (int i = 0; i < res.length; i++) { + result += res[i]; + } + + } + return addStrandSeparators(result); + + } + + public String getStructDBN(int[] str) { + String result = ""; + for (int i = 0; i < str.length; i++) { + if (str[i] == -1) { + result += "."; + } else if (str[i] > i) { + result += "("; + } else { + result += ")"; + } + } + return addStrandSeparators(result); + } + + /** + * Returns the raw nucleotides sequence for the displayed RNA + * + * @return The RNA sequence + */ + public String getSeq() { + String result = ""; + for (int i = 0; i < _listeBases.size(); i++) { + result += ((ModeleBase) _listeBases.get(i)).getContent(); + } + return addStrandSeparators(result); + } + + public String getStructBPSEQ() { + String result = ""; + int[] str = getNonOverlappingStruct(); + for (int i = 0; i < _listeBases.size(); i++) { + result += (i + 1) + " " + + ((ModeleBaseNucleotide) _listeBases.get(i)).getContent() + + " " + (str[i] + 1) + "\n"; + } + return result; + } + + public int[] getNonCrossingStruct() { + int[] result = new int[_listeBases.size()]; + // Adding "planar" base-pairs + for (int i = 0; i < _listeBases.size(); i++) { + result[i] = _listeBases.get(i).getElementStructure(); + } + return result; + } + + public int[] getNonOverlappingStruct() { + int[] result = getNonCrossingStruct(); + // Adding additional base pairs when possible (No more than one + // base-pair per base) + for (int i = 0; i < _structureAux.size(); i++) { + ModeleBP msbp = _structureAux.get(i); + ModeleBase mb5 = msbp.getPartner5(); + ModeleBase mb3 = msbp.getPartner3(); + int j5 = mb5.getIndex(); + int j3 = mb3.getIndex(); + if ((result[j3] == -1) && (result[j5] == -1)) { + result[j3] = j5; + result[j5] = j3; + } + } + return result; + } + + public String getStructCT() { + String result = ""; + for (int i = 0; i < _listeBases.size(); i++) { + result += (i + 1) + " " + + ((ModeleBase) _listeBases.get(i)).getContent() + " " + i + + " " + (i + 2) + " " + + (_listeBases.get(i).getElementStructure() + 1) + " " + + (i + 1) + "\n"; + } + return result; + } + + public void saveAsBPSEQ(String path, String title) + throws ExceptionExportFailed, ExceptionPermissionDenied { + try { + FileWriter f = new FileWriter(path); + f.write("# " + title + "\n"); + f.write(this.getStructBPSEQ() + "\n"); + f.close(); + } catch (IOException e) { + throw new ExceptionExportFailed(e.getMessage(), path); + } + } + + public void saveAsCT(String path, String title) + throws ExceptionExportFailed, ExceptionPermissionDenied { + try { + FileWriter f = new FileWriter(path); + f.write("" + _listeBases.size() + " " + title + "\n"); + f.write(this.getStructCT() + "\n"); + f.close(); + } catch (IOException e) { + throw new ExceptionExportFailed(e.getMessage(), path); + } + } + + public void saveAsDBN(String path, String title) + throws ExceptionExportFailed, ExceptionPermissionDenied { + try { + FileWriter f = new FileWriter(path); + f.write("> " + title + "\n"); + f.write(getListeBasesToString() + "\n"); + f.write(getStructDBN() + "\n"); + f.close(); + } catch (IOException e) { + throw new ExceptionExportFailed(e.getMessage(), path); + } + } + + public String getListeBasesToString() { + String s = new String(); + for (int i = 0; i < _listeBases.size(); i++) { + s += ((ModeleBaseNucleotide) _listeBases.get(i)).getContent(); + } + return addStrandSeparators(s); + } + + public void applyBPs(ArrayList allbps) { + ArrayList planar = new ArrayList(); + ArrayList others = new ArrayList(); + // System.err.println("Sequence: "+this.getSeq()); + RNAMLParser.planarize(allbps, planar, others, getSize()); + // System.err.println("All:"+allbps); + // System.err.println("=> Planar: "+planar); + // System.err.println("=> Others: "+others); + + for (ModeleBP mb : planar) { + addBPnow(mb.getPartner5().getIndex(), mb.getPartner3().getIndex(), + mb); + } + + for (ModeleBP mb : others) { + addBPAux(mb.getPartner5().getIndex(), mb.getPartner3().getIndex(), + mb); + } + } + + public void set_listeBases(ArrayList _liste) { + this._listeBases = _liste; + } + + public void addVARNAListener(InterfaceVARNAListener rl) { + _listeVARNAListener.add(rl); + } + + public void warningEmition(String warningMessage) { + for (int i = 0; i < _listeVARNAListener.size(); i++) { + _listeVARNAListener.get(i).onWarningEmitted(warningMessage); + } + } + + public void applyStyleOnBases(ArrayList basesList, + ModelBaseStyle style) { + for (int i = 1; i < basesList.size(); i++) { + _listeBases.get(basesList.get(i)).setStyleBase(style); + } + } + + private int[] correctReciprocity(int[] str) { + int[] result = new int[str.length]; + for (int i = 0; i < str.length; i++) { + if (str[i] != -1) { + if (i == str[str[i]]) { + result[i] = str[i]; + } else { + str[str[i]] = i; + } + } else { + result[i] = -1; + } + } + return result; + } + + private void applyStruct(int[] str) throws ExceptionFileFormatOrSyntax { + str = correctReciprocity(str); + + int[] planarSubset = RNAMLParser.planarize(str); + _structureAux.clear(); + + for (int i = 0; i < planarSubset.length; i++) { + if (str[i] > i) { + if (planarSubset[i] > i) { + addBPNow(i, planarSubset[i]); + } else if ((planarSubset[i] != str[i])) { + addBPAux(i, str[i]); + } + } + } + + } + + public ArrayList get_listeBases() { + return _listeBases; + } + + public int getSize() { + return _listeBases.size(); + } + + public ArrayList findAll() { + ArrayList listAll = new ArrayList(); + for (int i = 0; i < get_listeBases().size(); i++) { + listAll.add(i); + } + return listAll; + } + + public ArrayList findBulge(int index) { + ArrayList listUp = new ArrayList(); + if (get_listeBases().get(index).getElementStructure() == -1) { + int i = index; + boolean over = false; + while ((i < get_listeBases().size()) && !over) { + int j = get_listeBases().get(i).getElementStructure(); + if (j == -1) { + listUp.add(i); + i++; + } else { + over = true; + } + } + i = index - 1; + over = false; + while ((i >= 0) && !over) { + int j = get_listeBases().get(i).getElementStructure(); + if (j == -1) { + listUp.add(i); + i--; + } else { + over = true; + } + } + } + return listUp; + } + + public ArrayList findStem(int index) { + ArrayList listUp = new ArrayList(); + int i = index; + do { + listUp.add(i); + int j = get_listeBases().get(i).getElementStructure(); + if (j == -1) { + i = (i + 1) % getSize(); + } else { + if ((j < i) && (index <= i) && (j <= index)) { + i = j; + } else { + i = (i + 1) % getSize(); + } + } + } while (i != index); + return listUp; + } + + public int getHelixCountOnLoop(int indice) { + int cptHelice = 0; + if (indice < 0 || indice >= get_listeBases().size()) + return cptHelice; + int i = indice; + int j = get_listeBases().get(i).getElementStructure(); + // Only way to distinguish "supporting base-pair" from others + boolean justJumped = false; + if ((j != -1) && (j < i)) { + i = j + 1; + indice = i; + } + do { + j = get_listeBases().get(i).getElementStructure(); + if ((j != -1) && (!justJumped)) { + i = j; + justJumped = true; + cptHelice++; + } else { + i = (i + 1) % get_listeBases().size(); + justJumped = false; + } + } while (i != indice); + return cptHelice; + } + + public ArrayList findLoop(int indice) { + return findLoopForward(indice); + } + + public ArrayList findLoopForward(int indice) { + ArrayList base = new ArrayList(); + if (indice < 0 || indice >= get_listeBases().size()) + return base; + int i = indice; + int j = get_listeBases().get(i).getElementStructure(); + // Only way to distinguish "supporting base-pair" from others + boolean justJumped = false; + if (j != -1) { + i = Math.min(i, j) + 1; + indice = i; + } + do { + base.add(i); + j = get_listeBases().get(i).getElementStructure(); + if ((j != -1) && (!justJumped)) { + i = j; + justJumped = true; + } else { + i = (i + 1) % get_listeBases().size(); + justJumped = false; + } + } while (i != indice); + return base; + } + + public ArrayList findPair(int indice) { + ArrayList base = new ArrayList(); + int j = get_listeBases().get(indice).getElementStructure(); + if (j != -1) { + base.add(Math.min(indice, j)); + base.add(Math.max(indice, j)); + } + + return base; + + } + + public ArrayList findLoopBackward(int indice) { + ArrayList base = new ArrayList(); + if (indice < 0 || indice >= get_listeBases().size()) + return base; + int i = indice; + int j = get_listeBases().get(i).getElementStructure(); + // Only way to distinguish "supporting base-pair" from others + boolean justJumped = false; + if (j != -1) { + i = Math.min(i, j) - 1; + indice = i; + } + if (i < 0) { + return base; + } + do { + base.add(i); + j = get_listeBases().get(i).getElementStructure(); + if ((j != -1) && (!justJumped)) { + i = j; + justJumped = true; + } else { + i = (i + get_listeBases().size() - 1) % get_listeBases().size(); + justJumped = false; + } + } while (i != indice); + return base; + } + + public ArrayList findHelix(int indice) { + ArrayList list = new ArrayList(); + if (get_listeBases().get(indice).getElementStructure() != -1) { + list.add(indice); + list.add(get_listeBases().get(indice).getElementStructure()); + int i = 1, prec = get_listeBases().get(indice) + .getElementStructure(); + while (indice + i < get_listeBases().size() + && get_listeBases().get(indice + i).getElementStructure() != -1 + && get_listeBases().get(indice + i).getElementStructure() == prec - 1) { + list.add(indice + i); + list.add(get_listeBases().get(indice + i).getElementStructure()); + prec = get_listeBases().get(indice + i).getElementStructure(); + i++; + } + i = -1; + prec = get_listeBases().get(indice).getElementStructure(); + while (indice + i >= 0 + && get_listeBases().get(indice + i).getElementStructure() != -1 + && get_listeBases().get(indice + i).getElementStructure() == prec + 1) { + list.add(indice + i); + list.add(get_listeBases().get(indice + i).getElementStructure()); + prec = get_listeBases().get(indice + i).getElementStructure(); + i--; + } + } + return list; + } + + public ArrayList find3Prime(int indice) { + ArrayList list = new ArrayList(); + boolean over = false; + while ((indice >= 0) && !over) { + over = (get_listeBases().get(indice).getElementStructure() != -1); + indice--; + } + indice++; + if (over) { + indice++; + } + for (int i = indice; i < get_listeBases().size(); i++) { + list.add(i); + if (get_listeBases().get(i).getElementStructure() != -1) { + return new ArrayList(); + } + } + return list; + } + + public ArrayList find5Prime(int indice) { + ArrayList list = new ArrayList(); + for (int i = 0; i <= indice; i++) { + list.add(i); + if (get_listeBases().get(i).getElementStructure() != -1) { + return new ArrayList(); + } + } + return list; + } + + public static Double angle(Point2D.Double p1, Point2D.Double p2, + Point2D.Double p3) { + Double alpha = Math.atan2(p1.y - p2.y, p1.x - p2.x); + Double beta = Math.atan2(p3.y - p2.y, p3.x - p2.x); + Double angle = (beta - alpha); + + // Correction de l'angle pour le resituer entre 0 et 2PI + while (angle < 0.0 || angle > 2 * Math.PI) { + if (angle < 0.0) + angle += 2 * Math.PI; + else if (angle > 2 * Math.PI) + angle -= 2 * Math.PI; + } + return angle; + } + + public ArrayList findNonPairedBaseGroup(Integer get_nearestBase) { + // detection 3', 5', bulge + ArrayList list = new ArrayList(); + int indice = get_nearestBase; + boolean nonpairedUp = true, nonpairedDown = true; + while (indice < get_listeBases().size() && nonpairedUp) { + if (get_listeBases().get(indice).getElementStructure() == -1) { + list.add(indice); + indice++; + } else { + nonpairedUp = false; + } + } + indice = get_nearestBase - 1; + while (indice >= 0 && nonpairedDown) { + if (get_listeBases().get(indice).getElementStructure() == -1) { + list.add(indice); + indice--; + } else { + nonpairedDown = false; + } + } + return list; + } + + /* + * public boolean getDrawn() { return _drawn; } + */ + + public ArrayList getStructureAux() { + return _structureAux; + } + + /** + * Translates a base number into its corresponding index. Although both + * should be unique, base numbers are not necessarily contiguous, and + * indices should be preferred for any reasonably complex algorithmic + * treatment. + * + * @param num + * The base number + * @return The first index whose associated Base model has base number + * num, -1 of no such base model exists. + */ + + public int getIndexFromBaseNumber(int num) { + for (int i = 0; i < this._listeBases.size(); i++) { + if (_listeBases.get(i).getBaseNumber() == num) { + return i; + } + } + return -1; + } + + /** + * Adds a base pair to this RNA's structure. Tries to add it to the + * secondary structure first, eventually adding it to the 'tertiary' + * interactions if it clashes with the current secondary structure. + * + * @param baseNumber5 + * - Base number of the origin of this base pair + * @param baseNumber3 + * - Base number of the destination of this base pair + */ + + public void addBPToStructureUsingNumbers(int baseNumber5, int baseNumber3) { + int i = getIndexFromBaseNumber(baseNumber5); + int j = getIndexFromBaseNumber(baseNumber3); + addBP(i, j); + } + + /** + * Adds a base pair to this RNA's structure. Tries to add it to the + * secondary structure first, possibly adding it to the 'tertiary' + * interactions if it clashes with the current secondary structure. + * + * @param number5 + * - Base number of the origin of this base pair + * @param number3 + * - Base number of the destination of this base pair + */ + + public void addBPToStructureUsingNumbers(int number5, int number3, + ModeleBP msbp) { + addBP(getIndexFromBaseNumber(number5), getIndexFromBaseNumber(number3), + msbp); + } + + public void addBP(int index5, int index3) { + int i = index5; + int j = index3; + ModeleBase part5 = _listeBases.get(i); + ModeleBase part3 = _listeBases.get(j); + ModeleBP msbp = new ModeleBP(part5, part3); + addBP(i, j, msbp); + } + + public void addBP(int index5, int index3, ModeleBP msbp) { + int i = index5; + int j = index3; + + if (j < i) { + int k = j; + j = i; + i = k; + } + if (i != -1) { + for (int k = i; k <= j; k++) { + ModeleBase tmp = _listeBases.get(k); + int l = tmp.getElementStructure(); + if (l != -1) { + if ((l <= i) || (l >= j)) { + addBPAux(i, j, msbp); + return; + } + } + } + addBPnow(i, j, msbp); + } + } + + public void removeBP(ModeleBP ms) { + if (_structureAux.contains(ms)) { + _structureAux.remove(ms); + } else { + ModeleBase m5 = ms.getPartner5(); + ModeleBase m3 = ms.getPartner3(); + int i = m5.getIndex(); + int j = m3.getIndex(); + if ((m5.getElementStructure() == m3.getIndex()) + && (m3.getElementStructure() == m5.getIndex())) { + m5.removeElementStructure(); + m3.removeElementStructure(); + } + } + } + + /** + * Register base-pair, no question asked. More precisely, this function will + * not try to determine if the base-pairs crosses any other. + * + * @param i + * @param j + * @param msbp + */ + private void addBPNow(int i, int j) { + if (j < i) { + int k = j; + j = i; + i = k; + } + + ModeleBase part5 = _listeBases.get(i); + ModeleBase part3 = _listeBases.get(j); + ModeleBP msbp = new ModeleBP(part5, part3); + addBPnow(i, j, msbp); + } + + /** + * Register base-pair, no question asked. More precisely, this function will + * not try to determine if the base-pairs crosses any other. + * + * @param i + * @param j + * @param msbp + */ + private void addBPnow(int i, int j, ModeleBP msbp) { + if (j < i) { + int k = j; + j = i; + i = k; + } + ModeleBase part5 = _listeBases.get(i); + ModeleBase part3 = _listeBases.get(j); + msbp.setPartner5(part5); + msbp.setPartner3(part3); + part5.setElementStructure(j, msbp); + part3.setElementStructure(i, msbp); + } + + public void addBPAux(int i, int j) { + ModeleBase part5 = _listeBases.get(i); + ModeleBase part3 = _listeBases.get(j); + ModeleBP msbp = new ModeleBP(part5, part3); + addBPAux(i, j, msbp); + } + + public void addBPAux(int i, int j, ModeleBP msbp) { + if (j < i) { + int k = j; + j = i; + i = k; + } + ModeleBase part5 = _listeBases.get(i); + ModeleBase part3 = _listeBases.get(j); + msbp.setPartner5(part5); + msbp.setPartner3(part3); + _structureAux.add(msbp); + } + + public ArrayList getBPsAt(int i) { + ArrayList result = new ArrayList(); + if (_listeBases.get(i).getElementStructure() != -1) { + result.add(_listeBases.get(i).getStyleBP()); + } + for (int k = 0; k < _structureAux.size(); k++) { + ModeleBP bp = _structureAux.get(k); + if ((bp.getPartner5().getIndex() == i) + || (bp.getPartner3().getIndex() == i)) { + result.add(bp); + } + } + return result; + + } + + public ModeleBP getBPStyle(int i, int j) { + ModeleBP result = null; + if (i > j) { + int k = j; + j = i; + i = k; + } + if (_listeBases.get(i).getElementStructure() == j) { + result = _listeBases.get(i).getStyleBP(); + } + for (int k = 0; k < _structureAux.size(); k++) { + ModeleBP bp = _structureAux.get(k); + if ((bp.getPartner5().getIndex() == i) + && (bp.getPartner3().getIndex() == j)) { + result = bp; + } + } + return result; + } + + public ArrayList getSecStrBPs() { + ArrayList result = new ArrayList(); + for (int i = 0; i < this.getSize(); i++) { + ModeleBase mb = _listeBases.get(i); + int k = mb.getElementStructure(); + if ((k != -1) && (k > i)) { + result.add(mb.getStyleBP()); + } + } + return result; + } + + public ArrayList getAuxBPs() { + ArrayList result = new ArrayList(); + for (ModeleBP bp : _structureAux) { + result.add(bp); + } + return result; + } + + public ArrayList getAllBPs() { + ArrayList result = new ArrayList(); + result.addAll(getSecStrBPs()); + result.addAll(getAuxBPs()); + return result; + } + + public ArrayList getAuxBPs(int i) { + ArrayList result = new ArrayList(); + for (ModeleBP bp : _structureAux) { + if ((bp.getPartner5().getIndex() == i) + || (bp.getPartner3().getIndex() == i)) { + result.add(bp); + } + } + return result; + } + + public void setBaseInnerColor(Color c) { + for (int i = 0; i < _listeBases.size(); i++) { + ModeleBase mb = _listeBases.get(i); + mb.getStyleBase().setBaseInnerColor(c); + } + } + + public void setBaseNumbersColor(Color c) { + for (int i = 0; i < _listeBases.size(); i++) { + ModeleBase mb = _listeBases.get(i); + mb.getStyleBase().setBaseNumberColor(c); + } + } + + public void setBaseNameColor(Color c) { + for (int i = 0; i < _listeBases.size(); i++) { + ModeleBase mb = _listeBases.get(i); + mb.getStyleBase().setBaseNameColor(c); + } + } + + public void setBaseOutlineColor(Color c) { + for (int i = 0; i < _listeBases.size(); i++) { + ModeleBase mb = _listeBases.get(i); + mb.getStyleBase().setBaseOutlineColor(c); + } + } + + public String getName() { + return _name; + } + + public void setName(String n) { + _name = n; + } + + public ArrayList getAnnotations() { + return _listeAnnotations; + } + + public boolean removeAnnotation(TextAnnotation t) { + return _listeAnnotations.remove(t); + } + + public void addAnnotation(TextAnnotation t) { + _listeAnnotations.add(t); + } + + public void removeAnnotation(String filter) { + ArrayList condamne = new ArrayList(); + for (TextAnnotation t : _listeAnnotations) { + if (t.getTexte().contains(filter)) { + condamne.add(t); + } + } + for (TextAnnotation t : condamne) { + _listeAnnotations.remove(t); + } + } + + public void clearAnnotations() { + _listeAnnotations.clear(); + } + + private boolean _strandEndsAnnotated = false; + + public void autoAnnotateStrandEnds() { + if (!_strandEndsAnnotated) { + int tailleListBases = _listeBases.size(); + boolean endAnnotate = false; + addAnnotation(new TextAnnotation("5'", _listeBases.get(0))); + for (int i = 0; i < _listeBases.size() - 1; i++) { + int realposA = _listeBases.get(i).getBaseNumber(); + int realposB = _listeBases.get(i + 1).getBaseNumber(); + if (realposB - realposA != 1) { + addAnnotation(new TextAnnotation("3'", _listeBases.get(i))); + addAnnotation(new TextAnnotation("5'", + _listeBases.get(i + 1))); + if (i + 1 == _listeBases.size() - 1) { + endAnnotate = true; + } + } + } + if (!endAnnotate) { + addAnnotation(new TextAnnotation("3'", + _listeBases.get(tailleListBases - 1))); + } + _strandEndsAnnotated = true; + } else { + removeAnnotation("3'"); + removeAnnotation("5'"); + _strandEndsAnnotated = false; + } + } + + public void autoAnnotateHelices() { + Stack p = new Stack(); + p.push(0); + int nbH = 1; + while (!p.empty()) { + int i = p.pop(); + if (i < _listeBases.size()) { + ModeleBase mb = _listeBases.get(i); + int j = mb.getElementStructure(); + if (j == -1) { + p.push(i + 1); + } else { + if (j > i) { + ModeleBase mbp = _listeBases.get(j); + p.push(j + 1); + ArrayList h = new ArrayList(); + int k = 1; + while (mb.getElementStructure() == mbp.getIndex()) { + h.add(mb); + h.add(mbp); + mb = _listeBases.get(i + k); + mbp = _listeBases.get(j - k); + + k++; + } + try { + addAnnotation(new TextAnnotation("H" + nbH++, h, + TextAnnotation.AnchorType.HELIX)); + } catch (Exception e) { + e.printStackTrace(); + } + p.push(i + k); + } + } + } + } + } + + public void autoAnnotateTerminalLoops() { + Stack p = new Stack(); + p.push(0); + int nbT = 1; + while (!p.empty()) { + int i = p.pop(); + if (i < _listeBases.size()) { + ModeleBase mb = _listeBases.get(i); + int j = mb.getElementStructure(); + if (j == -1) { + int k = 1; + ArrayList t = new ArrayList(); + while ((i + k < getSize()) + && (mb.getElementStructure() == -1)) { + t.add(mb); + mb = _listeBases.get(i + k); + k++; + } + if (mb.getElementStructure() != -1) { + if (mb.getElementStructure() == i - 1) { + try { + t.add(_listeBases.get(i - 1)); + t.add(_listeBases.get(i + k - 1)); + addAnnotation(new TextAnnotation("T" + nbT++, + t, TextAnnotation.AnchorType.LOOP)); + } catch (Exception e) { + e.printStackTrace(); + } + } + p.push(i + k - 1); + } + + } else { + if (j > i) { + p.push(j + 1); + p.push(i + 1); + } + } + } + } + } + + public void autoAnnotateInteriorLoops() { + Stack p = new Stack(); + p.push(0); + int nbT = 1; + while (!p.empty()) { + int i = p.pop(); + if (i < _listeBases.size()) { + ModeleBase mb = _listeBases.get(i); + int j = mb.getElementStructure(); + if (j == -1) { + int k = i + 1; + ArrayList t = new ArrayList(); + boolean terminal = true; + while ((k < getSize()) + && ((mb.getElementStructure() >= i) || (mb + .getElementStructure() == -1))) { + t.add(mb); + mb = _listeBases.get(k); + if ((mb.getElementStructure() == -1) + || (mb.getElementStructure() < k)) + k++; + else { + p.push(k); + terminal = false; + k = mb.getElementStructure(); + } + } + if (mb.getElementStructure() != -1) { + if ((mb.getElementStructure() == i - 1) && !terminal) { + try { + t.add(_listeBases.get(i - 1)); + t.add(_listeBases.get(k - 1)); + addAnnotation(new TextAnnotation("I" + nbT++, + t, TextAnnotation.AnchorType.LOOP)); + } catch (Exception e) { + e.printStackTrace(); + } + p.push(k - 1); + } + } + } else { + if (j > i) { + p.push(i + 1); + } + } + } + } + } + + @SuppressWarnings("unchecked") + public TextAnnotation getAnnotation(TextAnnotation.AnchorType type, + ModeleBase base) { + TextAnnotation result = null; + for (TextAnnotation t : _listeAnnotations) { + if (t.getType() == type) { + switch (type) { + case BASE: + if (base == (ModeleBase) t.getAncrage()) + return t; + break; + case HELIX: + case LOOP: { + ArrayList mbl = (ArrayList) t + .getAncrage(); + if (mbl.contains(base)) + return t; + } + break; + } + } + } + return result; + } + + public void addChemProbAnnotation(ChemProbAnnotation cpa) { + //System.err.println(cpa.isOut()); + _chemProbAnnotations.add(cpa); + } + + public ArrayList getChemProbAnnotations() { + return _chemProbAnnotations; + } + + public void setColorMapValues(Double[] values, ModeleColorMap cm) { + setColorMapValues(values, cm, false); + } + + public void adaptColorMapToValues(ModeleColorMap cm) { + double min = Double.MAX_VALUE; + double max = Double.MIN_VALUE; + for (int i = 0; i < Math.min(_listeBases.size(), _listeBases.size()); i++) { + ModeleBase mb = _listeBases.get(i); + max = Math.max(max, mb.getValue()); + min = Math.min(min, mb.getValue()); + } + cm.rescale(min, max); + } + + + private ArrayList loadDotPlot(StreamTokenizer st) + { + ArrayList result = new ArrayList(); + try { + boolean inSeq = false; + String sequence = ""; + ArrayList accumulator = new ArrayList(); + int type = st.nextToken(); + Hashtable,Double> BP = new Hashtable,Double>(); + while (type != StreamTokenizer.TT_EOF) { + switch (type) { + case (StreamTokenizer.TT_NUMBER): + accumulator.add(st.nval); + break; + case (StreamTokenizer.TT_EOL): + break; + case (StreamTokenizer.TT_WORD): + if (st.sval.equals("/sequence")) + { + inSeq = true; + } + else if (st.sval.equals("ubox")) + { + int i = accumulator.get(accumulator.size()-3).intValue()-1; + int j = accumulator.get(accumulator.size()-2).intValue()-1; + double val = accumulator.get(accumulator.size()-1); + //System.err.println((char) type); + BP.put(new Couple(Math.min(i, j), Math.max(i, j)),val*val); + accumulator.clear(); + } + else if (inSeq) + { + sequence += st.sval; + } + break; + case ')': + inSeq = false; + break; + } + type = st.nextToken(); + } + for (int i = 0; i < getSize(); i++) { + int j = getBaseAt(i).getElementStructure(); + if (j != -1) { + Couple coor = new Couple( + Math.min(i, j), Math.max(i, j)); + if (BP.containsKey(coor)) { + result.add(BP.get(coor)); + } else { + result.add(0.); + } + } else { + double acc = 1.0; + for (int k = 0; k < getSize(); k++) { + Couple coor = new Couple( + Math.min(i, k), Math.max(i, k)); + if (BP.containsKey(coor)) { + acc -= BP.get(coor); + } + } + result.add(acc); + } + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return result; + } + + public void readValues(Reader r, ModeleColorMap cm) { + try { + StreamTokenizer st = new StreamTokenizer(r); + st.eolIsSignificant(true); + st.wordChars('/', '/'); + st.parseNumbers(); + ArrayList vals = new ArrayList(); + ArrayList curVals = new ArrayList(); + int type = st.nextToken(); + boolean isDotPlot = false; + if (type=='%') + { + vals = loadDotPlot(st); + isDotPlot = true; + } + else + { + while (type != StreamTokenizer.TT_EOF) { + switch (type) { + case (StreamTokenizer.TT_NUMBER): + curVals.add(st.nval); + break; + case (StreamTokenizer.TT_EOL): + if (curVals.size() > 0) { + vals.add(curVals.get(curVals.size()-1)); + curVals = new ArrayList(); + } + break; + } + type = st.nextToken(); + } + if (curVals.size() > 0) + vals.add(curVals.get(curVals.size()-1)); + } + + Double[] v = new Double[vals.size()]; + for (int i = 0; i < Math.min(vals.size(), getSize()); i++) { + v[i] = vals.get(i); + } + setColorMapValues(v, cm, true); + if (isDotPlot) + { + cm.setMinValue(0.0); + cm.setMaxValue(1.0); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void setColorMapValues(Double[] values, ModeleColorMap cm, + boolean rescaleColorMap) { + if (values.length > 0) { + for (int i = 0; i < Math.min(values.length, _listeBases.size()); i++) { + ModeleBase mb = _listeBases.get(i); + mb.setValue(values[i]); + } + if (rescaleColorMap) { + adaptColorMapToValues(cm); + } + } + } + + public Double[] getColorMapValues() { + Double[] values = new Double[_listeBases.size()]; + for (int i = 0; i < _listeBases.size(); i++) { + values[i] = _listeBases.get(i).getValue(); + } + return values; + } + + public void rescaleColorMap(ModeleColorMap cm) { + Double max = Double.MIN_VALUE; + Double min = Double.MAX_VALUE; + for (int i = 0; i < _listeBases.size(); i++) { + Double value = _listeBases.get(i).getValue(); + max = Math.max(max, value); + min = Math.min(min, value); + } + cm.rescale(min, max); + } + + public void addBase(ModeleBase mb) { + _listeBases.add(mb); + } + + public void setSequence(String s) { + setSequence(RNA.explodeSequence(s)); + } + + public void setSequence(List s) { + int i = 0; + int j = 0; + while ((i < s.size()) && (j < _listeBases.size())) { + ModeleBase mb = _listeBases.get(j); + if (mb instanceof ModeleBaseNucleotide) { + ((ModeleBaseNucleotide) mb).setBase(s.get(i)); + i++; + j++; + } else if (mb instanceof ModeleBasesComparison) { + ((ModeleBasesComparison) mb) + .setBase1(((s.get(i).length() > 0) ? s.get(i).charAt(0) + : ' ')); + ((ModeleBasesComparison) mb) + .setBase2(((s.get(i + 1).length() > 0) ? s.get(i + 1) + .charAt(0) : ' ')); + i += 2; + j++; + } else + j++; + } + for (i = _listeBases.size(); i < s.size(); i++) { + _listeBases.add(new ModeleBaseNucleotide(s.get(i), i)); + } + } + + public void eraseSequence() { + int j = 0; + while ((j < _listeBases.size())) { + ModeleBase mb = _listeBases.get(j); + if (mb instanceof ModeleBaseNucleotide) { + ((ModeleBaseNucleotide) mb).setBase(""); + j++; + } else if (mb instanceof ModeleBasesComparison) { + ((ModeleBasesComparison) mb).setBase1(' '); + ((ModeleBasesComparison) mb).setBase2(' '); + j++; + } else + j++; + } + } + + public RNA clone() { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream oout = new ObjectOutputStream(out); + oout.writeObject(this); + + ObjectInputStream in = new ObjectInputStream( + new ByteArrayInputStream(out.toByteArray())); + return (RNA) in.readObject(); + } catch (Exception e) { + throw new RuntimeException("cannot clone class [" + + this.getClass().getName() + "] via serialization: " + + e.toString()); + } + } + + /** + * Returns the base at index index. Indices are contiguous in + * the sequence over an interval [0,this.getSize()-1], where + * n is the length of the sequence. + * + * @param index + * The index, 0 ≤ index < this.getSize(), of the + * base model + * @return The base model of index index + */ + public ModeleBase getBaseAt(int index) { + return this._listeBases.get(index); + } + + /** + * Returns the set of bases of indices in indices. Indices are + * contiguous in the sequence, and belong to an interval + * [0,n-1], where n is the length of the sequence. + * + * @param indices + * A Collection of indices i, + * 0 ≤ index < this.getSize(), where some base + * models are found. + * @return A list of base model of indices in indices + */ + public ArrayList getBasesAt( + Collection indices) { + ArrayList mbs = new ArrayList(); + for (int i : indices) { + mbs.add(getBaseAt(i)); + } + return mbs; + } + + public ArrayList getBasesBetween(int from, int to) { + ArrayList mbs = new ArrayList(); + int bck = Math.min(from, to); + to = Math.max(from, to); + from = bck; + for (int i = from; i <= to; i++) { + mbs.add(getBaseAt(i)); + } + return mbs; + } + + public void addHighlightRegion(HighlightRegionAnnotation n) { + _listeRegionHighlights.add(n); + } + + public void removeHighlightRegion(HighlightRegionAnnotation n) { + _listeRegionHighlights.remove(n); + } + + public void removeChemProbAnnotation(ChemProbAnnotation a) { + _chemProbAnnotations.remove(a); + } + + public void clearChemProbAnnotations() { + _chemProbAnnotations.clear(); + } + + public void addHighlightRegion(int from, int to, Color fill, Color outline, + double radius) { + _listeRegionHighlights.add(new HighlightRegionAnnotation( + getBasesBetween(from, to), fill, outline, radius)); + } + + public void addHighlightRegion(int from, int to) { + _listeRegionHighlights.add(new HighlightRegionAnnotation( + getBasesBetween(from, to))); + } + + public ArrayList getHighlightRegion() { + return _listeRegionHighlights; + } + + /** + * Rotates the RNA coordinates by a certain angle + * + * @param angleDegres + * Rotation angle, in degrees + */ + public void globalRotation(Double angleDegres) { + if (_listeBases.size() > 0) { + + // angle en radian + Double angle = angleDegres * Math.PI / 180; + + // initialisation du minimum et dumaximum + Double maxX = _listeBases.get(0).getCoords().x; + Double maxY = _listeBases.get(0).getCoords().y; + Double minX = _listeBases.get(0).getCoords().x; + Double minY = _listeBases.get(0).getCoords().y; + // mise a jour du minimum et du maximum + for (int i = 0; i < _listeBases.size(); i++) { + if (_listeBases.get(i).getCoords().getX() < minX) + minX = _listeBases.get(i).getCoords().getX(); + if (_listeBases.get(i).getCoords().getY() < minY) + minY = _listeBases.get(i).getCoords().getY(); + if (_listeBases.get(i).getCoords().getX() > maxX) + maxX = _listeBases.get(i).getCoords().getX(); + if (_listeBases.get(i).getCoords().getX() > maxY) + maxY = _listeBases.get(i).getCoords().getY(); + } + // creation du point central + Point2D.Double centre = new Point2D.Double((maxX - minX) / 2, + (maxY - minY) / 2); + Double x, y; + for (int i = 0; i < _listeBases.size(); i++) { + // application de la rotation au centre de chaque base + // x' = cos(theta)*(x-xc) - sin(theta)*(y-yc) + xc + x = Math.cos(angle) + * (_listeBases.get(i).getCenter().getX() - centre.x) + - Math.sin(angle) + * (_listeBases.get(i).getCenter().getY() - centre.y) + + centre.x; + // y' = sin(theta)*(x-xc) + cos(theta)*(y-yc) + yc + y = Math.sin(angle) + * (_listeBases.get(i).getCenter().getX() - centre.x) + + Math.cos(angle) + * (_listeBases.get(i).getCenter().getY() - centre.y) + + centre.y; + _listeBases.get(i).setCenter(new Point2D.Double(x, y)); + + // application de la rotation au coordonnees de chaque + // base + // x' = cos(theta)*(x-xc) - sin(theta)*(y-yc) + xc + x = Math.cos(angle) + * (_listeBases.get(i).getCoords().getX() - centre.x) + - Math.sin(angle) + * (_listeBases.get(i).getCoords().getY() - centre.y) + + centre.x; + // y' = sin(theta)*(x-xc) + cos(theta)*(y-yc) + yc + y = Math.sin(angle) + * (_listeBases.get(i).getCoords().getX() - centre.x) + + Math.cos(angle) + * (_listeBases.get(i).getCoords().getY() - centre.y) + + centre.y; + _listeBases.get(i).setCoords(new Point2D.Double(x, y)); + } + } + } + + private static double MIN_DISTANCE = 10.; + + + /** + * Flip an helix around its supporting base + */ + public void flipHelix(Point h) { + if (h.x!=-1 && h.y!=-1 && h.x!=h.y) + { + int hBeg=h.x; + int hEnd=h.y; + Point2D.Double A = getCoords(hBeg); + Point2D.Double B = getCoords(hEnd); + Point2D.Double AB = new Point2D.Double(B.x - A.x, B.y - A.y); + double normAB = Math.sqrt(AB.x * AB.x + AB.y * AB.y); + // Creating a coordinate system centered on A and having + // unit x-vector Ox. + Point2D.Double O = A; + Point2D.Double Ox = new Point2D.Double(AB.x / normAB, AB.y / normAB); + Hashtable old = new Hashtable(); + for (int i = hBeg + 1; i < hEnd; i++) { + Point2D.Double P = getCoords(i); + Point2D.Double nP = project(O, Ox, P); + old.put(i, nP); + setCoord(i, nP); + Point2D.Double Center = getCenter(i); + setCenter(i, project(O, Ox, Center)); + } + } + } + + public static Point2D.Double project(Point2D.Double O, Point2D.Double Ox, + Point2D.Double C) { + Point2D.Double OC = new Point2D.Double(C.x - O.x, C.y - O.y); + // Projection of OC on OI => OX + double normOX = (Ox.x * OC.x + Ox.y * OC.y); + Point2D.Double OX = new Point2D.Double((normOX * Ox.x), (normOX * Ox.y)); + // Portion of OC orthogonal to Ox => XC + Point2D.Double XC = new Point2D.Double(OC.x - OX.x, OC.y - OX.y); + // Reflexive image of C with respect to Ox => CP + Point2D.Double OCP = new Point2D.Double(OX.x - XC.x, OX.y - XC.y); + Point2D.Double CP = new Point2D.Double(O.x + OCP.x, O.y + OCP.y); + return CP; + } + + + public boolean testDirectionality(int i, int j, int k) { + + // Which direction are we heading toward? + Point2D.Double pi = getCoords(i); + Point2D.Double pj = getCoords(j); + Point2D.Double pk = getCoords(k); + return testDirectionality(pi, pj, pk); + } + + public static boolean testDirectionality(Point2D.Double pi, + Point2D.Double pj, Point2D.Double pk) { + + // Which direction are we heading toward? + double test = (pj.x - pi.x) * (pk.y - pj.y) - (pj.y - pi.y) + * (pk.x - pj.x); + return test < 0.0; + } + + public double getOrientation() { + double maxDist = Double.MIN_VALUE; + double angle = 0; + for (int i = 0; i < _listeBases.size(); i++) { + ModeleBase b1 = _listeBases.get(i); + for (int j = i + 1; j < _listeBases.size(); j++) { + ModeleBase b2 = _listeBases.get(j); + Point2D.Double p1 = b1._coords.toPoint2D(); + Point2D.Double p2 = b2._coords.toPoint2D(); + double dist = p1.distance(p2); + if (dist > maxDist) { + maxDist = dist; + angle = computeAngle(p1, p2); + } + } + } + return angle; + } + + public boolean hasVirtualLoops() { + boolean consecutiveBPs = false; + for (int i = 0; i < _listeBases.size(); i++) { + int j = _listeBases.get(i).getElementStructure(); + if (j == i + 1) { + consecutiveBPs = true; + } + + } + return ((_drawMode != DRAW_MODE_LINEAR) + && (_drawMode != DRAW_MODE_CIRCULAR) && (consecutiveBPs)); + } + + public String getHTMLDescription() { + String result = ""; + result += ""; + result += ""; + result += ""; + return result + "
Name:" + this._name + "
Length:" + this.getSize() + + " nts
Base-pairs:" + + this.getAllBPs().size() + "
"; + } + + public String getID() { + return _id; + } + + public void setID(String id) { + _id = id; + } + + public static ArrayList getGapPositions(String gapString) { + ArrayList result = new ArrayList(); + for (int i = 0; i < gapString.length(); i++) { + char c = gapString.charAt(i); + if (c == '.' || c == ':') { + result.add(i); + } + } + return result; + } + + public RNA restrictTo(String gapString) { + return restrictTo(getGapPositions(gapString)); + } + + public RNA restrictTo(ArrayList positions) { + RNA result = new RNA(); + String oldSeq = this.getSeq(); + String newSeq = ""; + HashSet removedPos = new HashSet(positions); + int[] matching = new int[oldSeq.length()]; + int j = 0; + for (int i = 0; i < oldSeq.length(); i++) { + matching[i] = j; + if (!removedPos.contains(i)) { + newSeq += oldSeq.charAt(i); + j++; + } + } + result.setRNA(newSeq); + for (ModeleBP m : getAllBPs()) { + if (removedPos.contains(m.getIndex5()) + || removedPos.contains(m.getIndex3())) { + int i5 = matching[m.getIndex5()]; + int i3 = matching[m.getIndex3()]; + ModeleBP msbp = new ModeleBP(result.getBaseAt(i5), + result.getBaseAt(i3), m.getEdgePartner5(), + m.getEdgePartner3(), m.getStericity()); + result.addBP(i5, i3, msbp); + } + } + return result; + } + + public void rescale(double d) { + for (ModeleBase mb : _listeBases) { + mb._coords.x *= d; + mb._coords.y *= d; + mb._center.x *= d; + mb._center.y *= d; + } + } + + /** + * Necessary for DrawRNATemplate (which is why the method is + * package-visible). + */ + ArrayList getListeBases() { + return _listeBases; + } +}