Source for gnu.java.awt.java2d.CubicSegment

   1: /* CubicSegment.java -- Cubic segment used for BasicStroke
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.java.awt.java2d;
  40: 
  41: 
  42: import java.awt.geom.CubicCurve2D;
  43: import java.awt.geom.Point2D;
  44: 
  45: /**
  46:  * Cubic Bezier curve segment
  47:  */
  48: public class CubicSegment extends Segment
  49: {
  50:   public Point2D cp1; // control points
  51:   public Point2D cp2; // control points
  52: 
  53:   /**
  54:    * Constructor - takes coordinates of the starting point,
  55:    * first control point, second control point and end point,
  56:    * respecively.
  57:    */
  58:   public CubicSegment(double x1, double y1, double c1x, double c1y,
  59:                       double c2x, double c2y, double x2, double y2)
  60:   {
  61:     super();
  62:     P1 = new Point2D.Double(x1, y1);
  63:     P2 = new Point2D.Double(x2, y2);
  64:     cp1 = new Point2D.Double(c1x, c1y);
  65:     cp2 = new Point2D.Double(c2x, c2y);
  66:   }
  67: 
  68:   public CubicSegment(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2)
  69:   {
  70:     super();
  71:     P1 = p1;
  72:     P2 = p2;
  73:     this.cp1 = cp1;
  74:     this.cp2 = cp2;
  75:   }
  76: 
  77:   /**
  78:    * Clones this segment
  79:    */
  80:   public Object clone()
  81:   {
  82:     CubicSegment segment = null;
  83: 
  84:     try
  85:       {
  86:         segment = (CubicSegment) super.clone();
  87: 
  88:         segment.P1 = (Point2D) P1.clone();
  89:         segment.P2 = (Point2D) P2.clone();
  90:         segment.cp1 = (Point2D) cp1.clone();
  91:         segment.cp2 = (Point2D) cp2.clone();
  92:       }
  93:     catch (CloneNotSupportedException cnse)
  94:       {
  95:         InternalError ie = new InternalError();
  96:         ie.initCause(cnse);
  97:         throw ie;
  98:       }
  99: 
 100:     return segment;
 101:   }
 102: 
 103:   /**
 104:    * Get the "top" and "bottom" segments of this segment. First array element is
 105:    * p0 + normal, second is p0 - normal.
 106:    */
 107:   public Segment[] getDisplacedSegments(double radius)
 108:   {
 109:     // It is, apparently, impossible to derive a curve parallel to a bezier
 110:     // curve (unless it's a straight line), so we have no choice but to
 111:     // approximate the displaced segments. Similar to FlattenPathIterator.
 112: 
 113:     Segment segmentTop = null;
 114:     Segment segmentBottom = null;
 115:     this.radius = radius;
 116: 
 117:     CubicCurve2D[] curves = new CubicCurve2D[10];
 118:     curves[0] = new CubicCurve2D.Double(P1.getX(), P1.getY(), cp1.getX(),
 119:                                         cp1.getY(), cp2.getX(), cp2.getY(),
 120:                                         P2.getX(), P2.getY());
 121:     int numCurves = 1;
 122: 
 123:     // Hard-coded a recursion limit of 10 and flatness of 1... should we make
 124:     // this an option somewhere?
 125:     while (numCurves > 0)
 126:       {
 127:         // The curve is flat enough, or we've reached our recursion limit,
 128:         // so take the current start/end points and add it as a line segment
 129:         // to our final approximated curves
 130:         if (curves[numCurves - 1].getFlatnessSq() <= (radius / 3) || numCurves == 10)
 131:           {
 132:             Segment[] displaced = new LineSegment(
 133:                                                   curves[numCurves - 1].getP1(),
 134:                                                   curves[numCurves - 1].getP2()).getDisplacedSegments(radius);
 135:             if (segmentTop == null)
 136:               {
 137:                 segmentTop = displaced[0];
 138:                 segmentBottom = displaced[1];
 139:               }
 140:             else
 141:               {
 142:                 segmentTop.add(displaced[0]);
 143:                 segmentBottom.add(displaced[1]);
 144:               }
 145:             numCurves--;
 146:           }
 147: 
 148:         // Otherwise, subdivide again and continue
 149:         else
 150:           {
 151:             CubicCurve2D left = new CubicCurve2D.Double();
 152:             CubicCurve2D right = new CubicCurve2D.Double();
 153:             curves[numCurves - 1].subdivide(left, right);
 154:             curves[numCurves - 1] = right;
 155:             curves[numCurves] = left;
 156:             curves[numCurves - 1] = right;
 157:             curves[numCurves] = left;
 158:             numCurves++;
 159:           }
 160:       }
 161: 
 162:     return new Segment[] { segmentTop, segmentBottom };
 163:   }
 164: 
 165:   public void reverse()
 166:   {
 167:     Point2D temp = P1;
 168:     P1 = P2;
 169:     P2 = temp;
 170:     temp = cp1;
 171:     cp1 = cp2;
 172:     cp2 = temp;
 173:   }
 174: 
 175:   public double[] cp1()
 176:   {
 177:     return new double[]{cp1.getX(), cp1.getY()};
 178:   }
 179: 
 180:   public double[] cp2()
 181:   {
 182:     return new double[]{cp2.getX(), cp2.getY()};
 183:   }
 184: } // class CubicSegment