1 /* Interface for NSGeometry routines for GNUStep
2  * Copyright (C) 1995 Free Software Foundation, Inc.
3  *
4  * Written by:  Adam Fedor <fedor@boulder.colorado.edu>
5  * Date: 1995,199
6  *
7  * This file is part of the GNUstep Base Library.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02111 USA.
23  */
24 
25 #ifndef __NSGeometry_h_GNUSTEP_BASE_INCLUDE
26 #define __NSGeometry_h_GNUSTEP_BASE_INCLUDE
27 #import	"../GNUstepBase/GSVersionMacros.h"
28 
29 #import <objc/objc.h>
30 
31 #import "NSString.h"
32 
33 #if	defined(__cplusplus)
34 extern "C" {
35 #endif
36 
37 /**** Type, Constant, and Macro Definitions **********************************/
38 
39 #ifndef MAX
40 #define MAX(a,b) \
41        ({__typeof__(a) _MAX_a = (a); __typeof__(b) _MAX_b = (b);  \
42          _MAX_a > _MAX_b ? _MAX_a : _MAX_b; })
43 #define	GS_DEFINED_MAX
44 #endif
45 
46 #ifndef MIN
47 #define MIN(a,b) \
48        ({__typeof__(a) _MIN_a = (a); __typeof__(b) _MIN_b = (b);  \
49          _MIN_a < _MIN_b ? _MIN_a : _MIN_b; })
50 #define	GS_DEFINED_MIN
51 #endif
52 
53 /**
54 <example>{
55   CGFloat x;
56   CGFloat y;
57 }</example>
58  <p>Represents a 2-d cartesian position.</p> */
59 typedef struct _NSPoint NSPoint;
60 struct _NSPoint
61 {
62   CGFloat x;
63   CGFloat y;
64 };
65 
66 #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
67 /** Array of NSPoint structs. */
68 typedef NSPoint *NSPointArray;
69 /** Pointer to NSPoint struct. */
70 typedef NSPoint *NSPointPointer;
71 #endif
72 
73 /**
74 <example>{
75   CGFloat width;
76   CGFloat height;
77 }</example>
78  <p>Floating point rectangle size.</p> */
79 typedef struct _NSSize NSSize;
80 struct _NSSize
81 {
82   CGFloat width;
83   CGFloat height;
84 };
85 
86 #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
87 /** Array of NSSize structs. */
88 typedef NSSize *NSSizeArray;
89 /** Pointer to NSSize struct. */
90 typedef NSSize *NSSizePointer;
91 #endif
92 
93 /**
94 <example>{
95   NSPoint origin;
96   NSSize size;
97 }</example>
98 
99  <p>Rectangle.</p> */
100 typedef struct _NSRect NSRect;
101 struct _NSRect
102 {
103   NSPoint origin;
104   NSSize size;
105 };
106 
107 #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
108 /** Array of NSRect structs. */
109 typedef NSRect *NSRectArray;
110 /** Pointer to NSRect struct. */
111 typedef NSRect *NSRectPointer;
112 #endif
113 
114 enum
115 {
116   NSMinXEdge = 0,
117   NSMinYEdge = 1,
118   NSMaxXEdge = 2,
119   NSMaxYEdge = 3
120 };
121 /** Sides of a rectangle.
122 <example>
123 {
124   NSMinXEdge,
125   NSMinYEdge,
126   NSMaxXEdge,
127   NSMaxYEdge
128 }
129 </example>
130  */
131 typedef NSUInteger NSRectEdge;
132 
133 /**
134 <example>{
135   CGFloat top;
136   CGFloat left;
137   CGFloat bottom;
138   CGFloat right;
139 }</example>
140 
141  <p>A description of the distance between the edges of two rectangles.</p> */
142 #if OS_API_VERSION(MAC_OS_X_VERSION_10_7, GS_API_LATEST)
143 typedef struct NSEdgeInsets {
144     CGFloat top;
145     CGFloat left;
146     CGFloat bottom;
147     CGFloat right;
148 } NSEdgeInsets;
149 #endif
150 
151 /** Point at 0,0 */
152 static const NSPoint NSZeroPoint __attribute__((unused)) = {0.0,0.0};
153 /** Zero-size rectangle at 0,0 */
154 static const NSRect NSZeroRect __attribute__((unused)) = {{0.0,0.0},{0.0,0.0}};
155 /** Zero size */
156 static const NSSize NSZeroSize __attribute__((unused)) = {0.0,0.0};
157 
158 #if OS_API_VERSION(MAC_OS_X_VERSION_10_7, GS_API_LATEST)
159 /** Zero edge insets **/
160 static const NSEdgeInsets NSEdgeInsetsZero __attribute__((unused))  = {0.0,0.0,0.0,0.0};
161 #endif
162 
163 /**** Function Prototypes ****************************************************/
164 
165 /*
166  *	All but the most complex functions are declared static inline in this
167  *	header file so that they are maximally efficient.  In order to provide
168  *	true functions (for code modules that don't have this header) this
169  *	header is included in NSGeometry.m where the functions are no longer
170  *	declared inline.
171  */
172 #ifdef	IN_NSGEOMETRY_M
173 #define	GS_GEOM_SCOPE	extern
174 #define GS_GEOM_ATTR
175 #else
176 #define	GS_GEOM_SCOPE	static inline
177 #define GS_GEOM_ATTR	__attribute__((unused))
178 #endif
179 
180 /** Create Basic Structures... **/
181 
182 GS_GEOM_SCOPE NSPoint
183 NSMakePoint(CGFloat x, CGFloat y) GS_GEOM_ATTR;
184 
185 /** Returns an NSPoint having x-coordinate X and y-coordinate Y. */
186 GS_GEOM_SCOPE NSPoint
NSMakePoint(CGFloat x,CGFloat y)187 NSMakePoint(CGFloat x, CGFloat y)
188 {
189   NSPoint point;
190 
191   point.x = x;
192   point.y = y;
193   return point;
194 }
195 
196 GS_GEOM_SCOPE NSSize
197 NSMakeSize(CGFloat w, CGFloat h) GS_GEOM_ATTR;
198 
199 /** Returns an NSSize having width w and height h. */
200 GS_GEOM_SCOPE NSSize
NSMakeSize(CGFloat w,CGFloat h)201 NSMakeSize(CGFloat w, CGFloat h)
202 {
203   NSSize size;
204 
205   size.width = w;
206   size.height = h;
207   return size;
208 }
209 
210 GS_GEOM_SCOPE NSRect
211 NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h) GS_GEOM_ATTR;
212 
213 /** Returns an NSRect having point of origin (x, y) and size {w, h}. */
214 GS_GEOM_SCOPE NSRect
NSMakeRect(CGFloat x,CGFloat y,CGFloat w,CGFloat h)215 NSMakeRect(CGFloat x, CGFloat y, CGFloat w, CGFloat h)
216 {
217   NSRect rect;
218 
219   rect.origin.x = x;
220   rect.origin.y = y;
221   rect.size.width = w;
222   rect.size.height = h;
223   return rect;
224 }
225 
226 /** Constructs NSEdgeInsets. **/
227 #if OS_API_VERSION(MAC_OS_X_VERSION_10_7, GS_API_LATEST)
228 GS_GEOM_SCOPE NSEdgeInsets
229 NSEdgeInsetsMake(CGFloat top, CGFloat left,
230                  CGFloat bottom, CGFloat right) GS_GEOM_ATTR;
231 
232 GS_GEOM_SCOPE NSEdgeInsets
NSEdgeInsetsMake(CGFloat top,CGFloat left,CGFloat bottom,CGFloat right)233 NSEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right)
234 {
235   NSEdgeInsets edgeInsets;
236 
237   edgeInsets.top = top;
238   edgeInsets.left = left;
239   edgeInsets.bottom = bottom;
240   edgeInsets.right = right;
241 
242   return edgeInsets;
243 }
244 
245 #if OS_API_VERSION(MAC_OS_X_VERSION_10_10, GS_API_LATEST)
246 /** Compares two edge insets for equality. **/
247 GS_EXPORT BOOL
248 NSEdgeInsetsEqual(NSEdgeInsets e1, NSEdgeInsets e2);
249 #endif
250 
251 #endif
252 
253 /** Get a Rectangle's Coordinates... **/
254 
255 GS_GEOM_SCOPE CGFloat
256 NSMaxX(NSRect aRect) GS_GEOM_ATTR;
257 
258 /** Returns the greatest x-coordinate value still inside aRect. */
259 GS_GEOM_SCOPE CGFloat
NSMaxX(NSRect aRect)260 NSMaxX(NSRect aRect)
261 {
262   return aRect.origin.x + aRect.size.width;
263 }
264 
265 GS_GEOM_SCOPE CGFloat
266 NSMaxY(NSRect aRect) GS_GEOM_ATTR;
267 
268 /** Returns the greatest y-coordinate value still inside aRect. */
269 GS_GEOM_SCOPE CGFloat
NSMaxY(NSRect aRect)270 NSMaxY(NSRect aRect)
271 {
272   return aRect.origin.y + aRect.size.height;
273 }
274 
275 GS_GEOM_SCOPE CGFloat
276 NSMidX(NSRect aRect) GS_GEOM_ATTR;
277 
278 /** Returns the x-coordinate of aRect's middle point. */
279 GS_GEOM_SCOPE CGFloat
NSMidX(NSRect aRect)280 NSMidX(NSRect aRect)
281 {
282   return aRect.origin.x + (aRect.size.width / 2.0);
283 }
284 
285 GS_GEOM_SCOPE CGFloat
286 NSMidY(NSRect aRect) GS_GEOM_ATTR;
287 
288 /** Returns the y-coordinate of aRect's middle point. */
289 GS_GEOM_SCOPE CGFloat
NSMidY(NSRect aRect)290 NSMidY(NSRect aRect)
291 {
292   return aRect.origin.y + (aRect.size.height / 2.0);
293 }
294 
295 GS_GEOM_SCOPE CGFloat
296 NSMinX(NSRect aRect) GS_GEOM_ATTR;
297 
298 /** Returns the least x-coordinate value still inside aRect. */
299 GS_GEOM_SCOPE CGFloat
NSMinX(NSRect aRect)300 NSMinX(NSRect aRect)
301 {
302   return aRect.origin.x;
303 }
304 
305 GS_GEOM_SCOPE CGFloat
306 NSMinY(NSRect aRect) GS_GEOM_ATTR;
307 
308 /** Returns the least y-coordinate value still inside aRect. */
309 GS_GEOM_SCOPE CGFloat
NSMinY(NSRect aRect)310 NSMinY(NSRect aRect)
311 {
312   return aRect.origin.y;
313 }
314 
315 GS_GEOM_SCOPE CGFloat
316 NSWidth(NSRect aRect) GS_GEOM_ATTR;
317 
318 /** Returns aRect's width. */
319 GS_GEOM_SCOPE CGFloat
NSWidth(NSRect aRect)320 NSWidth(NSRect aRect)
321 {
322   return aRect.size.width;
323 }
324 
325 GS_GEOM_SCOPE CGFloat
326 NSHeight(NSRect aRect) GS_GEOM_ATTR;
327 
328 /** Returns aRect's height. */
329 GS_GEOM_SCOPE CGFloat
NSHeight(NSRect aRect)330 NSHeight(NSRect aRect)
331 {
332   return aRect.size.height;
333 }
334 
335 GS_GEOM_SCOPE BOOL
336 NSIsEmptyRect(NSRect aRect) GS_GEOM_ATTR;
337 
338 /** Returns 'YES' iff the area of aRect is zero (i.e., iff either
339  * of aRect's width or height is negative or zero). */
340 GS_GEOM_SCOPE BOOL
NSIsEmptyRect(NSRect aRect)341 NSIsEmptyRect(NSRect aRect)
342 {
343   return ((NSWidth(aRect) > 0) && (NSHeight(aRect) > 0)) ? NO : YES;
344 }
345 
346 /** Modify a Copy of a Rectangle... **/
347 
348 GS_GEOM_SCOPE NSRect
349 NSOffsetRect(NSRect aRect, CGFloat dx, CGFloat dy) GS_GEOM_ATTR;
350 
351 /** Returns the rectangle obtained by translating aRect
352  * horizontally by dx and vertically by dy. */
353 GS_GEOM_SCOPE NSRect
NSOffsetRect(NSRect aRect,CGFloat dx,CGFloat dy)354 NSOffsetRect(NSRect aRect, CGFloat dx, CGFloat dy)
355 {
356   NSRect rect = aRect;
357 
358   rect.origin.x += dx;
359   rect.origin.y += dy;
360   return rect;
361 }
362 
363 GS_GEOM_SCOPE NSRect
364 NSInsetRect(NSRect aRect, CGFloat dX, CGFloat dY) GS_GEOM_ATTR;
365 
366 /** Returns the rectangle obtained by moving each of aRect's
367  * horizontal sides inward by dy and each of aRect's vertical
368  * sides inward by dx.<br />
369  * NB. For MacOS-X compatability, this is permitted to return
370  * a rectanglew with nagative width or height, strange as that seems.
371  */
372 GS_GEOM_SCOPE NSRect
NSInsetRect(NSRect aRect,CGFloat dX,CGFloat dY)373 NSInsetRect(NSRect aRect, CGFloat dX, CGFloat dY)
374 {
375   NSRect rect;
376 
377   rect = NSOffsetRect(aRect, dX, dY);
378   rect.size.width -= (2 * dX);
379   rect.size.height -= (2 * dY);
380   return rect;
381 }
382 
383 /** Divides aRect into two rectangles (namely slice and remainder) by
384  * "cutting" aRect---parallel to, and a distance amount from the given edge
385  * of aRect.  You may pass 0 in as either of slice or
386  * remainder to avoid obtaining either of the created rectangles. */
387 GS_EXPORT void
388 NSDivideRect(NSRect aRect,
389              NSRect *slice,
390              NSRect *remainder,
391              CGFloat amount,
392              NSRectEdge edge);
393 
394 /** Returns a rectangle obtained by expanding aRect minimally
395  * so that all four of its defining components are integers. */
396 GS_EXPORT NSRect
397 NSIntegralRect(NSRect aRect);
398 
399 /** Compute a Third Rectangle from Two Rectangles... **/
400 
401 GS_GEOM_SCOPE NSRect
402 NSUnionRect(NSRect aRect, NSRect bRect) GS_GEOM_ATTR;
403 
404 /** Returns the smallest rectangle which contains both aRect
405  * and bRect (modulo a set of measure zero).  If either of aRect
406  * or bRect is an empty rectangle, then the other rectangle is
407  * returned.  If both are empty, then the empty rectangle is returned. */
408 GS_GEOM_SCOPE NSRect
NSUnionRect(NSRect aRect,NSRect bRect)409 NSUnionRect(NSRect aRect, NSRect bRect)
410 {
411   NSRect rect;
412 
413   if (NSIsEmptyRect(aRect) && NSIsEmptyRect(bRect))
414     return NSMakeRect(0.0,0.0,0.0,0.0);
415   else if (NSIsEmptyRect(aRect))
416     return bRect;
417   else if (NSIsEmptyRect(bRect))
418     return aRect;
419 
420   rect = NSMakeRect(MIN(NSMinX(aRect), NSMinX(bRect)),
421                     MIN(NSMinY(aRect), NSMinY(bRect)), 0.0, 0.0);
422 
423   rect = NSMakeRect(NSMinX(rect),
424                     NSMinY(rect),
425                     MAX(NSMaxX(aRect), NSMaxX(bRect)) - NSMinX(rect),
426                     MAX(NSMaxY(aRect), NSMaxY(bRect)) - NSMinY(rect));
427 
428   return rect;
429 }
430 
431 GS_GEOM_SCOPE NSRect
432 NSIntersectionRect(NSRect aRect, NSRect bRect) GS_GEOM_ATTR;
433 
434 /** Returns the largest rectangle which lies in both aRect and
435  * bRect.  If aRect and bRect have empty intersection (or, rather,
436  * intersection of measure zero, since this includes having their
437  * intersection be only a point or a line), then the empty
438  * rectangle is returned. */
439 GS_GEOM_SCOPE NSRect
NSIntersectionRect(NSRect aRect,NSRect bRect)440 NSIntersectionRect (NSRect aRect, NSRect bRect)
441 {
442   if (NSMaxX(aRect) <= NSMinX(bRect) || NSMaxX(bRect) <= NSMinX(aRect)
443     || NSMaxY(aRect) <= NSMinY(bRect) || NSMaxY(bRect) <= NSMinY(aRect))
444     {
445       return NSMakeRect(0.0, 0.0, 0.0, 0.0);
446     }
447   else
448     {
449       NSRect    rect;
450 
451       if (NSMinX(aRect) <= NSMinX(bRect))
452         rect.origin.x = bRect.origin.x;
453       else
454         rect.origin.x = aRect.origin.x;
455 
456       if (NSMinY(aRect) <= NSMinY(bRect))
457         rect.origin.y = bRect.origin.y;
458       else
459         rect.origin.y = aRect.origin.y;
460 
461       if (NSMaxX(aRect) >= NSMaxX(bRect))
462         rect.size.width = NSMaxX(bRect) - rect.origin.x;
463       else
464         rect.size.width = NSMaxX(aRect) - rect.origin.x;
465 
466       if (NSMaxY(aRect) >= NSMaxY(bRect))
467         rect.size.height = NSMaxY(bRect) - rect.origin.y;
468       else
469         rect.size.height = NSMaxY(aRect) - rect.origin.y;
470 
471       return rect;
472     }
473 }
474 
475 /** Test geometric relationships... **/
476 
477 /** Returns 'YES' iff aRect's and bRect's origin and size are the same. */
478 GS_EXPORT BOOL
479 NSEqualRects(NSRect aRect, NSRect bRect) GS_GEOM_ATTR;
480 
481 /** Returns 'YES' iff aSize's and bSize's width and height are the same. */
482 GS_EXPORT BOOL
483 NSEqualSizes(NSSize aSize, NSSize bSize) GS_GEOM_ATTR;
484 
485 /** Returns 'YES' iff aPoint's and bPoint's x- and y-coordinates
486  * are the same. */
487 GS_EXPORT BOOL
488 NSEqualPoints(NSPoint aPoint, NSPoint bPoint) GS_GEOM_ATTR;
489 
490 GS_GEOM_SCOPE BOOL
491 NSMouseInRect(NSPoint aPoint, NSRect aRect, BOOL flipped) GS_GEOM_ATTR;
492 
493 /** Returns 'YES' iff aPoint is inside aRect. */
494 GS_GEOM_SCOPE BOOL
NSMouseInRect(NSPoint aPoint,NSRect aRect,BOOL flipped)495 NSMouseInRect(NSPoint aPoint, NSRect aRect, BOOL flipped)
496 {
497   if (flipped)
498     {
499       return ((aPoint.x >= NSMinX(aRect))
500         && (aPoint.y >= NSMinY(aRect))
501         && (aPoint.x < NSMaxX(aRect))
502         && (aPoint.y < NSMaxY(aRect))) ? YES : NO;
503     }
504   else
505     {
506       return ((aPoint.x >= NSMinX(aRect))
507         && (aPoint.y > NSMinY(aRect))
508         && (aPoint.x < NSMaxX(aRect))
509         && (aPoint.y <= NSMaxY(aRect))) ? YES : NO;
510     }
511 }
512 
513 GS_GEOM_SCOPE BOOL
514 NSPointInRect(NSPoint aPoint, NSRect aRect) GS_GEOM_ATTR;
515 
516 /** Just like 'NSMouseInRect(aPoint, aRect, YES)'. */
517 GS_GEOM_SCOPE BOOL
NSPointInRect(NSPoint aPoint,NSRect aRect)518 NSPointInRect(NSPoint aPoint, NSRect aRect)
519 {
520   return NSMouseInRect(aPoint, aRect, YES);
521 }
522 
523 GS_GEOM_SCOPE BOOL
524 NSContainsRect(NSRect aRect, NSRect bRect) GS_GEOM_ATTR;
525 
526 /** Returns 'YES' iff aRect totally encloses bRect.  NOTE: For
527  * this to be the case, aRect cannot be empty, nor can any side
528  * of bRect go beyond any side of aRect. Note that this behavior
529  * is different than the original OpenStep behavior, where the sides
530  * of bRect could not touch aRect. */
531 GS_GEOM_SCOPE BOOL
NSContainsRect(NSRect aRect,NSRect bRect)532 NSContainsRect(NSRect aRect, NSRect bRect)
533 {
534   return (!NSIsEmptyRect(bRect)
535     && (NSMinX(aRect) <= NSMinX(bRect))
536     && (NSMinY(aRect) <= NSMinY(bRect))
537     && (NSMaxX(aRect) >= NSMaxX(bRect))
538     && (NSMaxY(aRect) >= NSMaxY(bRect))) ? YES : NO;
539 }
540 
541 #if OS_API_VERSION(GS_API_MACOSX, GS_API_LATEST)
542 GS_GEOM_SCOPE BOOL
543 NSIntersectsRect(NSRect aRect, NSRect bRect) GS_GEOM_ATTR;
544 
545 /** Returns YES if aRect and bRect have non-zero intersection area
546     (intersecting at a line or a point doesn't count). */
547 GS_GEOM_SCOPE BOOL
NSIntersectsRect(NSRect aRect,NSRect bRect)548 NSIntersectsRect(NSRect aRect, NSRect bRect)
549 {
550   /* Note that intersecting at a line or a point doesn't count */
551   return (NSMaxX(aRect) <= NSMinX(bRect)
552     || NSMaxX(bRect) <= NSMinX(aRect)
553     || NSMaxY(aRect) <= NSMinY(bRect)
554     || NSMaxY(bRect) <= NSMinY(aRect)
555     || NSIsEmptyRect(aRect)
556     || NSIsEmptyRect(bRect)) ? NO : YES;
557 }
558 #endif
559 
560 /** Get a String Representation... **/
561 
562 #ifdef __OBJC__
563 /** Returns an NSString of the form "{x=X; y=Y}", where
564  * X and Y are the x- and y-coordinates of aPoint, respectively. */
565 GS_EXPORT NSString *
566 NSStringFromPoint(NSPoint aPoint);
567 
568 /** Returns an NSString of the form "{x=X; y=Y; width=W; height=H}",
569  * where X, Y, W, and H are the x-coordinate, y-coordinate,
570  * width, and height of aRect, respectively. */
571 GS_EXPORT NSString *
572 NSStringFromRect(NSRect aRect);
573 
574 /** Returns an NSString of the form "{width=W; height=H}", where
575  * W and H are the width and height of aSize, respectively. */
576 GS_EXPORT NSString *
577 NSStringFromSize(NSSize aSize);
578 
579 /** Parses point from string of form "<code>{x=a; y=b}</code>". (0,0) returned
580     if parsing fails. */
581 GS_EXPORT NSPoint	NSPointFromString(NSString* string);
582 
583 /** Parses size from string of form "<code>{width=a; height=b}</code>". Size of
584     0,0 returned if parsing fails. */
585 GS_EXPORT NSSize	NSSizeFromString(NSString* string);
586 
587 /** Parses point from string of form "<code>{x=a; y=b; width=c;
588     height=d}</code>".  Rectangle of 0 size at origin returned if parsing
589     fails.
590 */
591 GS_EXPORT NSRect	NSRectFromString(NSString* string);
592 
593 #endif /* __OBJC__ */
594 
595 #ifdef	GS_DEFINED_MAX
596 #undef	GS_DEFINED_MAX
597 #undef	MAX
598 #endif
599 
600 #ifdef	GS_DEFINED_MIN
601 #undef	GS_DEFINED_MIN
602 #undef	MIN
603 #endif
604 
605 #if	defined(__cplusplus)
606 }
607 #endif
608 
609 #endif /* __NSGeometry_h_GNUSTEP_BASE_INCLUDE */
610