Index: src/main/java/common/java/awt/geom/Area.java =================================================================== --- src/main/java/common/java/awt/geom/Area.java (revision 524085) +++ src/main/java/common/java/awt/geom/Area.java (working copy) @@ -14,56 +14,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/** - * @author Denis M. Kishenko - * @version $Revision$ - */ package java.awt.geom; import java.awt.Rectangle; import java.awt.Shape; -import java.awt.geom.PathIterator; -import java.awt.geom.Rectangle2D; +import java.util.List; import java.util.NoSuchElementException; +import org.apache.harmony.awt.gl.Crossing; +import org.apache.harmony.awt.internal.CrossingHelper; +import org.apache.harmony.awt.internal.IntersectPoint; import org.apache.harmony.awt.internal.nls.Messages; + public class Area implements Shape, Cloneable { + // the coordinates array of the shape vertices + private double coords[] = new double[50]; + // the rules array for the drawing of the shape edges + private int rules[] = new int[25]; + // the coordinates quantity + private int coordsSize = 0; + // the rules quantity + private int rulesSize = 0; + // the quantity of MOVETO rule occurences + private int moveToCount = 0; - /** - * The source Shape object - */ - Shape s; - - private static class NullIterator implements PathIterator { - - NullIterator() { - } - - public int getWindingRule() { - return WIND_NON_ZERO; - } - - public boolean isDone() { - return true; - } - - public void next() { - // nothing - } - - public int currentSegment(double[] coords) { - // awt.4B=Iterator out of bounds - throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ - } - - public int currentSegment(float[] coords) { - // awt.4B=Iterator out of bounds - throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ - } - - } - + public Area() { } @@ -71,142 +47,645 @@ if (s == null) { throw new NullPointerException(); } - this.s = s; + double temp[] = new double[6]; + double lastMoveX = 0.0, lastMoveY = 0.0; + for (PathIterator pi = s.getPathIterator(null); !pi.isDone(); pi.next()) { + coords = checkSize(coords, coordsSize + 6); + rules = checkSize(rules, rulesSize + 1); + rules[rulesSize] = pi.currentSegment(temp); + switch (rules[rulesSize]) { + case PathIterator.SEG_MOVETO: + coords[coordsSize++] = temp[0]; + coords[coordsSize++] = temp[1]; + lastMoveX = temp[0]; + lastMoveY = temp[1]; + moveToCount++; + break; + case PathIterator.SEG_LINETO: + if (temp[0] != lastMoveX || temp[1] != lastMoveY) { + coords[coordsSize++] = temp[0]; + coords[coordsSize++] = temp[1]; + } else { + --rulesSize; + } + break; + case PathIterator.SEG_QUADTO: + System.arraycopy(temp, 0, coords, coordsSize, 4); + coordsSize += 4; + break; + case PathIterator.SEG_CUBICTO: + System.arraycopy(temp, 0, coords, coordsSize, 6); + coordsSize += 6; + break; + case PathIterator.SEG_CLOSE: + break; + } + ++rulesSize; + } + if (rulesSize != 0 && rules[rulesSize - 1] != PathIterator.SEG_CLOSE) { + rules[rulesSize] = PathIterator.SEG_CLOSE; + } } + // return true if the area interior contains the point (x, y) public boolean contains(double x, double y) { - return s == null ? false : s.contains(x, y); + if(isEmpty()) { + return false; + } + int crossCount = Crossing.crossPath(getPathIterator(null), x, y); + return Crossing.isInsideEvenOdd(crossCount); } + // return true if the area interior contains the rectangle + // Rectangle2D.Double(x, y, width, height) public boolean contains(double x, double y, double width, double height) { - return s == null ? false : s.contains(x, y, width, height); + int crossCount = Crossing.intersectPath(getPathIterator(null), x, y, width, height); + return crossCount != Crossing.CROSSING && Crossing.isInsideEvenOdd(crossCount); } + // return true if the area interior contains the point p public boolean contains(Point2D p) { - if (p == null) { - throw new NullPointerException(); - } - return s == null ? false : s.contains(p); + return contains(p.getX(), p.getY()); } + // return true if the area interior contains the rectangle r. public boolean contains(Rectangle2D r) { - if (r == null) { - throw new NullPointerException(); - } - return s == null ? false : s.contains(r); + return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } - public boolean equals(Area obj) throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public PathIterator getPathIterator(AffineTransform t) { + return new AreaPathIterator(this, t); } + public boolean equals(Area obj) { + if (this == obj) { + return true; + } + + if (rulesSize != obj.rulesSize || coordsSize != obj.coordsSize) { + return false; + } + for (int i = 0; i < rulesSize; i++) { + if (rules[i] != obj.rules[i]) { + return false; + } + } + for (int i = 0; i < coordsSize; i++) { + if (coords[i] != obj.coords[i]) { + return false; + } + } + + return true; + } + public boolean intersects(double x, double y, double width, double height) { - return s == null ? false : s.intersects(x, y, width, height); + return getBounds2D().intersects(new Rectangle2D.Double(x, y, width, height)); } public boolean intersects(Rectangle2D r) { - if (r == null) { - throw new NullPointerException(); - } - return s == null ? false : s.intersects(r); + return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } public Rectangle getBounds() { - return s == null ? new Rectangle() : s.getBounds(); + return getBounds2D().getBounds(); } public Rectangle2D getBounds2D() { - return s == null ? new Rectangle2D.Double(): s.getBounds2D(); - } + double maxX = coords[0]; + double maxY = coords[1]; + double minX = coords[0]; + double minY = coords[1]; - public PathIterator getPathIterator(AffineTransform t) { - return s == null ? new NullIterator() : s.getPathIterator(t); + for (int i = 0; i < coordsSize; i++) { + if (i % 2 == 0) { + if (minX > coords[i]) { + minX = coords[i]; + } + if (maxX < coords[i]) { + maxX = coords[i]; + } + } else { + if (minY > coords[i]) { + minY = coords[i]; + } + if (maxY < coords[i]) { + maxY = coords[i]; + } + } + + } + return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY); } public PathIterator getPathIterator(AffineTransform t, double flatness) { - return s == null ? new NullIterator() : s.getPathIterator(t, flatness); + return new FlatteningPathIterator(getPathIterator(t), flatness); } - public void add(Area area) throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public void add(Area area) { + CrossingHelper crossHelper = new CrossingHelper(); + crossHelper.add(coords, coordsSize); + crossHelper.add(area.coords, area.coordsSize); + List intersectPoints = crossHelper.findCrossing(); + + // check up if one figure lies inside into another or two figures don't intersect + if (intersectPoints.size() == 0) { + if (area.contains(getBounds2D())) { + coords = area.coords; + rules = area.rules; + coordsSize = area.coordsSize; + rulesSize = area.rulesSize; + } else if (!contains(area.getBounds2D())) { + double[] addCoords = area.coords; + coords = checkSize(coords, coordsSize + area.coordsSize); + for (int i = 0; i < area.coordsSize; i++) { + coords[coordsSize++] = addCoords[i]; + } + rules = checkSize(rules, rulesSize + area.rulesSize); + int[] addRules = area.rules; + for (int i = 0; i < area.rulesSize; i++) { + rules[rulesSize++] = addRules[i]; + } + } + return; + } + int isectIndex = -1; + int index1 = -1; + int index2 = -1; + int areaNumber = 0; + double[] resultCoords = new double[coordsSize + area.coordsSize]; + int[] resultRules = new int[rulesSize + area.rulesSize]; + int resultCurPos = 0; + int resultRulesCount = 0; + resultRules[resultRulesCount++] = PathIterator.SEG_MOVETO; + do { + int end = intersectPoints.get(Math.abs(isectIndex)-1).getEndIndex1(); + if (end < 0) { + if (areaNumber == 0) { + areaNumber = 1; + } else { + areaNumber = 0; + } + } else if (area.contains(coords[2*end], coords[2*end+1])) { // 4 variants + areaNumber = 1; + } else { + areaNumber = 0; + } + index1 = end; + index2 = intersectPoints.get(Math.abs(isectIndex)-1).getEndIndex2(); + resultCoords[resultCurPos++] = intersectPoints.get(Math.abs(isectIndex)-1).getX(); + resultCoords[resultCurPos++] = intersectPoints.get(Math.abs(isectIndex)-1).getY(); + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + if (areaNumber == 0) { + while (index1 >= 0 && index1 < coordsSize/2) { + resultCoords[resultCurPos++] = coords[2*index1]; + resultCoords[resultCurPos++] = coords[2*index1+1]; + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + ++index1; + if (index1 == coordsSize/2) { + index1 = 0; + } + for (int k = intersectPoints.size() - 1; k > -1; k--) { + if ((intersectPoints.get(k).getEndIndex1() < 0 && + intersectPoints.get(k).getBegIndex1() == index1 - 1) || + (intersectPoints.get(k).getEndIndex1() == index1)) { + index1 = -(k + 1); + isectIndex = -(k + 1); + break; + } + } + index2 = isectIndex; + } + } else { + while (index2 >= 0 && index2 < area.coordsSize/2) { + resultCoords[resultCurPos++] = area.coords[2*index2]; + resultCoords[resultCurPos++] = area.coords[2*index2+1]; + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + ++index2; + if (index2 == area.coordsSize/2) { + index2 = 0; + } + for (int k = intersectPoints.size() - 1; k > -1; k--) { + if ((intersectPoints.get(k).getEndIndex2() < 0 && + intersectPoints.get(k).getBegIndex2() == (index2 - 1)) || + (intersectPoints.get(k).getEndIndex2() == index2)) { + index2 = -(k + 1); + isectIndex = -(k + 1); + break; + } + } + index1 = isectIndex; + } + } + } while (index1 != -1 && index2 != -1); + + resultRules[resultRulesCount - 1] = PathIterator.SEG_CLOSE; + coords = checkSize(coords, resultCoords.length + 1); + rules = checkSize(rules, resultRules.length + 1); + this.coords = resultCoords; + this.rules = resultRules; + this.coordsSize = resultCurPos; + this.rulesSize = resultRulesCount; + return; } - public void exclusiveOr(Area area) throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public void exclusiveOr(Area area) { + Area a = (Area)clone(); + a.intersect(area); + add(area); + subtract(a); } /** * Extract Rectangle2D from the source shape - * @return a Rectangle2D object if the source shape is rectangle, or null if shape is empty or not rectangle. + * @return a Rectangle2D object if the source shape is rectangle, or null if shape is empty or not rectangle. */ - Rectangle2D extractRectangle() { - if (s == null) { - return null; - } - float[] points = new float[12]; - int count = 0; - PathIterator p = s.getPathIterator(null); - float[] coords = new float[6]; - while(!p.isDone()) { - int type = p.currentSegment(coords); - if (count > 12 || type == PathIterator.SEG_QUADTO || type == PathIterator.SEG_CUBICTO) { + private Rectangle2D extractRectangle() { + for (int i = 0; i < rulesSize; i++) { + if (rules[i] == PathIterator.SEG_CUBICTO || rules[i] == PathIterator.SEG_QUADTO) { return null; } - points[count++] = coords[0]; - points[count++] = coords[1]; - p.next(); } - if (points[0] == points[6] && points[6] == points[8] && points[2] == points[4] && - points[1] == points[3] && points[3] == points[9] && points[5] == points[7]) - { - return new Rectangle2D.Float(points[0], points[1], points[2] - points[0], points[7] - points[1]); + if ((coords[1] == coords[3]) && (coords[7] == coords[5]) && + (coords[0] == coords[6]) && (coords[2] == coords[4])) { + return new Rectangle2D.Double(coords[0], coords[1], + (coords[2] - coords[0]), (coords[5] - coords[3])); } return null; } - + public void intersect(Area area) { - Rectangle2D src1 = extractRectangle(); - Rectangle2D src2 = area.extractRectangle(); - if (src1 != null && src2 != null) { - Rectangle2D.intersect(src1, src2, (Rectangle2D)s); + CrossingHelper crossHelper = new CrossingHelper(); + crossHelper.add(coords, coordsSize); + crossHelper.add(area.coords, area.coordsSize); + List intersectPoints = crossHelper.findCrossing(); + + // check up if one figure lies inside into another or two figures don't intersect + if (intersectPoints.size() == 0) { + if (contains(area.getBounds2D())) { + coords = area.coords; + rules = area.rules; + coordsSize = area.coordsSize; + rulesSize = area.rulesSize; + } else if (!area.contains(getBounds2D())) { + reset(); + } + return; } + int isectIndex = -1; + int index1 = -1; + int index2 = -1; + int areaNumber = 0; + double[] resultCoords = new double[coordsSize + area.coordsSize]; + int[] resultRules = new int[rulesSize + area.rulesSize]; + int resultCurPos = 0; + int resultRulesCount = 0; + resultRules[resultRulesCount++] = PathIterator.SEG_MOVETO; + do { + int end = intersectPoints.get(Math.abs(isectIndex)-1).getEndIndex1(); + if (end < 0) { + if (areaNumber == 0) { + areaNumber = 1; + } else { + areaNumber = 0; + } + } else if (area.contains(coords[2*end], coords[2*end+1])) { // 4 variants + areaNumber = 0; + } else { + areaNumber = 1; + } + index1 = end; + index2 = intersectPoints.get(Math.abs(isectIndex)-1).getEndIndex2(); + resultCoords[resultCurPos++] = intersectPoints.get(Math.abs(isectIndex)-1).getX(); + resultCoords[resultCurPos++] = intersectPoints.get(Math.abs(isectIndex)-1).getY(); + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + if (areaNumber == 0) { + while (index1 >= 0 && index1 < coordsSize/2) { + resultCoords[resultCurPos++] = coords[2*index1]; + resultCoords[resultCurPos++] = coords[2*index1+1]; + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + ++index1; + if (index1 == coordsSize/2) { + index1 = 0; + } + for (int k = intersectPoints.size() - 1; k > -1; k--) { + if (intersectPoints.get(k).getEndIndex1() == index1) { + index1 = -(k + 1); + isectIndex = -(k + 1); + break; + } + } + index2 = isectIndex; + } + } else { + while (index2 >= 0 && index2 < area.coordsSize/2) { + resultCoords[resultCurPos++] = area.coords[2*index2]; + resultCoords[resultCurPos++] = area.coords[2*index2+1]; + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + ++index2; + if (index2 == area.coordsSize/2) { + index2 = 0; + } + for (int k = intersectPoints.size() - 1; k > -1; k--) { + if (intersectPoints.get(k).getEndIndex2() == index2) { + index2 = -(k + 1); + isectIndex = -(k + 1); + break; + } + } + index1 = isectIndex; + } + } + } while (index1 != -1 && index2 != -1); + + resultRules[resultRulesCount - 1] = PathIterator.SEG_CLOSE; + coords = checkSize(coords, resultCoords.length + 1); + rules = checkSize(rules, resultRules.length + 1); + this.coords = resultCoords; + this.rules = resultRules; + this.coordsSize = resultCurPos; + this.rulesSize = resultRulesCount; + return; + } - public void subtract(Area area) throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public void subtract(Area area) { + CrossingHelper crossHelper = new CrossingHelper(); + crossHelper.add(coords, coordsSize); + crossHelper.add(area.coords, area.coordsSize); + List intersectPoints = crossHelper.findCrossing(); + + // check up if one figure lies inside into another or two figures don't intersect !! + if (intersectPoints.size() == 0) { + if (contains(area.getBounds2D())) { + double[] addCoords = area.coords; + coords = checkSize(coords, coordsSize + area.coordsSize); + for (int i = 0; i < area.coordsSize; i++) { + coords[coordsSize++] = addCoords[i]; + } + rules = checkSize(rules, rulesSize + area.rulesSize); + int[] addRules = area.rules; + for (int i = 0; i < area.rulesSize; i++) { + rules[rulesSize++] = addRules[i]; + } + } + return; + } + int isectIndex = -1; + int index1 = -1; + int index2 = -1; + int areaNumber = 0; + double[] resultCoords = new double[coordsSize + area.coordsSize]; + int[] resultRules = new int[rulesSize + area.rulesSize]; + int resultCurPos = 0; + int resultRulesCount = 0; + resultRules[resultRulesCount++] = PathIterator.SEG_MOVETO; + do { + int end = intersectPoints.get(Math.abs(isectIndex)-1).getEndIndex1(); + if (end < 0) { + if (areaNumber == 0) { + areaNumber = 1; + } else { + areaNumber = 0; + } + } else if (area.contains(coords[2*end], coords[2*end+1])) { // 4 variants + areaNumber = 1; + } else { + areaNumber = 0; + } + index1 = end; + index2 = intersectPoints.get(Math.abs(isectIndex)-1).getBegIndex2(); + resultCoords[resultCurPos++] = intersectPoints.get(Math.abs(isectIndex)-1).getX(); + resultCoords[resultCurPos++] = intersectPoints.get(Math.abs(isectIndex)-1).getY(); + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + if (areaNumber == 0) { + while (index1 >= 0 && index1 < coordsSize/2) { + resultCoords[resultCurPos++] = coords[2*index1]; + resultCoords[resultCurPos++] = coords[2*index1+1]; + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + ++index1; + if (index1 == coordsSize/2) { + index1 = 0; + } + for (int k = intersectPoints.size() - 1; k > -1; k--) { + if ((intersectPoints.get(k).getEndIndex1() < 0 && + intersectPoints.get(k).getBegIndex1() == index1 - 1) || + (intersectPoints.get(k).getEndIndex1() == index1)) { + index1 = -(k + 1); + isectIndex = -(k + 1); + break; + } + } + index2 = isectIndex; + } + } else { + if (index2 < 0) { + isectIndex = index2; + index1 = isectIndex; + } + while (index2 >= 0 && index2 < area.coordsSize/2) { + resultCoords[resultCurPos++] = area.coords[2*index2]; + resultCoords[resultCurPos++] = area.coords[2*index2+1]; + resultRules[resultRulesCount++] = PathIterator.SEG_LINETO; + --index2; + if (index2 == -1) { + index2 = area.coordsSize/2 - 1; + } + for (int k = intersectPoints.size() - 1; k > -1; k--) { + if ((intersectPoints.get(k).getBegIndex2() < 0 && + intersectPoints.get(k).getEndIndex2() == index1 + 1) || + (intersectPoints.get(k).getBegIndex2() == index2)) { + index2 = -(k + 1); + isectIndex = -(k + 1); + break; + } + } + index1 = isectIndex; + } + } + } while (index1 != -1 && index2 != -1); + + resultRules[resultRulesCount - 1] = PathIterator.SEG_CLOSE; + coords = checkSize(coords, resultCoords.length + 1); + rules = checkSize(rules, resultRules.length + 1); + this.coords = resultCoords; + this.rules = resultRules; + this.coordsSize = resultCurPos; + this.rulesSize = resultRulesCount; + return; } - public boolean isEmpty() throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public boolean isEmpty() { + return rulesSize == 0 || coords.length == 0; } - public boolean isPolygonal() throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public boolean isPolygonal() { + if (isRectangular()) { + return true; + } + if (isSingular()) { + int count = 0; + for (int i = 0; i < rulesSize; i++) { + if (i == PathIterator.SEG_CUBICTO || i == PathIterator.SEG_QUADTO) { + break; + } + // ? + if (i == PathIterator.SEG_CLOSE) { + if (++count > 1) { + break; + } + } + } + } + return false; } - public boolean isRectangular() throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public boolean isRectangular() { + if (extractRectangle() != null) { + return true; + } + return false; } - public boolean isSingular() throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public boolean isSingular() { + if (moveToCount <= 1) { + return true; + } + return false; } - public void reset() throws org.apache.harmony.luni.util.NotImplementedException { - throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + public void reset() { + coordsSize = 0; + rulesSize = 0; + coords = new double[10]; + rules = new int[10]; } public void transform(AffineTransform t) { - s = t.createTransformedShape(s); + t.createTransformedShape(this); } public Area createTransformedArea(AffineTransform t) { - return s == null ? new Area() : new Area(t.createTransformedShape(s)); + Area a = (Area)clone(); + if (a != null) { + a.transform(t); + } + return a; } - @Override public Object clone() { return new Area(this); } -} + // twice increase array size + private static double[] checkSize(double[] array, int newSize) { + if (newSize < array.length) { + return array; + } + double[] newArray = new double[2*newSize]; + System.arraycopy(array, 0, newArray, 0, array.length); + return newArray; + } + + private static int[] checkSize(int[] array, int newSize) { + if (newSize < array.length) { + return array; + } + int[] newArray = new int[2*newSize]; + System.arraycopy(array, 0, newArray, 0, array.length); + return newArray; + } + + // internal class implemented PathIterator + private class AreaPathIterator implements PathIterator { + + AffineTransform t; + Area area; + + int currentRuleIndex = 0; + int currentCoordIndex = 0; + + int windingRule; + + + AreaPathIterator(Area area) { + this(area, null); + } + + AreaPathIterator(Area area, AffineTransform t) { + this.area = area; + this.t = t; + } + + public int getWindingRule() { + // TODO + return WIND_EVEN_ODD; + } + + public boolean isDone() { + return currentRuleIndex >= rulesSize; + } + + public void next() { + if (rules[currentRuleIndex] == PathIterator.SEG_MOVETO + || rules[currentRuleIndex] == PathIterator.SEG_LINETO) { + currentCoordIndex = currentCoordIndex + 2; + } + if (rules[currentRuleIndex] == PathIterator.SEG_QUADTO) { + currentCoordIndex = currentCoordIndex + 4; + } + if (rules[currentRuleIndex] == PathIterator.SEG_CUBICTO) { + currentCoordIndex = currentCoordIndex + 6; + } + currentRuleIndex++; + } + + public int currentSegment(double[] c) { + if (isDone()) { + throw new NoSuchElementException(Messages.getString("awt.4B")); + } + if (rules[currentRuleIndex] == PathIterator.SEG_MOVETO + || rules[currentRuleIndex] == PathIterator.SEG_LINETO) { + c[0] = coords[currentCoordIndex]; + c[1] = coords[currentCoordIndex+1]; + } else if (rules[currentRuleIndex] == PathIterator.SEG_QUADTO) { + c[0] = coords[currentCoordIndex]; + c[1] = coords[currentCoordIndex+1]; + c[2] = coords[currentCoordIndex+2]; + c[3] = coords[currentCoordIndex+3]; + } else if (rules[currentRuleIndex] == PathIterator.SEG_CUBICTO) { + c[0] = coords[currentCoordIndex]; + c[1] = coords[currentCoordIndex+1]; + c[2] = coords[currentCoordIndex+2]; + c[3] = coords[currentCoordIndex+3]; + c[4] = coords[currentCoordIndex+4]; + c[5] = coords[currentCoordIndex+5]; + } + return rules[currentRuleIndex]; + } + + public int currentSegment(float[] c) { + if (isDone()) { + throw new NoSuchElementException(Messages.getString("awt.4B")); + } + if (rules[currentRuleIndex] == PathIterator.SEG_MOVETO + || rules[currentRuleIndex] == PathIterator.SEG_LINETO) { + c[0] = (float)coords[currentCoordIndex]; + c[1] = (float)coords[currentCoordIndex+1]; + } else if (rules[currentRuleIndex] == PathIterator.SEG_QUADTO) { + c[0] = (float)coords[currentCoordIndex]; + c[1] = (float)coords[currentCoordIndex+1]; + c[2] = (float)coords[currentCoordIndex+2]; + c[3] = (float)coords[currentCoordIndex+3]; + } else if (rules[currentRuleIndex] == PathIterator.SEG_CUBICTO) { + c[0] = (float)coords[currentCoordIndex]; + c[1] = (float)coords[currentCoordIndex+1]; + c[2] = (float)coords[currentCoordIndex+2]; + c[3] = (float)coords[currentCoordIndex+3]; + c[4] = (float)coords[currentCoordIndex+4]; + c[5] = (float)coords[currentCoordIndex+5]; + } + return rules[currentRuleIndex]; + } + } +} \ No newline at end of file Index: src/main/java/common/org/apache/harmony/awt/internal/Edge.java =================================================================== --- src/main/java/common/org/apache/harmony/awt/internal/Edge.java (revision 0) +++ src/main/java/common/org/apache/harmony/awt/internal/Edge.java (revision 0) @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.awt.internal; + + +// the class represents the edge of shape +public class Edge { + + private int begIndex; + private int endIndex; + private int areaNumber; + + public Edge (int begIndex, int endIndex, int areaNumber) { + this.begIndex = begIndex; + this.endIndex = endIndex; + this.areaNumber = areaNumber; + } + + public int getBegIndex () { + return begIndex; + } + + public int getEndIndex () { + return endIndex; + } + + public int getAreaNumber () { + return areaNumber; + } + + public boolean reverseCompare (int begIndex, int endIndex) { + return this.begIndex == endIndex && this.endIndex == begIndex; + } +} Index: src/main/java/common/org/apache/harmony/awt/internal/CrossingHelper.java =================================================================== --- src/main/java/common/org/apache/harmony/awt/internal/CrossingHelper.java (revision 0) +++ src/main/java/common/org/apache/harmony/awt/internal/CrossingHelper.java (revision 0) @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.awt.internal; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + + +public class CrossingHelper { + private final double epsilon = Math.pow(10, -15); + + private List coords = new ArrayList(); + private List sizes = new ArrayList(); + List isectPoints = new ArrayList(); + + public void add(double[] coords, int size) { + this.coords.add(coords); + this.sizes.add(new Integer(size)); + } + + public List findCrossing() { + int length1 = sizes.get(0).intValue()/2; + int length2 = sizes.get(1).intValue()/2; + int[] index = new int[length2 + length1]; + + for(int i = 0; i < length1 + length2; i++) { + index[i] = i; + } + sort(length1, length2, index, coords.get(0), coords.get(1)); + // the set for the shapes edges storing + List edges = new ArrayList(); + + for (int i = 0; i < index.length; i++) { + Edge edge = null; + int begIndex = index[i]; + int endIndex = begIndex - 1; + int areaNumber; + if (begIndex < length1 && endIndex < 0) { + endIndex = length1 - 1; + } else if (begIndex >= length1 && endIndex < length1) { + endIndex = length2 + length1 - 1; + } + if (endIndex < length1) { + areaNumber = 0; + } else { + areaNumber = 1; + endIndex -= length1; + begIndex -= length1; + } + if ((edge = addEdge(edges, begIndex, endIndex, areaNumber)) != null) { + intersectShape(edges, coords.get(0), coords.get(1), edge, length1, length2); + edges.add(edge); + } + begIndex = index[i]; + endIndex = begIndex + 1; + if (begIndex < length1 && endIndex == length1) { + endIndex = 0; + } else if (begIndex >= length1 && endIndex == (length2 + length1)) { + endIndex = length1; + } + if (endIndex < length1) { + areaNumber = 0; + } else { + areaNumber = 1; + endIndex -= length1; + begIndex -= length1; + } + if ((edge = addEdge(edges, begIndex, endIndex, areaNumber)) != null) { + intersectShape(edges, coords.get(0), coords.get(1), edge, length1, length2); + edges.add(edge); + } + } + return isectPoints; + } + + private Edge addEdge (List edges, + int begin, int end, int areaNumber) { + boolean add = true; + Edge edge = null; + for (Iterator iter = edges.iterator(); iter.hasNext();) { + edge = (Edge)iter.next(); + if (edge.reverseCompare(begin, end)) { + edges.remove(edge); + add = false; + break; + } + } + if (add) { + Edge addEdge = new Edge(begin, end, areaNumber); + return addEdge; + } + return null; + } + + // return the quantity of intersect points + private int intersectShape(List edges, + double[] coords, double[] coords1, Edge initEdge, + int length1, int length2) { + int areaOfEdge1, areaOfEdge2; + double x1, y1, x2, y2, x3, y3, x4, y4; + double[] point = new double[2]; + Edge edge = null; + + if (initEdge.getAreaNumber() == 0) { + x1 = coords[2*initEdge.getBegIndex()]; + y1 = coords[2*initEdge.getBegIndex() + 1]; + x2 = coords[2*initEdge.getEndIndex()]; + y2 = coords[2*initEdge.getEndIndex() + 1]; + areaOfEdge1 = 0; + } else { + x1 = coords1[2*initEdge.getBegIndex()]; + y1 = coords1[2*initEdge.getBegIndex() + 1]; + x2 = coords1[2*initEdge.getEndIndex()]; + y2 = coords1[2*initEdge.getEndIndex() + 1]; + areaOfEdge1 = 1; + } + + for (Iterator iter = edges.iterator(); iter.hasNext(); ) { + edge = (Edge) iter.next(); + if (edge.getAreaNumber() == 0) { + x3 = coords[2*edge.getBegIndex()]; + y3 = coords[2*edge.getBegIndex() + 1]; + x4 = coords[2*edge.getEndIndex()]; + y4 = coords[2*edge.getEndIndex() + 1]; + areaOfEdge2 = 0; + } else { + x3 = coords1[2*edge.getBegIndex()]; + y3 = coords1[2*edge.getBegIndex() + 1]; + x4 = coords1[2*edge.getEndIndex()]; + y4 = coords1[2*edge.getEndIndex() + 1]; + areaOfEdge2 = 1; + } + if (intersectLines(x1, y1, x2, y2, x3, y3, x4, y4, areaOfEdge1, areaOfEdge2, point) && + !containsPoint(point)) { + int initBegin, initEnd; + int addBegin, addEnd; + if (initEdge.getAreaNumber() == 0) { + initBegin = initEdge.getBegIndex(); + initEnd = initEdge.getEndIndex(); + addBegin = edge.getBegIndex(); + addEnd = edge.getEndIndex(); + } else { + initBegin = edge.getBegIndex(); + initEnd = edge.getEndIndex(); + addBegin = initEdge.getBegIndex(); + addEnd = initEdge.getEndIndex(); + } + if ((initEnd == length1 - 1 && initBegin == 0 && initEnd > initBegin) || + ((initEnd != length1 - 1 || initBegin != 0) && (initBegin != length1 - 1 || + initEnd != 0) && initBegin > initEnd)) { + int temp = initBegin; + initBegin = initEnd; + initEnd = temp; + } + if ((addEnd == length2 - 1 && addBegin == 0 && addEnd > addBegin) || + ((addEnd != length2 - 1 || addBegin != 0) && (addBegin != length2 - 1 || + addEnd != 0) && addBegin > addEnd)) { + int temp = addBegin; + addBegin = addEnd; + addEnd = temp; + } + + IntersectPoint ip = null; + for (Iterator i = isectPoints.iterator(); i.hasNext(); ) { + ip = (IntersectPoint)i.next(); + if (initBegin == ip.getBegIndex1() && initEnd == ip.getEndIndex1()) { + if (compare(ip.getX(), ip.getY(), point[0], point[1]) > 0) { + initEnd = - (isectPoints.indexOf(ip) + 1); + ip.setBegIndex1(-(isectPoints.size() + 1)); + } else { + initBegin = - (isectPoints.indexOf(ip) + 1); + ip.setEndIndex1(-(isectPoints.size() + 1)); + } + } + if (addBegin == ip.getBegIndex2() && addEnd == ip.getEndIndex2()) { + if (compare(ip.getX(), ip.getY(), point[0], point[1]) > 0) { + addEnd = - (isectPoints.indexOf(ip) + 1); + ip.setBegIndex2(-(isectPoints.size() + 1)); + } else { + addBegin = - (isectPoints.indexOf(ip) + 1); + ip.setEndIndex2(-(isectPoints.size() + 1)); + } + } + } + isectPoints.add(new IntersectPoint(initBegin, initEnd, addBegin, addEnd, + point[0], point[1])); + } + } + return 0; // TODO + } + + private boolean intersectLines(double x1, double y1, double x2, double y2, + double x3, double y3, double x4, double y4, + int areaOfEdge1, int areaOfEdge2, + double[] point) { + + if (areaOfEdge1 == areaOfEdge2) { + return false; + } + + double A1 = -(y2 - y1); + double B1 = (x2 - x1); + double C1 = x1*y2 - x2*y1; + double A2 = -(y4 - y3); + double B2 = (x4 - x3); + double C2 = x3*y4 - x4*y3; + double coefParallel = A1*B2 - A2*B1; + // double comparison + if (Math.abs(coefParallel) < epsilon ) { + return false; + } + point[0] = (B1*C2 - B2*C1)/coefParallel; + point[1] = (A2*C1 - A1*C2)/coefParallel; + + if (((point[0] >= x1) && (point[0] >= x3) && (point[0] <= x2) && (point[0] <= x4) && + (point[1] >= y1) && (point[1] >= y3) && (point[1] <= y2) && (point[1] <= y4))) { + return true; + } + return false; + } + + // array sorting + private static void sort(int length1, int length2, int[] array, + double[] coords, double[] coords1) { + int temp; + int length = length1 + length2; + + for (int i = 1; i < length; i++) { + double x1, y1, x2, y2; + if (array[i-1] < length1) { + x1 = coords[2*array[i-1]]; + y1 = coords[2*array[i-1] + 1]; + } else { + x1 = coords1[2*(array[i-1] - length1)]; + y1 = coords1[2*(array[i-1] - length1) + 1]; + } + if (array[i] < length1) { + x2 = coords[2*array[i]]; + y2 = coords[2*array[i] + 1]; + } else { + x2 = coords1[2*(array[i] - length1)]; + y2 = coords1[2*(array[i] - length1) + 1]; + } + int j = i; + while (j > 0 && compare(x1, y1, x2, y2) < 0) { + temp = array[j]; + array[j] = array[j-1]; + array[j-1] = temp; + j--; + if (j > 0) { + if (array[j-1] < length1) { + x1 = coords[2*array[j-1]]; + y1 = coords[2*array[j-1] + 1]; + } else { + x1 = coords1[2*(array[j-1] - length1)]; + y1 = coords1[2*(array[j-1] - length1) + 1]; + } + if (array[j] < length1) { + x2 = coords[2*array[j]]; + y2 = coords[2*array[j] + 1]; + } else { + x2 = coords1[2*(array[j] - length1)]; + y2 = coords1[2*(array[j] - length1) + 1]; + } + } + } + } + } + + private boolean containsPoint(double[] point) { + IntersectPoint ipoint; + for (Iterator i = isectPoints.iterator(); i.hasNext(); ) { + ipoint = (IntersectPoint)i.next(); + if (ipoint.getX() == point[0] && ipoint.getY() == point[1]) { + return true; + } + } + return false; + } + + private static int compare(double x1, double y1, double x2, double y2) { + if ((x1 < x2) || (x1 == x2 && y1 <= y2)) { + return 1; + } + return -1; + } +} \ No newline at end of file Index: src/main/java/common/org/apache/harmony/awt/internal/IntersectPoint.java =================================================================== --- src/main/java/common/org/apache/harmony/awt/internal/IntersectPoint.java (revision 0) +++ src/main/java/common/org/apache/harmony/awt/internal/IntersectPoint.java (revision 0) @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.awt.internal; + + +// the class represents the intersect point of two lines +public class IntersectPoint { + // the edge begin number of first line + private int begIndex1; + // the edge end number of first line + private int endIndex1; + // the edge begin number of second line + private int begIndex2; + // the edge end number of second line + private int endIndex2; + // the absciss coordinate of the point + private double x; + // the ordinate coordinate of the point + private double y; + + public IntersectPoint (int begIndex1, int endIndex1, + int begIndex2, int endIndex2, + double x, double y) { + this.begIndex1 = begIndex1; + this.endIndex1 = endIndex1; + this.begIndex2 = begIndex2; + this.endIndex2 = endIndex2; + this.x = x; + this.y = y; + } + + public int getBegIndex1() { + return begIndex1; + } + + public void setBegIndex1(int begIndex) { + this.begIndex1 = begIndex; + } + + public int getEndIndex1() { + return endIndex1; + } + + public void setEndIndex1(int endIndex) { + this.endIndex1 = endIndex; + } + + public int getBegIndex2() { + return begIndex2; + } + + public void setBegIndex2(int begIndex) { + this.begIndex2 = begIndex; + } + + public int getEndIndex2() { + return endIndex2; + } + + public void setEndIndex2(int endIndex) { + this.endIndex2 = endIndex; + } + + public double getX() { + return x; + } + + public double getY() { + return y; + } +} \ No newline at end of file