home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / awt / BasicStroke.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  13.5 KB  |  480 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)BasicStroke.java    1.27 98/06/24
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.awt;
  16.  
  17. import java.awt.geom.GeneralPath;
  18. import java.awt.geom.PathIterator;
  19. import sun.dc.path.FastPathProducer;
  20. import sun.dc.path.PathConsumer;
  21. import sun.dc.path.PathException;
  22. import sun.dc.pr.PathStroker;
  23. import sun.dc.pr.PathDasher;
  24. import sun.dc.pr.Rasterizer;
  25.  
  26. /**
  27.  * The <code>BasicStroke</code> class defines a basic set of rendering
  28.  * attributes for the outlines of graphics primitives.
  29.  * These attributes describe the shape of the mark made by a pen drawn along 
  30.  * the outline of a {@link Shape} object and the decorations applied at
  31.  * the ends and joins of path segments of the <code>Shape</code> object.
  32.  * These attributes include:
  33.  * <dl compact>
  34.  * <dt><i>width</i>
  35.  * <dd>The pen width, measured perpendicularly to the pen trajectory.
  36.  * <dt><i>end caps</i>
  37.  * <dd>The decoration applied to the ends of unclosed subpaths or dash
  38.  * segments.
  39.  * <dt><i>line joins</i>
  40.  * <dd>The decoration applied where two path segments are joined.
  41.  * <dt><i>dash attributes</i>
  42.  * <dd>The definition of how to make a dash pattern by alternating
  43.  * between opaque and transparent sections.
  44.  * </dl>
  45.  *
  46.  * @version 10 Feb 1997
  47.  * @author Jim Graham
  48.  */
  49. public class BasicStroke implements Stroke {
  50.  
  51.     /**
  52.      * Joins path segments by extending their outside edges until
  53.      * they meet.
  54.      */
  55.     public final static int JOIN_MITER = 0;
  56.  
  57.     /**
  58.      * Joins path segments by rounding off the corner at a radius
  59.      * of half the line width.
  60.      */
  61.     public final static int JOIN_ROUND = 1;
  62.  
  63.     /**
  64.      * Joins path segments by connecting the outer corners of their
  65.      * wide outlines with a straight segment.
  66.      */
  67.     public final static int JOIN_BEVEL = 2;
  68.  
  69.     /**
  70.      * Ends unclosed subpaths and dash segments with no added
  71.      * decoration.
  72.      */
  73.     public final static int CAP_BUTT = 0;
  74.  
  75.     /**
  76.      * Ends unclosed subpaths and dash segments with a round
  77.      * decoration that has a radius equal to half of the width
  78.      * of the pen.
  79.      */
  80.     public final static int CAP_ROUND = 1;
  81.  
  82.     /**
  83.      * Ends unclosed subpaths and dash segments with a square
  84.      * projection that extends beyond the end of the segment
  85.      * to a distance equal to half of the line width.
  86.      */
  87.     public final static int CAP_SQUARE = 2;
  88.  
  89.     float width;
  90.  
  91.     int join;
  92.     int cap;
  93.     float miterlimit;
  94.  
  95.     float dash[];
  96.     float dash_phase;
  97.  
  98.     /**
  99.      * Constructs a new <code>BasicStroke</code> with the specified
  100.      * attributes.
  101.      * @param width the width of the <code>BasicStroke</code>
  102.      * @param cap the decoration of the ends of a <code>BasicStroke</code>
  103.      * @param join the decoration applied where path segments meet
  104.      * @param miterlimit the limit to trim the miter join
  105.      * @param dash the array representing the dashing pattern
  106.      * @param dash_phase the offset to start the dashing pattern
  107.      */
  108.     public BasicStroke(float width, int cap, int join, float miterlimit,
  109.                float dash[], float dash_phase) {
  110.     if (width < 0.0f) {
  111.         throw new IllegalArgumentException("negative width");
  112.     }
  113.     if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) {
  114.         throw new IllegalArgumentException("illegal end cap value");
  115.     }
  116.     if (join == JOIN_MITER) {
  117.         if (miterlimit < 1.0f) {
  118.         throw new IllegalArgumentException("miter limit < 1");
  119.         }
  120.     } else if (join != JOIN_ROUND && join != JOIN_BEVEL) {
  121.         throw new IllegalArgumentException("illegal line join value");
  122.     }
  123.     if (dash != null) {
  124.         if (dash_phase < 0.0f) {
  125.         throw new IllegalArgumentException("negative dash phase");
  126.         }
  127.         boolean allzero = true;
  128.         for (int i = 0; i < dash.length; i++) {
  129.         float d = dash[i];
  130.         if (d > 0.0) {
  131.             allzero = false;
  132.         } else if (d < 0.0) {
  133.             throw new IllegalArgumentException("negative dash length");
  134.         }
  135.         }
  136.         if (allzero) {
  137.         throw new IllegalArgumentException("dash lengths all zero");
  138.         }
  139.     }
  140.     this.width    = width;
  141.     this.cap    = cap;
  142.     this.join    = join;
  143.     this.miterlimit    = miterlimit;
  144.         if (dash != null) {
  145.             this.dash = (float []) dash.clone();
  146.         }
  147.     this.dash_phase    = dash_phase;
  148.     }
  149.  
  150.     /**
  151.      * Constructs a solid <code>BasicStroke</code> with the specified 
  152.      * attributes.
  153.      * @param width the width of the <code>BasicStroke</code>
  154.      * @param cap the decoration of the ends of a <code>BasicStroke</code>
  155.      * @param join the decoration applied where path segments meet
  156.      * @param miterlimit the limit to trim the miter join
  157.      */
  158.     public BasicStroke(float width, int cap, int join, float miterlimit) {
  159.     this(width, cap, join, miterlimit, null, 0.0f);
  160.     }
  161.  
  162.     /**
  163.      * Constructs a solid <code>BasicStroke</code> with the specified 
  164.      * attributes.  The <code>miterlimit</code> parameter is 
  165.      * unnecessary in cases where the default is allowable or the 
  166.      * line joins are not specified as JOIN_MITER.
  167.      * @param width the width of the <code>BasicStroke</code>
  168.      * @param cap the decoration of the ends of a <code>BasicStroke</code>
  169.      * @param join the decoration applied where path segments meet
  170.      */
  171.     public BasicStroke(float width, int cap, int join) {
  172.     this(width, cap, join, 10.0f, null, 0.0f);
  173.     }
  174.  
  175.     /**
  176.      * Constructs a solid <code>BasicStroke</code> with the specified 
  177.      * line width and with default values for the cap and join 
  178.      * styles.
  179.      * @param width the width of the <code>BasicStroke</code>
  180.      */
  181.     public BasicStroke(float width) {
  182.     this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
  183.     }
  184.  
  185.     /**
  186.      * Constructs a new <code>BasicStroke</code> with defaults for all 
  187.      * attributes.
  188.      * The default attributes are a solid line of width 1.0, CAP_SQUARE,
  189.      * JOIN_MITER, a miter limit of 10.0.
  190.      */
  191.     public BasicStroke() {
  192.     this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
  193.     }
  194.  
  195.  
  196.     /**
  197.      * Returns a <code>Shape</code> whose interior defines the 
  198.      * stroked outline of a specified <code>Shape</code>.
  199.      * @param s the <code>Shape</code> boundary be stroked
  200.      * @return the <code>Shape</code> of the stroked outline.
  201.      */
  202.     public Shape createStrokedShape(Shape s) {
  203.     FillAdapter filler = new FillAdapter();
  204.     PathStroker stroker = new PathStroker(filler);
  205.     PathConsumer consumer;
  206.  
  207.     stroker.setPenDiameter(width);
  208.     stroker.setPenT4(null);
  209.     stroker.setCaps(RasterizerCaps[cap]);
  210.     stroker.setCorners(RasterizerCorners[join], miterlimit);
  211.     if (dash != null) {
  212.         PathDasher dasher = new PathDasher(stroker);
  213.         dasher.setDash(dash, dash_phase);
  214.         dasher.setDashT4(null);
  215.         consumer = dasher;
  216.     } else {
  217.         consumer = stroker;
  218.     }
  219.  
  220.     PathIterator pi = s.getPathIterator(null);
  221.  
  222.     try {
  223.         consumer.beginPath();
  224.         boolean pathClosed = false;
  225.         float mx = 0.0f;
  226.         float my = 0.0f;
  227.         float point[]  = new float[6];
  228.  
  229.         while (!pi.isDone()) {
  230.         int type = pi.currentSegment(point);
  231.         if (pathClosed == true) {
  232.             pathClosed = false;
  233.             if (type != PathIterator.SEG_MOVETO) {
  234.             // Force current point back to last moveto point
  235.             consumer.beginSubpath(mx, my);
  236.             }
  237.         }
  238.         switch (type) {
  239.         case PathIterator.SEG_MOVETO:
  240.             mx = point[0];
  241.             my = point[1];
  242.             consumer.beginSubpath(point[0], point[1]);
  243.             break;
  244.         case PathIterator.SEG_LINETO:
  245.             consumer.appendLine(point[0], point[1]);
  246.             break;
  247.         case PathIterator.SEG_QUADTO:
  248.             // Quadratic curves take two points
  249.             consumer.appendQuadratic(point[0], point[1],
  250.                          point[2], point[3]);
  251.             break;
  252.         case PathIterator.SEG_CUBICTO:
  253.             // Cubic curves take three points
  254.             consumer.appendCubic(point[0], point[1],
  255.                      point[2], point[3],
  256.                      point[4], point[5]);
  257.             break;
  258.         case PathIterator.SEG_CLOSE:
  259.             consumer.closedSubpath();
  260.             pathClosed = true;
  261.             break;
  262.         }
  263.         pi.next();
  264.         }
  265.  
  266.         consumer.endPath();
  267.     } catch (PathException e) {
  268.         throw new InternalError("Unable to Stroke shape ("+
  269.                     e.getMessage()+")");
  270.     }
  271.  
  272.     return filler.getShape();
  273.     }
  274.  
  275.     /**
  276.      * Returns the line width.  Line width is represented in user space.
  277.      * @return the line width of this <code>BasicStroke</code>.
  278.      */
  279.     public float getLineWidth() {
  280.     return width;
  281.     }
  282.  
  283.     /**
  284.      * Returns the end cap style.
  285.      * @return the end cap style of this <code>BasicStroke</code> as one
  286.      * of the static <code>int</code> values that define possible end cap
  287.      * styles.
  288.      */
  289.     public int getEndCap() {
  290.     return cap;
  291.     }
  292.  
  293.     /**
  294.      * Returns the line join style.
  295.      * @return the line join style of the <code>BasicStroke</code> as one
  296.      * of the static <code>int</code> values that define possible line
  297.      * join styles.
  298.      */
  299.     public int getLineJoin() {
  300.     return join;
  301.     }
  302.  
  303.     /**
  304.      * Returns the limit of miter joins.
  305.      * @return the limit of miter joins of the <code>BasicStroke</code>.
  306.      */
  307.     public float getMiterLimit() {
  308.     return miterlimit;
  309.     }
  310.  
  311.     /**
  312.      * Returns the array representing the lengths of the dash segments.
  313.      * Alternate entries in the array represent the user space lengths
  314.      * of the opaque and transparent segments of the dashes.
  315.      * As the pen moves along the outline of the <code>Shape</code>
  316.      * to be stroked, the user space
  317.      * distance that the pen travels is accumulated.  The distance
  318.      * value is used to index into the dash array.
  319.      * The pen is opaque when its current cumulative distance maps
  320.      * to an even element of the dash array and transparent otherwise.
  321.      * @return the dash array.
  322.      */
  323.     public float[] getDashArray() {
  324.         if (dash == null) {
  325.             return null;
  326.         }
  327.  
  328.         return (float[]) dash.clone();
  329.     }
  330.  
  331.     /**
  332.      * Returns the current dash phase.
  333.      * The dash phase is a distance specified in user coordinates that 
  334.      * represents an offset into the dashing pattern. In other words, the dash 
  335.      * phase defines the point in the dashing pattern that will correspond to 
  336.      * the beginning of the stroke.
  337.      * @return the dash phase as a <code>float</code> value.
  338.      */
  339.     public float getDashPhase() {
  340.     return dash_phase;
  341.     }
  342.  
  343.     /**
  344.      * Returns the hashcode for this stroke.
  345.      * @return      a hash code for this stroke.
  346.      */
  347.     public int hashCode() {
  348.     int hash = Float.floatToIntBits(width);
  349.     hash = hash * 31 + join;
  350.     hash = hash * 31 + cap;
  351.     hash = hash * 31 + Float.floatToIntBits(miterlimit);
  352.     if (dash != null) {
  353.         hash = hash * 31 + Float.floatToIntBits(dash_phase);
  354.         for (int i = 0; i < dash.length; i++) {
  355.         hash = hash * 31 + Float.floatToIntBits(dash[i]);
  356.         }
  357.     }
  358.     return hash;
  359.     }
  360.  
  361.     /**
  362.      * Returns true if this BasicStroke represents the same
  363.      * stroking operation as the given argument.
  364.      */
  365.    /**
  366.     * Tests if a specified object is equal to this <code>BasicStroke</code>
  367.     * by first testing if it is a <code>BasicStroke</code> and then comparing 
  368.     * its width, join, cap, miter limit, dash, and dash phase attributes with 
  369.     * those of this <code>BasicStroke</code>.
  370.     * @param  obj the specified object to compare to this 
  371.     *              <code>BasicStroke</code>
  372.     * @return <code>true</code> if the width, join, cap, miter limit, dash, and
  373.     *            dash phase are the same for both objects;
  374.     *            <code>false</code> otherwise.
  375.     */
  376.     public boolean equals(Object obj) {
  377.         if (!(obj instanceof BasicStroke)) {
  378.             return false;
  379.         }
  380.  
  381.         BasicStroke bs = (BasicStroke) obj;
  382.         if (width != bs.width) {
  383.             return false;
  384.         }
  385.  
  386.         if (join != bs.join) {
  387.             return false;
  388.         }
  389.  
  390.         if (cap != bs.cap) {
  391.             return false;
  392.         }
  393.  
  394.         if (miterlimit != bs.miterlimit) {
  395.             return false;
  396.         }
  397.  
  398.         if (dash != null) {
  399.         if (dash_phase != bs.dash_phase) {
  400.         return false;
  401.         }
  402.  
  403.         if (!java.util.Arrays.equals(dash, bs.dash)) {
  404.         return false;
  405.         }
  406.         }
  407.         else if (bs.dash != null) {
  408.             return false;
  409.         }
  410.  
  411.         return true;
  412.     }
  413.  
  414.     private static final int RasterizerCaps[] = {
  415.     Rasterizer.BUTT, Rasterizer.ROUND, Rasterizer.SQUARE
  416.     };
  417.  
  418.     private static final int RasterizerCorners[] = {
  419.     Rasterizer.MITER, Rasterizer.ROUND, Rasterizer.BEVEL
  420.     };
  421.  
  422.     private class FillAdapter implements PathConsumer {
  423.     boolean closed;
  424.     GeneralPath path;
  425.  
  426.     public FillAdapter() {
  427.         path = new GeneralPath(GeneralPath.WIND_NON_ZERO);
  428.     }
  429.  
  430.     public Shape getShape() {
  431.         return path;
  432.     }
  433.  
  434.     public void beginPath() {}
  435.  
  436.     public void beginSubpath(float x0, float y0) {
  437.         if (closed) {
  438.         path.closePath();
  439.         closed = false;
  440.         }
  441.         path.moveTo(x0, y0);
  442.     }
  443.  
  444.     public void appendLine(float x1, float y1) {
  445.         path.lineTo(x1, y1);
  446.     }
  447.  
  448.     public void appendQuadratic(float xm, float ym, float x1, float y1) {
  449.         path.quadTo(xm, ym, x1, y1);
  450.     }
  451.  
  452.     public void appendCubic(float xm, float ym,
  453.                 float xn, float yn,
  454.                 float x1, float y1) {
  455.         path.curveTo(xm, ym, xn, yn, x1, y1);
  456.     }
  457.  
  458.     public void closedSubpath() {
  459.         closed = true;
  460.     }
  461.  
  462.     public void endPath() {
  463.         if (closed) {
  464.         path.closePath();
  465.         closed = false;
  466.         }
  467.     }
  468.  
  469.     public void useProxy(FastPathProducer proxy)
  470.         throws PathException
  471.     {
  472.         proxy.sendTo(this);
  473.     }
  474.  
  475.     public long getCPathConsumer() {
  476.         return 0;
  477.     }
  478.     }
  479. }
  480.