home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / BasicStroke.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  11.5 KB  |  437 lines

  1. /*
  2.  * @(#)BasicStroke.java    1.18 98/03/18
  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.  * Defines a basic set of rendering attributes for stroked graphics
  28.  * primitives.
  29.  * These attributes describe the shape of a pen drawn along the
  30.  * trajectory of the path and the decorations applied where path
  31.  * segments are joined and where they begin and end.
  32.  * These attributes include:
  33.  * <dl compact>
  34.  * <dt><i>width</i>
  35.  * <dd>The width of the pen measured perpendicular to its trajectory.
  36.  * <dt><i>end caps</i>
  37.  * <dd>The decoration of the path where line segments begin and end.
  38.  * <dt><i>line joins</i>
  39.  * <dd>The decoration of the path between connected line segments.
  40.  * <dt><i>dash attributes</i>
  41.  * <dd>The definition of how to make a dash pattern along the
  42.  * trajectory of the path by creating new segments which alternate
  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.      * Join line segments by extending their outside edges until
  53.      * they meet.
  54.      */
  55.     public final static int JOIN_MITER = 0;
  56.  
  57.     /**
  58.      * Join line 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.      * Join line 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.      * End unclosed subpaths and dash segments with no added
  71.      * decoration.
  72.      */
  73.     public final static int CAP_BUTT = 0;
  74.  
  75.     /**
  76.      * End unclosed subpaths and dash segments with a round
  77.      * decoration with radius equal to half of the line width.
  78.      */
  79.     public final static int CAP_ROUND = 1;
  80.  
  81.     /**
  82.      * End unclosed subpaths and dash segments with a square
  83.      * projection that extends beyond the end of the segment
  84.      * to a distance equal to half of the line width.
  85.      */
  86.     public final static int CAP_SQUARE = 2;
  87.  
  88.     float width;
  89.  
  90.     int join;
  91.     int cap;
  92.     float miterlimit;
  93.  
  94.     float dash[];
  95.     float dash_phase;
  96.  
  97.     /**
  98.      * Construct a new stroke with the specified attributes.
  99.      * @param width The width of the stroke.
  100.      * @param cap The style of the ends of a stroke.
  101.      * @param join The style to join strokes together.
  102.      * @param miterlimit The limit to trim the miter join.
  103.      * @param dash The array representing the dashing pattern.
  104.      * @param dash_phase The offset to start the dashing pattern.
  105.      */
  106.     public BasicStroke(float width, int cap, int join, float miterlimit,
  107.                float dash[], float dash_phase) {
  108.     if (width < 0.0f) {
  109.         throw new IllegalArgumentException("negative width");
  110.     }
  111.     if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) {
  112.         throw new IllegalArgumentException("illegal end cap value");
  113.     }
  114.     if (join == JOIN_MITER) {
  115.         if (miterlimit < 0.0f) {
  116.         throw new IllegalArgumentException("negative miter limit");
  117.         }
  118.     } else if (join != JOIN_ROUND && join != JOIN_BEVEL) {
  119.         throw new IllegalArgumentException("illegal line join value");
  120.     }
  121.     if (dash != null) {
  122.         if (dash_phase < 0.0f) {
  123.         throw new IllegalArgumentException("negative dash phase");
  124.         }
  125.         boolean allzero = true;
  126.         for (int i = 0; i < dash.length; i++) {
  127.         float d = dash[i];
  128.         if (d > 0.0) {
  129.             allzero = false;
  130.         } else if (d < 0.0) {
  131.             throw new IllegalArgumentException("negative dash length");
  132.         }
  133.         }
  134.         if (allzero) {
  135.         throw new IllegalArgumentException("dash lengths all zero");
  136.         }
  137.     }
  138.     this.width    = width;
  139.     this.cap    = cap;
  140.     this.join    = join;
  141.     this.miterlimit    = miterlimit;
  142.     this.dash    = dash;
  143.     this.dash_phase    = dash_phase;
  144.     }
  145.  
  146.     /**
  147.      * Construct a new stroke with the specified attributes, but
  148.      * no dashing.
  149.      * @param width The width of the stroke.
  150.      * @param cap The style of the ends of a stroke.
  151.      * @param join The style to join strokes together.
  152.      * @param miterlimit The limit to trim the miter join.
  153.      */
  154.     public BasicStroke(float width, int cap, int join, float miterlimit) {
  155.     this(width, cap, join, miterlimit, null, 0.0f);
  156.     }
  157.  
  158.     /**
  159.      * Construct a new stroke with the specified attributes, but
  160.      * no dashing.  The miter limit parameter is unnecessary in
  161.      * cases where the default is allowable or the line joins
  162.      * are not specified as JOIN_MITER.
  163.      * @param width The width of the stroke.
  164.      * @param cap The style of the ends of a stroke.
  165.      * @param join The style to join strokes together.
  166.      */
  167.     public BasicStroke(float width, int cap, int join) {
  168.     this(width, cap, join, 10.0f, null, 0.0f);
  169.     }
  170.  
  171.     /**
  172.      * Construct a new stroke with the specified line width, and
  173.      * with default values for the cap and join styles and no dashing.
  174.      * @param width The width of the stroke.
  175.      */
  176.     public BasicStroke(float width) {
  177.     this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
  178.     }
  179.  
  180.     /**
  181.      * Construct a new stroke with defaults for all attributes.
  182.      * The default attributes are a line width of 1.0, CAP_SQUARE,
  183.      * JOIN_MITER, a miter limit of 10.0, and no dashing.
  184.      */
  185.     public BasicStroke() {
  186.     this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f);
  187.     }
  188.  
  189.  
  190.     /**
  191.      * Returns a shape whose interior defines the stroked outline of
  192.      * a given shape.
  193.      * @param s The shape whose boundary should be stroked.
  194.      * @return The shape of the stroked outline.
  195.      * @see Stroke#createStrokedShape
  196.      */
  197.     public Shape createStrokedShape(Shape s) {
  198.     FillAdapter filler = new FillAdapter();
  199.     PathStroker stroker = new PathStroker(filler);
  200.     PathConsumer consumer;
  201.  
  202.     stroker.setPenDiameter(width);
  203.     stroker.setPenT4(null);
  204.     stroker.setCaps(RasterizerCaps[cap]);
  205.     stroker.setCorners(RasterizerCorners[join], miterlimit);
  206.     if (dash != null) {
  207.         PathDasher dasher = new PathDasher(stroker);
  208.         dasher.setDash(dash, dash_phase);
  209.         dasher.setDashT4(null);
  210.         consumer = dasher;
  211.     } else {
  212.         consumer = stroker;
  213.     }
  214.  
  215.     PathIterator pi = s.getPathIterator(null);
  216.  
  217.     try {
  218.         consumer.beginPath();
  219.         boolean pathClosed = false;
  220.         float mx = 0.0f;
  221.         float my = 0.0f;
  222.         float point[]  = new float[6];
  223.  
  224.         while (!pi.isDone()) {
  225.         int type = pi.currentSegment(point);
  226.         if (pathClosed == true) {
  227.             pathClosed = false;
  228.             if (type != PathIterator.SEG_MOVETO) {
  229.             // Force current point back to last moveto point
  230.             consumer.beginSubpath(mx, my);
  231.             }
  232.         }
  233.         switch (type) {
  234.         case PathIterator.SEG_MOVETO:
  235.             mx = point[0];
  236.             my = point[1];
  237.             consumer.beginSubpath(point[0], point[1]);
  238.             break;
  239.         case PathIterator.SEG_LINETO:
  240.             consumer.appendLine(point[0], point[1]);
  241.             break;
  242.         case PathIterator.SEG_QUADTO:
  243.             // Quadratic curves take two points
  244.             consumer.appendQuadratic(point[0], point[1],
  245.                          point[2], point[3]);
  246.             break;
  247.         case PathIterator.SEG_CUBICTO:
  248.             // Cubic curves take three points
  249.             consumer.appendCubic(point[0], point[1],
  250.                      point[2], point[3],
  251.                      point[4], point[5]);
  252.             break;
  253.         case PathIterator.SEG_CLOSE:
  254.             consumer.closedSubpath();
  255.             pathClosed = true;
  256.             break;
  257.         }
  258.         pi.next();
  259.         }
  260.  
  261.         consumer.endPath();
  262.     } catch (PathException e) {
  263.         throw new InternalError("Unable to Stroke shape ("+
  264.                     e.getMessage()+")");
  265.     }
  266.  
  267.     return filler.getShape();
  268.     }
  269.  
  270.     /**
  271.      * Returns the line width.  Line width is represented in user space.
  272.      * @return The line width of the stroke.
  273.      */
  274.     public float getLineWidth() {
  275.     return width;
  276.     }
  277.  
  278.     /**
  279.      * Returns the end cap style.
  280.      * @return The end cap style of the stroke.
  281.      */
  282.     public int getEndCap() {
  283.     return cap;
  284.     }
  285.  
  286.     /**
  287.      * Returns the line join style.
  288.      * @return The line join style of the stroke.
  289.      */
  290.     public int getLineJoin() {
  291.     return join;
  292.     }
  293.  
  294.     /**
  295.      * Returns the limit of miter joins.
  296.      * @return The limit of miter joins.
  297.      */
  298.     public float getMiterLimit() {
  299.     return miterlimit;
  300.     }
  301.  
  302.     /**
  303.      * Return the array representing the lengths of the dash segments.
  304.      * Alternate entries in the array represent the user space lengths
  305.      * of the opaque and transparent segments of the dashes.
  306.      * As the pen moves along the path to be stroked, the user space
  307.      * distance that the pen travels will be accumulated to index
  308.      * into the dash array.
  309.      * The pen will be opaque when its current cumulative distance maps
  310.      * to an odd element of the dash array and transparent otherwise.
  311.      * @return The dash array.
  312.      */
  313.     public float[] getDashArray() {
  314.     if (dash == null) {
  315.         return null;
  316.     }
  317.     float ret[] = new float[dash.length];
  318.     System.arraycopy(dash, 0, ret, 0, dash.length);
  319.     return ret;
  320.     }
  321.  
  322.     /**
  323.      * Returns the dash phase.
  324.      * The dash phase is a user space distance that is used to initialize
  325.      * the path distance accumulation variable before the first segment
  326.      * of the first subpath is stroked.
  327.      * @return the dash phase.
  328.      */
  329.     public float getDashPhase() {
  330.     return dash_phase;
  331.     }
  332.  
  333.     public boolean equals(Object obj) {
  334.         if (!(obj instanceof BasicStroke)) {
  335.             return false;
  336.         }
  337.  
  338.         BasicStroke bs = (BasicStroke) obj;
  339.         if (width != bs.width) {
  340.             return false;
  341.         }
  342.  
  343.         if (join != bs.join) {
  344.             return false;
  345.         }
  346.  
  347.         if (cap != bs.cap) {
  348.             return false;
  349.         }
  350.  
  351.         if (miterlimit != bs.miterlimit) {
  352.             return false;
  353.         }
  354.  
  355.         if (dash != null) {
  356.             if (!dash.equals(bs.dash)) {
  357.                 return false;
  358.             }
  359.         }
  360.         else if (bs.dash != null) {
  361.             return false;
  362.         }
  363.  
  364.         if (dash_phase != bs.dash_phase) {
  365.             return false;
  366.         }
  367.  
  368.         return true;
  369.     }
  370.  
  371.     private static final int RasterizerCaps[] = {
  372.     Rasterizer.BUTT, Rasterizer.ROUND, Rasterizer.SQUARE
  373.     };
  374.  
  375.     private static final int RasterizerCorners[] = {
  376.     Rasterizer.MITER, Rasterizer.ROUND, Rasterizer.BEVEL
  377.     };
  378.  
  379.     private class FillAdapter implements PathConsumer {
  380.     boolean closed;
  381.     GeneralPath path;
  382.  
  383.     public FillAdapter() {
  384.         path = new GeneralPath(GeneralPath.NON_ZERO);
  385.     }
  386.  
  387.     public Shape getShape() {
  388.         return path;
  389.     }
  390.  
  391.     public void beginPath() {}
  392.  
  393.     public void beginSubpath(float x0, float y0) {
  394.         if (closed) {
  395.         path.closePath();
  396.         closed = false;
  397.         }
  398.         path.moveTo(x0, y0);
  399.     }
  400.  
  401.     public void appendLine(float x1, float y1) {
  402.         path.lineTo(x1, y1);
  403.     }
  404.  
  405.     public void appendQuadratic(float xm, float ym, float x1, float y1) {
  406.         path.quadTo(xm, ym, x1, y1);
  407.     }
  408.  
  409.     public void appendCubic(float xm, float ym,
  410.                 float xn, float yn,
  411.                 float x1, float y1) {
  412.         path.curveTo(xm, ym, xn, yn, x1, y1);
  413.     }
  414.  
  415.     public void closedSubpath() {
  416.         closed = true;
  417.     }
  418.  
  419.     public void endPath() {
  420.         if (closed) {
  421.         path.closePath();
  422.         closed = false;
  423.         }
  424.     }
  425.  
  426.     public void useProxy(FastPathProducer proxy)
  427.         throws PathException
  428.     {
  429.         proxy.sendTo(this);
  430.     }
  431.  
  432.     public long getCPathConsumer() {
  433.         return 0;
  434.     }
  435.     }
  436. }
  437.