diff --git a/ChangeLog b/ChangeLog index ed2b910eb..fc6fda6e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-02-23 Richard Frith-Macdonald + + * Headers/Foundation/NSGeometry.h: + * Source/NSGeometry.m: + Inspired by Matt Rice's comments on NSEqualRects(), moved the + equality testing functions from the header to the implementation + file and added conditionally compiled code to allow us to do a + fuzzy equality test. Still need to decide whether this is actually + the correct thing to do though. + 2009-02-22 Richard Frith-Macdonald * Source/NSUnarchiver.m: diff --git a/Headers/Foundation/NSGeometry.h b/Headers/Foundation/NSGeometry.h index c2ff44dff..835a8d3c3 100644 --- a/Headers/Foundation/NSGeometry.h +++ b/Headers/Foundation/NSGeometry.h @@ -423,41 +423,18 @@ NSIntersectionRect (NSRect aRect, NSRect bRect) /** Test geometric relationships... **/ -GS_GEOM_SCOPE BOOL +/** Returns 'YES' iff aRect's and bRect's origin and size are the same. */ +GS_EXPORT BOOL NSEqualRects(NSRect aRect, NSRect bRect) GS_GEOM_ATTR; -/** Returns 'YES' iff aRect's and bRect's origin and size are the same. */ -GS_GEOM_SCOPE BOOL -NSEqualRects(NSRect aRect, NSRect bRect) -{ - return ((NSMinX(aRect) == NSMinX(bRect)) - && (NSMinY(aRect) == NSMinY(bRect)) - && (NSWidth(aRect) == NSWidth(bRect)) - && (NSHeight(aRect) == NSHeight(bRect))) ? YES : NO; -} - -GS_GEOM_SCOPE BOOL -NSEqualSizes(NSSize aSize, NSSize bSize) GS_GEOM_ATTR; - /** Returns 'YES' iff aSize's and bSize's width and height are the same. */ -GS_GEOM_SCOPE BOOL -NSEqualSizes(NSSize aSize, NSSize bSize) -{ - return ((aSize.width == bSize.width) - && (aSize.height == bSize.height)) ? YES : NO; -} - -GS_GEOM_SCOPE BOOL -NSEqualPoints(NSPoint aPoint, NSPoint bPoint) GS_GEOM_ATTR; +GS_EXPORT BOOL +NSEqualSizes(NSSize aSize, NSSize bSize) GS_GEOM_ATTR; /** Returns 'YES' iff aPoint's and bPoint's x- and y-coordinates * are the same. */ -GS_GEOM_SCOPE BOOL -NSEqualPoints(NSPoint aPoint, NSPoint bPoint) -{ - return ((aPoint.x == bPoint.x) - && (aPoint.y == bPoint.y)) ? YES : NO; -} +GS_EXPORT BOOL +NSEqualPoints(NSPoint aPoint, NSPoint bPoint) GS_GEOM_ATTR; GS_GEOM_SCOPE BOOL NSMouseInRect(NSPoint aPoint, NSRect aRect, BOOL flipped) GS_GEOM_ATTR; diff --git a/Source/NSGeometry.m b/Source/NSGeometry.m index 55f038267..9527f78e9 100644 --- a/Source/NSGeometry.m +++ b/Source/NSGeometry.m @@ -36,6 +36,7 @@ #include "config.h" #include +#include #include "GNUstepBase/preface.h" #include "Foundation/NSString.h" #include "Foundation/NSGeometry.h" @@ -388,3 +389,109 @@ NSRectFromString(NSString* string) } } +/* Tests for equality of floats/doubles. + * WARNING assumes the values are in the standard IEEE format ... + * this may not be true on all systems, though afaik it is the case + * on all systems we target. + * + * We use integer arithmetic for speed, assigning the float/double + * to an integer of the same size and then converting any negative + * values to twos-complement integer values so that a simple integer + * comparison can be done. + * + * MAX_ULP specified the number of Units in the Last Place by which + * the two values may differ and still be considered equal. A value + * of zero means that the two numbers must be identical. + * + * The way that infinity is represented means that it will be considered + * equal to MAX_FLT (or MAX_DBL) unless we are doing an exact comparison + * with MAX_ULP set to zero. + * + * The implementation will also treat two NaN values as being equal, which + * is technically wrong ... but is it worth adding a check for that? + */ +#define MAX_ULP 0 +static inline BOOL +almostEqual(CGFloat A, CGFloat B) +{ +#if MAX_ULP == 0 + return (A == B) ? YES : NO; +#else /* MAX_UPL == 0 */ +#if defined(CGFLOAT_IS_DBL) + union {int64_t i; double d;} valA, valB; + + valA.d = A; + valB.d = B; +#if GS_SIZEOF_LONG == 8 + if (valA.i < 0) + { + valA.i = 0x8000000000000000L - valA.i; + } + if (valB.i < 0) + { + valB.i = 0x8000000000000000L - valB.i; + } + if (labs(valA.i - valB.i) <= MAX_ULP) + { + return YES; + } +#else /* GS_SIZEOF_LONG == 8 */ + if (valA.i < 0) + { + valA.i = 0x8000000000000000LL - valA.i; + } + if (valB.i < 0) + { + valB.i = 0x8000000000000000LL - valB.i; + } + if (llabs(valA.i - valB.i) <= MAX_ULP) + { + return YES; + } +#endif /* GS_SIZEOF_LONG == 8 */ + return NO; +#else /* DEFINED(CGFLOAT_IS_DBL) */ + union {int32_t i; float f;} valA, valB; + + valA.f = A; + if (valA.i < 0) + { + valA.i = 0x80000000 - valA.i; + } + valB.f = B; + if (valB.i < 0) + { + valB.i = 0x80000000 - valB.i; + } + if (abs(valA.i - valB.i) <= MAX_ULP) + { + return YES; + } + return NO; +#endif /* DEFINED(CGFLOAT_IS_DBL) */ +#endif /* MAX_UPL == 0 */ +} + +BOOL +NSEqualRects(NSRect aRect, NSRect bRect) +{ + return (almostEqual(NSMinX(aRect), NSMinX(bRect)) + && almostEqual(NSMinY(aRect), NSMinY(bRect)) + && almostEqual(NSWidth(aRect), NSWidth(bRect)) + && almostEqual(NSHeight(aRect), NSHeight(bRect))) ? YES : NO; +} + +BOOL +NSEqualSizes(NSSize aSize, NSSize bSize) +{ + return (almostEqual(aSize.width, bSize.width) + && almostEqual(aSize.height, bSize.height)) ? YES : NO; +} + +BOOL +NSEqualPoints(NSPoint aPoint, NSPoint bPoint) +{ + return (almostEqual(aPoint.x, bPoint.x) + && almostEqual(aPoint.y, bPoint.y)) ? YES : NO; +} +