001 /*
002 * Copyright 1997 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.awt.geom;
027
028 import java.util.*;
029
030 /**
031 * A utility class to iterate over the path segments of an rounded rectangle
032 * through the PathIterator interface.
033 *
034 * @version 10 Feb 1997
035 * @author Jim Graham
036 */
037 class RoundRectIterator implements PathIterator {
038 double x, y, w, h, aw, ah;
039 AffineTransform affine;
040 int index;
041
042 RoundRectIterator(RoundRectangle2D rr, AffineTransform at) {
043 this .x = rr.getX();
044 this .y = rr.getY();
045 this .w = rr.getWidth();
046 this .h = rr.getHeight();
047 this .aw = Math.min(w, Math.abs(rr.getArcWidth()));
048 this .ah = Math.min(h, Math.abs(rr.getArcHeight()));
049 this .affine = at;
050 if (aw < 0 || ah < 0) {
051 // Don't draw anything...
052 index = ctrlpts.length;
053 }
054 }
055
056 /**
057 * Return the winding rule for determining the insideness of the
058 * path.
059 * @see #WIND_EVEN_ODD
060 * @see #WIND_NON_ZERO
061 */
062 public int getWindingRule() {
063 return WIND_NON_ZERO;
064 }
065
066 /**
067 * Tests if there are more points to read.
068 * @return true if there are more points to read
069 */
070 public boolean isDone() {
071 return index >= ctrlpts.length;
072 }
073
074 /**
075 * Moves the iterator to the next segment of the path forwards
076 * along the primary direction of traversal as long as there are
077 * more points in that direction.
078 */
079 public void next() {
080 index++;
081 }
082
083 private static final double angle = Math.PI / 4.0;
084 private static final double a = 1.0 - Math.cos(angle);
085 private static final double b = Math.tan(angle);
086 private static final double c = Math.sqrt(1.0 + b * b) - 1 + a;
087 private static final double cv = 4.0 / 3.0 * a * b / c;
088 private static final double acv = (1.0 - cv) / 2.0;
089
090 // For each array:
091 // 4 values for each point {v0, v1, v2, v3}:
092 // point = (x + v0 * w + v1 * arcWidth,
093 // y + v2 * h + v3 * arcHeight);
094 private static double ctrlpts[][] = {
095 { 0.0, 0.0, 0.0, 0.5 },
096 { 0.0, 0.0, 1.0, -0.5 },
097 { 0.0, 0.0, 1.0, -acv, 0.0, acv, 1.0, 0.0, 0.0, 0.5, 1.0,
098 0.0 },
099 { 1.0, -0.5, 1.0, 0.0 },
100 { 1.0, -acv, 1.0, 0.0, 1.0, 0.0, 1.0, -acv, 1.0, 0.0, 1.0,
101 -0.5 },
102 { 1.0, 0.0, 0.0, 0.5 },
103 { 1.0, 0.0, 0.0, acv, 1.0, -acv, 0.0, 0.0, 1.0, -0.5, 0.0,
104 0.0 },
105 { 0.0, 0.5, 0.0, 0.0 },
106 { 0.0, acv, 0.0, 0.0, 0.0, 0.0, 0.0, acv, 0.0, 0.0, 0.0,
107 0.5 }, {}, };
108 private static int types[] = { SEG_MOVETO, SEG_LINETO, SEG_CUBICTO,
109 SEG_LINETO, SEG_CUBICTO, SEG_LINETO, SEG_CUBICTO,
110 SEG_LINETO, SEG_CUBICTO, SEG_CLOSE, };
111
112 /**
113 * Returns the coordinates and type of the current path segment in
114 * the iteration.
115 * The return value is the path segment type:
116 * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
117 * A float array of length 6 must be passed in and may be used to
118 * store the coordinates of the point(s).
119 * Each point is stored as a pair of float x,y coordinates.
120 * SEG_MOVETO and SEG_LINETO types will return one point,
121 * SEG_QUADTO will return two points,
122 * SEG_CUBICTO will return 3 points
123 * and SEG_CLOSE will not return any points.
124 * @see #SEG_MOVETO
125 * @see #SEG_LINETO
126 * @see #SEG_QUADTO
127 * @see #SEG_CUBICTO
128 * @see #SEG_CLOSE
129 */
130 public int currentSegment(float[] coords) {
131 if (isDone()) {
132 throw new NoSuchElementException(
133 "roundrect iterator out of bounds");
134 }
135 double ctrls[] = ctrlpts[index];
136 int nc = 0;
137 for (int i = 0; i < ctrls.length; i += 4) {
138 coords[nc++] = (float) (x + ctrls[i + 0] * w + ctrls[i + 1]
139 * aw);
140 coords[nc++] = (float) (y + ctrls[i + 2] * h + ctrls[i + 3]
141 * ah);
142 }
143 if (affine != null) {
144 affine.transform(coords, 0, coords, 0, nc / 2);
145 }
146 return types[index];
147 }
148
149 /**
150 * Returns the coordinates and type of the current path segment in
151 * the iteration.
152 * The return value is the path segment type:
153 * SEG_MOVETO, SEG_LINETO, SEG_QUADTO, SEG_CUBICTO, or SEG_CLOSE.
154 * A double array of length 6 must be passed in and may be used to
155 * store the coordinates of the point(s).
156 * Each point is stored as a pair of double x,y coordinates.
157 * SEG_MOVETO and SEG_LINETO types will return one point,
158 * SEG_QUADTO will return two points,
159 * SEG_CUBICTO will return 3 points
160 * and SEG_CLOSE will not return any points.
161 * @see #SEG_MOVETO
162 * @see #SEG_LINETO
163 * @see #SEG_QUADTO
164 * @see #SEG_CUBICTO
165 * @see #SEG_CLOSE
166 */
167 public int currentSegment(double[] coords) {
168 if (isDone()) {
169 throw new NoSuchElementException(
170 "roundrect iterator out of bounds");
171 }
172 double ctrls[] = ctrlpts[index];
173 int nc = 0;
174 for (int i = 0; i < ctrls.length; i += 4) {
175 coords[nc++] = (x + ctrls[i + 0] * w + ctrls[i + 1] * aw);
176 coords[nc++] = (y + ctrls[i + 2] * h + ctrls[i + 3] * ah);
177 }
178 if (affine != null) {
179 affine.transform(coords, 0, coords, 0, nc / 2);
180 }
181 return types[index];
182 }
183 }
|