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: package org.apache.harmony.awt.geom;
018:
019: import java.awt.geom.PathIterator;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.ArrayList;
023:
024: public class CurveCrossingHelper {
025: private double[][] coords;
026: private int[][] rules;
027: private int[] sizes;
028: private int[] rulesSizes;
029: private int[][] offsets;
030: private List<IntersectPoint> isectPoints = new ArrayList<IntersectPoint>();
031:
032: public CurveCrossingHelper(double[][] coords, int[] sizes,
033: int[][] rules, int[] rulesSizes, int[][] offsets) {
034: this .coords = coords;
035: this .rules = rules;
036: this .sizes = sizes;
037: this .rulesSizes = rulesSizes;
038: this .offsets = offsets;
039: }
040:
041: public IntersectPoint[] findCrossing() {
042: double[] edge1 = new double[8];
043: double[] edge2 = new double[8];
044: double[] points = new double[6];
045: double[] params = new double[6];
046: double[] mp1 = new double[2];
047: double[] cp1 = new double[2];
048: double[] mp2 = new double[2];
049: double[] cp2 = new double[2];
050: int rule1, rule2, endIndex1, endIndex2;
051: int ipCount = 0;
052:
053: for (int i = 0; i < rulesSizes[0]; i++) {
054: rule1 = rules[0][i];
055: endIndex1 = getCurrentEdge(0, i, edge1, mp1, cp1);
056: for (int j = 0; j < rulesSizes[1]; j++) {
057: ipCount = 0;
058: rule2 = rules[1][j];
059: endIndex2 = getCurrentEdge(1, j, edge2, mp2, cp2);
060: if (((rule1 == PathIterator.SEG_LINETO) || (rule1 == PathIterator.SEG_CLOSE))
061: && ((rule2 == PathIterator.SEG_LINETO) || (rule2 == PathIterator.SEG_CLOSE))) {
062:
063: ipCount = GeometryUtil.intersectLinesWithParams(
064: edge1[0], edge1[1], edge1[2], edge1[3],
065: edge2[0], edge2[1], edge2[2], edge2[3],
066: params);
067:
068: if (ipCount != 0) {
069: points[0] = GeometryUtil.line(params[0],
070: edge1[0], edge1[2]);
071: points[1] = GeometryUtil.line(params[0],
072: edge1[1], edge1[3]);
073: }
074: } else if (((rule1 == PathIterator.SEG_LINETO) || (rule1 == PathIterator.SEG_CLOSE))
075: && (rule2 == PathIterator.SEG_QUADTO)) {
076: ipCount = GeometryUtil.intersectLineAndQuad(
077: edge1[0], edge1[1], edge1[2], edge1[3],
078: edge2[0], edge2[1], edge2[2], edge2[3],
079: edge2[4], edge2[5], params);
080: for (int k = 0; k < ipCount; k++) {
081: points[2 * k] = GeometryUtil.line(
082: params[2 * k], edge1[0], edge1[2]);
083: points[2 * k + 1] = GeometryUtil.line(
084: params[2 * k], edge1[1], edge1[3]);
085: }
086: } else if (rule1 == PathIterator.SEG_QUADTO
087: && (rule2 == PathIterator.SEG_LINETO || rule2 == PathIterator.SEG_CLOSE)) {
088: ipCount = GeometryUtil.intersectLineAndQuad(
089: edge2[0], edge2[1], edge2[2], edge2[3],
090: edge1[0], edge1[1], edge1[2], edge1[3],
091: edge1[4], edge1[5], params);
092: for (int k = 0; k < ipCount; k++) {
093: points[2 * k] = GeometryUtil.line(
094: params[2 * k + 1], edge2[0], edge2[2]);
095: points[2 * k + 1] = GeometryUtil.line(
096: params[2 * k + 1], edge2[1], edge2[3]);
097: }
098: } else if ((rule1 == PathIterator.SEG_CUBICTO)
099: && ((rule2 == PathIterator.SEG_LINETO) || (rule2 == PathIterator.SEG_CLOSE))) {
100: ipCount = GeometryUtil.intersectLineAndCubic(
101: edge1[0], edge1[1], edge1[2], edge1[3],
102: edge1[4], edge1[5], edge1[6], edge1[7],
103: edge2[0], edge2[1], edge2[2], edge2[3],
104: params);
105:
106: for (int k = 0; k < ipCount; k++) {
107: points[2 * k] = GeometryUtil.line(
108: params[2 * k + 1], edge2[0], edge2[2]);
109: points[2 * k + 1] = GeometryUtil.line(
110: params[2 * k + 1], edge2[1], edge2[3]);
111: }
112: } else if (((rule1 == PathIterator.SEG_LINETO) || (rule1 == PathIterator.SEG_CLOSE))
113: && (rule2 == PathIterator.SEG_CUBICTO)) {
114: ipCount = GeometryUtil.intersectLineAndCubic(
115: edge1[0], edge1[1], edge1[2], edge1[3],
116: edge2[0], edge2[1], edge2[2], edge2[3],
117: edge2[4], edge2[5], edge2[6], edge2[7],
118: params);
119:
120: for (int k = 0; k < ipCount; k++) {
121: points[2 * k] = GeometryUtil.line(
122: params[2 * k], edge1[0], edge1[2]);
123: points[2 * k + 1] = GeometryUtil.line(
124: params[2 * k], edge1[1], edge1[3]);
125: }
126: } else if ((rule1 == PathIterator.SEG_QUADTO)
127: && (rule2 == PathIterator.SEG_QUADTO)) {
128: ipCount = GeometryUtil.intersectQuads(edge1[0],
129: edge1[1], edge1[2], edge1[3], edge1[4],
130: edge1[5], edge2[0], edge2[1], edge2[2],
131: edge2[3], edge2[4], edge2[5], params);
132: for (int k = 0; k < ipCount; k++) {
133: points[2 * k] = GeometryUtil.quad(
134: params[2 * k], edge1[0], edge1[2],
135: edge1[4]);
136: points[2 * k + 1] = GeometryUtil.quad(
137: params[2 * k], edge1[1], edge1[3],
138: edge1[5]);
139: }
140: } else if ((rule1 == PathIterator.SEG_QUADTO)
141: && (rule2 == PathIterator.SEG_CUBICTO)) {
142: ipCount = GeometryUtil.intersectQuadAndCubic(
143: edge1[0], edge1[1], edge1[2], edge1[3],
144: edge1[4], edge1[5], edge2[0], edge2[1],
145: edge2[2], edge2[3], edge2[4], edge2[5],
146: edge2[6], edge2[7], params);
147:
148: for (int k = 0; k < ipCount; k++) {
149: points[2 * k] = GeometryUtil.quad(
150: params[2 * k], edge1[0], edge1[2],
151: edge1[4]);
152: points[2 * k + 1] = GeometryUtil.quad(
153: params[2 * k], edge1[1], edge1[3],
154: edge1[5]);
155: }
156: } else if ((rule1 == PathIterator.SEG_CUBICTO)
157: && (rule2 == PathIterator.SEG_QUADTO)) {
158: ipCount = GeometryUtil.intersectQuadAndCubic(
159: edge2[0], edge2[1], edge2[2], edge2[3],
160: edge2[4], edge2[5], edge1[0], edge1[1],
161: edge1[2], edge1[3], edge1[4], edge1[5],
162: edge2[6], edge2[7], params);
163:
164: for (int k = 0; k < ipCount; k++) {
165: points[2 * k] = GeometryUtil.quad(
166: params[2 * k + 1], edge2[0], edge2[2],
167: edge2[4]);
168: points[2 * k + 1] = GeometryUtil.quad(
169: params[2 * k + 1], edge2[1], edge2[3],
170: edge2[5]);
171: }
172: } else if ((rule1 == PathIterator.SEG_CUBICTO)
173: && (rule2 == PathIterator.SEG_CUBICTO)) {
174: ipCount = GeometryUtil.intersectCubics(edge1[0],
175: edge1[1], edge1[2], edge1[3], edge1[4],
176: edge1[5], edge1[6], edge1[7], edge2[0],
177: edge2[1], edge2[2], edge2[3], edge2[4],
178: edge2[5], edge2[6], edge2[7], params);
179:
180: for (int k = 0; k < ipCount; k++) {
181: points[2 * k] = GeometryUtil.cubic(
182: params[2 * k], edge1[0], edge1[2],
183: edge1[4], edge1[6]);
184: points[2 * k + 1] = GeometryUtil.cubic(
185: params[2 * k], edge1[1], edge1[3],
186: edge1[5], edge1[7]);
187: }
188: }
189:
190: endIndex1 = i;
191: endIndex2 = j;
192: int begIndex1 = i - 1;
193: int begIndex2 = j - 1;
194:
195: for (int k = 0; k < ipCount; k++) {
196: IntersectPoint ip = null;
197: if (!containsPoint(points[2 * k], points[2 * k + 1])) {
198: for (Iterator iter = isectPoints.iterator(); iter
199: .hasNext();) {
200: ip = (IntersectPoint) iter.next();
201: if ((begIndex1 == ip.getBegIndex(true))
202: && (endIndex1 == ip
203: .getEndIndex(true))) {
204:
205: if (ip.getParam(true) > params[2 * k]) {
206: endIndex1 = -(isectPoints
207: .indexOf(ip) + 1);
208: ip.setBegIndex1(-(isectPoints
209: .size() + 1));
210: } else {
211: begIndex1 = -(isectPoints
212: .indexOf(ip) + 1);
213: ip.setEndIndex1(-(isectPoints
214: .size() + 1));
215: }
216: }
217:
218: if ((begIndex2 == ip.getBegIndex(false))
219: && (endIndex2 == ip
220: .getEndIndex(false))) {
221:
222: if (ip.getParam(false) > params[2 * k + 1]) {
223: endIndex2 = -(isectPoints
224: .indexOf(ip) + 1);
225: ip.setBegIndex2(-(isectPoints
226: .size() + 1));
227: } else {
228: begIndex2 = -(isectPoints
229: .indexOf(ip) + 1);
230: ip.setEndIndex2(-(isectPoints
231: .size() + 1));
232: }
233: }
234: }
235:
236: if (rule1 == PathIterator.SEG_CLOSE) {
237: rule1 = PathIterator.SEG_LINETO;
238: }
239:
240: if (rule2 == PathIterator.SEG_CLOSE) {
241: rule2 = PathIterator.SEG_LINETO;
242: }
243:
244: isectPoints.add(new IntersectPoint(begIndex1,
245: endIndex1, rule1, i, begIndex2,
246: endIndex2, rule2, j, points[2 * k],
247: points[2 * k + 1], params[2 * k],
248: params[2 * k + 1]));
249: }
250: }
251: }
252: }
253: return isectPoints.toArray(new IntersectPoint[isectPoints
254: .size()]);
255: }
256:
257: private int getCurrentEdge(int areaIndex, int index, double[] c,
258: double[] mp, double[] cp) {
259: int endIndex = 0;
260:
261: switch (rules[areaIndex][index]) {
262: case PathIterator.SEG_MOVETO:
263: cp[0] = mp[0] = coords[areaIndex][offsets[areaIndex][index]];
264: cp[1] = mp[1] = coords[areaIndex][offsets[areaIndex][index] + 1];
265: break;
266: case PathIterator.SEG_LINETO:
267: c[0] = cp[0];
268: c[1] = cp[1];
269: cp[0] = c[2] = coords[areaIndex][offsets[areaIndex][index]];
270: cp[1] = c[3] = coords[areaIndex][offsets[areaIndex][index] + 1];
271: endIndex = 0;
272: break;
273: case PathIterator.SEG_QUADTO:
274: c[0] = cp[0];
275: c[1] = cp[1];
276: c[2] = coords[areaIndex][offsets[areaIndex][index]];
277: c[3] = coords[areaIndex][offsets[areaIndex][index] + 1];
278: cp[0] = c[4] = coords[areaIndex][offsets[areaIndex][index] + 2];
279: cp[1] = c[5] = coords[areaIndex][offsets[areaIndex][index] + 3];
280: endIndex = 2;
281: break;
282: case PathIterator.SEG_CUBICTO:
283: c[0] = cp[0];
284: c[1] = cp[1];
285: c[2] = coords[areaIndex][offsets[areaIndex][index]];
286: c[3] = coords[areaIndex][offsets[areaIndex][index] + 1];
287: c[4] = coords[areaIndex][offsets[areaIndex][index] + 2];
288: c[5] = coords[areaIndex][offsets[areaIndex][index] + 3];
289: cp[0] = c[6] = coords[areaIndex][offsets[areaIndex][index] + 4];
290: cp[1] = c[7] = coords[areaIndex][offsets[areaIndex][index] + 5];
291: endIndex = 4;
292: break;
293: case PathIterator.SEG_CLOSE:
294: c[0] = cp[0];
295: c[1] = cp[1];
296: cp[0] = c[2] = mp[0];
297: cp[1] = c[3] = mp[1];
298: if (offsets[areaIndex][index] >= sizes[areaIndex]) {
299: endIndex = -sizes[areaIndex];
300: } else {
301: endIndex = 0;
302: }
303: break;
304: }
305: return offsets[areaIndex][index] + endIndex;
306: }
307:
308: private boolean containsPoint(double x, double y) {
309: IntersectPoint ipoint;
310:
311: for (Iterator i = isectPoints.iterator(); i.hasNext();) {
312: ipoint = (IntersectPoint) i.next();
313:
314: if ((Math.abs(ipoint.getX() - x) < Math.pow(10, -6))
315: && (Math.abs(ipoint.getY() - y) < Math.pow(10, -6))) {
316: return true;
317: }
318: }
319:
320: return false;
321: }
322: }
|