/*
* 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.geom;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class CrossingHelper {
private double[][] coords;
private int[] sizes;
private List<IntersectPoint> isectPoints = new ArrayList<IntersectPoint>();
public CrossingHelper(double[][] coords, int[] sizes) {
this.coords = coords;
this.sizes = sizes;
}
public IntersectPoint[] findCrossing() {
int pointCount1 = sizes[0] / 2;
int pointCount2 = sizes[1] / 2;
int[] indices = new int[pointCount1 + pointCount2];
for(int i = 0; i < pointCount1 + pointCount2; i++) {
indices[i] = i;
}
sort(coords[0], pointCount1, coords[1], pointCount2, indices);
// the set for the shapes edges storing
List<Edge> edges = new ArrayList<Edge>();
Edge edge;
int begIndex, endIndex;
int areaNumber;
for (int i = 0; i < indices.length; i++) {
if (indices[i] < pointCount1) {
begIndex = indices[i];
endIndex = indices[i] - 1;
if (endIndex < 0) {
endIndex = pointCount1 - 1;
}
areaNumber = 0;
} else if (indices[i] < pointCount1 + pointCount2) {
begIndex = indices[i] - pointCount1;
endIndex = indices[i] - 1 - pointCount1;
if (endIndex < 0) {
endIndex = pointCount2 - 1;
}
areaNumber = 1;
} else {
throw new IndexOutOfBoundsException();
}
if (!removeEdge(edges, begIndex, endIndex)) {
edge = new Edge(begIndex, endIndex, areaNumber);
intersectShape(edges, coords[0], pointCount1,
coords[1], pointCount2, edge);
edges.add(edge);
}
begIndex = indices[i];
endIndex = indices[i] + 1;
if ((begIndex < pointCount1) && (endIndex == pointCount1)) {
endIndex = 0;
} else if ((begIndex >= pointCount1) &&
(endIndex == (pointCount2 + pointCount1))) {
endIndex = pointCount1;
}
if (endIndex < pointCount1) {
areaNumber = 0;
} else {
areaNumber = 1;
endIndex -= pointCount1;
begIndex -= pointCount1;
}
if (!removeEdge(edges, begIndex, endIndex)) {
edge = new Edge(begIndex, endIndex, areaNumber);
intersectShape(edges, coords[0], pointCount1,
coords[1], pointCount2, edge);
edges.add(edge);
}
}
return isectPoints.toArray(new IntersectPoint[isectPoints.size()]);
}
private boolean removeEdge(List<Edge> edges, int begIndex, int endIndex) {
for (Edge edge : edges) {
if (edge.reverseCompare(begIndex, endIndex)) {
edges.remove(edge);
return true;
}
}
return false;
}
// return the quantity of intersect points
private void intersectShape(List<Edge> edges,
double[] coords1, int length1,
double[] coords2, int length2,
Edge initEdge) {
int areaOfEdge1, areaOfEdge2;
int initBegin, initEnd;
int addBegin, addEnd;
double x1, y1, x2, y2, x3, y3, x4, y4;
double[] point = new double[2];
Edge edge;
if (initEdge.areaNumber == 0) {
x1 = coords1[2* initEdge.begIndex];
y1 = coords1[2* initEdge.begIndex + 1];
x2 = coords1[2* initEdge.endIndex];
y2 = coords1[2* initEdge.endIndex + 1];
areaOfEdge1 = 0;
} else {
x1 = coords2[2* initEdge.begIndex];
y1 = coords2[2* initEdge.begIndex + 1];
x2 = coords2[2* initEdge.endIndex];
y2 = coords2[2* initEdge.endIndex + 1];
areaOfEdge1 = 1;
}
for (Iterator<Edge> iter = edges.iterator(); iter.hasNext(); ) {
edge = iter.next();
if (edge.areaNumber == 0) {
x3 = coords1[2* edge.begIndex];
y3 = coords1[2* edge.begIndex + 1];
x4 = coords1[2* edge.endIndex];
y4 = coords1[2* edge.endIndex + 1];
areaOfEdge2 = 0;
} else {
x3 = coords2[2* edge.begIndex];
y3 = coords2[2* edge.begIndex + 1];
x4 = coords2[2* edge.endIndex];
y4 = coords2[2* edge.endIndex + 1];
areaOfEdge2 = 1;
}
if ((areaOfEdge1 != areaOfEdge2) &&
(GeometryUtil.intersectLines(
x1, y1, x2, y2, x3, y3, x4, y4, point) == 1) &&
(!containsPoint(point))) {
if (initEdge.areaNumber == 0) {
initBegin = initEdge.begIndex;
initEnd = initEdge.endIndex;
addBegin = edge.begIndex;
addEnd = edge.endIndex;
} else {
initBegin = edge.begIndex;
initEnd = edge.endIndex;
addBegin = initEdge.begIndex;
addEnd = initEdge.endIndex;
}
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;
for (Iterator<IntersectPoint> i = isectPoints.iterator(); i.hasNext(); ) {
ip = i.next();
if ((initBegin == ip.getBegIndex(true)) &&
(initEnd == ip.getEndIndex(true))) {
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.getBegIndex(false)) &&
(addEnd == ip.getEndIndex(false))) {
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]));
}
}
}
// the array sorting
private static void sort(double[] coords1, int length1,
double[] coords2, int length2,
int[] array) {
int temp;
int length = length1 + length2;
double x1, y1, x2, y2;
for (int i = 1; i < length; i++) {
if (array[i-1] < length1) {
x1 = coords1[2*array[i-1]];
y1 = coords1[2*array[i-1] + 1];
} else {
x1 = coords2[2*(array[i-1] - length1)];
y1 = coords2[2*(array[i-1] - length1) + 1];
}
if (array[i] < length1) {
x2 = coords1[2*array[i]];
y2 = coords1[2*array[i] + 1];
} else {
x2 = coords2[2*(array[i] - length1)];
y2 = coords2[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 = coords1[2*array[j-1]];
y1 = coords1[2*array[j-1] + 1];
} else {
x1 = coords2[2*(array[j-1] - length1)];
y1 = coords2[2*(array[j-1] - length1) + 1];
}
if (array[j] < length1) {
x2 = coords1[2*array[j]];
y2 = coords1[2*array[j] + 1];
} else {
x2 = coords2[2*(array[j] - length1)];
y2 = coords2[2*(array[j] - length1) + 1];
}
}
}
}
}
public boolean containsPoint(double[] point) {
IntersectPoint ipoint;
for (Iterator<IntersectPoint> i = isectPoints.iterator(); i.hasNext(); ) {
ipoint = i.next();
if (ipoint.getX() == point[0] && ipoint.getY() == point[1]) {
return true;
}
}
return false;
}
public static int compare(double x1, double y1, double x2, double y2) {
if ((x1 < x2) || (x1 == x2 && y1 < y2)) {
return 1;
} else if (x1 == x2 && y1 == y2) {
return 0;
}
return -1;
}
private static final class Edge {
final int begIndex;
final int endIndex;
final int areaNumber;
Edge(int begIndex, int endIndex, int areaNumber) {
this.begIndex = begIndex;
this.endIndex = endIndex;
this.areaNumber = areaNumber;
}
boolean reverseCompare (int begIndex, int endIndex) {
return this.begIndex == endIndex && this.endIndex == begIndex;
}
}
}