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
250 * @param devBounds a non-null Region specifying some bounds to
251 * clip the geometry to
252 * @param normalize a boolean indicating whether or not to apply
253 * normalization
254 * @param s a non-null Shape object specifying the geometry enclosing
255 * the pixels of interest
256 * @param at an optional {@code AffineTransform} to be applied to the
257 * coordinates as they are returned in the iteration, or
258 * {@code null} if untransformed coordinates are desired
259 */
260 public static Region getInstance(Region devBounds, boolean normalize,
261 Shape s, AffineTransform at)
262 {
263 // Optimize for empty shapes to avoid involving the SpanIterator
264 if (s instanceof RectangularShape &&
265 ((RectangularShape)s).isEmpty())
266 {
267 return EMPTY_REGION;
268 }
269
270 int box[] = new int[4];
271 ShapeSpanIterator sr = new ShapeSpanIterator(normalize);
272 try {
273 sr.setOutputArea(devBounds);
274 sr.appendPath(s.getPathIterator(at));
275 sr.getPathBox(box);
276 return Region.getInstance(box, sr);
277 } finally {
278 sr.dispose();
279 }
280 }
281
282 /**
283 * Returns a Region object with a rectangle of interest specified by the
284 * indicated rectangular area in lox, loy, hix, hiy and edges array, which
285 * is located relative to the rectangular area. Edges array - 0,1 are y
286 * range, 2N,2N+1 are x ranges, 1 per y range.
287 *
288 * @see TransformHelper
289 */
290 static Region getInstance(final int lox, final int loy, final int hix,
329 }
330
331 /**
332 * Returns a Region object with a rectangle of interest specified
333 * by the indicated rectangular area in x, y, width, height format.
334 * <p>
335 * This method can also be used to create a simple rectangular
336 * region.
337 */
338 public static Region getInstanceXYWH(int x, int y, int w, int h) {
339 return Region.getInstanceXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
340 }
341
342 /**
343 * Returns a Region object with a rectangle of interest specified
344 * by the indicated span array.
345 * <p>
346 * This method can also be used to create a simple rectangular
347 * region.
348 */
349 public static Region getInstance(int box[]) {
350 return new Region(box[0], box[1], box[2], box[3]);
351 }
352
353 /**
354 * Returns a Region object with a rectangle of interest specified
355 * by the indicated rectangular area in lox, loy, hix, hiy format.
356 * <p>
357 * This method can also be used to create a simple rectangular
358 * region.
359 */
360 public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) {
361 return new Region(lox, loy, hix, hiy);
362 }
363
364 /**
365 * Returns a Region object with a rectangle of interest specified by the
366 * indicated rectangular area in lox, loy, hix, hiy format.
367 * <p/>
368 * Appends the list of spans returned from the indicated SpanIterator. Each
369 * span must be at a higher starting Y coordinate than the previous data or
370 * it must have a Y range equal to the highest Y band in the region and a
371 * higher X coordinate than any of the spans in that band.
372 */
373 public static Region getInstance(int box[], SpanIterator si) {
374 Region ret = new Region(box[0], box[1], box[2], box[3]);
375 ret.appendSpans(si);
376 return ret;
377 }
378
379 /**
380 * Appends the list of spans returned from the indicated
381 * SpanIterator. Each span must be at a higher starting
382 * Y coordinate than the previous data or it must have a
383 * Y range equal to the highest Y band in the region and a
384 * higher X coordinate than any of the spans in that band.
385 */
386 private void appendSpans(SpanIterator si) {
387 int[] box = new int[6];
388
389 while (si.nextSpan(box)) {
390 appendSpan(box);
391 }
392
393 endRow(box);
394 calcBBox();
395 }
396
397 /**
398 * Returns a Region object that represents the same list of rectangles as
399 * the current Region object, scaled by the specified sx, sy factors.
400 */
401 public Region getScaledRegion(final double sx, final double sy) {
402 if (sx == 0 || sy == 0 || this == EMPTY_REGION) {
403 return EMPTY_REGION;
404 }
405 if ((sx == 1.0 && sy == 1.0) || (this == WHOLE_REGION)) {
406 return this;
407 }
408
409 int tlox = clipScale(lox, sx);
410 int tloy = clipScale(loy, sy);
411 int thix = clipScale(hix, sx);
412 int thiy = clipScale(hiy, sy);
413 Region ret = new Region(tlox, tloy, thix, thiy);
414 int bands[] = this.bands;
415 if (bands != null) {
416 int end = endIndex;
417 int newbands[] = new int[end];
418 int i = 0; // index for source bands
419 int j = 0; // index for translated newbands
420 int ncol;
421 while (i < end) {
422 int y1, y2;
423 newbands[j++] = y1 = clipScale(bands[i++], sy);
424 newbands[j++] = y2 = clipScale(bands[i++], sy);
425 newbands[j++] = ncol = bands[i++];
426 int savej = j;
427 if (y1 < y2) {
428 while (--ncol >= 0) {
429 int x1 = clipScale(bands[i++], sx);
430 int x2 = clipScale(bands[i++], sx);
431 if (x1 < x2) {
432 newbands[j++] = x1;
433 newbands[j++] = x2;
434 }
435 }
436 } else {
437 i += ncol * 2;
471 * Returns a Region object that represents the same list of
472 * rectangles as the current Region object, translated by
473 * the specified dx, dy translation factors.
474 */
475 public Region getTranslatedRegion(int dx, int dy) {
476 if ((dx | dy) == 0) {
477 return this;
478 }
479 int tlox = lox + dx;
480 int tloy = loy + dy;
481 int thix = hix + dx;
482 int thiy = hiy + dy;
483 if ((tlox > lox) != (dx > 0) ||
484 (tloy > loy) != (dy > 0) ||
485 (thix > hix) != (dx > 0) ||
486 (thiy > hiy) != (dy > 0))
487 {
488 return getSafeTranslatedRegion(dx, dy);
489 }
490 Region ret = new Region(tlox, tloy, thix, thiy);
491 int bands[] = this.bands;
492 if (bands != null) {
493 int end = endIndex;
494 ret.endIndex = end;
495 int newbands[] = new int[end];
496 ret.bands = newbands;
497 int i = 0;
498 int ncol;
499 while (i < end) {
500 newbands[i] = bands[i] + dy; i++;
501 newbands[i] = bands[i] + dy; i++;
502 newbands[i] = ncol = bands[i]; i++;
503 while (--ncol >= 0) {
504 newbands[i] = bands[i] + dx; i++;
505 newbands[i] = bands[i] + dx; i++;
506 }
507 }
508 }
509 return ret;
510 }
511
512 private Region getSafeTranslatedRegion(int dx, int dy) {
513 int tlox = clipAdd(lox, dx);
514 int tloy = clipAdd(loy, dy);
515 int thix = clipAdd(hix, dx);
516 int thiy = clipAdd(hiy, dy);
517 Region ret = new Region(tlox, tloy, thix, thiy);
518 int bands[] = this.bands;
519 if (bands != null) {
520 int end = endIndex;
521 int newbands[] = new int[end];
522 int i = 0; // index for source bands
523 int j = 0; // index for translated newbands
524 int ncol;
525 while (i < end) {
526 int y1, y2;
527 newbands[j++] = y1 = clipAdd(bands[i++], dy);
528 newbands[j++] = y2 = clipAdd(bands[i++], dy);
529 newbands[j++] = ncol = bands[i++];
530 int savej = j;
531 if (y1 < y2) {
532 while (--ncol >= 0) {
533 int x1 = clipAdd(bands[i++], dx);
534 int x2 = clipAdd(bands[i++], dx);
535 if (x1 < x2) {
536 newbands[j++] = x1;
537 newbands[j++] = x2;
538 }
539 }
540 } else {
541 i += ncol * 2;
729 public Region getExclusiveOr(Region r) {
730 if (r.isEmpty()) {
731 return this;
732 }
733 if (this.isEmpty()) {
734 return r;
735 }
736 Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox,
737 (r.loy > this.loy) ? this.loy : r.loy,
738 (r.hix < this.hix) ? this.hix : r.hix,
739 (r.hiy < this.hiy) ? this.hiy : r.hiy);
740 ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B);
741 return ret;
742 }
743
744 private static final int INCLUDE_A = 1;
745 private static final int INCLUDE_B = 2;
746 private static final int INCLUDE_COMMON = 4;
747
748 private void filterSpans(Region ra, Region rb, int flags) {
749 int abands[] = ra.bands;
750 int bbands[] = rb.bands;
751 if (abands == null) {
752 abands = new int[] {ra.loy, ra.hiy, 1, ra.lox, ra.hix};
753 }
754 if (bbands == null) {
755 bbands = new int[] {rb.loy, rb.hiy, 1, rb.lox, rb.hix};
756 }
757 int box[] = new int[6];
758 int acolstart = 0;
759 int ay1 = abands[acolstart++];
760 int ay2 = abands[acolstart++];
761 int acolend = abands[acolstart++];
762 acolend = acolstart + 2 * acolend;
763 int bcolstart = 0;
764 int by1 = bbands[bcolstart++];
765 int by2 = bbands[bcolstart++];
766 int bcolend = bbands[bcolstart++];
767 bcolend = bcolstart + 2 * bcolend;
768 int y = loy;
769 while (y < hiy) {
770 if (y >= ay2) {
771 if (acolend < ra.endIndex) {
772 acolstart = acolend;
773 ay1 = abands[acolstart++];
774 ay2 = abands[acolstart++];
775 acolend = abands[acolstart++];
776 acolend = acolstart + 2 * acolend;
777 } else {
948 if (this.encompasses(r)) {
949 return r;
950 }
951 if (r.encompasses(this)) {
952 return this;
953 }
954 return new Region((r.lox < this.lox) ? this.lox : r.lox,
955 (r.loy < this.loy) ? this.loy : r.loy,
956 (r.hix > this.hix) ? this.hix : r.hix,
957 (r.hiy > this.hiy) ? this.hiy : r.hiy);
958 }
959
960 /**
961 * Appends a single span defined by the 4 parameters
962 * spanlox, spanloy, spanhix, spanhiy.
963 * This span must be at a higher starting Y coordinate than
964 * the previous data or it must have a Y range equal to the
965 * highest Y band in the region and a higher X coordinate
966 * than any of the spans in that band.
967 */
968 private void appendSpan(int box[]) {
969 int spanlox, spanloy, spanhix, spanhiy;
970 if ((spanlox = box[0]) < lox) spanlox = lox;
971 if ((spanloy = box[1]) < loy) spanloy = loy;
972 if ((spanhix = box[2]) > hix) spanhix = hix;
973 if ((spanhiy = box[3]) > hiy) spanhiy = hiy;
974 if (spanhix <= spanlox || spanhiy <= spanloy) {
975 return;
976 }
977
978 int curYrow = box[4];
979 if (endIndex == 0 || spanloy >= bands[curYrow + 1]) {
980 if (bands == null) {
981 bands = new int[INIT_SIZE];
982 } else {
983 needSpace(5);
984 endRow(box);
985 curYrow = box[4];
986 }
987 bands[endIndex++] = spanloy;
988 bands[endIndex++] = spanhiy;
994 bands[endIndex - 1] = spanhix;
995 return;
996 }
997 needSpace(2);
998 } else {
999 throw new InternalError("bad span");
1000 }
1001 bands[endIndex++] = spanlox;
1002 bands[endIndex++] = spanhix;
1003 bands[curYrow + 2]++;
1004 }
1005
1006 private void needSpace(int num) {
1007 if (endIndex + num >= bands.length) {
1008 int[] newbands = new int[bands.length + GROW_SIZE];
1009 System.arraycopy(bands, 0, newbands, 0, endIndex);
1010 bands = newbands;
1011 }
1012 }
1013
1014 private void endRow(int box[]) {
1015 int cur = box[4];
1016 int prev = box[5];
1017 if (cur > prev) {
1018 int[] bands = this.bands;
1019 if (bands[prev + 1] == bands[cur] &&
1020 bands[prev + 2] == bands[cur + 2])
1021 {
1022 int num = bands[cur + 2] * 2;
1023 cur += 3;
1024 prev += 3;
1025 while (num > 0) {
1026 if (bands[cur++] != bands[prev++]) {
1027 break;
1028 }
1029 num--;
1030 }
1031 if (num == 0) {
1032 // prev == box[4]
1033 bands[box[5] + 1] = bands[prev + 1];
1034 endIndex = prev;
1256 public boolean encompassesXYWH(int x, int y, int w, int h) {
1257 return encompassesXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
1258 }
1259
1260 /**
1261 * Quickly checks if this Region surrounds the specified
1262 * rectangular area specified in lox, loy, hix, hiy format.
1263 * <p>
1264 * This method will return false if this Region object is
1265 * not a simple rectangle.
1266 */
1267 public boolean encompassesXYXY(int lox, int loy, int hix, int hiy) {
1268 return (this.bands == null &&
1269 this.lox <= lox && this.loy <= loy &&
1270 this.hix >= hix && this.hiy >= hiy);
1271 }
1272
1273 /**
1274 * Gets the bbox of the available spans, clipped to the OutputArea.
1275 */
1276 public void getBounds(int pathbox[]) {
1277 pathbox[0] = lox;
1278 pathbox[1] = loy;
1279 pathbox[2] = hix;
1280 pathbox[3] = hiy;
1281 }
1282
1283 /**
1284 * Clips the indicated bbox array to the bounds of this Region.
1285 */
1286 public void clipBoxToBounds(int bbox[]) {
1287 if (bbox[0] < lox) bbox[0] = lox;
1288 if (bbox[1] < loy) bbox[1] = loy;
1289 if (bbox[2] > hix) bbox[2] = hix;
1290 if (bbox[3] > hiy) bbox[3] = hiy;
1291 }
1292
1293 /**
1294 * Gets an iterator object to iterate over the spans in this region.
1295 */
1296 public RegionIterator getIterator() {
1297 return new RegionIterator(this);
1298 }
1299
1300 /**
1301 * Gets a span iterator object that iterates over the spans in this region
1302 */
1303 public SpanIterator getSpanIterator() {
1304 return new RegionSpanIterator(this);
1305 }
1306
1307 /**
1308 * Gets a span iterator object that iterates over the spans in this region
1309 * but clipped to the bounds given in the argument (xlo, ylo, xhi, yhi).
1310 */
1311 public SpanIterator getSpanIterator(int bbox[]) {
1312 SpanIterator result = getSpanIterator();
1313 result.intersectClipBox(bbox[0], bbox[1], bbox[2], bbox[3]);
1314 return result;
1315 }
1316
1317 /**
1318 * Returns a SpanIterator that is the argument iterator filtered by
1319 * this region.
1320 */
1321 public SpanIterator filter(SpanIterator si) {
1322 if (bands == null) {
1323 si.intersectClipBox(lox, loy, hix, hiy);
1324 } else {
1325 si = new RegionClipSpanIterator(this, si);
1326 }
1327 return si;
1328 }
1329
1330 @Override
1331 public String toString() {
1378 }
1379 Region r = (Region) o;
1380 if (this.isEmpty()) {
1381 return r.isEmpty();
1382 } else if (r.isEmpty()) {
1383 return false;
1384 }
1385 if (r.lox != this.lox || r.loy != this.loy ||
1386 r.hix != this.hix || r.hiy != this.hiy)
1387 {
1388 return false;
1389 }
1390 if (this.bands == null) {
1391 return (r.bands == null);
1392 } else if (r.bands == null) {
1393 return false;
1394 }
1395 if (this.endIndex != r.endIndex) {
1396 return false;
1397 }
1398 int abands[] = this.bands;
1399 int bbands[] = r.bands;
1400 for (int i = 0; i < endIndex; i++) {
1401 if (abands[i] != bbands[i]) {
1402 return false;
1403 }
1404 }
1405 return true;
1406 }
1407 }
|
1 /*
2 * Copyright (c) 1998, 2018, 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
250 * @param devBounds a non-null Region specifying some bounds to
251 * clip the geometry to
252 * @param normalize a boolean indicating whether or not to apply
253 * normalization
254 * @param s a non-null Shape object specifying the geometry enclosing
255 * the pixels of interest
256 * @param at an optional {@code AffineTransform} to be applied to the
257 * coordinates as they are returned in the iteration, or
258 * {@code null} if untransformed coordinates are desired
259 */
260 public static Region getInstance(Region devBounds, boolean normalize,
261 Shape s, AffineTransform at)
262 {
263 // Optimize for empty shapes to avoid involving the SpanIterator
264 if (s instanceof RectangularShape &&
265 ((RectangularShape)s).isEmpty())
266 {
267 return EMPTY_REGION;
268 }
269
270 int[] box = new int[4];
271 ShapeSpanIterator sr = new ShapeSpanIterator(normalize);
272 try {
273 sr.setOutputArea(devBounds);
274 sr.appendPath(s.getPathIterator(at));
275 sr.getPathBox(box);
276 return Region.getInstance(box, sr);
277 } finally {
278 sr.dispose();
279 }
280 }
281
282 /**
283 * Returns a Region object with a rectangle of interest specified by the
284 * indicated rectangular area in lox, loy, hix, hiy and edges array, which
285 * is located relative to the rectangular area. Edges array - 0,1 are y
286 * range, 2N,2N+1 are x ranges, 1 per y range.
287 *
288 * @see TransformHelper
289 */
290 static Region getInstance(final int lox, final int loy, final int hix,
329 }
330
331 /**
332 * Returns a Region object with a rectangle of interest specified
333 * by the indicated rectangular area in x, y, width, height format.
334 * <p>
335 * This method can also be used to create a simple rectangular
336 * region.
337 */
338 public static Region getInstanceXYWH(int x, int y, int w, int h) {
339 return Region.getInstanceXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
340 }
341
342 /**
343 * Returns a Region object with a rectangle of interest specified
344 * by the indicated span array.
345 * <p>
346 * This method can also be used to create a simple rectangular
347 * region.
348 */
349 public static Region getInstance(int[] box) {
350 return new Region(box[0], box[1], box[2], box[3]);
351 }
352
353 /**
354 * Returns a Region object with a rectangle of interest specified
355 * by the indicated rectangular area in lox, loy, hix, hiy format.
356 * <p>
357 * This method can also be used to create a simple rectangular
358 * region.
359 */
360 public static Region getInstanceXYXY(int lox, int loy, int hix, int hiy) {
361 return new Region(lox, loy, hix, hiy);
362 }
363
364 /**
365 * Returns a Region object with a rectangle of interest specified by the
366 * indicated rectangular area in lox, loy, hix, hiy format.
367 * <p/>
368 * Appends the list of spans returned from the indicated SpanIterator. Each
369 * span must be at a higher starting Y coordinate than the previous data or
370 * it must have a Y range equal to the highest Y band in the region and a
371 * higher X coordinate than any of the spans in that band.
372 */
373 public static Region getInstance(int[] box, SpanIterator si) {
374 Region ret = new Region(box[0], box[1], box[2], box[3]);
375 ret.appendSpans(si);
376 return ret;
377 }
378
379 /**
380 * Appends the list of spans returned from the indicated
381 * SpanIterator. Each span must be at a higher starting
382 * Y coordinate than the previous data or it must have a
383 * Y range equal to the highest Y band in the region and a
384 * higher X coordinate than any of the spans in that band.
385 */
386 private void appendSpans(SpanIterator si) {
387 int[] box = new int[6];
388
389 while (si.nextSpan(box)) {
390 appendSpan(box);
391 }
392
393 endRow(box);
394 calcBBox();
395 }
396
397 /**
398 * Returns a Region object that represents the same list of rectangles as
399 * the current Region object, scaled by the specified sx, sy factors.
400 */
401 public Region getScaledRegion(final double sx, final double sy) {
402 if (sx == 0 || sy == 0 || this == EMPTY_REGION) {
403 return EMPTY_REGION;
404 }
405 if ((sx == 1.0 && sy == 1.0) || (this == WHOLE_REGION)) {
406 return this;
407 }
408
409 int tlox = clipScale(lox, sx);
410 int tloy = clipScale(loy, sy);
411 int thix = clipScale(hix, sx);
412 int thiy = clipScale(hiy, sy);
413 Region ret = new Region(tlox, tloy, thix, thiy);
414 int[] bands = this.bands;
415 if (bands != null) {
416 int end = endIndex;
417 int[] newbands = new int[end];
418 int i = 0; // index for source bands
419 int j = 0; // index for translated newbands
420 int ncol;
421 while (i < end) {
422 int y1, y2;
423 newbands[j++] = y1 = clipScale(bands[i++], sy);
424 newbands[j++] = y2 = clipScale(bands[i++], sy);
425 newbands[j++] = ncol = bands[i++];
426 int savej = j;
427 if (y1 < y2) {
428 while (--ncol >= 0) {
429 int x1 = clipScale(bands[i++], sx);
430 int x2 = clipScale(bands[i++], sx);
431 if (x1 < x2) {
432 newbands[j++] = x1;
433 newbands[j++] = x2;
434 }
435 }
436 } else {
437 i += ncol * 2;
471 * Returns a Region object that represents the same list of
472 * rectangles as the current Region object, translated by
473 * the specified dx, dy translation factors.
474 */
475 public Region getTranslatedRegion(int dx, int dy) {
476 if ((dx | dy) == 0) {
477 return this;
478 }
479 int tlox = lox + dx;
480 int tloy = loy + dy;
481 int thix = hix + dx;
482 int thiy = hiy + dy;
483 if ((tlox > lox) != (dx > 0) ||
484 (tloy > loy) != (dy > 0) ||
485 (thix > hix) != (dx > 0) ||
486 (thiy > hiy) != (dy > 0))
487 {
488 return getSafeTranslatedRegion(dx, dy);
489 }
490 Region ret = new Region(tlox, tloy, thix, thiy);
491 int[] bands = this.bands;
492 if (bands != null) {
493 int end = endIndex;
494 ret.endIndex = end;
495 int[] newbands = new int[end];
496 ret.bands = newbands;
497 int i = 0;
498 int ncol;
499 while (i < end) {
500 newbands[i] = bands[i] + dy; i++;
501 newbands[i] = bands[i] + dy; i++;
502 newbands[i] = ncol = bands[i]; i++;
503 while (--ncol >= 0) {
504 newbands[i] = bands[i] + dx; i++;
505 newbands[i] = bands[i] + dx; i++;
506 }
507 }
508 }
509 return ret;
510 }
511
512 private Region getSafeTranslatedRegion(int dx, int dy) {
513 int tlox = clipAdd(lox, dx);
514 int tloy = clipAdd(loy, dy);
515 int thix = clipAdd(hix, dx);
516 int thiy = clipAdd(hiy, dy);
517 Region ret = new Region(tlox, tloy, thix, thiy);
518 int[] bands = this.bands;
519 if (bands != null) {
520 int end = endIndex;
521 int[] newbands = new int[end];
522 int i = 0; // index for source bands
523 int j = 0; // index for translated newbands
524 int ncol;
525 while (i < end) {
526 int y1, y2;
527 newbands[j++] = y1 = clipAdd(bands[i++], dy);
528 newbands[j++] = y2 = clipAdd(bands[i++], dy);
529 newbands[j++] = ncol = bands[i++];
530 int savej = j;
531 if (y1 < y2) {
532 while (--ncol >= 0) {
533 int x1 = clipAdd(bands[i++], dx);
534 int x2 = clipAdd(bands[i++], dx);
535 if (x1 < x2) {
536 newbands[j++] = x1;
537 newbands[j++] = x2;
538 }
539 }
540 } else {
541 i += ncol * 2;
729 public Region getExclusiveOr(Region r) {
730 if (r.isEmpty()) {
731 return this;
732 }
733 if (this.isEmpty()) {
734 return r;
735 }
736 Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox,
737 (r.loy > this.loy) ? this.loy : r.loy,
738 (r.hix < this.hix) ? this.hix : r.hix,
739 (r.hiy < this.hiy) ? this.hiy : r.hiy);
740 ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B);
741 return ret;
742 }
743
744 private static final int INCLUDE_A = 1;
745 private static final int INCLUDE_B = 2;
746 private static final int INCLUDE_COMMON = 4;
747
748 private void filterSpans(Region ra, Region rb, int flags) {
749 int[] abands = ra.bands;
750 int[] bbands = rb.bands;
751 if (abands == null) {
752 abands = new int[] {ra.loy, ra.hiy, 1, ra.lox, ra.hix};
753 }
754 if (bbands == null) {
755 bbands = new int[] {rb.loy, rb.hiy, 1, rb.lox, rb.hix};
756 }
757 int[] box = new int[6];
758 int acolstart = 0;
759 int ay1 = abands[acolstart++];
760 int ay2 = abands[acolstart++];
761 int acolend = abands[acolstart++];
762 acolend = acolstart + 2 * acolend;
763 int bcolstart = 0;
764 int by1 = bbands[bcolstart++];
765 int by2 = bbands[bcolstart++];
766 int bcolend = bbands[bcolstart++];
767 bcolend = bcolstart + 2 * bcolend;
768 int y = loy;
769 while (y < hiy) {
770 if (y >= ay2) {
771 if (acolend < ra.endIndex) {
772 acolstart = acolend;
773 ay1 = abands[acolstart++];
774 ay2 = abands[acolstart++];
775 acolend = abands[acolstart++];
776 acolend = acolstart + 2 * acolend;
777 } else {
948 if (this.encompasses(r)) {
949 return r;
950 }
951 if (r.encompasses(this)) {
952 return this;
953 }
954 return new Region((r.lox < this.lox) ? this.lox : r.lox,
955 (r.loy < this.loy) ? this.loy : r.loy,
956 (r.hix > this.hix) ? this.hix : r.hix,
957 (r.hiy > this.hiy) ? this.hiy : r.hiy);
958 }
959
960 /**
961 * Appends a single span defined by the 4 parameters
962 * spanlox, spanloy, spanhix, spanhiy.
963 * This span must be at a higher starting Y coordinate than
964 * the previous data or it must have a Y range equal to the
965 * highest Y band in the region and a higher X coordinate
966 * than any of the spans in that band.
967 */
968 private void appendSpan(int[] box) {
969 int spanlox, spanloy, spanhix, spanhiy;
970 if ((spanlox = box[0]) < lox) spanlox = lox;
971 if ((spanloy = box[1]) < loy) spanloy = loy;
972 if ((spanhix = box[2]) > hix) spanhix = hix;
973 if ((spanhiy = box[3]) > hiy) spanhiy = hiy;
974 if (spanhix <= spanlox || spanhiy <= spanloy) {
975 return;
976 }
977
978 int curYrow = box[4];
979 if (endIndex == 0 || spanloy >= bands[curYrow + 1]) {
980 if (bands == null) {
981 bands = new int[INIT_SIZE];
982 } else {
983 needSpace(5);
984 endRow(box);
985 curYrow = box[4];
986 }
987 bands[endIndex++] = spanloy;
988 bands[endIndex++] = spanhiy;
994 bands[endIndex - 1] = spanhix;
995 return;
996 }
997 needSpace(2);
998 } else {
999 throw new InternalError("bad span");
1000 }
1001 bands[endIndex++] = spanlox;
1002 bands[endIndex++] = spanhix;
1003 bands[curYrow + 2]++;
1004 }
1005
1006 private void needSpace(int num) {
1007 if (endIndex + num >= bands.length) {
1008 int[] newbands = new int[bands.length + GROW_SIZE];
1009 System.arraycopy(bands, 0, newbands, 0, endIndex);
1010 bands = newbands;
1011 }
1012 }
1013
1014 private void endRow(int[] box) {
1015 int cur = box[4];
1016 int prev = box[5];
1017 if (cur > prev) {
1018 int[] bands = this.bands;
1019 if (bands[prev + 1] == bands[cur] &&
1020 bands[prev + 2] == bands[cur + 2])
1021 {
1022 int num = bands[cur + 2] * 2;
1023 cur += 3;
1024 prev += 3;
1025 while (num > 0) {
1026 if (bands[cur++] != bands[prev++]) {
1027 break;
1028 }
1029 num--;
1030 }
1031 if (num == 0) {
1032 // prev == box[4]
1033 bands[box[5] + 1] = bands[prev + 1];
1034 endIndex = prev;
1256 public boolean encompassesXYWH(int x, int y, int w, int h) {
1257 return encompassesXYXY(x, y, dimAdd(x, w), dimAdd(y, h));
1258 }
1259
1260 /**
1261 * Quickly checks if this Region surrounds the specified
1262 * rectangular area specified in lox, loy, hix, hiy format.
1263 * <p>
1264 * This method will return false if this Region object is
1265 * not a simple rectangle.
1266 */
1267 public boolean encompassesXYXY(int lox, int loy, int hix, int hiy) {
1268 return (this.bands == null &&
1269 this.lox <= lox && this.loy <= loy &&
1270 this.hix >= hix && this.hiy >= hiy);
1271 }
1272
1273 /**
1274 * Gets the bbox of the available spans, clipped to the OutputArea.
1275 */
1276 public void getBounds(int[] pathbox) {
1277 pathbox[0] = lox;
1278 pathbox[1] = loy;
1279 pathbox[2] = hix;
1280 pathbox[3] = hiy;
1281 }
1282
1283 /**
1284 * Clips the indicated bbox array to the bounds of this Region.
1285 */
1286 public void clipBoxToBounds(int[] bbox) {
1287 if (bbox[0] < lox) bbox[0] = lox;
1288 if (bbox[1] < loy) bbox[1] = loy;
1289 if (bbox[2] > hix) bbox[2] = hix;
1290 if (bbox[3] > hiy) bbox[3] = hiy;
1291 }
1292
1293 /**
1294 * Gets an iterator object to iterate over the spans in this region.
1295 */
1296 public RegionIterator getIterator() {
1297 return new RegionIterator(this);
1298 }
1299
1300 /**
1301 * Gets a span iterator object that iterates over the spans in this region
1302 */
1303 public SpanIterator getSpanIterator() {
1304 return new RegionSpanIterator(this);
1305 }
1306
1307 /**
1308 * Gets a span iterator object that iterates over the spans in this region
1309 * but clipped to the bounds given in the argument (xlo, ylo, xhi, yhi).
1310 */
1311 public SpanIterator getSpanIterator(int[] bbox) {
1312 SpanIterator result = getSpanIterator();
1313 result.intersectClipBox(bbox[0], bbox[1], bbox[2], bbox[3]);
1314 return result;
1315 }
1316
1317 /**
1318 * Returns a SpanIterator that is the argument iterator filtered by
1319 * this region.
1320 */
1321 public SpanIterator filter(SpanIterator si) {
1322 if (bands == null) {
1323 si.intersectClipBox(lox, loy, hix, hiy);
1324 } else {
1325 si = new RegionClipSpanIterator(this, si);
1326 }
1327 return si;
1328 }
1329
1330 @Override
1331 public String toString() {
1378 }
1379 Region r = (Region) o;
1380 if (this.isEmpty()) {
1381 return r.isEmpty();
1382 } else if (r.isEmpty()) {
1383 return false;
1384 }
1385 if (r.lox != this.lox || r.loy != this.loy ||
1386 r.hix != this.hix || r.hiy != this.hiy)
1387 {
1388 return false;
1389 }
1390 if (this.bands == null) {
1391 return (r.bands == null);
1392 } else if (r.bands == null) {
1393 return false;
1394 }
1395 if (this.endIndex != r.endIndex) {
1396 return false;
1397 }
1398 int[] abands = this.bands;
1399 int[] bbands = r.bands;
1400 for (int i = 0; i < endIndex; i++) {
1401 if (abands[i] != bbands[i]) {
1402 return false;
1403 }
1404 }
1405 return true;
1406 }
1407 }
|