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</code> to the coordinate
108 * <code>start</code> with appropriate clipping. If
109 * <code>dim</code> 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</code>.
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;
116 return dim;
117 }
118
119 /**
120 * Adds the delta {@code dv} to the value {@code v} with
121 * appropriate clipping to the bounds of Integer resolution.
122 * If the answer would be greater than {@code Integer.MAX_VALUE}
123 * then {@code Integer.MAX_VALUE} is returned.
124 * If the answer would be less than {@code Integer.MIN_VALUE}
125 * then {@code Integer.MIN_VALUE} is returned.
126 * Otherwise the sum is returned.
127 */
128 public static int clipAdd(int v, int dv) {
129 int newv = v + dv;
130 if ((newv > v) != (dv > 0)) {
131 newv = (dv < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE;
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.
179 *
180 * @param s a non-null Shape object specifying the geometry enclosing
181 * the pixels of interest
182 * @param at an optional <code>AffineTransform</code> to be applied to the
183 * coordinates as they are returned in the iteration, or
184 * <code>null</code> if untransformed coordinates are desired
185 */
186 public static Region getInstance(Shape s, AffineTransform at) {
187 return getInstance(WHOLE_REGION, false, s, at);
188 }
189
190 /**
191 * Returns a Region object covering the pixels which would be
192 * touched by a fill or clip operation on a Graphics implementation
193 * on the specified Shape object under the optionally specified
194 * AffineTransform object further restricted by the specified
195 * device bounds.
196 * <p>
197 * Note that only the bounds of the specified Region are used to
198 * restrict the resulting Region.
199 * If devBounds is non-rectangular and clipping to the specific
200 * bands of devBounds is needed, then an intersection of the
201 * resulting Region with devBounds must be performed in a
202 * subsequent step.
203 *
204 * @param devBounds a non-null Region specifying some bounds to
205 * clip the geometry to
206 * @param s a non-null Shape object specifying the geometry enclosing
207 * the pixels of interest
208 * @param at an optional <code>AffineTransform</code> to be applied to the
209 * coordinates as they are returned in the iteration, or
210 * <code>null</code> if untransformed coordinates are desired
211 */
212 public static Region getInstance(Region devBounds,
213 Shape s, AffineTransform at)
214 {
215 return getInstance(devBounds, false, s, at);
216 }
217
218 /**
219 * Returns a Region object covering the pixels which would be
220 * touched by a fill or clip operation on a Graphics implementation
221 * on the specified Shape object under the optionally specified
222 * AffineTransform object further restricted by the specified
223 * device bounds.
224 * If the normalize parameter is true then coordinate normalization
225 * is performed as per the 2D Graphics non-antialiasing implementation
226 * of the VALUE_STROKE_NORMALIZE hint.
227 * <p>
228 * Note that only the bounds of the specified Region are used to
229 * restrict the resulting Region.
230 * If devBounds is non-rectangular and clipping to the specific
231 * bands of devBounds is needed, then an intersection of the
232 * resulting Region with devBounds must be performed in a
233 * subsequent step.
234 *
235 * @param devBounds a non-null Region specifying some bounds to
236 * clip the geometry to
237 * @param normalize a boolean indicating whether or not to apply
238 * normalization
239 * @param s a non-null Shape object specifying the geometry enclosing
240 * the pixels of interest
241 * @param at an optional <code>AffineTransform</code> to be applied to the
242 * coordinates as they are returned in the iteration, or
243 * <code>null</code> 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;
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</code>.
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];
620 */
621 public Region getIntersectionXYXY(int lox, int loy, int hix, int hiy) {
622 if (isInsideXYXY(lox, loy, hix, hiy)) {
623 return this;
624 }
625 Region ret = new Region((lox < this.lox) ? this.lox : lox,
626 (loy < this.loy) ? this.loy : loy,
627 (hix > this.hix) ? this.hix : hix,
628 (hiy > this.hiy) ? this.hiy : hiy);
629 if (bands != null) {
630 ret.appendSpans(this.getSpanIterator());
631 }
632 return ret;
633 }
634
635 /**
636 * Returns a Region object that represents the intersection of this
637 * object with the specified Region object.
638 * <p>
639 * If {@code A} and {@code B} are both Region Objects and
640 * <code>C = A.getIntersection(B);</code> then a point will
641 * be contained in {@code C} iff it is contained in both
642 * {@code A} and {@code B}.
643 * <p>
644 * The return value may be this same object or the argument
645 * Region object if no clipping occurs.
646 */
647 public Region getIntersection(Region r) {
648 if (this.isInsideQuickCheck(r)) {
649 return this;
650 }
651 if (r.isInsideQuickCheck(this)) {
652 return r;
653 }
654 Region ret = new Region((r.lox < this.lox) ? this.lox : r.lox,
655 (r.loy < this.loy) ? this.loy : r.loy,
656 (r.hix > this.hix) ? this.hix : r.hix,
657 (r.hiy > this.hiy) ? this.hiy : r.hiy);
658 if (!ret.isEmpty()) {
659 ret.filterSpans(this, r, INCLUDE_COMMON);
660 }
661 return ret;
662 }
663
664 /**
665 * Returns a Region object that represents the union of this
666 * object with the specified Region object.
667 * <p>
668 * If {@code A} and {@code B} are both Region Objects and
669 * <code>C = A.getUnion(B);</code> then a point will
670 * be contained in {@code C} iff it is contained in either
671 * {@code A} or {@code B}.
672 * <p>
673 * The return value may be this same object or the argument
674 * Region object if no augmentation occurs.
675 */
676 public Region getUnion(Region r) {
677 if (r.isEmpty() || r.isInsideQuickCheck(this)) {
678 return this;
679 }
680 if (this.isEmpty() || this.isInsideQuickCheck(r)) {
681 return r;
682 }
683 Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox,
684 (r.loy > this.loy) ? this.loy : r.loy,
685 (r.hix < this.hix) ? this.hix : r.hix,
686 (r.hiy < this.hiy) ? this.hiy : r.hiy);
687 ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B | INCLUDE_COMMON);
688 return ret;
689 }
690
691 /**
692 * Returns a Region object that represents the difference of the
693 * specified Region object subtracted from this object.
694 * <p>
695 * If {@code A} and {@code B} are both Region Objects and
696 * <code>C = A.getDifference(B);</code> then a point will
697 * be contained in {@code C} iff it is contained in
698 * {@code A} but not contained in {@code B}.
699 * <p>
700 * The return value may be this same object or the argument
701 * Region object if no clipping occurs.
702 */
703 public Region getDifference(Region r) {
704 if (!r.intersectsQuickCheck(this)) {
705 return this;
706 }
707 if (this.isInsideQuickCheck(r)) {
708 return EMPTY_REGION;
709 }
710 Region ret = new Region(this.lox, this.loy, this.hix, this.hiy);
711 ret.filterSpans(this, r, INCLUDE_A);
712 return ret;
713 }
714
715 /**
716 * Returns a Region object that represents the exclusive or of this
717 * object with the specified Region object.
718 * <p>
719 * If {@code A} and {@code B} are both Region Objects and
720 * <code>C = A.getExclusiveOr(B);</code> then a point will
721 * be contained in {@code C} iff it is contained in either
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 }
|
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;
116 return dim;
117 }
118
119 /**
120 * Adds the delta {@code dv} to the value {@code v} with
121 * appropriate clipping to the bounds of Integer resolution.
122 * If the answer would be greater than {@code Integer.MAX_VALUE}
123 * then {@code Integer.MAX_VALUE} is returned.
124 * If the answer would be less than {@code Integer.MIN_VALUE}
125 * then {@code Integer.MIN_VALUE} is returned.
126 * Otherwise the sum is returned.
127 */
128 public static int clipAdd(int v, int dv) {
129 int newv = v + dv;
130 if ((newv > v) != (dv > 0)) {
131 newv = (dv < 0) ? Integer.MIN_VALUE : Integer.MAX_VALUE;
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.
179 *
180 * @param s a non-null Shape object specifying the geometry enclosing
181 * the pixels of interest
182 * @param at an optional {@code AffineTransform} to be applied to the
183 * coordinates as they are returned in the iteration, or
184 * {@code null} if untransformed coordinates are desired
185 */
186 public static Region getInstance(Shape s, AffineTransform at) {
187 return getInstance(WHOLE_REGION, false, s, at);
188 }
189
190 /**
191 * Returns a Region object covering the pixels which would be
192 * touched by a fill or clip operation on a Graphics implementation
193 * on the specified Shape object under the optionally specified
194 * AffineTransform object further restricted by the specified
195 * device bounds.
196 * <p>
197 * Note that only the bounds of the specified Region are used to
198 * restrict the resulting Region.
199 * If devBounds is non-rectangular and clipping to the specific
200 * bands of devBounds is needed, then an intersection of the
201 * resulting Region with devBounds must be performed in a
202 * subsequent step.
203 *
204 * @param devBounds a non-null Region specifying some bounds to
205 * clip the geometry to
206 * @param s a non-null Shape object specifying the geometry enclosing
207 * the pixels of interest
208 * @param at an optional {@code AffineTransform} to be applied to the
209 * coordinates as they are returned in the iteration, or
210 * {@code null} if untransformed coordinates are desired
211 */
212 public static Region getInstance(Region devBounds,
213 Shape s, AffineTransform at)
214 {
215 return getInstance(devBounds, false, s, at);
216 }
217
218 /**
219 * Returns a Region object covering the pixels which would be
220 * touched by a fill or clip operation on a Graphics implementation
221 * on the specified Shape object under the optionally specified
222 * AffineTransform object further restricted by the specified
223 * device bounds.
224 * If the normalize parameter is true then coordinate normalization
225 * is performed as per the 2D Graphics non-antialiasing implementation
226 * of the VALUE_STROKE_NORMALIZE hint.
227 * <p>
228 * Note that only the bounds of the specified Region are used to
229 * restrict the resulting Region.
230 * If devBounds is non-rectangular and clipping to the specific
231 * bands of devBounds is needed, then an intersection of the
232 * resulting Region with devBounds must be performed in a
233 * subsequent step.
234 *
235 * @param devBounds a non-null Region specifying some bounds to
236 * clip the geometry to
237 * @param normalize a boolean indicating whether or not to apply
238 * normalization
239 * @param s a non-null Shape object specifying the geometry enclosing
240 * the pixels of interest
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;
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];
620 */
621 public Region getIntersectionXYXY(int lox, int loy, int hix, int hiy) {
622 if (isInsideXYXY(lox, loy, hix, hiy)) {
623 return this;
624 }
625 Region ret = new Region((lox < this.lox) ? this.lox : lox,
626 (loy < this.loy) ? this.loy : loy,
627 (hix > this.hix) ? this.hix : hix,
628 (hiy > this.hiy) ? this.hiy : hiy);
629 if (bands != null) {
630 ret.appendSpans(this.getSpanIterator());
631 }
632 return ret;
633 }
634
635 /**
636 * Returns a Region object that represents the intersection of this
637 * object with the specified Region object.
638 * <p>
639 * If {@code A} and {@code B} are both Region Objects and
640 * {@code C = A.getIntersection(B);} then a point will
641 * be contained in {@code C} iff it is contained in both
642 * {@code A} and {@code B}.
643 * <p>
644 * The return value may be this same object or the argument
645 * Region object if no clipping occurs.
646 */
647 public Region getIntersection(Region r) {
648 if (this.isInsideQuickCheck(r)) {
649 return this;
650 }
651 if (r.isInsideQuickCheck(this)) {
652 return r;
653 }
654 Region ret = new Region((r.lox < this.lox) ? this.lox : r.lox,
655 (r.loy < this.loy) ? this.loy : r.loy,
656 (r.hix > this.hix) ? this.hix : r.hix,
657 (r.hiy > this.hiy) ? this.hiy : r.hiy);
658 if (!ret.isEmpty()) {
659 ret.filterSpans(this, r, INCLUDE_COMMON);
660 }
661 return ret;
662 }
663
664 /**
665 * Returns a Region object that represents the union of this
666 * object with the specified Region object.
667 * <p>
668 * If {@code A} and {@code B} are both Region Objects and
669 * {@code C = A.getUnion(B);} then a point will
670 * be contained in {@code C} iff it is contained in either
671 * {@code A} or {@code B}.
672 * <p>
673 * The return value may be this same object or the argument
674 * Region object if no augmentation occurs.
675 */
676 public Region getUnion(Region r) {
677 if (r.isEmpty() || r.isInsideQuickCheck(this)) {
678 return this;
679 }
680 if (this.isEmpty() || this.isInsideQuickCheck(r)) {
681 return r;
682 }
683 Region ret = new Region((r.lox > this.lox) ? this.lox : r.lox,
684 (r.loy > this.loy) ? this.loy : r.loy,
685 (r.hix < this.hix) ? this.hix : r.hix,
686 (r.hiy < this.hiy) ? this.hiy : r.hiy);
687 ret.filterSpans(this, r, INCLUDE_A | INCLUDE_B | INCLUDE_COMMON);
688 return ret;
689 }
690
691 /**
692 * Returns a Region object that represents the difference of the
693 * specified Region object subtracted from this object.
694 * <p>
695 * If {@code A} and {@code B} are both Region Objects and
696 * {@code C = A.getDifference(B);} then a point will
697 * be contained in {@code C} iff it is contained in
698 * {@code A} but not contained in {@code B}.
699 * <p>
700 * The return value may be this same object or the argument
701 * Region object if no clipping occurs.
702 */
703 public Region getDifference(Region r) {
704 if (!r.intersectsQuickCheck(this)) {
705 return this;
706 }
707 if (this.isInsideQuickCheck(r)) {
708 return EMPTY_REGION;
709 }
710 Region ret = new Region(this.lox, this.loy, this.hix, this.hiy);
711 ret.filterSpans(this, r, INCLUDE_A);
712 return ret;
713 }
714
715 /**
716 * Returns a Region object that represents the exclusive or of this
717 * object with the specified Region object.
718 * <p>
719 * If {@code A} and {@code B} are both Region Objects and
720 * {@code C = A.getExclusiveOr(B);} then a point will
721 * be contained in {@code C} iff it is contained in either
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 }
|