// Copyright 2000-2007 Omni Development, Inc.  All rights reserved.
//
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// <http://www.omnigroup.com/developer/sourcecode/sourcelicense/>.
//
// $Header: svn+ssh://source.omnigroup.com/Source/svn/Omni/tags/OmniSourceRelease/2008-03-20/OmniGroup/Frameworks/OmniAppKit/OpenStepExtensions.subproj/NSBezierPath-OAExtensions.h 91941 2007-09-26 20:46:20Z wiml $

#import <AppKit/NSBezierPath.h>

@class NSCountedSet, NSDictionary, NSMutableDictionary;

//#define	DEBUGGING_CURVE_INTERSECTIONS  0

// defines copied over from OmniBase - avoids needing a large dependency on additional code from Omni for this one category

#if !defined(SWAP)
#define SWAP(A, B)                  \
	do {                            \
		__typeof__(A) __temp = (A); \
		(A) = (B);                  \
		(B) = __temp;               \
	} while (0)
#endif

#define OBPRECONDITION(expression)
#define OBPOSTCONDITION(expression)
#define OBINVARIANT(expression)
#define OBASSERT(expression)
#define OBASSERT_NOT_REACHED(reason)

void OACGAddRoundedRect(CGContextRef context, NSRect rect, CGFloat topLeft, CGFloat topRight, CGFloat bottomLeft, CGFloat bottomRight);

// enum OAIntersectionAspect {
typedef NS_ENUM(int, OAIntersectionAspect) {
	intersectionEntryLeft = -1,	 // Other path crosses from left to right
	intersectionEntryAt = 0,	 // Collinear or osculating
	intersectionEntryRight = 1,	 // Other path crosses from right to left
	intersectionEntryBogus = -2, // Garbage value for unit testing
};

typedef NSInteger NSBezierPathSegmentIndex; // It would make more sense for this to be unsigned, but NSBezierPath uses int, and so we follow its lead

typedef struct OABezierPathPosition {
	NSBezierPathSegmentIndex segment;
	double parameter;
} OABezierPathPosition;

typedef struct {
	struct OABezierPathIntersectionHalf {
		NSBezierPathSegmentIndex segment;
		double parameter;
		double parameterDistance;
		// Unlike the lower-level calls, these aspects are ordered according to their occurrence on this path, not the other path.
		// So 'firstAspect' is the aspect of the other line where it crosses us at (parameter), and 'secondAspect' is the aspect at (parameter.parameterDistance).

		OAIntersectionAspect firstAspect, secondAspect;
	} left, right;
	NSPoint location;
} OABezierPathIntersection;

struct OABezierPathIntersectionList {
	NSUInteger count;
	OABezierPathIntersection *intersections;
};

typedef struct OABezierPathIntersectionList PathIntersectionList;

// Utility functions used internally, may be of use to other callers as well
void splitBezierCurveTo(const NSPoint *c, CGFloat t, NSPoint *l, NSPoint *r);

@interface NSBezierPath (OAExtensions)

- (NSPoint)currentPointForSegment:(NSInteger)i; // Raises an exception if no current point

- (BOOL)strokesSimilarlyIgnoringEndcapsToPath:(NSBezierPath *)otherPath;

- (NSCountedSet *)countedSetOfEncodedStrokeSegments;

- (BOOL)intersectsRect:(NSRect)rect;

- (BOOL)intersectionWithLine:(NSPoint *)result lineStart:(NSPoint)lineStart lineEnd:(NSPoint)lineEnd;

- (NSArray<NSValue *> *)intersectionsWithLineFrom:(NSPoint)lineStart to:(NSPoint)lineEnd;

#if 0
// Returns the first intersection with the given line (that is, the intersection closest to the start of the receiver's bezier path).
- (BOOL)firstIntersectionWithLine:(OABezierPathIntersection *)result lineStart:(NSPoint)lineStart lineEnd:(NSPoint)lineEnd;
#endif

#ifndef GLYPHS_VIEWER
// Returns a list of all the intersections between the receiver and the specified path. As a special case, if other==self, it does the useful thing and returns only the nontrivial self-intersections.
- (struct OABezierPathIntersectionList)allIntersectionsWithPath:(NSBezierPath *)other;

