/*	MiscRoundedRectShape.m

	Copyright 1996 Uwe Hoffmann.

	This notice may not be removed from this source code.
	The use and distribution of this software is governed by the
	terms of the MiscKit license agreement.  Refer to the license
	document included with the MiscKit distribution for the terms.

	Version 2 (August 1996)
*/

#import <Foundation/Foundation.h>

#import "MiscRoundedRectShape.h"
#import "MiscUserPath.h"
#import "MiscHitPath.h"
#import "MiscTDUtils.h"

@implementation MiscRoundedRectShape 

- (NSRect)innerBounds
{
	NSRect br,ir;
	NSPoint m;
	float a,b,cx,cy,r;
	
	br = [path bounds];
	r = MIN(br.size.width / 3, br.size.height / 3);
	m.x = br.origin.x + br.size.width / 2;
	m.y = br.origin.y + br.size.height / 2;
	a = br.size.width / 2;
	b = br.size.height / 2;
	cx = a - r / 2;
	cy = b - 0.1339746 * r;
	ir.origin.x = m.x - cx;
	ir.origin.y = m.y - cy;
	ir.size.width = 2 * cx;
	ir.size.height = 2 * cy;
	return ir;
}

- (MiscShapeType)shapeType
{
	return MiscRoundedRectShapeType;
}

