Save This Page
Home » openjdk-7 » java » awt » geom » [javadoc | source]
    1   /*
    2    * Copyright 1997-1998 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.awt.geom;
   27   
   28   import java.util;
   29   
   30   /**
   31    * The <code>FlatteningPathIterator</code> class returns a flattened view of
   32    * another {@link PathIterator} object.  Other {@link java.awt.Shape Shape}
   33    * classes can use this class to provide flattening behavior for their paths
   34    * without having to perform the interpolation calculations themselves.
   35    *
   36    * @author Jim Graham
   37    */
   38   public class FlatteningPathIterator implements PathIterator {
   39       static final int GROW_SIZE = 24;    // Multiple of cubic & quad curve size
   40   
   41       PathIterator src;                   // The source iterator
   42   
   43       double squareflat;                  // Square of the flatness parameter
   44                                           // for testing against squared lengths
   45   
   46       int limit;                          // Maximum number of recursion levels
   47   
   48       double hold[] = new double[14];     // The cache of interpolated coords
   49                                           // Note that this must be long enough
   50                                           // to store a full cubic segment and
   51                                           // a relative cubic segment to avoid
   52                                           // aliasing when copying the coords
   53                                           // of a curve to the end of the array.
   54                                           // This is also serendipitously equal
   55                                           // to the size of a full quad segment
   56                                           // and 2 relative quad segments.
   57   
   58       double curx, cury;                  // The ending x,y of the last segment
   59   
   60       double movx, movy;                  // The x,y of the last move segment
   61   
   62       int holdType;                       // The type of the curve being held
   63                                           // for interpolation
   64   
   65       int holdEnd;                        // The index of the last curve segment
   66                                           // being held for interpolation
   67   
   68       int holdIndex;                      // The index of the curve segment
   69                                           // that was last interpolated.  This
   70                                           // is the curve segment ready to be
   71                                           // returned in the next call to
   72                                           // currentSegment().
   73   
   74       int levels[];                       // The recursion level at which
   75                                           // each curve being held in storage
   76                                           // was generated.
   77   
   78       int levelIndex;                     // The index of the entry in the
   79                                           // levels array of the curve segment
   80                                           // at the holdIndex
   81   
   82       boolean done;                       // True when iteration is done
   83   
   84       /**
   85        * Constructs a new <code>FlatteningPathIterator</code> object that
   86        * flattens a path as it iterates over it.  The iterator does not
   87        * subdivide any curve read from the source iterator to more than
   88        * 10 levels of subdivision which yields a maximum of 1024 line
   89        * segments per curve.
   90        * @param src the original unflattened path being iterated over
   91        * @param flatness the maximum allowable distance between the
   92        * control points and the flattened curve
   93        */
   94       public FlatteningPathIterator(PathIterator src, double flatness) {
   95           this(src, flatness, 10);
   96       }
   97   
   98       /**
   99        * Constructs a new <code>FlatteningPathIterator</code> object
  100        * that flattens a path as it iterates over it.
  101        * The <code>limit</code> parameter allows you to control the
  102        * maximum number of recursive subdivisions that the iterator
  103        * can make before it assumes that the curve is flat enough
  104        * without measuring against the <code>flatness</code> parameter.
  105        * The flattened iteration therefore never generates more than
  106        * a maximum of <code>(2^limit)</code> line segments per curve.
  107        * @param src the original unflattened path being iterated over
  108        * @param flatness the maximum allowable distance between the
  109        * control points and the flattened curve
  110        * @param limit the maximum number of recursive subdivisions
  111        * allowed for any curved segment
  112        * @exception <code>IllegalArgumentException</code> if
  113        *          <code>flatness</code> or <code>limit</code>
  114        *          is less than zero
  115        */
  116       public FlatteningPathIterator(PathIterator src, double flatness,
  117                                     int limit) {
  118           if (flatness < 0.0) {
  119               throw new IllegalArgumentException("flatness must be >= 0");
  120           }
  121           if (limit < 0) {
  122               throw new IllegalArgumentException("limit must be >= 0");
  123           }
  124           this.src = src;
  125           this.squareflat = flatness * flatness;
  126           this.limit = limit;
  127           this.levels = new int[limit + 1];
  128           // prime the first path segment
  129           next(false);
  130       }
  131   
  132       /**
  133        * Returns the flatness of this iterator.
  134        * @return the flatness of this <code>FlatteningPathIterator</code>.
  135        */
  136       public double getFlatness() {
  137           return Math.sqrt(squareflat);
  138       }
  139   
  140       /**
  141        * Returns the recursion limit of this iterator.
  142        * @return the recursion limit of this
  143        * <code>FlatteningPathIterator</code>.
  144        */
  145       public int getRecursionLimit() {
  146           return limit;
  147       }
  148   
  149       /**
  150        * Returns the winding rule for determining the interior of the
  151        * path.
  152        * @return the winding rule of the original unflattened path being
  153        * iterated over.
  154        * @see PathIterator#WIND_EVEN_ODD
  155        * @see PathIterator#WIND_NON_ZERO
  156        */
  157       public int getWindingRule() {
  158           return src.getWindingRule();
  159       }
  160   
  161       /**
  162        * Tests if the iteration is complete.
  163        * @return <code>true</code> if all the segments have
  164        * been read; <code>false</code> otherwise.
  165        */
  166       public boolean isDone() {
  167           return done;
  168       }
  169   
  170       /*
  171        * Ensures that the hold array can hold up to (want) more values.
  172        * It is currently holding (hold.length - holdIndex) values.
  173        */
  174       void ensureHoldCapacity(int want) {
  175           if (holdIndex - want < 0) {
  176               int have = hold.length - holdIndex;
  177               int newsize = hold.length + GROW_SIZE;
  178               double newhold[] = new double[newsize];
  179               System.arraycopy(hold, holdIndex,
  180                                newhold, holdIndex + GROW_SIZE,
  181                                have);
  182               hold = newhold;
  183               holdIndex += GROW_SIZE;
  184               holdEnd += GROW_SIZE;
  185           }
  186       }
  187   
  188       /**
  189        * Moves the iterator to the next segment of the path forwards
  190        * along the primary direction of traversal as long as there are
  191        * more points in that direction.
  192        */
  193       public void next() {
  194           next(true);
  195       }
  196   
  197       private void next(boolean doNext) {
  198           int level;
  199   
  200           if (holdIndex >= holdEnd) {
  201               if (doNext) {
  202                   src.next();
  203               }
  204               if (src.isDone()) {
  205                   done = true;
  206                   return;
  207               }
  208               holdType = src.currentSegment(hold);
  209               levelIndex = 0;
  210               levels[0] = 0;
  211           }
  212   
  213           switch (holdType) {
  214           case SEG_MOVETO:
  215           case SEG_LINETO:
  216               curx = hold[0];
  217               cury = hold[1];
  218               if (holdType == SEG_MOVETO) {
  219                   movx = curx;
  220                   movy = cury;
  221               }
  222               holdIndex = 0;
  223               holdEnd = 0;
  224               break;
  225           case SEG_CLOSE:
  226               curx = movx;
  227               cury = movy;
  228               holdIndex = 0;
  229               holdEnd = 0;
  230               break;
  231           case SEG_QUADTO:
  232               if (holdIndex >= holdEnd) {
  233                   // Move the coordinates to the end of the array.
  234                   holdIndex = hold.length - 6;
  235                   holdEnd = hold.length - 2;
  236                   hold[holdIndex + 0] = curx;
  237                   hold[holdIndex + 1] = cury;
  238                   hold[holdIndex + 2] = hold[0];
  239                   hold[holdIndex + 3] = hold[1];
  240                   hold[holdIndex + 4] = curx = hold[2];
  241                   hold[holdIndex + 5] = cury = hold[3];
  242               }
  243   
  244               level = levels[levelIndex];
  245               while (level < limit) {
  246                   if (QuadCurve2D.getFlatnessSq(hold, holdIndex) < squareflat) {
  247                       break;
  248                   }
  249   
  250                   ensureHoldCapacity(4);
  251                   QuadCurve2D.subdivide(hold, holdIndex,
  252                                         hold, holdIndex - 4,
  253                                         hold, holdIndex);
  254                   holdIndex -= 4;
  255   
  256                   // Now that we have subdivided, we have constructed
  257                   // two curves of one depth lower than the original
  258                   // curve.  One of those curves is in the place of
  259                   // the former curve and one of them is in the next
  260                   // set of held coordinate slots.  We now set both
  261                   // curves level values to the next higher level.
  262                   level++;
  263                   levels[levelIndex] = level;
  264                   levelIndex++;
  265                   levels[levelIndex] = level;
  266               }
  267   
  268               // This curve segment is flat enough, or it is too deep
  269               // in recursion levels to try to flatten any more.  The
  270               // two coordinates at holdIndex+4 and holdIndex+5 now
  271               // contain the endpoint of the curve which can be the
  272               // endpoint of an approximating line segment.
  273               holdIndex += 4;
  274               levelIndex--;
  275               break;
  276           case SEG_CUBICTO:
  277               if (holdIndex >= holdEnd) {
  278                   // Move the coordinates to the end of the array.
  279                   holdIndex = hold.length - 8;
  280                   holdEnd = hold.length - 2;
  281                   hold[holdIndex + 0] = curx;
  282                   hold[holdIndex + 1] = cury;
  283                   hold[holdIndex + 2] = hold[0];
  284                   hold[holdIndex + 3] = hold[1];
  285                   hold[holdIndex + 4] = hold[2];
  286                   hold[holdIndex + 5] = hold[3];
  287                   hold[holdIndex + 6] = curx = hold[4];
  288                   hold[holdIndex + 7] = cury = hold[5];
  289               }
  290   
  291               level = levels[levelIndex];
  292               while (level < limit) {
  293                   if (CubicCurve2D.getFlatnessSq(hold, holdIndex) < squareflat) {
  294                       break;
  295                   }
  296   
  297                   ensureHoldCapacity(6);
  298                   CubicCurve2D.subdivide(hold, holdIndex,
  299                                          hold, holdIndex - 6,
  300                                          hold, holdIndex);
  301                   holdIndex -= 6;
  302   
  303                   // Now that we have subdivided, we have constructed
  304                   // two curves of one depth lower than the original
  305                   // curve.  One of those curves is in the place of
  306                   // the former curve and one of them is in the next
  307                   // set of held coordinate slots.  We now set both
  308                   // curves level values to the next higher level.
  309                   level++;
  310                   levels[levelIndex] = level;
  311                   levelIndex++;
  312                   levels[levelIndex] = level;
  313               }
  314   
  315               // This curve segment is flat enough, or it is too deep
  316               // in recursion levels to try to flatten any more.  The
  317               // two coordinates at holdIndex+6 and holdIndex+7 now
  318               // contain the endpoint of the curve which can be the
  319               // endpoint of an approximating line segment.
  320               holdIndex += 6;
  321               levelIndex--;
  322               break;
  323           }
  324       }
  325   
  326       /**
  327        * Returns the coordinates and type of the current path segment in
  328        * the iteration.
  329        * The return value is the path segment type:
  330        * SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
  331        * A float array of length 6 must be passed in and can be used to
  332        * store the coordinates of the point(s).
  333        * Each point is stored as a pair of float x,y coordinates.
  334        * SEG_MOVETO and SEG_LINETO types return one point,
  335        * and SEG_CLOSE does not return any points.
  336        * @param coords an array that holds the data returned from
  337        * this method
  338        * @return the path segment type of the current path segment.
  339        * @exception <code>NoSuchElementException</code> if there
  340        *          are no more elements in the flattening path to be
  341        *          returned.
  342        * @see PathIterator#SEG_MOVETO
  343        * @see PathIterator#SEG_LINETO
  344        * @see PathIterator#SEG_CLOSE
  345        */
  346       public int currentSegment(float[] coords) {
  347           if (isDone()) {
  348               throw new NoSuchElementException("flattening iterator out of bounds");
  349           }
  350           int type = holdType;
  351           if (type != SEG_CLOSE) {
  352               coords[0] = (float) hold[holdIndex + 0];
  353               coords[1] = (float) hold[holdIndex + 1];
  354               if (type != SEG_MOVETO) {
  355                   type = SEG_LINETO;
  356               }
  357           }
  358           return type;
  359       }
  360   
  361       /**
  362        * Returns the coordinates and type of the current path segment in
  363        * the iteration.
  364        * The return value is the path segment type:
  365        * SEG_MOVETO, SEG_LINETO, or SEG_CLOSE.
  366        * A double array of length 6 must be passed in and can be used to
  367        * store the coordinates of the point(s).
  368        * Each point is stored as a pair of double x,y coordinates.
  369        * SEG_MOVETO and SEG_LINETO types return one point,
  370        * and SEG_CLOSE does not return any points.
  371        * @param coords an array that holds the data returned from
  372        * this method
  373        * @return the path segment type of the current path segment.
  374        * @exception <code>NoSuchElementException</code> if there
  375        *          are no more elements in the flattening path to be
  376        *          returned.
  377        * @see PathIterator#SEG_MOVETO
  378        * @see PathIterator#SEG_LINETO
  379        * @see PathIterator#SEG_CLOSE
  380        */
  381       public int currentSegment(double[] coords) {
  382           if (isDone()) {
  383               throw new NoSuchElementException("flattening iterator out of bounds");
  384           }
  385           int type = holdType;
  386           if (type != SEG_CLOSE) {
  387               coords[0] = hold[holdIndex + 0];
  388               coords[1] = hold[holdIndex + 1];
  389               if (type != SEG_MOVETO) {
  390                   type = SEG_LINETO;
  391               }
  392           }
  393           return type;
  394       }
  395   }

Save This Page
Home » openjdk-7 » java » awt » geom » [javadoc | source]