001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.bio.gui.sequence; 022 023import java.awt.Color; 024import java.awt.Graphics2D; 025import java.awt.Paint; 026import java.awt.Shape; 027import java.awt.event.MouseEvent; 028import java.awt.geom.Area; 029import java.awt.geom.GeneralPath; 030import java.awt.geom.Rectangle2D; 031 032import org.biojava.bio.seq.Feature; 033import org.biojava.bio.seq.FeatureHolder; 034import org.biojava.bio.symbol.Location; 035 036 037/** 038 * A Feature Renderer that paints the Feature as a right facing arrow Based heavily on 039 * BasicFeatureRenderer 040 * 041 * @author Mark Southern 042 * @since 1.5 043 */ 044public class ArrowedFeatureRenderer implements FeatureRenderer { 045 private Paint fill; 046 private Paint outline; 047 private double arrowSize = 15.0; 048 private double arrowScoop = 4.0; 049 private double arrowHeadWidth = 5; 050 051 public ArrowedFeatureRenderer() { 052 fill = Color.red; 053 outline = Color.black; 054 } 055 056 public void setFill(Paint p) { 057 fill = p; 058 } 059 060 public Paint getFill() { 061 return fill; 062 } 063 064 public void setOutline(Paint p) { 065 outline = p; 066 } 067 068 public Paint getOutline() { 069 return outline; 070 } 071 072 public void setArrowSize(double arrowSize) { 073 this.arrowSize = arrowSize; 074 } 075 076 public double getArrowSize() { 077 return arrowSize; 078 } 079 080 public void setArrowScoop(double arrowScoop) { 081 this.arrowScoop = arrowScoop; 082 } 083 084 public double getArrowScoop() { 085 return arrowScoop; 086 } 087 088 public void setArrowHeadSize(double d) { 089 this.arrowHeadWidth = d; 090 } 091 092 public double getArrowHeadSize() { 093 return arrowHeadWidth; 094 } 095 096 public void renderFeature(Graphics2D g, Feature f, SequenceRenderContext src) { 097 Shape s = null; 098 Location loc = f.getLocation(); 099 float depth = ( float ) (arrowSize + (2.0 * arrowScoop)); 100 101 double minD; 102 double maxD; 103 104 if (src.getScale() > 1.0) { 105 minD = src.sequenceToGraphics(loc.getMin()); 106 maxD = src.sequenceToGraphics(loc.getMax() + 1) - 1.0; 107 } else { 108 minD = src.sequenceToGraphics(loc.getMin()); 109 maxD = src.sequenceToGraphics(loc.getMax()); 110 } 111 112 float min = ( float ) minD; 113 float max = ( float ) maxD; 114 115 float minBounds = ( float ) src.sequenceToGraphics(src.getRange().getMin() - 1); 116 float maxBounds = ( float ) src.sequenceToGraphics(src.getRange().getMax() + 1); 117 Shape bounds; 118 119 if (src.getDirection() == SequenceRenderContext.HORIZONTAL) { 120 bounds = new Rectangle2D.Double(minBounds, 0, maxBounds - minBounds, depth); 121 } else { 122 bounds = new Rectangle2D.Double(0, minBounds, depth, maxBounds - minBounds); 123 } 124 125 if ((max - min) >= arrowSize) { 126 if (src.getDirection() == SequenceRenderContext.HORIZONTAL) { 127 float minY = 0.0f; 128 float maxY = depth; 129 float minYS = minY + ( float ) arrowScoop; 130 float maxYS = maxY - ( float ) arrowScoop; 131 float midY = (minY + maxY) * 0.5f; 132 float minX = min; 133 float maxX = max; 134 135 float midX1 = maxX - ( float ) getArrowHeadSize(); 136 float midX2 = minX + ( float ) getArrowHeadSize(); 137 138 GeneralPath path = new GeneralPath(); 139 path.moveTo(minX, midY); 140 path.lineTo(midX2, minY); 141 path.lineTo(midX2, minYS); 142 path.lineTo(midX1, minYS); 143 path.lineTo(midX1, minY); 144 path.lineTo(maxX, midY); 145 path.lineTo(midX1, maxY); 146 path.lineTo(midX1, maxYS); 147 path.lineTo(midX2, maxYS); 148 path.lineTo(midX2, maxY); 149 path.closePath(); 150 s = path; 151 } 152 } 153 154 if (! bounds.contains(s.getBounds())) { 155 // System.err.println("Edgeclipping"); 156 s = new Area(s); 157 (( Area ) s).intersect(new Area(bounds)); 158 } 159 160 if (fill != null) { 161 g.setPaint(fill); 162 g.fill(s); 163 } 164 165 if ((outline != null) && ((maxD - minD) > 4.0)) { 166 g.setPaint(outline); 167 g.draw(s); 168 } else { 169 // System.err.println("Not drawing outline..."); 170 } 171 } 172 173 public double getDepth(SequenceRenderContext src) { 174 return arrowSize + (2.0 * arrowScoop) + 1.0; 175 } 176 177 public FeatureHolder processMouseEvent(FeatureHolder hits, SequenceRenderContext src, 178 MouseEvent me 179 ) { 180 return hits; 181 } 182}