/ 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 }