1 /*
2 * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
45 * last row. Each row consists of at least 3 + 2n entries (n >= 1)
46 * where the first 3 entries specify the Y range as start, end, and
47 * the number of X ranges in that Y range. These 3 entries are
48 * followed by pairs of X coordinates in ascending order:
49 * <pre>
50 * bands[rowstart+0] = Y0; // starting Y coordinate
51 * bands[rowstart+1] = Y1; // ending Y coordinate - endY > startY
52 * bands[rowstart+2] = N; // number of X bands - N >= 1
53 *
54 * bands[rowstart+3] = X10; // starting X coordinate of first band
55 * bands[rowstart+4] = X11; // ending X coordinate of first band
56 * bands[rowstart+5] = X20; // starting X coordinate of second band
57 * bands[rowstart+6] = X21; // ending X coordinate of second band
58 * ...
59 * bands[rowstart+3+N*2-2] = XN0; // starting X coord of last band
60 * bands[rowstart+3+N*2-1] = XN1; // ending X coord of last band
61 *
62 * bands[rowstart+3+N*2] = ... // start of next Y row
63 * </pre>
64 */
65 public class Region {
66 static final int INIT_SIZE = 50;
67 static final int GROW_SIZE = 50;
68
69 /**
70 * Immutable Region.
71 */
72 private static final class ImmutableRegion extends Region {
73 protected ImmutableRegion(int lox, int loy, int hix, int hiy) {
74 super(lox, loy, hix, hiy);
75 }
76
77 // Override all the methods that mutate the object
78 public void appendSpans(sun.java2d.pipe.SpanIterator si) {}
79 public void setOutputArea(java.awt.Rectangle r) {}
80 public void setOutputAreaXYWH(int x, int y, int w, int h) {}
81 public void setOutputArea(int[] box) {}
82 public void setOutputAreaXYXY(int lox, int loy, int hix, int hiy) {}
83 }
84
85 public static final Region EMPTY_REGION = new ImmutableRegion(0, 0, 0, 0);
86 public static final Region WHOLE_REGION = new ImmutableRegion(
87 Integer.MIN_VALUE,
88 Integer.MIN_VALUE,
89 Integer.MAX_VALUE,
90 Integer.MAX_VALUE);
91
92 int lox;
93 int loy;
94 int hix;
95 int hiy;
96
97 int endIndex;
98 int[] bands;
99
100 private static native void initIDs();
101
102 static {
103 initIDs();
104 }
105
106 /**
107 * Adds the dimension {@code dim} to the coordinate
108 * {@code start} with appropriate clipping. If
109 * {@code dim} is non-positive then the method returns
110 * the start coordinate. If the sum overflows an integer
111 * data type then the method returns {@code Integer.MAX_VALUE}.
112 */
113 public static int dimAdd(int start, int dim) {
114 if (dim <= 0) return start;
115 if ((dim += start) < start) return Integer.MAX_VALUE;
138 * appropriate clipping to the bounds of Integer resolution. If the answer
139 * would be greater than {@code Integer.MAX_VALUE} then {@code
140 * Integer.MAX_VALUE} is returned. If the answer would be less than {@code
141 * Integer.MIN_VALUE} then {@code Integer.MIN_VALUE} is returned. Otherwise
142 * the multiplication is returned.
143 */
144 public static int clipScale(final int v, final double sv) {
145 if (sv == 1.0) {
146 return v;
147 }
148 final double newv = v * sv;
149 if (newv < Integer.MIN_VALUE) {
150 return Integer.MIN_VALUE;
151 }
152 if (newv > Integer.MAX_VALUE) {
153 return Integer.MAX_VALUE;
154 }
155 return (int) Math.round(newv);
156 }
157
158 protected Region(int lox, int loy, int hix, int hiy) {
159 this.lox = lox;
160 this.loy = loy;
161 this.hix = hix;
162 this.hiy = hiy;
163 }
164
165 private Region(int lox, int loy, int hix, int hiy, int[] bands, int end) {
166 this.lox = lox;
167 this.loy = loy;
168 this.hix = hix;
169 this.hiy = hiy;
170 this.bands = bands;
171 this.endIndex = end;
172 }
173
174 /**
175 * Returns a Region object covering the pixels which would be
176 * touched by a fill or clip operation on a Graphics implementation
177 * on the specified Shape object under the optionally specified
178 * AffineTransform object.
241 * @param at an optional {@code AffineTransform} to be applied to the
242 * coordinates as they are returned in the iteration, or
243 * {@code null} if untransformed coordinates are desired
244 */
245 public static Region getInstance(Region devBounds, boolean normalize,
246 Shape s, AffineTransform at)
247 {
248 // Optimize for empty shapes to avoid involving the SpanIterator
249 if (s instanceof RectangularShape &&
250 ((RectangularShape)s).isEmpty())
251 {
252 return EMPTY_REGION;
253 }
254
255 int box[] = new int[4];
256 ShapeSpanIterator sr = new ShapeSpanIterator(normalize);
257 try {
258 sr.setOutputArea(devBounds);
259 sr.appendPath(s.getPathIterator(at));
260 sr.getPathBox(box);
261 Region r = Region.getInstance(box);
262 r.appendSpans(sr);
263 return r;
264 } finally {
265 sr.dispose();
266 }
267 }
268
269 /**
270 * Returns a Region object with a rectangle of interest specified by the
271 * indicated rectangular area in lox, loy, hix, hiy and edges array, which
272 * is located relative to the rectangular area. Edges array - 0,1 are y
273 * range, 2N,2N+1 are x ranges, 1 per y range.
274 *
275 * @see TransformHelper
276 */
277 static Region getInstance(final int lox, final int loy, final int hix,
278 final int hiy, final int[] edges) {
279 final int y1 = edges[0];
280 final int y2 = edges[1];
281 if (hiy <= loy || hix <= lox || y2 <= y1) {
282 return EMPTY_REGION;
283 }
332 * <p>
333 * This method can also be used to create a simple rectangular
334 * region.
335 */
336 public static Region getInstance(int box[]) {
337 return new Region(box[0], box[1], box[2], box[3]);
338 }
339
340 /**
341 * Returns a Region object with a rectangle of interest specified
342 * by the indicated rectangular area in lox, loy, hix, hiy format.
343 * <p>
344 * This method can also be used to create a simple rectangular
345 * region.
346 */
347 public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) {
348 return new Region(lox, loy, hix, hiy);
349 }
350
351 /**
352 * Sets the rectangle of interest for storing and returning
353 * region bands.
354 * <p>
355 * This method can also be used to initialize a simple rectangular
356 * region.
357 */
358 public void setOutputArea(Rectangle r) {
359 setOutputAreaXYWH(r.x, r.y, r.width, r.height);
360 }
361
362 /**
363 * Sets the rectangle of interest for storing and returning
364 * region bands. The rectangle is specified in x, y, width, height
365 * format and appropriate clipping is performed as per the method
366 * {@code dimAdd}.
367 * <p>
368 * This method can also be used to initialize a simple rectangular
369 * region.
370 */
371 public void setOutputAreaXYWH(int x, int y, int w, int h) {
372 setOutputAreaXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
373 }
374
375 /**
376 * Sets the rectangle of interest for storing and returning
377 * region bands. The rectangle is specified as a span array.
378 * <p>
379 * This method can also be used to initialize a simple rectangular
380 * region.
381 */
382 public void setOutputArea(int box[]) {
383 this.lox = box[0];
384 this.loy = box[1];
385 this.hix = box[2];
386 this.hiy = box[3];
387 }
388
389 /**
390 * Sets the rectangle of interest for storing and returning
391 * region bands. The rectangle is specified in lox, loy,
392 * hix, hiy format.
393 * <p>
394 * This method can also be used to initialize a simple rectangular
395 * region.
396 */
397 public void setOutputAreaXYXY(int lox, int loy, int hix, int hiy) {
398 this.lox = lox;
399 this.loy = loy;
400 this.hix = hix;
401 this.hiy = hiy;
402 }
403
404 /**
405 * Appends the list of spans returned from the indicated
406 * SpanIterator. Each span must be at a higher starting
407 * Y coordinate than the previous data or it must have a
408 * Y range equal to the highest Y band in the region and a
409 * higher X coordinate than any of the spans in that band.
410 */
411 public void appendSpans(SpanIterator si) {
412 int[] box = new int[6];
413
414 while (si.nextSpan(box)) {
415 appendSpan(box);
416 }
417
418 endRow(box);
419 calcBBox();
420 }
421
422 /**
423 * Returns a Region object that represents the same list of rectangles as
424 * the current Region object, scaled by the specified sx, sy factors.
425 */
426 public Region getScaledRegion(final double sx, final double sy) {
427 if (sx == 0 || sy == 0 || this == EMPTY_REGION) {
428 return EMPTY_REGION;
429 }
430 if ((sx == 1.0 && sy == 1.0) || (this == WHOLE_REGION)) {
431 return this;
722 * {@code A} or {@code B}, but not if it is contained in both.
723 * <p>
724 * The return value may be this same object or the argument
725 * Region object if either is empty.
726 */
727 public Region getExclusiveOr(Region r) {
728 if (r.isEmpty()) {
729 return this;
730 }
731 if (this.isEmpty()) {
732 return r;
733 }
734 Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox,
735 (r.loy > this.loy) ? this.loy : r.loy,
736 (r.hix < this.hix) ? this.hix : r.hix,
737 (r.hiy < this.hiy) ? this.hiy : r.hiy);
738 ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B);
739 return ret;
740 }
741
742 static final int INCLUDE_A = 1;
743 static final int INCLUDE_B = 2;
744 static final int INCLUDE_COMMON = 4;
745
746 private void filterSpans(Region ra, Region rb, int flags) {
747 int abands[] = ra.bands;
748 int bbands[] = rb.bands;
749 if (abands == null) {
750 abands = new int[] {ra.loy, ra.hiy, 1, ra.lox, ra.hix};
751 }
752 if (bbands == null) {
753 bbands = new int[] {rb.loy, rb.hiy, 1, rb.lox, rb.hix};
754 }
755 int box[] = new int[6];
756 int acolstart = 0;
757 int ay1 = abands[acolstart++];
758 int ay2 = abands[acolstart++];
759 int acolend = abands[acolstart++];
760 acolend = acolstart + 2 * acolend;
761 int bcolstart = 0;
762 int by1 = bbands[bcolstart++];
763 int by2 = bbands[bcolstart++];
764 int bcolend = bbands[bcolstart++];
1063 int numbands = bands[i + 2];
1064 i += 3;
1065 if (lox > bands[i]) {
1066 lox = bands[i];
1067 }
1068 i += numbands * 2;
1069 if (hix < bands[i - 1]) {
1070 hix = bands[i - 1];
1071 }
1072 }
1073
1074 this.lox = lox;
1075 this.loy = bands[0];
1076 this.hix = hix;
1077 this.hiy = bands[hiyindex + 1];
1078 }
1079
1080 /**
1081 * Returns the lowest X coordinate in the Region.
1082 */
1083 public final int getLoX() {
1084 return lox;
1085 }
1086
1087 /**
1088 * Returns the lowest Y coordinate in the Region.
1089 */
1090 public final int getLoY() {
1091 return loy;
1092 }
1093
1094 /**
1095 * Returns the highest X coordinate in the Region.
1096 */
1097 public final int getHiX() {
1098 return hix;
1099 }
1100
1101 /**
1102 * Returns the highest Y coordinate in the Region.
1103 */
1104 public final int getHiY() {
1105 return hiy;
1106 }
1107
1108 /**
1109 * Returns the width of this Region clipped to the range (0 - MAX_INT).
1110 */
1111 public final int getWidth() {
1112 if (hix < lox) return 0;
1113 int w;
1114 if ((w = hix - lox) < 0) {
1115 w = Integer.MAX_VALUE;
1116 }
1117 return w;
1308 */
1309 public SpanIterator getSpanIterator(int bbox[]) {
1310 SpanIterator result = getSpanIterator();
1311 result.intersectClipBox(bbox[0], bbox[1], bbox[2], bbox[3]);
1312 return result;
1313 }
1314
1315 /**
1316 * Returns a SpanIterator that is the argument iterator filtered by
1317 * this region.
1318 */
1319 public SpanIterator filter(SpanIterator si) {
1320 if (bands == null) {
1321 si.intersectClipBox(lox, loy, hix, hiy);
1322 } else {
1323 si = new RegionClipSpanIterator(this, si);
1324 }
1325 return si;
1326 }
1327
1328 public String toString() {
1329 StringBuilder sb = new StringBuilder();
1330 sb.append("Region[[");
1331 sb.append(lox);
1332 sb.append(", ");
1333 sb.append(loy);
1334 sb.append(" => ");
1335 sb.append(hix);
1336 sb.append(", ");
1337 sb.append(hiy);
1338 sb.append("]");
1339 if (bands != null) {
1340 int col = 0;
1341 while (col < endIndex) {
1342 sb.append("y{");
1343 sb.append(bands[col++]);
1344 sb.append(",");
1345 sb.append(bands[col++]);
1346 sb.append("}[");
1347 int end = bands[col++];
1348 end = col + end * 2;
1349 while (col < end) {
1350 sb.append("x(");
1351 sb.append(bands[col++]);
1352 sb.append(", ");
1353 sb.append(bands[col++]);
1354 sb.append(")");
1355 }
1356 sb.append("]");
1357 }
1358 }
1359 sb.append("]");
1360 return sb.toString();
1361 }
1362
1363 public int hashCode() {
1364 return (isEmpty() ? 0 : (lox * 3 + loy * 5 + hix * 7 + hiy * 9));
1365 }
1366
1367 public boolean equals(Object o) {
1368 if (!(o instanceof Region)) {
1369 return false;
1370 }
1371 Region r = (Region) o;
1372 if (this.isEmpty()) {
1373 return r.isEmpty();
1374 } else if (r.isEmpty()) {
1375 return false;
1376 }
1377 if (r.lox != this.lox || r.loy != this.loy ||
1378 r.hix != this.hix || r.hiy != this.hiy)
1379 {
1380 return false;
1381 }
1382 if (this.bands == null) {
1383 return (r.bands == null);
1384 } else if (r.bands == null) {
1385 return false;
1386 }
1387 if (this.endIndex != r.endIndex) {
|
1 /*
2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
45 * last row. Each row consists of at least 3 + 2n entries (n >= 1)
46 * where the first 3 entries specify the Y range as start, end, and
47 * the number of X ranges in that Y range. These 3 entries are
48 * followed by pairs of X coordinates in ascending order:
49 * <pre>
50 * bands[rowstart+0] = Y0; // starting Y coordinate
51 * bands[rowstart+1] = Y1; // ending Y coordinate - endY > startY
52 * bands[rowstart+2] = N; // number of X bands - N >= 1
53 *
54 * bands[rowstart+3] = X10; // starting X coordinate of first band
55 * bands[rowstart+4] = X11; // ending X coordinate of first band
56 * bands[rowstart+5] = X20; // starting X coordinate of second band
57 * bands[rowstart+6] = X21; // ending X coordinate of second band
58 * ...
59 * bands[rowstart+3+N*2-2] = XN0; // starting X coord of last band
60 * bands[rowstart+3+N*2-1] = XN1; // ending X coord of last band
61 *
62 * bands[rowstart+3+N*2] = ... // start of next Y row
63 * </pre>
64 */
65 public final class Region {
66 private static final int INIT_SIZE = 50;
67 private static final int GROW_SIZE = 50;
68
69 public static final Region EMPTY_REGION = new Region(0, 0, 0, 0);
70 public static final Region WHOLE_REGION = new Region(
71 Integer.MIN_VALUE,
72 Integer.MIN_VALUE,
73 Integer.MAX_VALUE,
74 Integer.MAX_VALUE);
75
76 private int lox;
77 private int loy;
78 private int hix;
79 private int hiy;
80
81 int endIndex;
82 int[] bands;
83
84 private static native void initIDs();
85
86 static {
87 initIDs();
88 }
89
90 /**
91 * Adds the dimension {@code dim} to the coordinate
92 * {@code start} with appropriate clipping. If
93 * {@code dim} is non-positive then the method returns
94 * the start coordinate. If the sum overflows an integer
95 * data type then the method returns {@code Integer.MAX_VALUE}.
96 */
97 public static int dimAdd(int start, int dim) {
98 if (dim <= 0) return start;
99 if ((dim += start) < start) return Integer.MAX_VALUE;
122 * appropriate clipping to the bounds of Integer resolution. If the answer
123 * would be greater than {@code Integer.MAX_VALUE} then {@code
124 * Integer.MAX_VALUE} is returned. If the answer would be less than {@code
125 * Integer.MIN_VALUE} then {@code Integer.MIN_VALUE} is returned. Otherwise
126 * the multiplication is returned.
127 */
128 public static int clipScale(final int v, final double sv) {
129 if (sv == 1.0) {
130 return v;
131 }
132 final double newv = v * sv;
133 if (newv < Integer.MIN_VALUE) {
134 return Integer.MIN_VALUE;
135 }
136 if (newv > Integer.MAX_VALUE) {
137 return Integer.MAX_VALUE;
138 }
139 return (int) Math.round(newv);
140 }
141
142 private Region(int lox, int loy, int hix, int hiy) {
143 this.lox = lox;
144 this.loy = loy;
145 this.hix = hix;
146 this.hiy = hiy;
147 }
148
149 private Region(int lox, int loy, int hix, int hiy, int[] bands, int end) {
150 this.lox = lox;
151 this.loy = loy;
152 this.hix = hix;
153 this.hiy = hiy;
154 this.bands = bands;
155 this.endIndex = end;
156 }
157
158 /**
159 * Returns a Region object covering the pixels which would be
160 * touched by a fill or clip operation on a Graphics implementation
161 * on the specified Shape object under the optionally specified
162 * AffineTransform object.
225 * @param at an optional {@code AffineTransform} to be applied to the
226 * coordinates as they are returned in the iteration, or
227 * {@code null} if untransformed coordinates are desired
228 */
229 public static Region getInstance(Region devBounds, boolean normalize,
230 Shape s, AffineTransform at)
231 {
232 // Optimize for empty shapes to avoid involving the SpanIterator
233 if (s instanceof RectangularShape &&
234 ((RectangularShape)s).isEmpty())
235 {
236 return EMPTY_REGION;
237 }
238
239 int box[] = new int[4];
240 ShapeSpanIterator sr = new ShapeSpanIterator(normalize);
241 try {
242 sr.setOutputArea(devBounds);
243 sr.appendPath(s.getPathIterator(at));
244 sr.getPathBox(box);
245 return Region.getInstance(box, sr);
246 } finally {
247 sr.dispose();
248 }
249 }
250
251 /**
252 * Returns a Region object with a rectangle of interest specified by the
253 * indicated rectangular area in lox, loy, hix, hiy and edges array, which
254 * is located relative to the rectangular area. Edges array - 0,1 are y
255 * range, 2N,2N+1 are x ranges, 1 per y range.
256 *
257 * @see TransformHelper
258 */
259 static Region getInstance(final int lox, final int loy, final int hix,
260 final int hiy, final int[] edges) {
261 final int y1 = edges[0];
262 final int y2 = edges[1];
263 if (hiy <= loy || hix <= lox || y2 <= y1) {
264 return EMPTY_REGION;
265 }
314 * <p>
315 * This method can also be used to create a simple rectangular
316 * region.
317 */
318 public static Region getInstance(int box[]) {
319 return new Region(box[0], box[1], box[2], box[3]);
320 }
321
322 /**
323 * Returns a Region object with a rectangle of interest specified
324 * by the indicated rectangular area in lox, loy, hix, hiy format.
325 * <p>
326 * This method can also be used to create a simple rectangular
327 * region.
328 */
329 public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) {
330 return new Region(lox, loy, hix, hiy);
331 }
332
333 /**
334 * Returns a Region object with a rectangle of interest specified by the
335 * indicated rectangular area in lox, loy, hix, hiy format.
336 * <p/>
337 * Appends the list of spans returned from the indicated SpanIterator. Each
338 * span must be at a higher starting Y coordinate than the previous data or
339 * it must have a Y range equal to the highest Y band in the region and a
340 * higher X coordinate than any of the spans in that band.
341 */
342 public static Region getInstance(int box[], SpanIterator si) {
343 Region ret = new Region(box[0], box[1], box[2], box[3]);
344 ret.appendSpans(si);
345 return ret;
346 }
347
348 /**
349 * Appends the list of spans returned from the indicated
350 * SpanIterator. Each span must be at a higher starting
351 * Y coordinate than the previous data or it must have a
352 * Y range equal to the highest Y band in the region and a
353 * higher X coordinate than any of the spans in that band.
354 */
355 private void appendSpans(SpanIterator si) {
356 int[] box = new int[6];
357
358 while (si.nextSpan(box)) {
359 appendSpan(box);
360 }
361
362 endRow(box);
363 calcBBox();
364 }
365
366 /**
367 * Returns a Region object that represents the same list of rectangles as
368 * the current Region object, scaled by the specified sx, sy factors.
369 */
370 public Region getScaledRegion(final double sx, final double sy) {
371 if (sx == 0 || sy == 0 || this == EMPTY_REGION) {
372 return EMPTY_REGION;
373 }
374 if ((sx == 1.0 && sy == 1.0) || (this == WHOLE_REGION)) {
375 return this;
666 * {@code A} or {@code B}, but not if it is contained in both.
667 * <p>
668 * The return value may be this same object or the argument
669 * Region object if either is empty.
670 */
671 public Region getExclusiveOr(Region r) {
672 if (r.isEmpty()) {
673 return this;
674 }
675 if (this.isEmpty()) {
676 return r;
677 }
678 Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox,
679 (r.loy > this.loy) ? this.loy : r.loy,
680 (r.hix < this.hix) ? this.hix : r.hix,
681 (r.hiy < this.hiy) ? this.hiy : r.hiy);
682 ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B);
683 return ret;
684 }
685
686 private static final int INCLUDE_A = 1;
687 private static final int INCLUDE_B = 2;
688 private static final int INCLUDE_COMMON = 4;
689
690 private void filterSpans(Region ra, Region rb, int flags) {
691 int abands[] = ra.bands;
692 int bbands[] = rb.bands;
693 if (abands == null) {
694 abands = new int[] {ra.loy, ra.hiy, 1, ra.lox, ra.hix};
695 }
696 if (bbands == null) {
697 bbands = new int[] {rb.loy, rb.hiy, 1, rb.lox, rb.hix};
698 }
699 int box[] = new int[6];
700 int acolstart = 0;
701 int ay1 = abands[acolstart++];
702 int ay2 = abands[acolstart++];
703 int acolend = abands[acolstart++];
704 acolend = acolstart + 2 * acolend;
705 int bcolstart = 0;
706 int by1 = bbands[bcolstart++];
707 int by2 = bbands[bcolstart++];
708 int bcolend = bbands[bcolstart++];
1007 int numbands = bands[i + 2];
1008 i += 3;
1009 if (lox > bands[i]) {
1010 lox = bands[i];
1011 }
1012 i += numbands * 2;
1013 if (hix < bands[i - 1]) {
1014 hix = bands[i - 1];
1015 }
1016 }
1017
1018 this.lox = lox;
1019 this.loy = bands[0];
1020 this.hix = hix;
1021 this.hiy = bands[hiyindex + 1];
1022 }
1023
1024 /**
1025 * Returns the lowest X coordinate in the Region.
1026 */
1027 public int getLoX() {
1028 return lox;
1029 }
1030
1031 /**
1032 * Returns the lowest Y coordinate in the Region.
1033 */
1034 public int getLoY() {
1035 return loy;
1036 }
1037
1038 /**
1039 * Returns the highest X coordinate in the Region.
1040 */
1041 public int getHiX() {
1042 return hix;
1043 }
1044
1045 /**
1046 * Returns the highest Y coordinate in the Region.
1047 */
1048 public final int getHiY() {
1049 return hiy;
1050 }
1051
1052 /**
1053 * Returns the width of this Region clipped to the range (0 - MAX_INT).
1054 */
1055 public final int getWidth() {
1056 if (hix < lox) return 0;
1057 int w;
1058 if ((w = hix - lox) < 0) {
1059 w = Integer.MAX_VALUE;
1060 }
1061 return w;
1252 */
1253 public SpanIterator getSpanIterator(int bbox[]) {
1254 SpanIterator result = getSpanIterator();
1255 result.intersectClipBox(bbox[0], bbox[1], bbox[2], bbox[3]);
1256 return result;
1257 }
1258
1259 /**
1260 * Returns a SpanIterator that is the argument iterator filtered by
1261 * this region.
1262 */
1263 public SpanIterator filter(SpanIterator si) {
1264 if (bands == null) {
1265 si.intersectClipBox(lox, loy, hix, hiy);
1266 } else {
1267 si = new RegionClipSpanIterator(this, si);
1268 }
1269 return si;
1270 }
1271
1272 @Override
1273 public String toString() {
1274 StringBuilder sb = new StringBuilder();
1275 sb.append("Region[[");
1276 sb.append(lox);
1277 sb.append(", ");
1278 sb.append(loy);
1279 sb.append(" => ");
1280 sb.append(hix);
1281 sb.append(", ");
1282 sb.append(hiy);
1283 sb.append(']');
1284 if (bands != null) {
1285 int col = 0;
1286 while (col < endIndex) {
1287 sb.append("y{");
1288 sb.append(bands[col++]);
1289 sb.append(',');
1290 sb.append(bands[col++]);
1291 sb.append("}[");
1292 int end = bands[col++];
1293 end = col + end * 2;
1294 while (col < end) {
1295 sb.append("x(");
1296 sb.append(bands[col++]);
1297 sb.append(", ");
1298 sb.append(bands[col++]);
1299 sb.append(')');
1300 }
1301 sb.append(']');
1302 }
1303 }
1304 sb.append(']');
1305 return sb.toString();
1306 }
1307
1308 @Override
1309 public int hashCode() {
1310 return (isEmpty() ? 0 : (lox * 3 + loy * 5 + hix * 7 + hiy * 9));
1311 }
1312
1313 @Override
1314 public boolean equals(Object o) {
1315 if (this == o) {
1316 return true;
1317 }
1318 if (!(o instanceof Region)) {
1319 return false;
1320 }
1321 Region r = (Region) o;
1322 if (this.isEmpty()) {
1323 return r.isEmpty();
1324 } else if (r.isEmpty()) {
1325 return false;
1326 }
1327 if (r.lox != this.lox || r.loy != this.loy ||
1328 r.hix != this.hix || r.hiy != this.hiy)
1329 {
1330 return false;
1331 }
1332 if (this.bands == null) {
1333 return (r.bands == null);
1334 } else if (r.bands == null) {
1335 return false;
1336 }
1337 if (this.endIndex != r.endIndex) {
|