- (void)calcIntersection:(NSPoint *)ip angle:(float *)alpha toPoint:(NSPoint)aPoint
{
	NSPoint middle,l1,l2,pos;
	float s,width,height,*bbox;
	float xm,ym,x0,y0,r,ausdruck;
	
	bbox = [path bbox];
	pos.x = bbox[0];
	pos.y = bbox[1];
	width = bbox[2] - bbox[0];
	height = bbox[3] - bbox[1];	middle.x = pos.x + width / 2;
	middle.y = pos.y + height / 2;
	if(aPoint.y == middle.y){
		ip->y = middle.y;
		if(aPoint.x > middle.x){
			*alpha = 0;		
			ip->x = pos.x + width;
		} else {
			*alpha = 180;		
			ip->x = pos.x;
		}
		return;
	}
	if(aPoint.x == middle.x){
		ip->x = middle.x;
		if(aPoint.y > middle.y){
			ip->y = pos.y + height;
			*alpha = 90;
		} else {
			ip->y = pos.y;
			*alpha = -90;
		}
		return;
	}
	s = (aPoint.y - middle.y) / (aPoint.x - middle.x);
	*alpha = 57.29577951 * atan(s);
	r = MIN(width,height) / 3;
	if(aPoint.y > middle.y){
		if(aPoint.x > middle.x){ 						// I. quadrant
			l1.x = middle.x;
			l1.y = pos.y + height;
			l2.x = pos.x + width - r;
			l2.y = pos.y + height;
			if(miscTD_straddles(l1, l2, middle, aPoint)){
				ip->y = l1.y;
				ip->x = middle.x + (ip->y - middle.y) / s;
			} else {
				l1.x = l2.x = pos.x + width;
				l1.y = middle.y;
				l2.y = pos.y + height - r;
				if(miscTD_straddles(l1, l2, middle, aPoint)){
					ip->x = l2.x;
					ip->y = middle.y + s * (ip->x - middle.x);	
				} else {
					x0 = middle.x;
					y0 = middle.y;
					xm = pos.x + width - r;
					ym = pos.y + height - r;
					ausdruck = (pow(r,2) + pow(r,2)*pow(s,2) - pow(s,2)*pow(xm,2) + 
          						2*pow(s,2)*xm*x0 - pow(s,2)*pow(x0,2) + 2*s*xm*ym - 2*s*x0*ym - 
          						pow(ym,2) - 2*s*xm*y0 + 2*s*x0*y0 + 2*ym*y0 - pow(y0,2));
					ip->x = (xm + pow(s,2)*x0 + s*ym - s*y0 + sqrt(ausdruck))/(1 + pow(s,2));
					ip->y = (s*xm - s*x0 + pow(s,2)*ym + y0 + s*sqrt(ausdruck))/(1 + pow(s,2));
					if(ip->y < ym){
						ip->x = (xm + pow(s,2)*x0 + s*ym - s*y0 - sqrt(ausdruck))/(1 + pow(s,2));
						ip->y = (s*xm - s*x0 + pow(s,2)*ym + y0 - s*sqrt(ausdruck))/(1 + pow(s,2));
					}
				}
			}
		} else { 										// II. quadrant
			l1.x = middle.x;
			l1.y = pos.y + height;
			l2.x = pos.x + r;
			l2.y = pos.y + height;
			if(miscTD_straddles(l1, l2, middle, aPoint)){
				ip->y = l1.y;
				ip->x = middle.x + (ip->y - middle.y) / s;
			} else {
				l1.x = l2.x = pos.x;
				l1.y = middle.y;
				l2.y = pos.y + height - r;
				if(miscTD_straddles(l1, l2, middle, aPoint)){
					ip->x = l2.x;
					ip->y = middle.y + s * (ip->x - middle.x);	
				} else {
					x0 = middle.x;
					y0 = middle.y;
					xm = pos.x + r;
					ym = pos.y + height - r;
					ausdruck = (pow(r,2) + pow(r,2)*pow(s,2) - pow(s,2)*pow(xm,2) + 
          						2*pow(s,2)*xm*x0 - pow(s,2)*pow(x0,2) + 2*s*xm*ym - 2*s*x0*ym - 
          						pow(ym,2) - 2*s*xm*y0 + 2*s*x0*y0 + 2*ym*y0 - pow(y0,2));
					ip->x = (xm + pow(s,2)*x0 + s*ym - s*y0 + sqrt(ausdruck))/(1 + pow(s,2));
					ip->y = (s*xm - s*x0 + pow(s,2)*ym + y0 + s*sqrt(ausdruck))/(1 + pow(s,2));
					if(ip->y < ym){
						ip->x = (xm + pow(s,2)*x0 + s*ym - s*y0 - sqrt(ausdruck))/(1 + pow(s,2));
						ip->y = (s*xm - s*x0 + pow(s,2)*ym + y0 - s*sqrt(ausdruck))/(1 + pow(s,2));
					}
				}
			}
             		*alpha += 180;
		}
	} else {
		if(aPoint.x > middle.x){ 						// IV. quadrant
			l1.x = middle.x;
			l1.y = pos.y;
			l2.x = pos.x + width - r;
			l2.y = pos.y;
			if(miscTD_straddles(l1, l2, middle, aPoint)){
				ip->y = l1.y;
				ip->x = middle.x + (ip->y - middle.y) / s;
			} else {
				l1.x = l2.x = pos.x + width;
				l1.y = middle.y;
				l2.y = pos.y + r;
				if(miscTD_straddles(l1, l2, middle, aPoint)){
					ip->x = l2.x;
					ip->y = middle.y + s * (ip->x - middle.x);	
				} else {
					x0 = middle.x;
					y0 = middle.y;
					xm = pos.x + width - r;
					ym = pos.y + r;
					ausdruck = (pow(r,2) + pow(r,2)*pow(s,2) - pow(s,2)*pow(xm,2) + 
          						2*pow(s,2)*xm*x0 - pow(s,2)*pow(x0,2) + 2*s*xm*ym - 2*s*x0*ym - 
          						pow(ym,2) - 2*s*xm*y0 + 2*s*x0*y0 + 2*ym*y0 - pow(y0,2));
					ip->x = (xm + pow(s,2)*x0 + s*ym - s*y0 + sqrt(ausdruck))/(1 + pow(s,2));
					ip->y = (s*xm - s*x0 + pow(s,2)*ym + y0 + s*sqrt(ausdruck))/(1 + pow(s,2));
					if(ip->y > ym){
						ip->x = (xm + pow(s,2)*x0 + s*ym - s*y0 - sqrt(ausdruck))/(1 + pow(s,2));
						ip->y = (s*xm - s*x0 + pow(s,2)*ym + y0 - s*sqrt(ausdruck))/(1 + pow(s,2));
					}
				}
			}
		} else { 										// III. quadrant
			l1.x = middle.x;
			l1.y = pos.y;
			l2.x = pos.x + r;
			l2.y = pos.y;
			if(miscTD_straddles(l1, l2, middle, aPoint)){
				ip->y = l1.y;
				ip->x = middle.x + (ip->y - middle.y) / s;
			} else {
				l1.x = l2.x = pos.x;
				l1.y = middle.y;
				l2.y = pos.y + r;
				if(miscTD_straddles(l1, l2, middle, aPoint)){
					ip->x = l2.x;
					ip->y = middle.y + s * (ip->x - middle.x);	
				} else {
					x0 = middle.x;
					y0 = middle.y;
					xm = pos.x + r;
					ym = pos.y + r;
					ausdruck = (pow(r,2) + pow(r,2)*pow(s,2) - pow(s,2)*pow(xm,2) + 
          						2*pow(s,2)*xm*x0 - pow(s,2)*pow(x0,2) + 2*s*xm*ym - 2*s*x0*ym - 
          						pow(ym,2) - 2*s*xm*y0 + 2*s*x0*y0 + 2*ym*y0 - pow(y0,2));
					ip->x = (xm + pow(s,2)*x0 + s*ym - s*y0 + sqrt(ausdruck))/(1 + pow(s,2));
					ip->y = (s*xm - s*x0 + pow(s,2)*ym + y0 + s*sqrt(ausdruck))/(1 + pow(s,2));
					if(ip->y > ym){
						ip->x = (xm + pow(s,2)*x0 + s*ym - s*y0 - sqrt(ausdruck))/(1 + pow(s,2));
						ip->y = (s*xm - s*x0 + pow(s,2)*ym + y0 - s*sqrt(ausdruck))/(1 + pow(s,2));
					}
				}
			}
                        *alpha += 180;
		}
	}
}
					
