package fr.orsay.lri.varna.applications.templateEditor; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.Shape; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import fr.orsay.lri.varna.exceptions.ExceptionInvalidRNATemplate; import fr.orsay.lri.varna.models.rna.RNA; import fr.orsay.lri.varna.models.templates.RNATemplate; import fr.orsay.lri.varna.models.templates.RNATemplate.EdgeEndPointPosition; import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateHelix; import fr.orsay.lri.varna.models.templates.RNATemplate.RNATemplateElement.EdgeEndPoint; public class Helix extends GraphicalTemplateElement{ RNATemplateHelix _h; public Helix(double x, double y, RNATemplate tmp, List existingRNAElements) { this(x,y,getNextAutomaticCaption(existingRNAElements),tmp); } public Helix(double x, double y, String cap, RNATemplate tmp) { _h = tmp.new RNATemplateHelix(cap); _h.setStartPosition(new Point2D.Double(x,y)); _h.setEndPosition(new Point2D.Double(x,y)); _h.setLength(1); _h.setCaption(cap); } public Helix(RNATemplateHelix templateHelix) { _h = templateHelix; } private static String getNextAutomaticCaption(List existingRNAElements) { // Find which captions are already used Set captions = new HashSet(); for (GraphicalTemplateElement element: existingRNAElements) { if (element instanceof Helix) { Helix helix = (Helix) element; if (helix.getCaption() != null) { captions.add(helix.getCaption()); } } } // Find a non-conflicting name for this helix for (int i=1;;i++) { String candidateCaption = "H" + i; if (! captions.contains(candidateCaption)) { return candidateCaption; } } } public void toggleFlipped() { _h.setFlipped(!_h.isFlipped()); updateAttachedUnpairedRegions(); } /** * When an helix is moved/resized/etc... it is necessary to update * the positions of endpoints from unpaired regions that are attached * to the helix. This function updates the endpoints positions of * attached unpaired regions. */ public void updateAttachedUnpairedRegions() { for (RelativePosition rpos: getConnectedEdges()) { Couple c = getAttachedElement(rpos); if (c != null && c.second instanceof UnpairedRegion) { UnpairedRegion unpairedRegion = (UnpairedRegion) c.second; Point2D.Double pos = getEdgePosition(rpos); if (c.first == RelativePosition.RP_CONNECT_START5) { unpairedRegion.setEdge5(pos); } else if (c.first == RelativePosition.RP_CONNECT_END3) { unpairedRegion.setEdge3(pos); } } } } public double getPosX() { return _h.getStartPosition().x; } public String getCaption() { return _h.getCaption(); } public double getPosY() { return _h.getStartPosition().y; } public RNATemplateHelix getTemplateElement() { return _h; } public void setX(double x) { _h.getStartPosition().x = x; } public void setY(double y) { _h.getStartPosition().y = y; } public void setPos(Point2D.Double p) { _h.setStartPosition(p); updateLength(); } public void setPos(double x, double y) { setPos(new Point2D.Double(x,y)); } public Point2D.Double getPos() { return _h.getStartPosition(); } public void moveCenter(double x, double y) { Point2D.Double center = new Point2D.Double((_h.getStartPosition().x+_h.getEndPosition().x)/2.0,(_h.getStartPosition().y+_h.getEndPosition().y)/2.0); double dx = x-center.x; double dy = y-center.y; _h.setStartPosition(new Point2D.Double(_h.getStartPosition().x+dx,_h.getStartPosition().y+dy)); _h.setEndPosition(new Point2D.Double(_h.getEndPosition().x+dx,_h.getEndPosition().y+dy)); } public void setExtent(double x, double y) { setExtent(new Point2D.Double(x,y)); } private void updateLength() { _h.setLength(getNbBP()); } public void setExtent(Point2D.Double p) { _h.setEndPosition(p); updateLength(); } public double getExtentX() { return _h.getEndPosition().x; } public Point2D.Double getExtent() { return _h.getEndPosition(); } public double getExtentY() { return _h.getEndPosition().y; } public static final double BASE_PAIR_DISTANCE = RNA.BASE_PAIR_DISTANCE; public static final double LOOP_DISTANCE = RNA.LOOP_DISTANCE; public static final double SELECTION_RADIUS = 15.0; public Point2D.Double getAbsStart5() { double dx = (_h.getStartPosition().x-_h.getEndPosition().x)/(_h.getStartPosition().distance(_h.getEndPosition())); double dy = (_h.getStartPosition().y-_h.getEndPosition().y)/(_h.getStartPosition().distance(_h.getEndPosition())); double nx = dy; double ny = -dx; Point2D.Double start5 = new Point2D.Double((getPosX()-Helix.BASE_PAIR_DISTANCE*nx/2.0),(getPosY()-Helix.BASE_PAIR_DISTANCE*ny/2.0)); return start5; } public Point2D.Double getAbsStart3() { double dx = (_h.getStartPosition().x-_h.getEndPosition().x)/(_h.getStartPosition().distance(_h.getEndPosition())); double dy = (_h.getStartPosition().y-_h.getEndPosition().y)/(_h.getStartPosition().distance(_h.getEndPosition())); double nx = dy; double ny = -dx; Point2D.Double start3 = new Point2D.Double((getPosX()+Helix.BASE_PAIR_DISTANCE*nx/2.0),(getPosY()+Helix.BASE_PAIR_DISTANCE*ny/2.0)); return start3; } public Point2D.Double getAbsEnd5() { double dx = (_h.getStartPosition().x-_h.getEndPosition().x)/(_h.getStartPosition().distance(_h.getEndPosition())); double dy = (_h.getStartPosition().y-_h.getEndPosition().y)/(_h.getStartPosition().distance(_h.getEndPosition())); double nx = dy; double ny = -dx; Point2D.Double end5 = new Point2D.Double((getExtentX()-Helix.BASE_PAIR_DISTANCE*nx/2.0),(getExtentY()-Helix.BASE_PAIR_DISTANCE*ny/2.0)); return end5; } public Point2D.Double getAbsEnd3() { double dx = (_h.getStartPosition().x-_h.getEndPosition().x)/(_h.getStartPosition().distance(_h.getEndPosition())); double dy = (_h.getStartPosition().y-_h.getEndPosition().y)/(_h.getStartPosition().distance(_h.getEndPosition())); double nx = dy; double ny = -dx; Point2D.Double end3 = new Point2D.Double((getExtentX()+Helix.BASE_PAIR_DISTANCE*nx/2.0),(getExtentY()+Helix.BASE_PAIR_DISTANCE*ny/2.0)); return end3; } public Point2D.Double getStart5() { if (_h.isFlipped()) return getAbsStart3(); else return getAbsStart5(); } public Point2D.Double getStart3() { if (_h.isFlipped()) return getAbsStart5(); else return getAbsStart3(); } public Point2D.Double getEnd5() { if (_h.isFlipped()) return getAbsEnd3(); else return getAbsEnd5(); } public Point2D.Double getEnd3() { if (_h.isFlipped()) return getAbsEnd5(); else return getAbsEnd3(); } public Polygon getBoundingPolygon() { double dx = (_h.getStartPosition().x-_h.getEndPosition().x)/(_h.getStartPosition().distance(_h.getEndPosition())); double dy = (_h.getStartPosition().y-_h.getEndPosition().y)/(_h.getStartPosition().distance(_h.getEndPosition())); double nx = dy; double ny = -dx; Point2D.Double start5 = new Point2D.Double((getPosX()+Helix.BASE_PAIR_DISTANCE*nx/2.0),(getPosY()+Helix.BASE_PAIR_DISTANCE*ny/2.0)); Point2D.Double end5 = new Point2D.Double((getExtentX()+Helix.BASE_PAIR_DISTANCE*nx/2.0),(getExtentY()+Helix.BASE_PAIR_DISTANCE*ny/2.0)); Point2D.Double start3 = new Point2D.Double((getPosX()-Helix.BASE_PAIR_DISTANCE*nx/2.0),(getPosY()-Helix.BASE_PAIR_DISTANCE*ny/2.0)); Point2D.Double end3 = new Point2D.Double((getExtentX()-Helix.BASE_PAIR_DISTANCE*nx/2.0),(getExtentY()-Helix.BASE_PAIR_DISTANCE*ny/2.0)); Polygon p = new Polygon(); p.addPoint((int)start5.x, (int)start5.y); p.addPoint((int)end5.x, (int)end5.y); p.addPoint((int)end3.x, (int)end3.y); p.addPoint((int)start3.x, (int)start3.y); return p; } public Point2D.Double getCenter() { return new Point2D.Double((int)((_h.getStartPosition().x+_h.getEndPosition().x)/2.0), (int)((_h.getStartPosition().y+_h.getEndPosition().y)/2.0)); } public Point2D.Double getCenterEditStart() { double dist = _h.getStartPosition().distance(_h.getEndPosition()); double dx = (_h.getEndPosition().x-_h.getStartPosition().x)/(dist); double dy = (_h.getEndPosition().y-_h.getStartPosition().y)/(dist); return new Point2D.Double((int)(_h.getStartPosition().x+(dist-10.0)*dx), (int)(_h.getStartPosition().y+(dist-10.0)*dy)); } public Point2D.Double getCenterEditEnd() { double dist = _h.getStartPosition().distance(_h.getEndPosition()); double dx = (_h.getEndPosition().x-_h.getStartPosition().x)/(dist); double dy = (_h.getEndPosition().y-_h.getStartPosition().y)/(dist); return new Point2D.Double((int)(_h.getStartPosition().x+(10.0)*dx), (int)(_h.getStartPosition().y+(10.0)*dy)); } public Shape getSelectionBox() { double dx = (_h.getStartPosition().x-_h.getEndPosition().x)/(_h.getStartPosition().distance(_h.getEndPosition())); double dy = (_h.getStartPosition().y-_h.getEndPosition().y)/(_h.getStartPosition().distance(_h.getEndPosition())); double nx = dy; double ny = -dx; Polygon hbox = getBoundingPolygon(); Polygon p = new Polygon(); Point2D.Double start5 = new Point2D.Double(hbox.xpoints[0]+SELECTION_RADIUS*(dx+nx),hbox.ypoints[0]+SELECTION_RADIUS*(dy+ny)); Point2D.Double end5 = new Point2D.Double(hbox.xpoints[1]+SELECTION_RADIUS*(-dx+nx),hbox.ypoints[1]+SELECTION_RADIUS*(-dy+ny)); Point2D.Double end3 = new Point2D.Double(hbox.xpoints[2]+SELECTION_RADIUS*(-dx-nx),hbox.ypoints[2]+SELECTION_RADIUS*(-dy-ny));; Point2D.Double start3 = new Point2D.Double(hbox.xpoints[3]+SELECTION_RADIUS*(dx-nx),hbox.ypoints[3]+SELECTION_RADIUS*(dy-ny));; p.addPoint((int)start5.x, (int)start5.y); p.addPoint((int)end5.x, (int)end5.y); p.addPoint((int)end3.x, (int)end3.y); p.addPoint((int)start3.x, (int)start3.y); return p; } public Shape getArea() { return getSelectionBox(); } public static final double EDIT_RADIUS = 10.0; public static final double MOVE_RADIUS = 13.0; public static final double BASE_RADIUS = 8.0; public static final double EDGE_BASE_RADIUS = 7.0; public RelativePosition getRelativePosition(double x, double y) { Point2D.Double current = new Point2D.Double(x,y); Shape p = getSelectionBox(); if (p.contains(current)) { if (getCenterEditStart().distance(current) getConnectedEdges() { ArrayList result = new ArrayList(); result.add(RelativePosition.RP_CONNECT_START5); result.add(RelativePosition.RP_CONNECT_START3); result.add(RelativePosition.RP_CONNECT_END5); result.add(RelativePosition.RP_CONNECT_END3); return result; } public String toString() { return "Helix " + getCaption(); } public RelativePosition relativePositionFromEdgeEndPointPosition( EdgeEndPointPosition pos) { switch (pos) { case IN1: return RelativePosition.RP_CONNECT_START5; case OUT1: return RelativePosition.RP_CONNECT_END5; case IN2: return RelativePosition.RP_CONNECT_END3; case OUT2: return RelativePosition.RP_CONNECT_START3; default: return null; } } }