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.awt.Rectangle;
023: import java.awt.Shape;
024: import java.util.NoSuchElementException;
025:
026: import org.apache.harmony.awt.gl.Crossing;
027: import org.apache.harmony.awt.internal.nls.Messages;
028:
029: public abstract class QuadCurve2D implements Shape, Cloneable {
030:
031: public static class Float extends QuadCurve2D {
032:
033: public float x1;
034: public float y1;
035: public float ctrlx;
036: public float ctrly;
037: public float x2;
038: public float y2;
039:
040: public Float() {
041: }
042:
043: public Float(float x1, float y1, float ctrlx, float ctrly,
044: float x2, float y2) {
045: setCurve(x1, y1, ctrlx, ctrly, x2, y2);
046: }
047:
048: @Override
049: public double getX1() {
050: return x1;
051: }
052:
053: @Override
054: public double getY1() {
055: return y1;
056: }
057:
058: @Override
059: public double getCtrlX() {
060: return ctrlx;
061: }
062:
063: @Override
064: public double getCtrlY() {
065: return ctrly;
066: }
067:
068: @Override
069: public double getX2() {
070: return x2;
071: }
072:
073: @Override
074: public double getY2() {
075: return y2;
076: }
077:
078: @Override
079: public Point2D getP1() {
080: return new Point2D.Float(x1, y1);
081: }
082:
083: @Override
084: public Point2D getCtrlPt() {
085: return new Point2D.Float(ctrlx, ctrly);
086: }
087:
088: @Override
089: public Point2D getP2() {
090: return new Point2D.Float(x2, y2);
091: }
092:
093: @Override
094: public void setCurve(double x1, double y1, double ctrlx,
095: double ctrly, double x2, double y2) {
096: this .x1 = (float) x1;
097: this .y1 = (float) y1;
098: this .ctrlx = (float) ctrlx;
099: this .ctrly = (float) ctrly;
100: this .x2 = (float) x2;
101: this .y2 = (float) y2;
102: }
103:
104: public void setCurve(float x1, float y1, float ctrlx,
105: float ctrly, float x2, float y2) {
106: this .x1 = x1;
107: this .y1 = y1;
108: this .ctrlx = ctrlx;
109: this .ctrly = ctrly;
110: this .x2 = x2;
111: this .y2 = y2;
112: }
113:
114: public Rectangle2D getBounds2D() {
115: float rx0 = Math.min(Math.min(x1, x2), ctrlx);
116: float ry0 = Math.min(Math.min(y1, y2), ctrly);
117: float rx1 = Math.max(Math.max(x1, x2), ctrlx);
118: float ry1 = Math.max(Math.max(y1, y2), ctrly);
119: return new Rectangle2D.Float(rx0, ry0, rx1 - rx0, ry1 - ry0);
120: }
121: }
122:
123: public static class Double extends QuadCurve2D {
124:
125: public double x1;
126: public double y1;
127: public double ctrlx;
128: public double ctrly;
129: public double x2;
130: public double y2;
131:
132: public Double() {
133: }
134:
135: public Double(double x1, double y1, double ctrlx, double ctrly,
136: double x2, double y2) {
137: setCurve(x1, y1, ctrlx, ctrly, x2, y2);
138: }
139:
140: @Override
141: public double getX1() {
142: return x1;
143: }
144:
145: @Override
146: public double getY1() {
147: return y1;
148: }
149:
150: @Override
151: public double getCtrlX() {
152: return ctrlx;
153: }
154:
155: @Override
156: public double getCtrlY() {
157: return ctrly;
158: }
159:
160: @Override
161: public double getX2() {
162: return x2;
163: }
164:
165: @Override
166: public double getY2() {
167: return y2;
168: }
169:
170: @Override
171: public Point2D getP1() {
172: return new Point2D.Double(x1, y1);
173: }
174:
175: @Override
176: public Point2D getCtrlPt() {
177: return new Point2D.Double(ctrlx, ctrly);
178: }
179:
180: @Override
181: public Point2D getP2() {
182: return new Point2D.Double(x2, y2);
183: }
184:
185: @Override
186: public void setCurve(double x1, double y1, double ctrlx,
187: double ctrly, double x2, double y2) {
188: this .x1 = x1;
189: this .y1 = y1;
190: this .ctrlx = ctrlx;
191: this .ctrly = ctrly;
192: this .x2 = x2;
193: this .y2 = y2;
194: }
195:
196: public Rectangle2D getBounds2D() {
197: double rx0 = Math.min(Math.min(x1, x2), ctrlx);
198: double ry0 = Math.min(Math.min(y1, y2), ctrly);
199: double rx1 = Math.max(Math.max(x1, x2), ctrlx);
200: double ry1 = Math.max(Math.max(y1, y2), ctrly);
201: return new Rectangle2D.Double(rx0, ry0, rx1 - rx0, ry1
202: - ry0);
203: }
204: }
205:
206: /*
207: * QuadCurve2D path iterator
208: */
209: class Iterator implements PathIterator {
210:
211: /**
212: * The source QuadCurve2D object
213: */
214: QuadCurve2D c;
215:
216: /**
217: * The path iterator transformation
218: */
219: AffineTransform t;
220:
221: /**
222: * The current segmenet index
223: */
224: int index;
225:
226: /**
227: * Constructs a new QuadCurve2D.Iterator for given line and transformation
228: * @param q - the source QuadCurve2D object
229: * @param at - the AffineTransform object to apply rectangle path
230: */
231: Iterator(QuadCurve2D q, AffineTransform t) {
232: this .c = q;
233: this .t = t;
234: }
235:
236: public int getWindingRule() {
237: return WIND_NON_ZERO;
238: }
239:
240: public boolean isDone() {
241: return (index > 1);
242: }
243:
244: public void next() {
245: index++;
246: }
247:
248: public int currentSegment(double[] coords) {
249: if (isDone()) {
250: // awt.4B=Iterator out of bounds
251: throw new NoSuchElementException(Messages
252: .getString("awt.4B")); //$NON-NLS-1$
253: }
254: int type;
255: int count;
256: if (index == 0) {
257: type = SEG_MOVETO;
258: coords[0] = c.getX1();
259: coords[1] = c.getY1();
260: count = 1;
261: } else {
262: type = SEG_QUADTO;
263: coords[0] = c.getCtrlX();
264: coords[1] = c.getCtrlY();
265: coords[2] = c.getX2();
266: coords[3] = c.getY2();
267: count = 2;
268: }
269: if (t != null) {
270: t.transform(coords, 0, coords, 0, count);
271: }
272: return type;
273: }
274:
275: public int currentSegment(float[] coords) {
276: if (isDone()) {
277: // awt.4B=Iterator out of bounds
278: throw new NoSuchElementException(Messages
279: .getString("awt.4B")); //$NON-NLS-1$
280: }
281: int type;
282: int count;
283: if (index == 0) {
284: type = SEG_MOVETO;
285: coords[0] = (float) c.getX1();
286: coords[1] = (float) c.getY1();
287: count = 1;
288: } else {
289: type = SEG_QUADTO;
290: coords[0] = (float) c.getCtrlX();
291: coords[1] = (float) c.getCtrlY();
292: coords[2] = (float) c.getX2();
293: coords[3] = (float) c.getY2();
294: count = 2;
295: }
296: if (t != null) {
297: t.transform(coords, 0, coords, 0, count);
298: }
299: return type;
300: }
301:
302: }
303:
304: protected QuadCurve2D() {
305: }
306:
307: public abstract double getX1();
308:
309: public abstract double getY1();
310:
311: public abstract Point2D getP1();
312:
313: public abstract double getCtrlX();
314:
315: public abstract double getCtrlY();
316:
317: public abstract Point2D getCtrlPt();
318:
319: public abstract double getX2();
320:
321: public abstract double getY2();
322:
323: public abstract Point2D getP2();
324:
325: public abstract void setCurve(double x1, double y1, double ctrlx,
326: double ctrly, double x2, double y2);
327:
328: public void setCurve(Point2D p1, Point2D cp, Point2D p2) {
329: setCurve(p1.getX(), p1.getY(), cp.getX(), cp.getY(), p2.getX(),
330: p2.getY());
331: }
332:
333: public void setCurve(double[] coords, int offset) {
334: setCurve(coords[offset + 0], coords[offset + 1],
335: coords[offset + 2], coords[offset + 3],
336: coords[offset + 4], coords[offset + 5]);
337: }
338:
339: public void setCurve(Point2D[] points, int offset) {
340: setCurve(points[offset + 0].getX(), points[offset + 0].getY(),
341: points[offset + 1].getX(), points[offset + 1].getY(),
342: points[offset + 2].getX(), points[offset + 2].getY());
343: }
344:
345: public void setCurve(QuadCurve2D curve) {
346: setCurve(curve.getX1(), curve.getY1(), curve.getCtrlX(), curve
347: .getCtrlY(), curve.getX2(), curve.getY2());
348: }
349:
350: public double getFlatnessSq() {
351: return Line2D.ptSegDistSq(getX1(), getY1(), getX2(), getY2(),
352: getCtrlX(), getCtrlY());
353: }
354:
355: public static double getFlatnessSq(double x1, double y1,
356: double ctrlx, double ctrly, double x2, double y2) {
357: return Line2D.ptSegDistSq(x1, y1, x2, y2, ctrlx, ctrly);
358: }
359:
360: public static double getFlatnessSq(double coords[], int offset) {
361: return Line2D.ptSegDistSq(coords[offset + 0],
362: coords[offset + 1], coords[offset + 4],
363: coords[offset + 5], coords[offset + 2],
364: coords[offset + 3]);
365: }
366:
367: public double getFlatness() {
368: return Line2D.ptSegDist(getX1(), getY1(), getX2(), getY2(),
369: getCtrlX(), getCtrlY());
370: }
371:
372: public static double getFlatness(double x1, double y1,
373: double ctrlx, double ctrly, double x2, double y2) {
374: return Line2D.ptSegDist(x1, y1, x2, y2, ctrlx, ctrly);
375: }
376:
377: public static double getFlatness(double coords[], int offset) {
378: return Line2D.ptSegDist(coords[offset + 0], coords[offset + 1],
379: coords[offset + 4], coords[offset + 5],
380: coords[offset + 2], coords[offset + 3]);
381: }
382:
383: public void subdivide(QuadCurve2D left, QuadCurve2D right) {
384: subdivide(this , left, right);
385: }
386:
387: public static void subdivide(QuadCurve2D src, QuadCurve2D left,
388: QuadCurve2D right) {
389: double x1 = src.getX1();
390: double y1 = src.getY1();
391: double cx = src.getCtrlX();
392: double cy = src.getCtrlY();
393: double x2 = src.getX2();
394: double y2 = src.getY2();
395: double cx1 = (x1 + cx) / 2.0;
396: double cy1 = (y1 + cy) / 2.0;
397: double cx2 = (x2 + cx) / 2.0;
398: double cy2 = (y2 + cy) / 2.0;
399: cx = (cx1 + cx2) / 2.0;
400: cy = (cy1 + cy2) / 2.0;
401: if (left != null) {
402: left.setCurve(x1, y1, cx1, cy1, cx, cy);
403: }
404: if (right != null) {
405: right.setCurve(cx, cy, cx2, cy2, x2, y2);
406: }
407: }
408:
409: public static void subdivide(double src[], int srcoff,
410: double left[], int leftOff, double right[], int rightOff) {
411: double x1 = src[srcoff + 0];
412: double y1 = src[srcoff + 1];
413: double cx = src[srcoff + 2];
414: double cy = src[srcoff + 3];
415: double x2 = src[srcoff + 4];
416: double y2 = src[srcoff + 5];
417: double cx1 = (x1 + cx) / 2.0;
418: double cy1 = (y1 + cy) / 2.0;
419: double cx2 = (x2 + cx) / 2.0;
420: double cy2 = (y2 + cy) / 2.0;
421: cx = (cx1 + cx2) / 2.0;
422: cy = (cy1 + cy2) / 2.0;
423: if (left != null) {
424: left[leftOff + 0] = x1;
425: left[leftOff + 1] = y1;
426: left[leftOff + 2] = cx1;
427: left[leftOff + 3] = cy1;
428: left[leftOff + 4] = cx;
429: left[leftOff + 5] = cy;
430: }
431: if (right != null) {
432: right[rightOff + 0] = cx;
433: right[rightOff + 1] = cy;
434: right[rightOff + 2] = cx2;
435: right[rightOff + 3] = cy2;
436: right[rightOff + 4] = x2;
437: right[rightOff + 5] = y2;
438: }
439: }
440:
441: public static int solveQuadratic(double eqn[]) {
442: return solveQuadratic(eqn, eqn);
443: }
444:
445: public static int solveQuadratic(double eqn[], double res[]) {
446: return Crossing.solveQuad(eqn, res);
447: }
448:
449: public boolean contains(double px, double py) {
450: return Crossing.isInsideEvenOdd(Crossing.crossShape(this , px,
451: py));
452: }
453:
454: public boolean contains(double rx, double ry, double rw, double rh) {
455: int cross = Crossing.intersectShape(this , rx, ry, rw, rh);
456: return cross != Crossing.CROSSING
457: && Crossing.isInsideEvenOdd(cross);
458: }
459:
460: public boolean intersects(double rx, double ry, double rw, double rh) {
461: int cross = Crossing.intersectShape(this , rx, ry, rw, rh);
462: return cross == Crossing.CROSSING
463: || Crossing.isInsideEvenOdd(cross);
464: }
465:
466: public boolean contains(Point2D p) {
467: return contains(p.getX(), p.getY());
468: }
469:
470: public boolean intersects(Rectangle2D r) {
471: return intersects(r.getX(), r.getY(), r.getWidth(), r
472: .getHeight());
473: }
474:
475: public boolean contains(Rectangle2D r) {
476: return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
477: }
478:
479: public Rectangle getBounds() {
480: return getBounds2D().getBounds();
481: }
482:
483: public PathIterator getPathIterator(AffineTransform t) {
484: return new Iterator(this , t);
485: }
486:
487: public PathIterator getPathIterator(AffineTransform t,
488: double flatness) {
489: return new FlatteningPathIterator(getPathIterator(t), flatness);
490: }
491:
492: @Override
493: public Object clone() {
494: try {
495: return super .clone();
496: } catch (CloneNotSupportedException e) {
497: throw new InternalError();
498: }
499: }
500:
501: }
|