- (void)makePathWithBounds:(NSRect)aRect
{
	float r;
	
	r = MIN(aRect.size.width / 3, aRect.size.height / 3);
	[path moveto:aRect.origin.x :aRect.origin.y + r];
	[path lineto:aRect.origin.x :aRect.origin.y + aRect.size.height - r];
	[path curveto:aRect.origin.x :aRect.origin.y + aRect.size.height - r + r * 0.5519
			:aRect.origin.x + r - r * 0.5519 :aRect.origin.y + aRect.size.height
			:aRect.origin.x + r :aRect.origin.y + aRect.size.height];
	[path lineto:aRect.origin.x + aRect.size.width - r :aRect.origin.y + aRect.size.height];
	[path curveto:aRect.origin.x + aRect.size.width - r + r * 0.5519 :aRect.origin.y + aRect.size.height
			:aRect.origin.x + aRect.size.width :aRect.origin.y + aRect.size.height - r + r * 0.5519
			:aRect.origin.x + aRect.size.width :aRect.origin.y + aRect.size.height - r];
	[path lineto:aRect.origin.x + aRect.size.width :aRect.origin.y + r];
	[path curveto:aRect.origin.x + aRect.size.width :aRect.origin.y + r - r * 0.5519
			:aRect.origin.x + aRect.size.width - r + r * 0.5519 :aRect.origin.y
			:aRect.origin.x + aRect.size.width - r :aRect.origin.y];
	[path lineto:aRect.origin.x + r :aRect.origin.y];
	[path curveto:aRect.origin.x + r - r * 0.5519 :aRect.origin.y
			:aRect.origin.x :aRect.origin.y + r - r * 0.5519  
			:aRect.origin.x :aRect.origin.y + r];
	[path closepath];
}
			
- (void)fillParamsWithBounds:(NSRect)aRect
{
	float *params, *bbox,r;
	
	params = [path params];
	bbox = [path bbox];
	bbox[0] = aRect.origin.x;
	bbox[1] = aRect.origin.y;
	bbox[2] = aRect.origin.x + aRect.size.width;
	bbox[3] = aRect.origin.y + aRect.size.height;
	r = MIN(aRect.size.width / 3, aRect.size.height / 3);
	params[0] = aRect.origin.x;
	params[1] = aRect.origin.y + r;
	params[2] = aRect.origin.x;
	params[3] = aRect.origin.y + aRect.size.height - r;
	params[4] = aRect.origin.x;
	params[5] = aRect.origin.y + aRect.size.height - r + r * 0.5519;
	params[6] = aRect.origin.x + r - r * 0.5519;
	params[7] = aRect.origin.y + aRect.size.height;
	params[8] = aRect.origin.x + r;
	params[9] = aRect.origin.y + aRect.size.height;
	params[10] = aRect.origin.x + aRect.size.width - r;
	params[11] = aRect.origin.y + aRect.size.height;
	params[12] = aRect.origin.x + aRect.size.width - r + r * 0.5519;
	params[13] = aRect.origin.y + aRect.size.height;
	params[14] = aRect.origin.x + aRect.size.width;
	params[15] = aRect.origin.y + aRect.size.height - r + r * 0.5519;
	params[16] = aRect.origin.x + aRect.size.width;
	params[17] = aRect.origin.y + aRect.size.height - r;
	params[18] = aRect.origin.x + aRect.size.width;
	params[19] = aRect.origin.y + r;
	params[20] = aRect.origin.x + aRect.size.width;
	params[21] = aRect.origin.y + r - r * 0.5519;
	params[22] = aRect.origin.x + aRect.size.width - r + r * 0.5519;
	params[23] = aRect.origin.y;
	params[24] = aRect.origin.x + aRect.size.width - r;
	params[25] = aRect.origin.y;
	params[26] = aRect.origin.x + r;
	params[27] = aRect.origin.y;
	params[28] = aRect.origin.x + r - r * 0.5519;
	params[29] = aRect.origin.y;
	params[30] = aRect.origin.x;
	params[31] = aRect.origin.y + r - r * 0.5519;
	params[32] = aRect.origin.x;
	params[33] = aRect.origin.y + r;
}

+ (NSSize)calcSizeForInnerSize:(NSSize)aSize
{
	NSSize os;
	float cx,cy;
	
	cx = aSize.width / 2;
	cy = aSize.height / 2;
	if(aSize.width > aSize.height){
		os.height = 2 * cy / (1 - 0.1339746 * 2 / 3);
		os.width = 2 * cx + os.height / 3;
	} else {
		os.width = 3 * cx;
		os.height = 2 * cy + os.width * 2 / 3 * 0.1339746;
	}
	return os;
}
		              
@end


	
