SDL  2.0
SDL_rect.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../SDL_internal.h"
22 
23 #include "SDL_rect.h"
24 #include "SDL_rect_c.h"
25 
27 SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B)
28 {
29  int Amin, Amax, Bmin, Bmax;
30 
31  if (!A) {
33  return SDL_FALSE;
34  }
35 
36  if (!B) {
38  return SDL_FALSE;
39  }
40 
41  /* Special cases for empty rects */
42  if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) {
43  return SDL_FALSE;
44  }
45 
46  /* Horizontal intersection */
47  Amin = A->x;
48  Amax = Amin + A->w;
49  Bmin = B->x;
50  Bmax = Bmin + B->w;
51  if (Bmin > Amin)
52  Amin = Bmin;
53  if (Bmax < Amax)
54  Amax = Bmax;
55  if (Amax <= Amin)
56  return SDL_FALSE;
57 
58  /* Vertical intersection */
59  Amin = A->y;
60  Amax = Amin + A->h;
61  Bmin = B->y;
62  Bmax = Bmin + B->h;
63  if (Bmin > Amin)
64  Amin = Bmin;
65  if (Bmax < Amax)
66  Amax = Bmax;
67  if (Amax <= Amin)
68  return SDL_FALSE;
69 
70  return SDL_TRUE;
71 }
72 
75 {
76  int Amin, Amax, Bmin, Bmax;
77 
78  if (!A) {
80  return SDL_FALSE;
81  }
82 
83  if (!B) {
85  return SDL_FALSE;
86  }
87 
88  if (!result) {
89  SDL_InvalidParamError("result");
90  return SDL_FALSE;
91  }
92 
93  /* Special cases for empty rects */
94  if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) {
95  result->w = 0;
96  result->h = 0;
97  return SDL_FALSE;
98  }
99 
100  /* Horizontal intersection */
101  Amin = A->x;
102  Amax = Amin + A->w;
103  Bmin = B->x;
104  Bmax = Bmin + B->w;
105  if (Bmin > Amin)
106  Amin = Bmin;
107  result->x = Amin;
108  if (Bmax < Amax)
109  Amax = Bmax;
110  result->w = Amax - Amin;
111 
112  /* Vertical intersection */
113  Amin = A->y;
114  Amax = Amin + A->h;
115  Bmin = B->y;
116  Bmax = Bmin + B->h;
117  if (Bmin > Amin)
118  Amin = Bmin;
119  result->y = Amin;
120  if (Bmax < Amax)
121  Amax = Bmax;
122  result->h = Amax - Amin;
123 
124  return !SDL_RectEmpty(result);
125 }
126 
127 void
129 {
130  int Amin, Amax, Bmin, Bmax;
131 
132  if (!A) {
134  return;
135  }
136 
137  if (!B) {
139  return;
140  }
141 
142  if (!result) {
143  SDL_InvalidParamError("result");
144  return;
145  }
146 
147  /* Special cases for empty Rects */
148  if (SDL_RectEmpty(A)) {
149  if (SDL_RectEmpty(B)) {
150  /* A and B empty */
151  return;
152  } else {
153  /* A empty, B not empty */
154  *result = *B;
155  return;
156  }
157  } else {
158  if (SDL_RectEmpty(B)) {
159  /* A not empty, B empty */
160  *result = *A;
161  return;
162  }
163  }
164 
165  /* Horizontal union */
166  Amin = A->x;
167  Amax = Amin + A->w;
168  Bmin = B->x;
169  Bmax = Bmin + B->w;
170  if (Bmin < Amin)
171  Amin = Bmin;
172  result->x = Amin;
173  if (Bmax > Amax)
174  Amax = Bmax;
175  result->w = Amax - Amin;
176 
177  /* Vertical union */
178  Amin = A->y;
179  Amax = Amin + A->h;
180  Bmin = B->y;
181  Bmax = Bmin + B->h;
182  if (Bmin < Amin)
183  Amin = Bmin;
184  result->y = Amin;
185  if (Bmax > Amax)
186  Amax = Bmax;
187  result->h = Amax - Amin;
188 }
189 
190 SDL_bool
191 SDL_EnclosePoints(const SDL_Point * points, int count, const SDL_Rect * clip,
192  SDL_Rect * result)
193 {
194  int minx = 0;
195  int miny = 0;
196  int maxx = 0;
197  int maxy = 0;
198  int x, y, i;
199 
200  if (!points) {
201  SDL_InvalidParamError("points");
202  return SDL_FALSE;
203  }
204 
205  if (count < 1) {
206  SDL_InvalidParamError("count");
207  return SDL_FALSE;
208  }
209 
210  if (clip) {
211  SDL_bool added = SDL_FALSE;
212  const int clip_minx = clip->x;
213  const int clip_miny = clip->y;
214  const int clip_maxx = clip->x+clip->w-1;
215  const int clip_maxy = clip->y+clip->h-1;
216 
217  /* Special case for empty rectangle */
218  if (SDL_RectEmpty(clip)) {
219  return SDL_FALSE;
220  }
221 
222  for (i = 0; i < count; ++i) {
223  x = points[i].x;
224  y = points[i].y;
225 
226  if (x < clip_minx || x > clip_maxx ||
227  y < clip_miny || y > clip_maxy) {
228  continue;
229  }
230  if (!added) {
231  /* Special case: if no result was requested, we are done */
232  if (result == NULL) {
233  return SDL_TRUE;
234  }
235 
236  /* First point added */
237  minx = maxx = x;
238  miny = maxy = y;
239  added = SDL_TRUE;
240  continue;
241  }
242  if (x < minx) {
243  minx = x;
244  } else if (x > maxx) {
245  maxx = x;
246  }
247  if (y < miny) {
248  miny = y;
249  } else if (y > maxy) {
250  maxy = y;
251  }
252  }
253  if (!added) {
254  return SDL_FALSE;
255  }
256  } else {
257  /* Special case: if no result was requested, we are done */
258  if (result == NULL) {
259  return SDL_TRUE;
260  }
261 
262  /* No clipping, always add the first point */
263  minx = maxx = points[0].x;
264  miny = maxy = points[0].y;
265 
266  for (i = 1; i < count; ++i) {
267  x = points[i].x;
268  y = points[i].y;
269 
270  if (x < minx) {
271  minx = x;
272  } else if (x > maxx) {
273  maxx = x;
274  }
275  if (y < miny) {
276  miny = y;
277  } else if (y > maxy) {
278  maxy = y;
279  }
280  }
281  }
282 
283  if (result) {
284  result->x = minx;
285  result->y = miny;
286  result->w = (maxx-minx)+1;
287  result->h = (maxy-miny)+1;
288  }
289  return SDL_TRUE;
290 }
291 
292 /* Use the Cohen-Sutherland algorithm for line clipping */
293 #define CODE_BOTTOM 1
294 #define CODE_TOP 2
295 #define CODE_LEFT 4
296 #define CODE_RIGHT 8
297 
298 static int
299 ComputeOutCode(const SDL_Rect * rect, int x, int y)
300 {
301  int code = 0;
302  if (y < rect->y) {
303  code |= CODE_TOP;
304  } else if (y >= rect->y + rect->h) {
305  code |= CODE_BOTTOM;
306  }
307  if (x < rect->x) {
308  code |= CODE_LEFT;
309  } else if (x >= rect->x + rect->w) {
310  code |= CODE_RIGHT;
311  }
312  return code;
313 }
314 
315 SDL_bool
316 SDL_IntersectRectAndLine(const SDL_Rect * rect, int *X1, int *Y1, int *X2,
317  int *Y2)
318 {
319  int x = 0;
320  int y = 0;
321  int x1, y1;
322  int x2, y2;
323  int rectx1;
324  int recty1;
325  int rectx2;
326  int recty2;
327  int outcode1, outcode2;
328 
329  if (!rect) {
330  SDL_InvalidParamError("rect");
331  return SDL_FALSE;
332  }
333 
334  if (!X1) {
335  SDL_InvalidParamError("X1");
336  return SDL_FALSE;
337  }
338 
339  if (!Y1) {
340  SDL_InvalidParamError("Y1");
341  return SDL_FALSE;
342  }
343 
344  if (!X2) {
345  SDL_InvalidParamError("X2");
346  return SDL_FALSE;
347  }
348 
349  if (!Y2) {
350  SDL_InvalidParamError("Y2");
351  return SDL_FALSE;
352  }
353 
354  /* Special case for empty rect */
355  if (SDL_RectEmpty(rect)) {
356  return SDL_FALSE;
357  }
358 
359  x1 = *X1;
360  y1 = *Y1;
361  x2 = *X2;
362  y2 = *Y2;
363  rectx1 = rect->x;
364  recty1 = rect->y;
365  rectx2 = rect->x + rect->w - 1;
366  recty2 = rect->y + rect->h - 1;
367 
368  /* Check to see if entire line is inside rect */
369  if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 &&
370  y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) {
371  return SDL_TRUE;
372  }
373 
374  /* Check to see if entire line is to one side of rect */
375  if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) ||
376  (y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) {
377  return SDL_FALSE;
378  }
379 
380  if (y1 == y2) {
381  /* Horizontal line, easy to clip */
382  if (x1 < rectx1) {
383  *X1 = rectx1;
384  } else if (x1 > rectx2) {
385  *X1 = rectx2;
386  }
387  if (x2 < rectx1) {
388  *X2 = rectx1;
389  } else if (x2 > rectx2) {
390  *X2 = rectx2;
391  }
392  return SDL_TRUE;
393  }
394 
395  if (x1 == x2) {
396  /* Vertical line, easy to clip */
397  if (y1 < recty1) {
398  *Y1 = recty1;
399  } else if (y1 > recty2) {
400  *Y1 = recty2;
401  }
402  if (y2 < recty1) {
403  *Y2 = recty1;
404  } else if (y2 > recty2) {
405  *Y2 = recty2;
406  }
407  return SDL_TRUE;
408  }
409 
410  /* More complicated Cohen-Sutherland algorithm */
411  outcode1 = ComputeOutCode(rect, x1, y1);
412  outcode2 = ComputeOutCode(rect, x2, y2);
413  while (outcode1 || outcode2) {
414  if (outcode1 & outcode2) {
415  return SDL_FALSE;
416  }
417 
418  if (outcode1) {
419  if (outcode1 & CODE_TOP) {
420  y = recty1;
421  x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
422  } else if (outcode1 & CODE_BOTTOM) {
423  y = recty2;
424  x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
425  } else if (outcode1 & CODE_LEFT) {
426  x = rectx1;
427  y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
428  } else if (outcode1 & CODE_RIGHT) {
429  x = rectx2;
430  y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
431  }
432  x1 = x;
433  y1 = y;
434  outcode1 = ComputeOutCode(rect, x, y);
435  } else {
436  if (outcode2 & CODE_TOP) {
437  y = recty1;
438  x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
439  } else if (outcode2 & CODE_BOTTOM) {
440  y = recty2;
441  x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
442  } else if (outcode2 & CODE_LEFT) {
443  /* If this assertion ever fires, here's the static analysis that warned about it:
444  http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-b0d01a.html#EndPath */
445  SDL_assert(x2 != x1); /* if equal: division by zero. */
446  x = rectx1;
447  y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
448  } else if (outcode2 & CODE_RIGHT) {
449  /* If this assertion ever fires, here's the static analysis that warned about it:
450  http://buildbot.libsdl.org/sdl-static-analysis/sdl-macosx-static-analysis/sdl-macosx-static-analysis-1101/report-39b114.html#EndPath */
451  SDL_assert(x2 != x1); /* if equal: division by zero. */
452  x = rectx2;
453  y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
454  }
455  x2 = x;
456  y2 = y;
457  outcode2 = ComputeOutCode(rect, x, y);
458  }
459  }
460  *X1 = x1;
461  *Y1 = y1;
462  *X2 = x2;
463  *Y2 = y2;
464  return SDL_TRUE;
465 }
466 
467 SDL_bool
469  int numrects, const SDL_Rect * rects, SDL_Rect *span)
470 {
471  int i;
472  int span_y1, span_y2;
473  int rect_y1, rect_y2;
474 
475  if (width < 1) {
476  SDL_InvalidParamError("width");
477  return SDL_FALSE;
478  }
479 
480  if (height < 1) {
481  SDL_InvalidParamError("height");
482  return SDL_FALSE;
483  }
484 
485  if (!rects) {
486  SDL_InvalidParamError("rects");
487  return SDL_FALSE;
488  }
489 
490  if (!span) {
491  SDL_InvalidParamError("span");
492  return SDL_FALSE;
493  }
494 
495  if (numrects < 1) {
496  SDL_InvalidParamError("numrects");
497  return SDL_FALSE;
498  }
499 
500  /* Initialize to empty rect */
501  span_y1 = height;
502  span_y2 = 0;
503 
504  for (i = 0; i < numrects; ++i) {
505  rect_y1 = rects[i].y;
506  rect_y2 = rect_y1 + rects[i].h;
507 
508  /* Clip out of bounds rectangles, and expand span rect */
509  if (rect_y1 < 0) {
510  span_y1 = 0;
511  } else if (rect_y1 < span_y1) {
512  span_y1 = rect_y1;
513  }
514  if (rect_y2 > height) {
515  span_y2 = height;
516  } else if (rect_y2 > span_y2) {
517  span_y2 = rect_y2;
518  }
519  }
520  if (span_y2 > span_y1) {
521  span->x = 0;
522  span->y = span_y1;
523  span->w = width;
524  span->h = (span_y2 - span_y1);
525  return SDL_TRUE;
526  }
527  return SDL_FALSE;
528 }
529 
530 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:171
#define SDL_InvalidParamError(param)
Definition: SDL_error.h:90
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLint GLint GLsizei width
Definition: SDL_opengl.h:1572
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLint GLint GLsizei GLsizei height
Definition: SDL_opengl.h:1572
GLfixed GLfixed GLint GLint GLfixed points
GLfixed GLfixed GLfixed y2
GLuint64EXT * result
GLfixed y1
GLuint GLfloat GLfloat GLfloat x1
GLfixed GLfixed x2
GLenum GLenum void void void * span
static int ComputeOutCode(const SDL_Rect *rect, int x, int y)
Definition: SDL_rect.c:299
#define CODE_BOTTOM
Definition: SDL_rect.c:293
SDL_bool SDL_IntersectRect(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *result)
Calculate the intersection of two rectangles.
Definition: SDL_rect.c:74
SDL_bool SDL_EnclosePoints(const SDL_Point *points, int count, const SDL_Rect *clip, SDL_Rect *result)
Calculate a minimal rectangle enclosing a set of points.
Definition: SDL_rect.c:191
#define CODE_RIGHT
Definition: SDL_rect.c:296
SDL_bool SDL_GetSpanEnclosingRect(int width, int height, int numrects, const SDL_Rect *rects, SDL_Rect *span)
Definition: SDL_rect.c:468
SDL_bool SDL_HasIntersection(const SDL_Rect *A, const SDL_Rect *B)
Determine whether two rectangles intersect.
Definition: SDL_rect.c:27
#define CODE_LEFT
Definition: SDL_rect.c:295
void SDL_UnionRect(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *result)
Calculate the union of two rectangles.
Definition: SDL_rect.c:128
SDL_bool SDL_IntersectRectAndLine(const SDL_Rect *rect, int *X1, int *Y1, int *X2, int *Y2)
Calculate the intersection of a rectangle and line segment.
Definition: SDL_rect.c:316
#define CODE_TOP
Definition: SDL_rect.c:294
SDL_FORCE_INLINE SDL_bool SDL_RectEmpty(const SDL_Rect *r)
Returns true if the rectangle has no area.
Definition: SDL_rect.h:108
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
EGLSurface EGLint * rects
Definition: eglext.h:282
The structure that defines a point (integer)
Definition: SDL_rect.h:49
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:78
int h
Definition: SDL_rect.h:80
int w
Definition: SDL_rect.h:80
int y
Definition: SDL_rect.h:79
int x
Definition: SDL_rect.h:79
SDL_Rect rect
Definition: testrelative.c:27