001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Denis M. Kishenko
019: * @version $Revision$
020: */package java.awt.geom;
021:
022: import java.util.NoSuchElementException;
023:
024: import org.apache.harmony.awt.internal.nls.Messages;
025:
026: public abstract class Ellipse2D extends RectangularShape {
027:
028: public static class Float extends Ellipse2D {
029:
030: public float x;
031: public float y;
032: public float width;
033: public float height;
034:
035: public Float() {
036: }
037:
038: public Float(float x, float y, float width, float height) {
039: setFrame(x, y, width, height);
040: }
041:
042: @Override
043: public double getX() {
044: return x;
045: }
046:
047: @Override
048: public double getY() {
049: return y;
050: }
051:
052: @Override
053: public double getWidth() {
054: return width;
055: }
056:
057: @Override
058: public double getHeight() {
059: return height;
060: }
061:
062: @Override
063: public boolean isEmpty() {
064: return width <= 0.0 || height <= 0.0;
065: }
066:
067: public void setFrame(float x, float y, float width, float height) {
068: this .x = x;
069: this .y = y;
070: this .width = width;
071: this .height = height;
072: }
073:
074: @Override
075: public void setFrame(double x, double y, double width,
076: double height) {
077: this .x = (float) x;
078: this .y = (float) y;
079: this .width = (float) width;
080: this .height = (float) height;
081: }
082:
083: public Rectangle2D getBounds2D() {
084: return new Rectangle2D.Float(x, y, width, height);
085: }
086: }
087:
088: public static class Double extends Ellipse2D {
089:
090: public double x;
091: public double y;
092: public double width;
093: public double height;
094:
095: public Double() {
096: }
097:
098: public Double(double x, double y, double width, double height) {
099: setFrame(x, y, width, height);
100: }
101:
102: @Override
103: public double getX() {
104: return x;
105: }
106:
107: @Override
108: public double getY() {
109: return y;
110: }
111:
112: @Override
113: public double getWidth() {
114: return width;
115: }
116:
117: @Override
118: public double getHeight() {
119: return height;
120: }
121:
122: @Override
123: public boolean isEmpty() {
124: return width <= 0.0 || height <= 0.0;
125: }
126:
127: @Override
128: public void setFrame(double x, double y, double width,
129: double height) {
130: this .x = x;
131: this .y = y;
132: this .width = width;
133: this .height = height;
134: }
135:
136: public Rectangle2D getBounds2D() {
137: return new Rectangle2D.Double(x, y, width, height);
138: }
139: }
140:
141: /*
142: * Ellipse2D path iterator
143: */
144: class Iterator implements PathIterator {
145:
146: /*
147: * Ellipse is subdivided into four quarters by x and y axis. Each part approximated by
148: * cubic Bezier curve. Arc in first quarter is started in (a, 0) and finished in (0, b) points.
149: * Control points for cubic curve wiil be (a, 0), (a, m), (n, b) and (0, b) where n and m are
150: * calculated based on requirement Bezier curve in point 0.5 should lay on the arc.
151: */
152:
153: /**
154: * The coefficient to calculate control points of Bezier curves
155: */
156: final double u = 2.0 / 3.0 * (Math.sqrt(2.0) - 1.0);
157:
158: /**
159: * The points coordinates calculation table.
160: */
161: final double points[][] = {
162: { 1.0, 0.5 + u, 0.5 + u, 1.0, 0.5, 1.0 },
163: { 0.5 - u, 1.0, 0.0, 0.5 + u, 0.0, 0.5 },
164: { 0.0, 0.5 - u, 0.5 - u, 0.0, 0.5, 0.0 },
165: { 0.5 + u, 0.0, 1.0, 0.5 - u, 1.0, 0.5 } };
166:
167: /**
168: * The x coordinate of left-upper corner of the ellipse bounds
169: */
170: double x;
171:
172: /**
173: * The y coordinate of left-upper corner of the ellipse bounds
174: */
175: double y;
176:
177: /**
178: * The width of the ellipse bounds
179: */
180: double width;
181:
182: /**
183: * The height of the ellipse bounds
184: */
185: double height;
186:
187: /**
188: * The path iterator transformation
189: */
190: AffineTransform t;
191:
192: /**
193: * The current segmenet index
194: */
195: int index;
196:
197: /**
198: * Constructs a new Ellipse2D.Iterator for given ellipse and transformation
199: * @param e - the source Ellipse2D object
200: * @param at - the AffineTransform object to apply rectangle path
201: */
202: Iterator(Ellipse2D e, AffineTransform t) {
203: this .x = e.getX();
204: this .y = e.getY();
205: this .width = e.getWidth();
206: this .height = e.getHeight();
207: this .t = t;
208: if (width < 0.0 || height < 0.0) {
209: index = 6;
210: }
211: }
212:
213: public int getWindingRule() {
214: return WIND_NON_ZERO;
215: }
216:
217: public boolean isDone() {
218: return index > 5;
219: }
220:
221: public void next() {
222: index++;
223: }
224:
225: public int currentSegment(double[] coords) {
226: if (isDone()) {
227: // awt.4B=Iterator out of bounds
228: throw new NoSuchElementException(Messages
229: .getString("awt.4B")); //$NON-NLS-1$
230: }
231: if (index == 5) {
232: return SEG_CLOSE;
233: }
234: int type;
235: int count;
236: if (index == 0) {
237: type = SEG_MOVETO;
238: count = 1;
239: double p[] = points[3];
240: coords[0] = x + p[4] * width;
241: coords[1] = y + p[5] * height;
242: } else {
243: type = SEG_CUBICTO;
244: count = 3;
245: double p[] = points[index - 1];
246: int j = 0;
247: for (int i = 0; i < 3; i++) {
248: coords[j] = x + p[j++] * width;
249: coords[j] = y + p[j++] * height;
250: }
251: }
252: if (t != null) {
253: t.transform(coords, 0, coords, 0, count);
254: }
255: return type;
256: }
257:
258: public int currentSegment(float[] coords) {
259: if (isDone()) {
260: // awt.4B=Iterator out of bounds
261: throw new NoSuchElementException(Messages
262: .getString("awt.4B")); //$NON-NLS-1$
263: }
264: if (index == 5) {
265: return SEG_CLOSE;
266: }
267: int type;
268: int count;
269: if (index == 0) {
270: type = SEG_MOVETO;
271: count = 1;
272: double p[] = points[3];
273: coords[0] = (float) (x + p[4] * width);
274: coords[1] = (float) (y + p[5] * height);
275: } else {
276: type = SEG_CUBICTO;
277: count = 3;
278: int j = 0;
279: double p[] = points[index - 1];
280: for (int i = 0; i < 3; i++) {
281: coords[j] = (float) (x + p[j++] * width);
282: coords[j] = (float) (y + p[j++] * height);
283: }
284: }
285: if (t != null) {
286: t.transform(coords, 0, coords, 0, count);
287: }
288: return type;
289: }
290:
291: }
292:
293: protected Ellipse2D() {
294: }
295:
296: public boolean contains(double px, double py) {
297: if (isEmpty()) {
298: return false;
299: }
300:
301: double a = (px - getX()) / getWidth() - 0.5;
302: double b = (py - getY()) / getHeight() - 0.5;
303:
304: return a * a + b * b < 0.25;
305: }
306:
307: public boolean intersects(double rx, double ry, double rw, double rh) {
308: if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
309: return false;
310: }
311:
312: double cx = getX() + getWidth() / 2.0;
313: double cy = getY() + getHeight() / 2.0;
314:
315: double rx1 = rx;
316: double ry1 = ry;
317: double rx2 = rx + rw;
318: double ry2 = ry + rh;
319:
320: double nx = cx < rx1 ? rx1 : (cx > rx2 ? rx2 : cx);
321: double ny = cy < ry1 ? ry1 : (cy > ry2 ? ry2 : cy);
322:
323: return contains(nx, ny);
324: }
325:
326: public boolean contains(double rx, double ry, double rw, double rh) {
327: if (isEmpty() || rw <= 0.0 || rh <= 0.0) {
328: return false;
329: }
330:
331: double rx1 = rx;
332: double ry1 = ry;
333: double rx2 = rx + rw;
334: double ry2 = ry + rh;
335:
336: return contains(rx1, ry1) && contains(rx2, ry1)
337: && contains(rx2, ry2) && contains(rx1, ry2);
338: }
339:
340: public PathIterator getPathIterator(AffineTransform at) {
341: return new Iterator(this, at);
342: }
343: }
|