source: trunk/src/org/expeditee/core/bounds/AxisAlignedBoxBounds.java@ 1097

Last change on this file since 1097 was 1097, checked in by davidb, 6 years ago

Newly structured files from Corey's work on logic/graphics separation

File size: 8.9 KB
Line 
1package org.expeditee.core.bounds;
2
3import org.expeditee.Util;
4import org.expeditee.core.Dimension;
5import org.expeditee.core.Line;
6import org.expeditee.core.Point;
7
8/**
9 * A bounds that represents a rectangular area where the left and right sides are parallel
10 * to the y-axis and the top and bottom sides are parallel to the x-axis.
11 *
12 * @author cts16
13 */
14public class AxisAlignedBoxBounds extends Bounds {
15
16 /** The top-left corner of the bounds. */
17 private Point _topLeft;
18 /** The width and height of the rectangular bounds. */
19 private Dimension _size;
20
21 /** Creates an AxisAlignedBoxBounds at the given location with the given size. */
22 public AxisAlignedBoxBounds(Point topLeft, Dimension size)
23 {
24 setTopLeft(topLeft);
25 setSize(size);
26 }
27
28 /** Creates an AxisAlignedBoxBounds at the given location with the given size. */
29 public AxisAlignedBoxBounds(int x, int y, int width, int height)
30 {
31 this(new Point(x, y), new Dimension(width, height));
32 }
33
34 /** Creates an AxisAlignedBoxBounds with the same location and size as <code>other</code>. */
35 public AxisAlignedBoxBounds(AxisAlignedBoxBounds other)
36 {
37 if (other != null) {
38 setTopLeft(other._topLeft);
39 setSize(other._size);
40 } else {
41 setTopLeft(null);
42 setSize(null);
43 }
44 }
45
46 /** Creates an AxisAlignedBoxBounds that completely encloses the given bounds. */
47 public static AxisAlignedBoxBounds getEnclosing(Bounds b)
48 {
49 if (b == null) return null;
50
51 int maxX = b.getMaxX();
52 int minX = b.getMinX();
53 int maxY = b.getMaxY();
54 int minY = b.getMinY();
55
56 Point topLeft = new Point(minX, minY);
57 Dimension size = new Dimension(maxX - minX + 1, maxY - minY + 1);
58
59 return new AxisAlignedBoxBounds(topLeft, size);
60 }
61
62 /** Gets the top-left corner position of this AxisAlignedBoxBounds. */
63 public Point getTopLeft()
64 {
65 return _topLeft;
66 }
67
68 /** Gets the top-left corner position of this AxisAlignedBoxBounds. */
69 public Point getBottomRight()
70 {
71 return _topLeft.clone().add(_size.width - 1, _size.height - 1);
72 }
73
74 /** Sets the top-left corner of this AxisAlignedBoxBounds to the given point. */
75 public void setTopLeft(Point topLeft)
76 {
77 if (topLeft == null) topLeft = new Point(0, 0);
78 this._topLeft = topLeft;
79 }
80
81 /** Gets the size of this Bounds. */
82 public Dimension getSize()
83 {
84 return _size;
85 }
86
87 /** Sets the size of this Bounds (null sets to 1x1). */
88 public void setSize(Dimension size)
89 {
90 if (size == null) size = new Dimension(1, 1);
91 this._size = size;
92 }
93
94 /** Gets the width of this AxisAlignedBoxBounds. */
95 public int getWidth()
96 {
97 return _size.width;
98 }
99
100 /** Gets the height of this AxisAlignedBoxBounds. */
101 public int getHeight()
102 {
103 return _size.height;
104 }
105
106 /** Gets the x-coordinate of the centre of this AxisAlignedBoxBounds. */
107 public int getCentreX()
108 {
109 return _topLeft.x + _size.width / 2;
110 }
111
112 /** Gets the y-coordinate of the centre of this AxisAlignedBoxBounds. */
113 public int getCentreY()
114 {
115 return _topLeft.y + _size.height / 2;
116 }
117
118 /** Gets the coordinates of the centre of this AxisAlignedBoxBounds. */
119 public Point getCentre()
120 {
121 return new Point(getCentreX(), getCentreY());
122 }
123
124 /**
125 * Updates this Bounds so it covers both its original area and
126 * the area of the given bounds (plus some possible extra area).
127 *
128 * E.g. /////////**********
129 * / / *
130 * / other / \\\\\\
131 * ///////// \ \
132 * * \this\
133 * * result \ \
134 * *************\\\\\\
135 */
136 public AxisAlignedBoxBounds combineWith(AxisAlignedBoxBounds other)
137 {
138 // Can't combine with nothing
139 if (other == null) return this;
140
141 int top = Math.min(this.getMinY(), other.getMinY());
142 int bottom = Math.max(this.getMaxY(), other.getMaxY());
143 int left = Math.min(this.getMinX(), other.getMinX());
144 int right = Math.max(this.getMaxX(), other.getMaxX());
145
146 _topLeft.set(left, top);
147 _size.width = right - left + 1;
148 _size.height = bottom - top + 1;
149
150 return this;
151 }
152
153 /**
154 * Expands the bounds to encompass the given point.
155 *
156 * @param p
157 * The point to cover.
158 */
159 public AxisAlignedBoxBounds combineWith(Point p)
160 {
161 if (p == null) return this;
162
163 return combineWith(new AxisAlignedBoxBounds(p, new Dimension(1, 1)));
164 }
165
166 @Override
167 public boolean contains(int x, int y)
168 {
169 return (x >= _topLeft.x &&
170 x < (_topLeft.x + _size.width) &&
171 y >= _topLeft.y &&
172 y < (_topLeft.y + _size.height));
173 }
174
175 @Override
176 public int getMaxX()
177 {
178 return _topLeft.x + _size.width - 1;
179 }
180
181 @Override
182 public int getMinX()
183 {
184 return _topLeft.x;
185 }
186
187 @Override
188 public int getMaxY()
189 {
190 return _topLeft.y + _size.height - 1;
191 }
192
193 @Override
194 public int getMinY()
195 {
196 return _topLeft.y;
197 }
198
199 @Override
200 public AxisAlignedBoxBounds translate(int x, int y)
201 {
202 _topLeft.add(x, y);
203
204 return this;
205 }
206
207 @Override
208 public boolean equals(Bounds other)
209 {
210 if (other instanceof AxisAlignedBoxBounds) {
211 return this.getTopLeft().equals(((AxisAlignedBoxBounds) other).getTopLeft()) && this.getSize().equals(((AxisAlignedBoxBounds) other).getSize());
212 }
213
214 return false;
215 }
216
217 @Override
218 public boolean intersects(AxisAlignedBoxBounds other)
219 {
220 if (other == null) return false;
221
222 boolean completelyAbove = other.getMaxY() < this.getMinY();
223 boolean completelyBelow = other.getMinY() > this.getMaxY();
224 boolean completelyLeft = other.getMaxX() < this.getMinX();
225 boolean completelyRight = other.getMinX() > this.getMaxX();
226
227 return !(completelyAbove || completelyBelow || completelyLeft || completelyRight);
228 }
229
230 @Override
231 public boolean intersects(CombinationBounds other)
232 {
233 // Defer to the CombinationBounds routine
234 return other.intersects(this);
235 }
236
237 @Override
238 public boolean intersects(EllipticalBounds other)
239 {
240 // Defer to the EllipticalBounds routine
241 return other.intersects(this);
242 }
243
244 @Override
245 public boolean intersects(PolygonBounds other)
246 {
247 // Defer to the PolygonBounds routine
248 return other.intersects(this);
249 }
250
251 /** Gets an array of four points representing the corners of the box. */
252 public Point[] getCorners()
253 {
254 Point[] corners = new Point[4];
255
256 corners[0] = new Point(getMinX(), getMinY());
257 corners[1] = new Point(getMaxX(), getMinY());
258 corners[2] = new Point(getMaxX(), getMaxY());
259 corners[3] = new Point(getMinX(), getMaxY());
260
261 return corners;
262 }
263
264 /** Gets an array of four lines representing the border of this Bounds. */
265 public Line[] getBorderLines()
266 {
267 Line[] lines = new Line[4];
268 Point[] corners = getCorners();
269
270 lines[0] = new Line(corners[0], corners[1]);
271 lines[1] = new Line(corners[1], corners[2]);
272 lines[2] = new Line(corners[2], corners[3]);
273 lines[3] = new Line(corners[3], corners[0]);
274
275 return lines;
276 }
277
278 @Override
279 public double getArea()
280 {
281 return _size.width * _size.height;
282 }
283
284 @Override
285 public boolean perimeterContains(Point p, double error)
286 {
287 Line[] borderLines = getBorderLines();
288
289 for (Line borderLine : borderLines) {
290 if (borderLine.contains(p, error)) return true;
291 }
292
293 return false;
294 }
295
296 @Override
297 public boolean completelyContains(AxisAlignedBoxBounds other)
298 {
299 if (other == null) return false;
300
301 return contains(other.getTopLeft()) && contains(other.getBottomRight());
302 }
303
304 @Override
305 public boolean completelyContains(CombinationBounds other)
306 {
307 if (other == null) return false;
308
309 return completelyContains(getEnclosing(other));
310 }
311
312 @Override
313 public boolean completelyContains(EllipticalBounds other)
314 {
315 if (other == null) return false;
316
317 return completelyContains(getEnclosing(other));
318 }
319
320 @Override
321 public boolean completelyContains(PolygonBounds other)
322 {
323 if (other == null) return false;
324
325 return completelyContains(getEnclosing(other));
326 }
327
328 /** Gets a polygon that represents the same area as this box. */
329 public PolygonBounds getPolygon()
330 {
331 return PolygonBounds.fromBox(this);
332 }
333
334 /** Gets the area of intersection between this box and the other. */
335 public AxisAlignedBoxBounds intersectionWith(AxisAlignedBoxBounds other)
336 {
337 if (intersects(other)) {
338 int minX = getMinX() > other.getMinX() ? getMinX() : other.getMinX();
339 int minY = getMinY() > other.getMinY() ? getMinY() : other.getMinY();
340 int maxX = getMaxX() < other.getMaxX() ? getMaxX() : other.getMaxX();
341 int maxY = getMaxY() < other.getMaxY() ? getMaxY() : other.getMaxY();
342
343 return new AxisAlignedBoxBounds(minX, minY, maxX - minX + 1, maxY - minY + 1);
344 } else {
345 return null;
346 }
347 }
348
349 /** Gets the bounds that is linearly-interpolated between the two given bounds. */
350 public static AxisAlignedBoxBounds lerp(AxisAlignedBoxBounds a, AxisAlignedBoxBounds b, float t)
351 {
352 if (a == null || b == null) return null;
353
354 int minX = (int) Util.lerp(a.getMinX(), b.getMinX(), t);
355 int minY = (int) Util.lerp(a.getMinY(), b.getMinY(), t);
356 int width = (int) Util.lerp(a.getWidth(), b.getWidth(), t);
357 int height = (int) Util.lerp(a.getHeight(), b.getHeight(), t);
358
359 return new AxisAlignedBoxBounds(minX, minY, width, height);
360 }
361
362 @Override
363 public AxisAlignedBoxBounds clone()
364 {
365 return new AxisAlignedBoxBounds(this);
366 }
367
368}
Note: See TracBrowser for help on using the repository browser.