- (BOOL)intersectWithPath:(NSBezierPath *)other;
#endif

- (void)getWinding:(NSInteger *)clockwiseWindingCount andHit:(NSUInteger *)strokeHitCount forPoint:(NSPoint)point;

- (NSInteger)segmentHitByPoint:(NSPoint)point padding:(CGFloat)padding;

- (NSInteger)segmentHitByPoint:(NSPoint)point; // 0 == no hit, padding == 5
- (BOOL)isStrokeHitByPoint:(NSPoint)point padding:(CGFloat)padding;

- (BOOL)isStrokeHitByPoint:(NSPoint)point; // padding == 5

//
- (void)appendBezierPathWithRoundedRectangle:(NSRect)rect withRadius:(CGFloat)radius;

- (void)appendBezierPathWithLeftRoundedRectangle:(NSRect)rect withRadius:(CGFloat)radius;

- (void)appendBezierPathWithRightRoundedRectangle:(NSRect)rect withRadius:(CGFloat)radius;

+ (NSBezierPath *)bezierPathWithTopRoundedRectangle:(NSRect)rect withRadius:(CGFloat)radius;

+ (NSBezierPath *)bezierPathWithBottomRoundedRectangle:(NSRect)rect withRadius:(CGFloat)radius;

// The "position" manipulated by these methods divides the range 0..1 equally into segments corresponding to the Bezier's segments, and position within each segment is proportional to the t-parameter (not proportional to linear distance).
- (NSPoint)getPointForPosition:(CGFloat)position andOffset:(CGFloat)offset;

- (CGFloat)getPositionForPoint:(NSPoint)point padding:(CGFloat)padding;

- (CGFloat)getPositionForPoint:(NSPoint)point;

- (CGFloat)getNormalForPosition:(CGFloat)position;

// "Length" is the actual length along the curve
- (double)lengthToSegment:(NSInteger)segment parameter:(double)parameter totalLength:(double *)totalLengthOut;

// Returns the segment and parameter corresponding to the point a certain distance along the curve. 'outParameter' may be NULL, which can save a small amount of computation if the parameter isn't needed.
- (NSInteger)segmentAndParameter:(double *)outParameter afterLength:(double)lengthFromStart fractional:(BOOL)lengthIsFractionOfTotal;

// Returns the location of a point specified as a (segment,parameter) pair.
- (NSPoint)getPointForPosition:(OABezierPathPosition)pos;

#if 0
- (BOOL)isClockwise;
#endif

// load and save
- (NSMutableDictionary *)propertyListRepresentation;

- (void)loadPropertyListRepresentation:(NSDictionary *)dict;

// NSObject overrides
- (BOOL)isEqual:(NSBezierPath *)otherBezierPath;

- (NSUInteger)hash;

@end

@interface NSBezierPath (PrivateOAExtensions)

/*
 Defined in NSBezierPath-OAInternal.h

struct intersectionInfo {
	double leftParameter, rightParameter;
	double leftParameterDistance, rightParameterDistance;
	enum OAIntersectionAspect leftEntryAspect, leftExitAspect;
};
*/

NSString *_roundedStringForPoint(NSPoint point);

void _parameterizeLine(NSPoint *coefficients, NSPoint startPoint, NSPoint endPoint);

void _parameterizeCurve(NSPoint *coefficients, NSPoint startPoint, NSPoint endPoint, NSPoint controlPoint1, NSPoint controlPoint2);

- (BOOL)_curvedIntersection:(CGFloat *)length time:(CGFloat *)time curve:(NSPoint *)c line:(NSPoint *)a;

- (BOOL)_straightLineIntersection:(CGFloat *)length time:(CGFloat *)time segment:(NSPoint *)s line:(NSPoint *)l;

- (BOOL)_straightLineHit:(NSPoint)startPoint
						:(NSPoint)endPoint
						:(NSPoint)point
						:(CGFloat *)position
				 padding:(CGFloat)padding;

- (NSInteger)_segmentHitByPoint:(NSPoint)point position:(CGFloat *)position padding:(CGFloat)padding;

- (NSPoint)_endPointForSegment:(NSInteger)i;

@end

// other functions:
