/ CoreGraphics / CGGeometry.m
CGGeometry.m
  1  /* Copyright (c) 2006-2007 Christopher J. W. Lloyd
  2  
  3  Permission is hereby granted, free of charge, to any person obtaining a copy of
  4  this software and associated documentation files (the "Software"), to deal in
  5  the Software without restriction, including without limitation the rights to
  6  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  7  the Software, and to permit persons to whom the Software is furnished to do so,
  8  subject to the following conditions:
  9  
 10  The above copyright notice and this permission notice shall be included in all
 11  copies or substantial portions of the Software.
 12  
 13  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 14  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 15  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 16  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 17  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 18  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
 19  
 20  #ifndef MIN
 21  #define MIN(a, b)                                                              \
 22      ({                                                                         \
 23          __typeof__(a) _a = (a);                                                \
 24          __typeof__(b) _b = (b);                                                \
 25          (_a < _b) ? _a : _b;                                                   \
 26      })
 27  #else
 28  #warning MIN is already defined, MIN(a, b) may not behave as expected.
 29  #endif
 30  
 31  #ifndef MAX
 32  #define MAX(a, b)                                                              \
 33      ({                                                                         \
 34          __typeof__(a) _a = (a);                                                \
 35          __typeof__(b) _b = (b);                                                \
 36          (_a > _b) ? _a : _b;                                                   \
 37      })
 38  #else
 39  #warning MAX is already defined, MAX(a, b) may not not behave as expected.
 40  #endif
 41  
 42  #import <CoreGraphics/CGGeometry.h>
 43  
 44  const CGRect CGRectZero = {{0, 0}, {0, 0}};
 45  const CGRect CGRectNull = {{INFINITY, INFINITY}, {0, 0}};
 46  const CGPoint CGPointZero = {0, 0};
 47  const CGSize CGSizeZero = {0, 0};
 48  // Is this value the same as Apple CG?
 49  const CGRect CGRectInfinite = {{0, 0}, {INFINITY, INFINITY}};
 50  
 51  CGRect CGRectIntersection(CGRect rect0, CGRect rect1) {
 52      CGRect result;
 53  
 54      if (CGRectGetMaxX(rect0) <= CGRectGetMinX(rect1) ||
 55          CGRectGetMinX(rect0) >= CGRectGetMaxX(rect1) ||
 56          CGRectGetMaxY(rect0) <= CGRectGetMinY(rect1) ||
 57          CGRectGetMinY(rect0) >= CGRectGetMaxY(rect1))
 58          return CGRectZero;
 59  
 60      result.origin.x = MAX(CGRectGetMinX(rect0), CGRectGetMinX(rect1));
 61      result.origin.y = MAX(CGRectGetMinY(rect0), CGRectGetMinY(rect1));
 62      result.size.width =
 63              MIN(CGRectGetMaxX(rect0), CGRectGetMaxX(rect1)) - result.origin.x;
 64      result.size.height =
 65              MIN(CGRectGetMaxY(rect0), CGRectGetMaxY(rect1)) - result.origin.y;
 66  
 67      return result;
 68  }
 69  
 70  CGRect CGRectIntegral(CGRect rect) {
 71      if (!CGRectIsEmpty(rect)) {
 72          CGFloat maxX = ceil(CGRectGetMaxX(rect));
 73          CGFloat maxY = ceil(CGRectGetMaxY(rect));
 74          rect.origin.x = floor(rect.origin.x);
 75          rect.origin.y = floor(rect.origin.y);
 76          rect.size.width = maxX - CGRectGetMinX(rect);
 77          rect.size.height = maxY - CGRectGetMinY(rect);
 78      }
 79      return rect;
 80  }
 81  
 82  CGRect CGRectUnion(CGRect a, CGRect b) {
 83      // make sure we handle null!
 84      if (CGRectIsNull(a)) {
 85          return b;
 86      }
 87  
 88      if (CGRectIsNull(b)) {
 89          return a;
 90      }
 91  
 92      CGFloat minX = MIN(CGRectGetMinX(a), CGRectGetMinX(b));
 93      CGFloat minY = MIN(CGRectGetMinY(a), CGRectGetMinY(b));
 94      CGFloat maxX = MAX(CGRectGetMaxX(a), CGRectGetMaxX(b));
 95      CGFloat maxY = MAX(CGRectGetMaxY(a), CGRectGetMaxY(b));
 96      return CGRectMake(minX, minY, maxX - minX, maxY - minY);
 97  }
 98  
 99  CFDictionaryRef CGPointCreateDictionaryRepresentation(CGPoint point) {
100      CFDictionaryRef dict;
101      CFStringRef keys[] = {CFSTR("X"), CFSTR("Y")};
102      CFNumberRef values[2];
103  
104      values[0] = CFNumberCreate(NULL, kCFNumberCGFloatType, &point.x);
105      values[1] = CFNumberCreate(NULL, kCFNumberCGFloatType, &point.y);
106  
107      dict = CFDictionaryCreate(
108              NULL, (const void **) keys, (const void **) values, 2,
109              &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
110  
111      CFRelease(values[0]);
112      CFRelease(values[1]);
113  
114      return dict;
115  }
116  
117  bool CGPointMakeWithDictionaryRepresentation(CFDictionaryRef dict,
118                                               CGPoint *point)
119  {
120      if (!dict || !point)
121          return NO;
122  
123      CFNumberRef num;
124  
125      num = (CFNumberRef) CFDictionaryGetValue(dict, CFSTR("X"));
126      if (CFGetTypeID(num) != CFNumberGetTypeID())
127          return NO;
128  
129      if (!CFNumberGetValue(num, kCFNumberCGFloatType, &point->x))
130          return NO;
131  
132      num = (CFNumberRef) CFDictionaryGetValue(dict, CFSTR("Y"));
133      if (CFGetTypeID(num) != CFNumberGetTypeID())
134          return NO;
135  
136      if (!CFNumberGetValue(num, kCFNumberCGFloatType, &point->y))
137          return NO;
138  
139      return YES;
140  }
141  
142  CFDictionaryRef CGSizeCreateDictionaryRepresentation(CGSize size) {
143      CFDictionaryRef dict;
144      CFStringRef keys[] = {CFSTR("Width"), CFSTR("Height")};
145      CFNumberRef values[2];
146  
147      values[0] = CFNumberCreate(NULL, kCFNumberCGFloatType, &size.width);
148      values[1] = CFNumberCreate(NULL, kCFNumberCGFloatType, &size.height);
149  
150      dict = CFDictionaryCreate(
151              NULL, (const void **) keys, (const void **) values, 2,
152              &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
153  
154      CFRelease(values[0]);
155      CFRelease(values[1]);
156  
157      return dict;
158  }
159  
160  bool CGSizeMakeWithDictionaryRepresentation(CFDictionaryRef dict, CGSize *size)
161  {
162      if (!dict || !size)
163          return NO;
164  
165      CFNumberRef num;
166  
167      num = (CFNumberRef) CFDictionaryGetValue(dict, CFSTR("Width"));
168      if (CFGetTypeID(num) != CFNumberGetTypeID())
169          return NO;
170  
171      if (!CFNumberGetValue(num, kCFNumberCGFloatType, &size->width))
172          return NO;
173  
174      num = (CFNumberRef) CFDictionaryGetValue(dict, CFSTR("Height"));
175      if (CFGetTypeID(num) != CFNumberGetTypeID())
176          return NO;
177  
178      if (!CFNumberGetValue(num, kCFNumberCGFloatType, &size->height))
179          return NO;
180  
181      return YES;
182  }
183  
184  CFDictionaryRef CGRectCreateDictionaryRepresentation(CGRect rect) {
185      CFDictionaryRef dict;
186      CFStringRef keys[] = {CFSTR("X"), CFSTR("Y"), CFSTR("Width"),
187                            CFSTR("Height")};
188      CFNumberRef values[4];
189  
190      values[0] = CFNumberCreate(NULL, kCFNumberCGFloatType, &rect.origin.x);
191      values[1] = CFNumberCreate(NULL, kCFNumberCGFloatType, &rect.origin.y);
192      values[2] = CFNumberCreate(NULL, kCFNumberCGFloatType, &rect.size.width);
193      values[3] = CFNumberCreate(NULL, kCFNumberCGFloatType, &rect.size.height);
194  
195      dict = CFDictionaryCreate(
196              NULL, (const void **) keys, (const void **) values, 4,
197              &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
198  
199      CFRelease(values[0]);
200      CFRelease(values[1]);
201      CFRelease(values[2]);
202      CFRelease(values[3]);
203  
204      return dict;
205  }
206  
207  bool CGRectMakeWithDictionaryRepresentation(CFDictionaryRef dict, CGRect *rect)
208  {
209      if (!dict || !rect)
210          return NO;
211  
212      if (!CGPointMakeWithDictionaryRepresentation(dict, &rect->origin))
213          return NO;
214      if (!CGSizeMakeWithDictionaryRepresentation(dict, &rect->size))
215          return NO;
216  
217      return YES;
218  }
219  
220  bool CGSizeEqualToSize(CGSize a, CGSize b) {
221      return a.width == b.width && a.height == b.height;
222  }
223  
224  CGFloat CGRectGetMinX(CGRect rect) {
225      return rect.origin.x;
226  }
227  
228  CGFloat CGRectGetMaxX(CGRect rect) {
229      return rect.origin.x + rect.size.width;
230  }
231  
232  CGFloat CGRectGetMidX(CGRect rect) {
233      return CGRectGetMinX(rect) +
234             ((CGRectGetMaxX(rect) - CGRectGetMinX(rect)) / 2.f);
235  }
236  
237  CGFloat CGRectGetMinY(CGRect rect) {
238      return rect.origin.y;
239  }
240  
241  CGFloat CGRectGetMaxY(CGRect rect) {
242      return rect.origin.y + rect.size.height;
243  }
244  
245  CGFloat CGRectGetMidY(CGRect rect) {
246      return CGRectGetMinY(rect) +
247             ((CGRectGetMaxY(rect) - CGRectGetMinY(rect)) / 2.f);
248  }
249  
250  CGFloat CGRectGetWidth(CGRect rect) {
251      return rect.size.width;
252  }
253  
254  CGFloat CGRectGetHeight(CGRect rect) {
255      return rect.size.height;
256  }
257  
258  bool CGRectContainsPoint(CGRect rect, CGPoint point) {
259      return (point.x >= CGRectGetMinX(rect) && point.x <= CGRectGetMaxX(rect)) &&
260             (point.y >= CGRectGetMinY(rect) && point.y <= CGRectGetMaxY(rect));
261  }
262  
263  bool CGPointEqualToPoint(CGPoint a, CGPoint b) {
264      return ((a.x == b.x) && (a.y == b.y)) ? TRUE : FALSE;
265  }
266  
267  CGRect CGRectInset(CGRect rect, CGFloat dx, CGFloat dy) {
268      rect.origin.x += dx;
269      rect.origin.y += dy;
270      rect.size.width -= dx * 2;
271      rect.size.height -= dy * 2;
272      return rect;
273  }
274  
275  CGRect CGRectOffset(CGRect rect, CGFloat dx, CGFloat dy) {
276      rect.origin.x += dx;
277      rect.origin.y += dy;
278      return rect;
279  }
280  
281  bool CGRectIsEmpty(CGRect rect) {
282      return ((rect.size.width == 0) && (rect.size.height == 0)) ? TRUE : FALSE;
283  }
284  
285  bool CGRectIntersectsRect(CGRect a, CGRect b) {
286      if (b.origin.x > a.origin.x + a.size.width)
287          return false;
288      if (b.origin.y > a.origin.y + a.size.height)
289          return false;
290      if (a.origin.x > b.origin.x + b.size.width)
291          return false;
292      if (a.origin.y > b.origin.y + b.size.height)
293          return false;
294      return true;
295  }
296  
297  bool CGRectEqualToRect(CGRect a, CGRect b) {
298      return CGPointEqualToPoint(a.origin, b.origin) &&
299             CGSizeEqualToSize(a.size, b.size);
300  }
301  
302  bool CGRectIsInfinite(CGRect rect) {
303      return (isinf(rect.origin.x) || isinf(rect.origin.y) ||
304              isinf(rect.size.width) || isinf(rect.size.height));
305  }
306  
307  bool CGRectIsNull(CGRect rect) {
308      return CGRectEqualToRect(rect, CGRectNull);
309  }
310  
311  bool CGRectContainsRect(CGRect a, CGRect b) {
312      return (CGRectGetMinX(b) >= CGRectGetMinX(a) &&
313              CGRectGetMaxX(b) <= CGRectGetMaxX(a) &&
314              CGRectGetMinY(b) >= CGRectGetMinY(a) &&
315              CGRectGetMaxY(b) <= CGRectGetMaxY(a));
316  }