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.Font;
024import java.awt.geom.Point2D;
025
026import org.biojava.bio.seq.FeatureHolder;
027import org.biojava.bio.seq.Sequence;
028import org.biojava.bio.symbol.RangeLocation;
029import org.biojava.bio.symbol.SymbolList;
030
031/**
032 * <p>
033 * A stand-alone SequenceRenderContext to make it easy to render to an image.
034 * </p>
035 *
036 * <p>
037 * This class makes it very easy to render sequence information into an
038 * arbitrary graphics object without the need to fuss about with AWT or
039 * Swing components. You chose the width of the image and the region of the
040 * sequence to render. It will calculate the scale factor to ensure that the
041 * whole region of the sequence fits into that width. You can then use the
042 * context to render any number of SequenceRenderer instances to any Graphics2D
043 * instance you want, for example, to an image that's to be written out by a
044 * servlet.
045 * </p>
046 *
047 * <h2>Example</h2>
048 *
049 * <pre>
050 * HeadlessRenderContext ctxt = new HeadlessRenderContext(
051 *   seq,   // the sequence to render
052 *   range, // a RangeLocation giving the block you want to render
053 *   width  // an int specifying the image width in pixles
054 * );
055 *
056 * BufferedImage img = new BufferedImage(
057 *   width,                                   // image width
058 *   (int) Math.ceil(seqRend.getDepth(ctxt),  // calculated height
059 *   BufferedImage.TYPE_INT_RGB               // let's use RGB
060 * );
061 *
062 * // set stuff up
063 * Graphics2D graph = img.createGraphics();
064 * graph.setPaint(Color.WHITE);
065 * graph.fillRect(0, 0, img.getWidth(), img.getHeight());
066 *
067 * // and now render the sequences
068 * sequenceRenderer.paint(graph, ctxt);
069 *
070 * // let's dump this out as a png
071 * ImageIO.write(image, "png", myFile);
072 * </pre>
073 *
074 * @since 1.3
075 * @author Matthew Pocock
076 */
077
078public class HeadlessRenderContext
079implements SequenceRenderContext {
080  private static final Font FONT = new Font(null, Font.PLAIN, 10);
081
082  private final RangeLocation range;
083  private final double scale;
084  private final Sequence seq;
085  private final double offset;
086
087  public HeadlessRenderContext(Sequence seq, RangeLocation range, int width) {
088    this.seq = seq;
089    this.range = range;
090    this.scale = (double) width /
091    (double) (range.getMax() - range.getMin() + 1);
092    offset = -( (double) range.getMin() * scale);
093  }
094
095  public int getDirection() {
096    return HORIZONTAL;
097  }
098
099  public FeatureHolder getFeatures() {
100    return seq;
101  }
102
103  public Font getFont() {
104    return FONT;
105  }
106
107  public SequenceRenderContext.Border getLeadingBorder() {
108    return new SequenceRenderContext.Border();
109  }
110
111  public RangeLocation getRange() {
112    return range;
113  }
114
115  public double getScale() {
116    return scale;
117  }
118
119  public SymbolList getSymbols() {
120    return seq;
121  }
122
123  public SequenceRenderContext.Border getTrailingBorder() {
124    return new SequenceRenderContext.Border();
125  }
126
127  public double sequenceToGraphics(int i) {
128    return ((double) (i - 1)) * scale + offset;
129  }
130
131  public int graphicsToSequence(Point2D point) {
132    return graphicsToSequence(point.getX());
133  }
134
135  public int graphicsToSequence(double d) {
136    return ((int) ((d - offset) / scale)) + 1;
137  }
138}