0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package java.awt.geom;
0018:
0019: import java.awt.Rectangle;
0020: import java.awt.Shape;
0021: import java.util.NoSuchElementException;
0022:
0023: import org.apache.harmony.awt.gl.Crossing;
0024: import org.apache.harmony.awt.geom.CrossingHelper;
0025: import org.apache.harmony.awt.geom.CurveCrossingHelper;
0026: import org.apache.harmony.awt.geom.GeometryUtil;
0027: import org.apache.harmony.awt.geom.IntersectPoint;
0028: import org.apache.harmony.awt.internal.nls.Messages;
0029:
0030: public class Area implements Shape, Cloneable {
0031:
0032: /**
0033: * the coordinates array of the shape vertices
0034: */
0035: private double coords[] = new double[20];
0036:
0037: /**
0038: * the coordinates quantity
0039: */
0040: private int coordsSize = 0;
0041:
0042: /**
0043: * the rules array for the drawing of the shape edges
0044: */
0045: private int rules[] = new int[10];
0046:
0047: /**
0048: * the rules quantity
0049: */
0050: private int rulesSize = 0;
0051:
0052: /**
0053: * offsets[i] - index in array of coords and i - index in array of rules
0054: */
0055: private int offsets[] = new int[10];
0056:
0057: /**
0058: * the quantity of MOVETO rule occurences
0059: */
0060: private int moveToCount = 0;
0061:
0062: /**
0063: * true if the shape is polygon
0064: */
0065: private boolean isPolygonal = true;
0066:
0067: public Area() {
0068: }
0069:
0070: public Area(Shape s) {
0071: double segmentCoords[] = new double[6];
0072: double lastMoveX = 0.0;
0073: double lastMoveY = 0.0;
0074: int rulesIndex = 0;
0075: int coordsIndex = 0;
0076:
0077: for (PathIterator pi = s.getPathIterator(null); !pi.isDone(); pi
0078: .next()) {
0079: coords = adjustSize(coords, coordsIndex + 6);
0080: rules = adjustSize(rules, rulesIndex + 1);
0081: offsets = adjustSize(offsets, rulesIndex + 1);
0082: rules[rulesIndex] = pi.currentSegment(segmentCoords);
0083: offsets[rulesIndex] = coordsIndex;
0084:
0085: switch (rules[rulesIndex]) {
0086: case PathIterator.SEG_MOVETO:
0087: coords[coordsIndex++] = segmentCoords[0];
0088: coords[coordsIndex++] = segmentCoords[1];
0089: lastMoveX = segmentCoords[0];
0090: lastMoveY = segmentCoords[1];
0091: ++moveToCount;
0092: break;
0093: case PathIterator.SEG_LINETO:
0094: if ((segmentCoords[0] != lastMoveX)
0095: || (segmentCoords[1] != lastMoveY)) {
0096: coords[coordsIndex++] = segmentCoords[0];
0097: coords[coordsIndex++] = segmentCoords[1];
0098: } else {
0099: --rulesIndex;
0100: }
0101: break;
0102: case PathIterator.SEG_QUADTO:
0103: System.arraycopy(segmentCoords, 0, coords, coordsIndex,
0104: 4);
0105: coordsIndex += 4;
0106: isPolygonal = false;
0107: break;
0108: case PathIterator.SEG_CUBICTO:
0109: System.arraycopy(segmentCoords, 0, coords, coordsIndex,
0110: 6);
0111: coordsIndex += 6;
0112: isPolygonal = false;
0113: break;
0114: case PathIterator.SEG_CLOSE:
0115: break;
0116: }
0117: ++rulesIndex;
0118: }
0119:
0120: if ((rulesIndex != 0)
0121: && (rules[rulesIndex - 1] != PathIterator.SEG_CLOSE)) {
0122: rules[rulesIndex] = PathIterator.SEG_CLOSE;
0123: offsets[rulesIndex] = coordsSize;
0124: }
0125:
0126: rulesSize = rulesIndex;
0127: coordsSize = coordsIndex;
0128: }
0129:
0130: public boolean contains(double x, double y) {
0131: return !isEmpty() && containsExact(x, y) > 0;
0132: }
0133:
0134: public boolean contains(double x, double y, double width,
0135: double height) {
0136: int crossCount = Crossing.intersectPath(getPathIterator(null),
0137: x, y, width, height);
0138: return crossCount != Crossing.CROSSING
0139: && Crossing.isInsideEvenOdd(crossCount);
0140: }
0141:
0142: public boolean contains(Point2D p) {
0143: return contains(p.getX(), p.getY());
0144: }
0145:
0146: public boolean contains(Rectangle2D r) {
0147: return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
0148: }
0149:
0150: public boolean equals(Area obj) {
0151: if (this == obj) {
0152: return true;
0153: }
0154:
0155: if (obj == null) {
0156: return false;
0157: }
0158:
0159: Area area = (Area) clone();
0160: area.subtract(obj);
0161: return area.isEmpty();
0162: }
0163:
0164: public boolean intersects(double x, double y, double width,
0165: double height) {
0166: if ((width <= 0.0) || (height <= 0.0)) {
0167: return false;
0168: } else if (!getBounds2D().intersects(x, y, width, height)) {
0169: return false;
0170: }
0171:
0172: int crossCount = Crossing.intersectShape(this , x, y, width,
0173: height);
0174: return Crossing.isInsideEvenOdd(crossCount);
0175: }
0176:
0177: public boolean intersects(Rectangle2D r) {
0178: return intersects(r.getX(), r.getY(), r.getWidth(), r
0179: .getHeight());
0180: }
0181:
0182: public Rectangle getBounds() {
0183: return getBounds2D().getBounds();
0184: }
0185:
0186: public Rectangle2D getBounds2D() {
0187: double maxX = coords[0];
0188: double maxY = coords[1];
0189: double minX = coords[0];
0190: double minY = coords[1];
0191:
0192: for (int i = 0; i < coordsSize;) {
0193: minX = Math.min(minX, coords[i]);
0194: maxX = Math.max(maxX, coords[i++]);
0195: minY = Math.min(minY, coords[i]);
0196: maxY = Math.max(maxY, coords[i++]);
0197: }
0198:
0199: return new Rectangle2D.Double(minX, minY, maxX - minX, maxY
0200: - minY);
0201: }
0202:
0203: public PathIterator getPathIterator(AffineTransform t) {
0204: return new AreaPathIterator(this , t);
0205: }
0206:
0207: public PathIterator getPathIterator(AffineTransform t,
0208: double flatness) {
0209: return new FlatteningPathIterator(getPathIterator(t), flatness);
0210: }
0211:
0212: public boolean isEmpty() {
0213: return (rulesSize == 0) && (coordsSize == 0);
0214: }
0215:
0216: public boolean isPolygonal() {
0217: return isPolygonal;
0218: }
0219:
0220: public boolean isRectangular() {
0221: return (isPolygonal) && (rulesSize <= 5) && (coordsSize <= 8)
0222: && (coords[1] == coords[3]) && (coords[7] == coords[5])
0223: && (coords[0] == coords[6]) && (coords[2] == coords[4]);
0224: }
0225:
0226: public boolean isSingular() {
0227: return (moveToCount <= 1);
0228: }
0229:
0230: public void reset() {
0231: coordsSize = 0;
0232: rulesSize = 0;
0233: }
0234:
0235: public void transform(AffineTransform t) {
0236: copy(new Area(t.createTransformedShape(this )), this );
0237: }
0238:
0239: public Area createTransformedArea(AffineTransform t) {
0240: return new Area(t.createTransformedShape(this ));
0241: }
0242:
0243: public Object clone() {
0244: Area area = new Area();
0245: copy(this , area);
0246: return area;
0247: }
0248:
0249: public void add(Area area) {
0250: if (area == null || area.isEmpty()) {
0251: return;
0252: } else if (isEmpty()) {
0253: copy(area, this );
0254: return;
0255: }
0256:
0257: if (isPolygonal() && area.isPolygonal()) {
0258: addPolygon(area);
0259: } else {
0260: addCurvePolygon(area);
0261: }
0262:
0263: if (getAreaBoundsSquare() < GeometryUtil.EPSILON) {
0264: reset();
0265: }
0266: }
0267:
0268: public void intersect(Area area) {
0269: if (area == null) {
0270: return;
0271: } else if (isEmpty() || area.isEmpty()) {
0272: reset();
0273: return;
0274: }
0275:
0276: if (isPolygonal() && area.isPolygonal()) {
0277: intersectPolygon(area);
0278: } else {
0279: intersectCurvePolygon(area);
0280: }
0281:
0282: if (getAreaBoundsSquare() < GeometryUtil.EPSILON) {
0283: reset();
0284: }
0285: }
0286:
0287: public void subtract(Area area) {
0288: if (area == null || isEmpty() || area.isEmpty()) {
0289: return;
0290: }
0291:
0292: if (isPolygonal() && area.isPolygonal()) {
0293: subtractPolygon(area);
0294: } else {
0295: subtractCurvePolygon(area);
0296: }
0297:
0298: if (getAreaBoundsSquare() < GeometryUtil.EPSILON) {
0299: reset();
0300: }
0301: }
0302:
0303: public void exclusiveOr(Area area) {
0304: Area a = (Area) clone();
0305: a.intersect(area);
0306: add(area);
0307: subtract(a);
0308: }
0309:
0310: private void addCurvePolygon(Area area) {
0311: CurveCrossingHelper crossHelper = new CurveCrossingHelper(
0312: new double[][] { coords, area.coords }, new int[] {
0313: coordsSize, area.coordsSize }, new int[][] {
0314: rules, area.rules }, new int[] { rulesSize,
0315: area.rulesSize }, new int[][] { offsets,
0316: area.offsets });
0317: IntersectPoint[] intersectPoints = crossHelper.findCrossing();
0318:
0319: if (intersectPoints.length == 0) {
0320: if (area.contains(getBounds2D())) {
0321: copy(area, this );
0322: } else if (!contains(area.getBounds2D())) {
0323: coords = adjustSize(coords, coordsSize
0324: + area.coordsSize);
0325: System.arraycopy(area.coords, 0, coords, coordsSize,
0326: area.coordsSize);
0327: coordsSize += area.coordsSize;
0328: rules = adjustSize(rules, rulesSize + area.rulesSize);
0329: System.arraycopy(area.rules, 0, rules, rulesSize,
0330: area.rulesSize);
0331: rulesSize += area.rulesSize;
0332: offsets = adjustSize(offsets, rulesSize
0333: + area.rulesSize);
0334: System.arraycopy(area.offsets, 0, offsets, rulesSize,
0335: area.rulesSize);
0336: }
0337:
0338: return;
0339: }
0340:
0341: double[] resultCoords = new double[coordsSize + area.coordsSize
0342: + intersectPoints.length];
0343: int[] resultRules = new int[rulesSize + area.rulesSize
0344: + intersectPoints.length];
0345: int[] resultOffsets = new int[rulesSize + area.rulesSize
0346: + intersectPoints.length];
0347: int resultCoordPos = 0;
0348: int resultRulesPos = 0;
0349: boolean isCurrentArea = true;
0350:
0351: IntersectPoint point = intersectPoints[0];
0352: resultRules[resultRulesPos] = PathIterator.SEG_MOVETO;
0353: resultOffsets[resultRulesPos++] = resultCoordPos;
0354:
0355: do {
0356: resultCoords[resultCoordPos++] = point.getX();
0357: resultCoords[resultCoordPos++] = point.getY();
0358: int curIndex = point.getEndIndex(true);
0359:
0360: if (curIndex < 0) {
0361: isCurrentArea = !isCurrentArea;
0362: } else if (area.containsExact(coords[2 * curIndex],
0363: coords[2 * curIndex + 1]) > 0) {
0364: isCurrentArea = false;
0365: } else {
0366: isCurrentArea = true;
0367: }
0368:
0369: IntersectPoint nextPoint = getNextIntersectPoint(
0370: intersectPoints, point, isCurrentArea);
0371: double[] coords = (isCurrentArea) ? this .coords
0372: : area.coords;
0373: int[] offsets = (isCurrentArea) ? this .offsets
0374: : area.offsets;
0375: int[] rules = (isCurrentArea) ? this .rules : area.rules;
0376: int offset = point.getRuleIndex(isCurrentArea);
0377: boolean isCopyUntilZero = false;
0378:
0379: if ((point.getRuleIndex(isCurrentArea) > nextPoint
0380: .getRuleIndex(isCurrentArea))) {
0381: int rulesSize = (isCurrentArea) ? this .rulesSize
0382: : area.rulesSize;
0383: resultCoordPos = includeCoordsAndRules(offset + 1,
0384: rulesSize, rules, offsets, resultRules,
0385: resultOffsets, resultCoords, coords,
0386: resultRulesPos, resultCoordPos, point,
0387: isCurrentArea, false, 0);
0388: resultRulesPos += rulesSize - offset - 1;
0389: offset = 1;
0390: isCopyUntilZero = true;
0391: }
0392:
0393: int length = nextPoint.getRuleIndex(isCurrentArea) - offset
0394: + 1;
0395:
0396: if (isCopyUntilZero) {
0397: offset = 0;
0398: }
0399:
0400: resultCoordPos = includeCoordsAndRules(offset, length,
0401: rules, offsets, resultRules, resultOffsets,
0402: resultCoords, coords, resultRulesPos,
0403: resultCoordPos, point, isCurrentArea, true, 0);
0404: resultRulesPos += length - offset;
0405: point = nextPoint;
0406: } while (point != intersectPoints[0]);
0407:
0408: resultRules[resultRulesPos++] = PathIterator.SEG_CLOSE;
0409: resultOffsets[resultRulesPos - 1] = resultCoordPos;
0410: this .coords = resultCoords;
0411: this .rules = resultRules;
0412: this .offsets = resultOffsets;
0413: this .coordsSize = resultCoordPos;
0414: this .rulesSize = resultRulesPos;
0415: }
0416:
0417: private void addPolygon(Area area) {
0418: CrossingHelper crossHelper = new CrossingHelper(new double[][] {
0419: coords, area.coords }, new int[] { coordsSize,
0420: area.coordsSize });
0421: IntersectPoint[] intersectPoints = crossHelper.findCrossing();
0422:
0423: if (intersectPoints.length == 0) {
0424: if (area.contains(getBounds2D())) {
0425: copy(area, this );
0426: } else if (!contains(area.getBounds2D())) {
0427: coords = adjustSize(coords, coordsSize
0428: + area.coordsSize);
0429: System.arraycopy(area.coords, 0, coords, coordsSize,
0430: area.coordsSize);
0431: coordsSize += area.coordsSize;
0432: rules = adjustSize(rules, rulesSize + area.rulesSize);
0433: System.arraycopy(area.rules, 0, rules, rulesSize,
0434: area.rulesSize);
0435: rulesSize += area.rulesSize;
0436: offsets = adjustSize(offsets, rulesSize
0437: + area.rulesSize);
0438: System.arraycopy(area.offsets, 0, offsets, rulesSize,
0439: area.rulesSize);
0440: }
0441: return;
0442: }
0443:
0444: double[] resultCoords = new double[coordsSize + area.coordsSize
0445: + intersectPoints.length];
0446: int[] resultRules = new int[rulesSize + area.rulesSize
0447: + intersectPoints.length];
0448: int[] resultOffsets = new int[rulesSize + area.rulesSize
0449: + intersectPoints.length];
0450: int resultCoordPos = 0;
0451: int resultRulesPos = 0;
0452: boolean isCurrentArea = true;
0453:
0454: IntersectPoint point = intersectPoints[0];
0455: resultRules[resultRulesPos] = PathIterator.SEG_MOVETO;
0456: resultOffsets[resultRulesPos++] = resultCoordPos;
0457:
0458: do {
0459: resultCoords[resultCoordPos++] = point.getX();
0460: resultCoords[resultCoordPos++] = point.getY();
0461: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0462: resultOffsets[resultRulesPos++] = resultCoordPos - 2;
0463: int curIndex = point.getEndIndex(true);
0464: if (curIndex < 0) {
0465: isCurrentArea = !isCurrentArea;
0466: } else if (area.containsExact(coords[2 * curIndex],
0467: coords[2 * curIndex + 1]) > 0) {
0468: isCurrentArea = false;
0469: } else {
0470: isCurrentArea = true;
0471: }
0472:
0473: IntersectPoint nextPoint = getNextIntersectPoint(
0474: intersectPoints, point, isCurrentArea);
0475: double[] coords = (isCurrentArea) ? this .coords
0476: : area.coords;
0477: int offset = 2 * point.getEndIndex(isCurrentArea);
0478:
0479: if ((offset >= 0)
0480: && (nextPoint.getBegIndex(isCurrentArea) < point
0481: .getEndIndex(isCurrentArea))) {
0482: int coordSize = (isCurrentArea) ? this .coordsSize
0483: : area.coordsSize;
0484: int length = coordSize - offset;
0485: System.arraycopy(coords, offset, resultCoords,
0486: resultCoordPos, length);
0487:
0488: for (int i = 0; i < length / 2; i++) {
0489: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0490: resultOffsets[resultRulesPos++] = resultCoordPos;
0491: resultCoordPos += 2;
0492: }
0493:
0494: offset = 0;
0495: }
0496:
0497: if (offset >= 0) {
0498: int length = 2 * nextPoint.getBegIndex(isCurrentArea)
0499: - offset + 2;
0500: System.arraycopy(coords, offset, resultCoords,
0501: resultCoordPos, length);
0502:
0503: for (int i = 0; i < length / 2; i++) {
0504: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0505: resultOffsets[resultRulesPos++] = resultCoordPos;
0506: resultCoordPos += 2;
0507: }
0508: }
0509:
0510: point = nextPoint;
0511: } while (point != intersectPoints[0]);
0512:
0513: resultRules[resultRulesPos - 1] = PathIterator.SEG_CLOSE;
0514: resultOffsets[resultRulesPos - 1] = resultCoordPos;
0515: coords = resultCoords;
0516: rules = resultRules;
0517: offsets = resultOffsets;
0518: coordsSize = resultCoordPos;
0519: rulesSize = resultRulesPos;
0520: }
0521:
0522: private void intersectCurvePolygon(Area area) {
0523: CurveCrossingHelper crossHelper = new CurveCrossingHelper(
0524: new double[][] { coords, area.coords }, new int[] {
0525: coordsSize, area.coordsSize }, new int[][] {
0526: rules, area.rules }, new int[] { rulesSize,
0527: area.rulesSize }, new int[][] { offsets,
0528: area.offsets });
0529: IntersectPoint[] intersectPoints = crossHelper.findCrossing();
0530:
0531: if (intersectPoints.length == 0) {
0532: if (contains(area.getBounds2D())) {
0533: copy(area, this );
0534: } else if (!area.contains(getBounds2D())) {
0535: reset();
0536: }
0537: return;
0538: }
0539:
0540: double[] resultCoords = new double[coordsSize + area.coordsSize
0541: + intersectPoints.length];
0542: int[] resultRules = new int[rulesSize + area.rulesSize
0543: + intersectPoints.length];
0544: int[] resultOffsets = new int[rulesSize + area.rulesSize
0545: + intersectPoints.length];
0546: int resultCoordPos = 0;
0547: int resultRulesPos = 0;
0548: boolean isCurrentArea = true;
0549:
0550: IntersectPoint point = intersectPoints[0];
0551: IntersectPoint nextPoint = intersectPoints[0];
0552: resultRules[resultRulesPos] = PathIterator.SEG_MOVETO;
0553: resultOffsets[resultRulesPos++] = resultCoordPos;
0554:
0555: do {
0556: resultCoords[resultCoordPos++] = point.getX();
0557: resultCoords[resultCoordPos++] = point.getY();
0558:
0559: int curIndex = point.getEndIndex(true);
0560: if ((curIndex < 0)
0561: || (area.containsExact(coords[2 * curIndex],
0562: coords[2 * curIndex + 1]) == 0)) {
0563: isCurrentArea = !isCurrentArea;
0564: } else if (area.containsExact(coords[2 * curIndex],
0565: coords[2 * curIndex + 1]) > 0) {
0566: isCurrentArea = true;
0567: } else {
0568: isCurrentArea = false;
0569: }
0570:
0571: nextPoint = getNextIntersectPoint(intersectPoints, point,
0572: isCurrentArea);
0573: double[] coords = (isCurrentArea) ? this .coords
0574: : area.coords;
0575: int[] offsets = (isCurrentArea) ? this .offsets
0576: : area.offsets;
0577: int[] rules = (isCurrentArea) ? this .rules : area.rules;
0578: int offset = point.getRuleIndex(isCurrentArea);
0579: boolean isCopyUntilZero = false;
0580:
0581: if (point.getRuleIndex(isCurrentArea) > nextPoint
0582: .getRuleIndex(isCurrentArea)) {
0583: int rulesSize = (isCurrentArea) ? this .rulesSize
0584: : area.rulesSize;
0585: resultCoordPos = includeCoordsAndRules(offset + 1,
0586: rulesSize, rules, offsets, resultRules,
0587: resultOffsets, resultCoords, coords,
0588: resultRulesPos, resultCoordPos, point,
0589: isCurrentArea, false, 1);
0590: resultRulesPos += rulesSize - offset - 1;
0591: offset = 1;
0592: isCopyUntilZero = true;
0593: }
0594:
0595: int length = nextPoint.getRuleIndex(isCurrentArea) - offset
0596: + 1;
0597:
0598: if (isCopyUntilZero) {
0599: offset = 0;
0600: isCopyUntilZero = false;
0601: }
0602: if ((length == offset)
0603: && (nextPoint.getRule(isCurrentArea) != PathIterator.SEG_LINETO)
0604: && (nextPoint.getRule(isCurrentArea) != PathIterator.SEG_CLOSE)
0605: && (point.getRule(isCurrentArea) != PathIterator.SEG_LINETO)
0606: && (point.getRule(isCurrentArea) != PathIterator.SEG_CLOSE)) {
0607:
0608: isCopyUntilZero = true;
0609: length++;
0610: }
0611:
0612: resultCoordPos = includeCoordsAndRules(offset, length,
0613: rules, offsets, resultRules, resultOffsets,
0614: resultCoords, coords, resultRulesPos,
0615: resultCoordPos, nextPoint, isCurrentArea, true, 1);
0616: resultRulesPos = ((length <= offset) || (isCopyUntilZero)) ? resultRulesPos + 1
0617: : resultRulesPos + length;
0618:
0619: point = nextPoint;
0620: } while (point != intersectPoints[0]);
0621:
0622: if (resultRules[resultRulesPos - 1] == PathIterator.SEG_LINETO) {
0623: resultRules[resultRulesPos - 1] = PathIterator.SEG_CLOSE;
0624: } else {
0625: resultCoords[resultCoordPos++] = nextPoint.getX();
0626: resultCoords[resultCoordPos++] = nextPoint.getY();
0627: resultRules[resultRulesPos++] = PathIterator.SEG_CLOSE;
0628: }
0629:
0630: resultOffsets[resultRulesPos - 1] = resultCoordPos;
0631: coords = resultCoords;
0632: rules = resultRules;
0633: offsets = resultOffsets;
0634: coordsSize = resultCoordPos;
0635: rulesSize = resultRulesPos;
0636: }
0637:
0638: private void intersectPolygon(Area area) {
0639: CrossingHelper crossHelper = new CrossingHelper(new double[][] {
0640: coords, area.coords }, new int[] { coordsSize,
0641: area.coordsSize });
0642: IntersectPoint[] intersectPoints = crossHelper.findCrossing();
0643:
0644: if (intersectPoints.length == 0) {
0645: if (contains(area.getBounds2D())) {
0646: copy(area, this );
0647: } else if (!area.contains(getBounds2D())) {
0648: reset();
0649: }
0650: return;
0651: }
0652:
0653: double[] resultCoords = new double[coordsSize + area.coordsSize
0654: + intersectPoints.length];
0655: int[] resultRules = new int[rulesSize + area.rulesSize
0656: + intersectPoints.length];
0657: int[] resultOffsets = new int[rulesSize + area.rulesSize
0658: + intersectPoints.length];
0659: int resultCoordPos = 0;
0660: int resultRulesPos = 0;
0661: boolean isCurrentArea = true;
0662:
0663: IntersectPoint point = intersectPoints[0];
0664: resultRules[resultRulesPos] = PathIterator.SEG_MOVETO;
0665: resultOffsets[resultRulesPos++] = resultCoordPos;
0666:
0667: do {
0668: resultCoords[resultCoordPos++] = point.getX();
0669: resultCoords[resultCoordPos++] = point.getY();
0670: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0671: resultOffsets[resultRulesPos++] = resultCoordPos - 2;
0672: int curIndex = point.getEndIndex(true);
0673:
0674: if ((curIndex < 0)
0675: || (area.containsExact(coords[2 * curIndex],
0676: coords[2 * curIndex + 1]) == 0)) {
0677: isCurrentArea = !isCurrentArea;
0678: } else if (area.containsExact(coords[2 * curIndex],
0679: coords[2 * curIndex + 1]) > 0) {
0680: isCurrentArea = true;
0681: } else {
0682: isCurrentArea = false;
0683: }
0684:
0685: IntersectPoint nextPoint = getNextIntersectPoint(
0686: intersectPoints, point, isCurrentArea);
0687: double[] coords = (isCurrentArea) ? this .coords
0688: : area.coords;
0689: int offset = 2 * point.getEndIndex(isCurrentArea);
0690: if ((offset >= 0)
0691: && (nextPoint.getBegIndex(isCurrentArea) < point
0692: .getEndIndex(isCurrentArea))) {
0693: int coordSize = (isCurrentArea) ? this .coordsSize
0694: : area.coordsSize;
0695: int length = coordSize - offset;
0696: System.arraycopy(coords, offset, resultCoords,
0697: resultCoordPos, length);
0698:
0699: for (int i = 0; i < length / 2; i++) {
0700: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0701: resultOffsets[resultRulesPos++] = resultCoordPos;
0702: resultCoordPos += 2;
0703: }
0704:
0705: offset = 0;
0706: }
0707:
0708: if (offset >= 0) {
0709: int length = 2 * nextPoint.getBegIndex(isCurrentArea)
0710: - offset + 2;
0711: System.arraycopy(coords, offset, resultCoords,
0712: resultCoordPos, length);
0713:
0714: for (int i = 0; i < length / 2; i++) {
0715: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0716: resultOffsets[resultRulesPos++] = resultCoordPos;
0717: resultCoordPos += 2;
0718: }
0719: }
0720:
0721: point = nextPoint;
0722: } while (point != intersectPoints[0]);
0723:
0724: resultRules[resultRulesPos - 1] = PathIterator.SEG_CLOSE;
0725: resultOffsets[resultRulesPos - 1] = resultCoordPos;
0726: coords = resultCoords;
0727: rules = resultRules;
0728: offsets = resultOffsets;
0729: coordsSize = resultCoordPos;
0730: rulesSize = resultRulesPos;
0731: }
0732:
0733: private void subtractCurvePolygon(Area area) {
0734: CurveCrossingHelper crossHelper = new CurveCrossingHelper(
0735: new double[][] { coords, area.coords }, new int[] {
0736: coordsSize, area.coordsSize }, new int[][] {
0737: rules, area.rules }, new int[] { rulesSize,
0738: area.rulesSize }, new int[][] { offsets,
0739: area.offsets });
0740: IntersectPoint[] intersectPoints = crossHelper.findCrossing();
0741:
0742: if (intersectPoints.length == 0 && contains(area.getBounds2D())) {
0743: copy(area, this );
0744: return;
0745: }
0746:
0747: double[] resultCoords = new double[coordsSize + area.coordsSize
0748: + intersectPoints.length];
0749: int[] resultRules = new int[rulesSize + area.rulesSize
0750: + intersectPoints.length];
0751: int[] resultOffsets = new int[rulesSize + area.rulesSize
0752: + intersectPoints.length];
0753: int resultCoordPos = 0;
0754: int resultRulesPos = 0;
0755: boolean isCurrentArea = true;
0756:
0757: IntersectPoint point = intersectPoints[0];
0758: resultRules[resultRulesPos] = PathIterator.SEG_MOVETO;
0759: resultOffsets[resultRulesPos++] = resultCoordPos;
0760:
0761: do {
0762: resultCoords[resultCoordPos++] = point.getX();
0763: resultCoords[resultCoordPos++] = point.getY();
0764: int curIndex = offsets[point.getRuleIndex(true)]
0765: % coordsSize;
0766:
0767: if (area.containsExact(coords[curIndex],
0768: coords[curIndex + 1]) == 0) {
0769: isCurrentArea = !isCurrentArea;
0770: } else if (area.containsExact(coords[curIndex],
0771: coords[curIndex + 1]) > 0) {
0772: isCurrentArea = false;
0773: } else {
0774: isCurrentArea = true;
0775: }
0776:
0777: IntersectPoint nextPoint = (isCurrentArea) ? getNextIntersectPoint(
0778: intersectPoints, point, isCurrentArea)
0779: : getPrevIntersectPoint(intersectPoints, point,
0780: isCurrentArea);
0781: double[] coords = (isCurrentArea) ? this .coords
0782: : area.coords;
0783: int[] offsets = (isCurrentArea) ? this .offsets
0784: : area.offsets;
0785: int[] rules = (isCurrentArea) ? this .rules : area.rules;
0786: int offset = (isCurrentArea) ? point
0787: .getRuleIndex(isCurrentArea) : nextPoint
0788: .getRuleIndex(isCurrentArea);
0789: boolean isCopyUntilZero = false;
0790:
0791: if (((isCurrentArea) && (point.getRuleIndex(isCurrentArea) > nextPoint
0792: .getRuleIndex(isCurrentArea)))
0793: || ((!isCurrentArea) && (nextPoint
0794: .getRuleIndex(isCurrentArea) > nextPoint
0795: .getRuleIndex(isCurrentArea)))) {
0796:
0797: int rulesSize = (isCurrentArea) ? this .rulesSize
0798: : area.rulesSize;
0799: resultCoordPos = includeCoordsAndRules(offset + 1,
0800: rulesSize, rules, offsets, resultRules,
0801: resultOffsets, resultCoords, coords,
0802: resultRulesPos, resultCoordPos, point,
0803: isCurrentArea, false, 2);
0804: resultRulesPos += rulesSize - offset - 1;
0805: offset = 1;
0806: isCopyUntilZero = true;
0807: }
0808:
0809: int length = nextPoint.getRuleIndex(isCurrentArea) - offset
0810: + 1;
0811:
0812: if (isCopyUntilZero) {
0813: offset = 0;
0814: isCopyUntilZero = false;
0815: }
0816:
0817: resultCoordPos = includeCoordsAndRules(offset, length,
0818: rules, offsets, resultRules, resultOffsets,
0819: resultCoords, coords, resultRulesPos,
0820: resultCoordPos, point, isCurrentArea, true, 2);
0821:
0822: if ((length == offset)
0823: && ((rules[offset] == PathIterator.SEG_QUADTO) || (rules[offset] == PathIterator.SEG_CUBICTO))) {
0824:
0825: resultRulesPos++;
0826: } else {
0827: resultRulesPos = (length < offset || isCopyUntilZero) ? resultRulesPos + 1
0828: : resultRulesPos + length - offset;
0829: }
0830:
0831: point = nextPoint;
0832: } while (point != intersectPoints[0]);
0833:
0834: resultRules[resultRulesPos++] = PathIterator.SEG_CLOSE;
0835: resultOffsets[resultRulesPos - 1] = resultCoordPos;
0836: coords = resultCoords;
0837: rules = resultRules;
0838: offsets = resultOffsets;
0839: coordsSize = resultCoordPos;
0840: rulesSize = resultRulesPos;
0841: }
0842:
0843: private void subtractPolygon(Area area) {
0844: CrossingHelper crossHelper = new CrossingHelper(new double[][] {
0845: coords, area.coords }, new int[] { coordsSize,
0846: area.coordsSize });
0847: IntersectPoint[] intersectPoints = crossHelper.findCrossing();
0848:
0849: if (intersectPoints.length == 0) {
0850: if (contains(area.getBounds2D())) {
0851: copy(area, this );
0852: return;
0853: }
0854: return;
0855: }
0856:
0857: double[] resultCoords = new double[2 * (coordsSize
0858: + area.coordsSize + intersectPoints.length)];
0859: int[] resultRules = new int[2 * (rulesSize + area.rulesSize + intersectPoints.length)];
0860: int[] resultOffsets = new int[2 * (rulesSize + area.rulesSize + intersectPoints.length)];
0861: int resultCoordPos = 0;
0862: int resultRulesPos = 0;
0863: boolean isCurrentArea = true;
0864: int countPoints = 0;
0865: boolean curArea = false;
0866: boolean addArea = false;
0867:
0868: IntersectPoint point = intersectPoints[0];
0869: resultRules[resultRulesPos] = PathIterator.SEG_MOVETO;
0870: resultOffsets[resultRulesPos++] = resultCoordPos;
0871:
0872: do {
0873: resultCoords[resultCoordPos++] = point.getX();
0874: resultCoords[resultCoordPos++] = point.getY();
0875: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0876: resultOffsets[resultRulesPos++] = resultCoordPos - 2;
0877: int curIndex = point.getEndIndex(true);
0878:
0879: if ((curIndex < 0)
0880: || (area.isVertex(coords[2 * curIndex],
0881: coords[2 * curIndex + 1])
0882: && crossHelper.containsPoint(new double[] {
0883: coords[2 * curIndex],
0884: coords[2 * curIndex + 1] }) && (coords[2 * curIndex] != point
0885: .getX() || coords[2 * curIndex + 1] != point
0886: .getY()))) {
0887: isCurrentArea = !isCurrentArea;
0888: } else if (area.containsExact(coords[2 * curIndex],
0889: coords[2 * curIndex + 1]) > 0) {
0890: isCurrentArea = false;
0891: } else {
0892: isCurrentArea = true;
0893: }
0894:
0895: if (countPoints >= intersectPoints.length) {
0896: isCurrentArea = !isCurrentArea;
0897: }
0898:
0899: if (isCurrentArea) {
0900: curArea = true;
0901: } else {
0902: addArea = true;
0903: }
0904:
0905: IntersectPoint nextPoint = (isCurrentArea) ? getNextIntersectPoint(
0906: intersectPoints, point, isCurrentArea)
0907: : getPrevIntersectPoint(intersectPoints, point,
0908: isCurrentArea);
0909: double[] coords = (isCurrentArea) ? this .coords
0910: : area.coords;
0911:
0912: int offset = (isCurrentArea) ? 2 * point
0913: .getEndIndex(isCurrentArea) : 2 * nextPoint
0914: .getEndIndex(isCurrentArea);
0915:
0916: if ((offset > 0)
0917: && (((isCurrentArea) && (nextPoint
0918: .getBegIndex(isCurrentArea) < point
0919: .getEndIndex(isCurrentArea))) || ((!isCurrentArea) && (nextPoint
0920: .getEndIndex(isCurrentArea) < nextPoint
0921: .getBegIndex(isCurrentArea))))) {
0922:
0923: int coordSize = (isCurrentArea) ? this .coordsSize
0924: : area.coordsSize;
0925: int length = coordSize - offset;
0926:
0927: if (isCurrentArea) {
0928: System.arraycopy(coords, offset, resultCoords,
0929: resultCoordPos, length);
0930: } else {
0931: double[] temp = new double[length];
0932: System.arraycopy(coords, offset, temp, 0, length);
0933: reverseCopy(temp);
0934: System.arraycopy(temp, 0, resultCoords,
0935: resultCoordPos, length);
0936: }
0937:
0938: for (int i = 0; i < length / 2; i++) {
0939: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0940: resultOffsets[resultRulesPos++] = resultCoordPos;
0941: resultCoordPos += 2;
0942: }
0943:
0944: offset = 0;
0945: }
0946:
0947: if (offset >= 0) {
0948: int length = (isCurrentArea) ? 2
0949: * nextPoint.getBegIndex(isCurrentArea) - offset
0950: + 2 : 2 * point.getBegIndex(isCurrentArea)
0951: - offset + 2;
0952:
0953: if (isCurrentArea) {
0954: System.arraycopy(coords, offset, resultCoords,
0955: resultCoordPos, length);
0956: } else {
0957: double[] temp = new double[length];
0958: System.arraycopy(coords, offset, temp, 0, length);
0959: reverseCopy(temp);
0960: System.arraycopy(temp, 0, resultCoords,
0961: resultCoordPos, length);
0962: }
0963:
0964: for (int i = 0; i < length / 2; i++) {
0965: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
0966: resultOffsets[resultRulesPos++] = resultCoordPos;
0967: resultCoordPos += 2;
0968: }
0969: }
0970:
0971: point = nextPoint;
0972: countPoints++;
0973: } while (point != intersectPoints[0] || !(curArea && addArea));
0974:
0975: resultRules[resultRulesPos - 1] = PathIterator.SEG_CLOSE;
0976: resultOffsets[resultRulesPos - 1] = resultCoordPos;
0977: coords = resultCoords;
0978: rules = resultRules;
0979: offsets = resultOffsets;
0980: coordsSize = resultCoordPos;
0981: rulesSize = resultRulesPos;
0982: }
0983:
0984: private IntersectPoint getNextIntersectPoint(
0985: IntersectPoint[] iPoints, IntersectPoint isectPoint,
0986: boolean isCurrentArea) {
0987: int endIndex = isectPoint.getEndIndex(isCurrentArea);
0988: if (endIndex < 0) {
0989: return iPoints[Math.abs(endIndex) - 1];
0990: }
0991:
0992: IntersectPoint firstIsectPoint = null;
0993: IntersectPoint nextIsectPoint = null;
0994: for (IntersectPoint point : iPoints) {
0995: int begIndex = point.getBegIndex(isCurrentArea);
0996:
0997: if (begIndex >= 0) {
0998: if (firstIsectPoint == null) {
0999: firstIsectPoint = point;
1000: } else if (begIndex < firstIsectPoint
1001: .getBegIndex(isCurrentArea)) {
1002: firstIsectPoint = point;
1003: }
1004: }
1005:
1006: if (endIndex <= begIndex) {
1007: if (nextIsectPoint == null) {
1008: nextIsectPoint = point;
1009: } else if (begIndex < nextIsectPoint
1010: .getBegIndex(isCurrentArea)) {
1011: nextIsectPoint = point;
1012: }
1013: }
1014: }
1015:
1016: return (nextIsectPoint != null) ? nextIsectPoint
1017: : firstIsectPoint;
1018: }
1019:
1020: private IntersectPoint getPrevIntersectPoint(
1021: IntersectPoint[] iPoints, IntersectPoint isectPoint,
1022: boolean isCurrentArea) {
1023:
1024: int begIndex = isectPoint.getBegIndex(isCurrentArea);
1025:
1026: if (begIndex < 0) {
1027: return iPoints[Math.abs(begIndex) - 1];
1028: }
1029:
1030: IntersectPoint firstIsectPoint = null;
1031: IntersectPoint predIsectPoint = null;
1032: for (IntersectPoint point : iPoints) {
1033: int endIndex = point.getEndIndex(isCurrentArea);
1034:
1035: if (endIndex >= 0) {
1036: if (firstIsectPoint == null) {
1037: firstIsectPoint = point;
1038: } else if (endIndex < firstIsectPoint
1039: .getEndIndex(isCurrentArea)) {
1040: firstIsectPoint = point;
1041: }
1042: }
1043:
1044: if (endIndex <= begIndex) {
1045: if (predIsectPoint == null) {
1046: predIsectPoint = point;
1047: } else if (endIndex > predIsectPoint
1048: .getEndIndex(isCurrentArea)) {
1049: predIsectPoint = point;
1050: }
1051: }
1052: }
1053:
1054: return (predIsectPoint != null) ? predIsectPoint
1055: : firstIsectPoint;
1056: }
1057:
1058: private int includeCoordsAndRules(int offset, int length,
1059: int[] rules, int[] offsets, int[] resultRules,
1060: int[] resultOffsets, double[] resultCoords,
1061: double[] coords, int resultRulesPos, int resultCoordPos,
1062: IntersectPoint point, boolean isCurrentArea, boolean way,
1063: int operation) {
1064:
1065: double[] temp = new double[8 * length];
1066: int coordsCount = 0;
1067: boolean isMoveIndex = true;
1068: boolean isMoveLength = true;
1069: boolean additional = false;
1070:
1071: if (length <= offset) {
1072: for (int i = resultRulesPos; i < resultRulesPos + 1; i++) {
1073: resultRules[i] = PathIterator.SEG_LINETO;
1074: }
1075: } else {
1076: int j = resultRulesPos;
1077: for (int i = offset; i < length; i++) {
1078: resultRules[j++] = PathIterator.SEG_LINETO;
1079: }
1080: }
1081:
1082: if ((length == offset)
1083: && ((rules[offset] == PathIterator.SEG_QUADTO) || (rules[offset] == PathIterator.SEG_CUBICTO))) {
1084: length++;
1085: additional = true;
1086: }
1087: for (int i = offset; i < length; i++) {
1088: int index = offsets[i];
1089:
1090: if (!isMoveIndex) {
1091: index -= 2;
1092: }
1093:
1094: if (!isMoveLength) {
1095: length++;
1096: isMoveLength = true;
1097: }
1098:
1099: switch (rules[i]) {
1100: case PathIterator.SEG_MOVETO:
1101: isMoveIndex = false;
1102: isMoveLength = false;
1103: break;
1104: case PathIterator.SEG_LINETO:
1105: case PathIterator.SEG_CLOSE:
1106: resultRules[resultRulesPos] = PathIterator.SEG_LINETO;
1107: resultOffsets[resultRulesPos++] = resultCoordPos + 2;
1108: boolean isLeft = CrossingHelper.compare(coords[index],
1109: coords[index + 1], point.getX(), point.getY()) > 0;
1110:
1111: if (way || !isLeft) {
1112: temp[coordsCount++] = coords[index];
1113: temp[coordsCount++] = coords[index + 1];
1114: }
1115: break;
1116: case PathIterator.SEG_QUADTO:
1117: resultRules[resultRulesPos] = PathIterator.SEG_QUADTO;
1118: resultOffsets[resultRulesPos++] = resultCoordPos + 4;
1119: double[] coefs = new double[] { coords[index - 2],
1120: coords[index - 1], coords[index],
1121: coords[index + 1], coords[index + 2],
1122: coords[index + 3] };
1123: isLeft = CrossingHelper.compare(coords[index - 2],
1124: coords[index - 1], point.getX(), point.getY()) > 0;
1125:
1126: if ((!additional) && (operation == 0 || operation == 2)) {
1127: isLeft = !isLeft;
1128: way = false;
1129: }
1130: GeometryUtil.subQuad(coefs, point
1131: .getParam(isCurrentArea), isLeft);
1132:
1133: if (way || isLeft) {
1134: temp[coordsCount++] = coefs[2];
1135: temp[coordsCount++] = coefs[3];
1136: } else {
1137: System.arraycopy(coefs, 2, temp, coordsCount, 4);
1138: coordsCount += 4;
1139: }
1140: break;
1141: case PathIterator.SEG_CUBICTO:
1142: resultRules[resultRulesPos] = PathIterator.SEG_CUBICTO;
1143: resultOffsets[resultRulesPos++] = resultCoordPos + 6;
1144: coefs = new double[] { coords[index - 2],
1145: coords[index - 1], coords[index],
1146: coords[index + 1], coords[index + 2],
1147: coords[index + 3], coords[index + 4],
1148: coords[index + 5] };
1149: isLeft = CrossingHelper.compare(coords[index - 2],
1150: coords[index - 1], point.getX(), point.getY()) > 0;
1151: GeometryUtil.subCubic(coefs, point
1152: .getParam(isCurrentArea), !isLeft);
1153:
1154: if (isLeft) {
1155: System.arraycopy(coefs, 2, temp, coordsCount, 6);
1156: coordsCount += 6;
1157: } else {
1158: System.arraycopy(coefs, 2, temp, coordsCount, 4);
1159: coordsCount += 4;
1160: }
1161: break;
1162: }
1163: }
1164:
1165: if (operation == 2 && !isCurrentArea && coordsCount > 2) {
1166: reverseCopy(temp);
1167: System.arraycopy(temp, 0, resultCoords, resultCoordPos,
1168: coordsCount);
1169: } else {
1170: System.arraycopy(temp, 0, resultCoords, resultCoordPos,
1171: coordsCount);
1172: }
1173:
1174: return (resultCoordPos + coordsCount);
1175: }
1176:
1177: // the method check up the array size and necessarily increases it.
1178: private static double[] adjustSize(double[] array, int newSize) {
1179: if (newSize <= array.length) {
1180: return array;
1181: }
1182: double[] newArray = new double[2 * newSize];
1183: System.arraycopy(array, 0, newArray, 0, array.length);
1184: return newArray;
1185: }
1186:
1187: private static int[] adjustSize(int[] array, int newSize) {
1188: if (newSize <= array.length) {
1189: return array;
1190: }
1191: int[] newArray = new int[2 * newSize];
1192: System.arraycopy(array, 0, newArray, 0, array.length);
1193: return newArray;
1194: }
1195:
1196: private void copy(Area src, Area dst) {
1197: dst.coordsSize = src.coordsSize;
1198: dst.coords = src.coords.clone();
1199: dst.rulesSize = src.rulesSize;
1200: dst.rules = src.rules.clone();
1201: dst.moveToCount = src.moveToCount;
1202: dst.offsets = src.offsets.clone();
1203: }
1204:
1205: private int containsExact(double x, double y) {
1206: PathIterator pi = getPathIterator(null);
1207: int crossCount = Crossing.crossPath(pi, x, y);
1208:
1209: if (Crossing.isInsideEvenOdd(crossCount)) {
1210: return 1;
1211: }
1212:
1213: double[] segmentCoords = new double[6];
1214: double[] resultPoints = new double[6];
1215: int rule;
1216: double curX = -1;
1217: double curY = -1;
1218: double moveX = -1;
1219: double moveY = -1;
1220:
1221: for (pi = getPathIterator(null); !pi.isDone(); pi.next()) {
1222: rule = pi.currentSegment(segmentCoords);
1223: switch (rule) {
1224: case PathIterator.SEG_MOVETO:
1225: moveX = curX = segmentCoords[0];
1226: moveY = curY = segmentCoords[1];
1227: break;
1228: case PathIterator.SEG_LINETO:
1229: if (GeometryUtil.intersectLines(curX, curY,
1230: segmentCoords[0], segmentCoords[1], x, y, x, y,
1231: resultPoints) != 0) {
1232: return 0;
1233: }
1234: curX = segmentCoords[0];
1235: curY = segmentCoords[1];
1236: break;
1237: case PathIterator.SEG_QUADTO:
1238: if (GeometryUtil.intersectLineAndQuad(x, y, x, y, curX,
1239: curY, segmentCoords[0], segmentCoords[1],
1240: segmentCoords[2], segmentCoords[3],
1241: resultPoints) > 0) {
1242: return 0;
1243: }
1244: curX = segmentCoords[2];
1245: curY = segmentCoords[3];
1246: break;
1247: case PathIterator.SEG_CUBICTO:
1248: if (GeometryUtil.intersectLineAndCubic(x, y, x, y,
1249: curX, curY, segmentCoords[0], segmentCoords[1],
1250: segmentCoords[2], segmentCoords[3],
1251: segmentCoords[4], segmentCoords[5],
1252: resultPoints) > 0) {
1253: return 0;
1254: }
1255: curX = segmentCoords[4];
1256: curY = segmentCoords[5];
1257: break;
1258: case PathIterator.SEG_CLOSE:
1259: if (GeometryUtil.intersectLines(curX, curY, moveX,
1260: moveY, x, y, x, y, resultPoints) != 0) {
1261: return 0;
1262: }
1263: curX = moveX;
1264: curY = moveY;
1265: break;
1266: }
1267: }
1268: return -1;
1269: }
1270:
1271: private void reverseCopy(double[] coords) {
1272: double[] temp = new double[coords.length];
1273: System.arraycopy(coords, 0, temp, 0, coords.length);
1274:
1275: for (int i = 0; i < coords.length;) {
1276: coords[i] = temp[coords.length - i - 2];
1277: coords[i + 1] = temp[coords.length - i - 1];
1278: i = i + 2;
1279: }
1280: }
1281:
1282: private double getAreaBoundsSquare() {
1283: Rectangle2D bounds = getBounds2D();
1284: return bounds.getHeight() * bounds.getWidth();
1285: }
1286:
1287: private boolean isVertex(double x, double y) {
1288: for (int i = 0; i < coordsSize;) {
1289: if (x == coords[i++] && y == coords[i++]) {
1290: return true;
1291: }
1292: }
1293: return false;
1294: }
1295:
1296: // the internal class implements PathIterator
1297: private class AreaPathIterator implements PathIterator {
1298:
1299: AffineTransform transform;
1300: Area area;
1301: int curRuleIndex = 0;
1302: int curCoordIndex = 0;
1303:
1304: AreaPathIterator(Area area) {
1305: this (area, null);
1306: }
1307:
1308: AreaPathIterator(Area area, AffineTransform t) {
1309: this .area = area;
1310: this .transform = t;
1311: }
1312:
1313: public int getWindingRule() {
1314: return WIND_EVEN_ODD;
1315: }
1316:
1317: public boolean isDone() {
1318: return curRuleIndex >= rulesSize;
1319: }
1320:
1321: public void next() {
1322: switch (rules[curRuleIndex]) {
1323: case PathIterator.SEG_MOVETO:
1324: case PathIterator.SEG_LINETO:
1325: curCoordIndex += 2;
1326: break;
1327: case PathIterator.SEG_QUADTO:
1328: curCoordIndex += 4;
1329: break;
1330: case PathIterator.SEG_CUBICTO:
1331: curCoordIndex += 6;
1332: break;
1333: }
1334: curRuleIndex++;
1335: }
1336:
1337: public int currentSegment(double[] c) {
1338: if (isDone()) {
1339: throw new NoSuchElementException(Messages
1340: .getString("awt.4B")); //$NON-NLS-1$
1341: }
1342:
1343: int count = 0;
1344:
1345: switch (rules[curRuleIndex]) {
1346: case PathIterator.SEG_CUBICTO:
1347: c[4] = coords[curCoordIndex + 4];
1348: c[5] = coords[curCoordIndex + 5];
1349: count = 1;
1350: case PathIterator.SEG_QUADTO:
1351: c[2] = coords[curCoordIndex + 2];
1352: c[3] = coords[curCoordIndex + 3];
1353: count += 1;
1354: case PathIterator.SEG_MOVETO:
1355: case PathIterator.SEG_LINETO:
1356: c[0] = coords[curCoordIndex];
1357: c[1] = coords[curCoordIndex + 1];
1358: count += 1;
1359: }
1360:
1361: if (transform != null) {
1362: transform.transform(c, 0, c, 0, count);
1363: }
1364:
1365: return rules[curRuleIndex];
1366: }
1367:
1368: public int currentSegment(float[] c) {
1369: double[] doubleCoords = new double[6];
1370: int rule = currentSegment(doubleCoords);
1371:
1372: for (int i = 0; i < 6; i++) {
1373: c[i] = (float) doubleCoords[i];
1374: }
1375: return rule;
1376: }
1377: }
1378: }
|