extern CYLINDER thecylinder;
extern CONE thecone;
extern CIRCLE thecircle;
extern PLANE theplane;
extern PARABOLA theparabola;
extern RECTONICAL therectonical;

extern WindowPtr outwindow;
extern PicHandle inpicture;

pascal void CYLINDERline(p2)
Point p2;
{
	short sx,sy;
	short mu,incr;
	Rect r;
	double x,y,theta,radius,dx,dy,dh,dv,length;
	Point p,p1;
	
	GetPen(&p1);
	
	/* Determine the centre of the window */
	r = outwindow->portRect;
	ClipRect(&r);
	sx = (r.right + r.left) / 2;
	sy = (r.bottom + r.top) / 2;
	
	/* Determine the bounds of the image being transformed */
	r = (*inpicture)->picFrame;
	dx = (thecylinder.theta1 - thecylinder.theta2) / (double)(r.right  - r.left);
	dy = (thecylinder.r1     - thecylinder.r2    ) / (double)(r.bottom - r.top );
	
	/*
		Calculate the length of the line and hence the resolution
		at which to draw it
	*/
	dh = p2.h - p1.h;
	dv = p2.v - p1.v;
	length = sqrt(dh*dh + dv*dv);
	if (length <= 3)
		incr = 1;
	else if (length < 10)
		incr = 3;
	else if (length < 100)
		incr = 15;
	else
		incr = 30;
	
	for (mu=0;mu<=incr;mu++) {
		x = p1.h + mu * dh / incr - r.left;
		y = p1.v + mu * dv / incr - r.top;
		theta  = x * dx + thecylinder.theta2;
		radius = y * dy + thecylinder.r2;
		
		p.h = sx + (short)(radius * cos(theta*DTOR));
		p.v = sy - (short)(radius * sin(theta*DTOR));
		if (mu == 0)
			MoveTo(p.h,p.v);
		else
			StdLine(p);
	}
}

pascal void CONEline(p2)
Point p2;
{
	short sx,sy;
	short mu,incr;
	Rect r;
	double x,y,theta,dx,dy,cx,cy,dh,dv,length;
	double radius,rnew,ra,slope;
	Point p,p1;
	
	GetPen(&p1);
	
	/* Determine the centre of the window */
	r = outwindow->portRect;
	ClipRect(&r);
	sx = (r.right + r.left) / 2;
	sy = (r.bottom + r.top) / 2;
	
	/* Determine the bounds of the image being transformed */
	r = (*inpicture)->picFrame;
	dx = (r.right - r.left) / 2.0;
	dy = (r.bottom - r.top) / 2.0;
	cx = (r.right + r.left) / 2.0;
	cy = (r.bottom + r.top) / 2.0;
	ra = sqrt(dx*dx + dy*dy);
	slope = (thecone.r1 - thecone.r2) / ra;
	
	/*
		Calculate the length of the line and hence the resolution
		at which to draw it
	*/
	dh = p2.h - p1.h;
	dv = p2.v - p1.v;
	length = sqrt(dh*dh + dv*dv);
	if (length <= 3)
		incr = 1;
	else if (length < 10)
		incr = 3;
	else if (length < 100)
		incr = 15;
	else
		incr = 30;
	
	for (mu=0;mu<=incr;mu++) {
		x = p1.h + (mu * dh) / incr - cx;
		y = p1.v + (mu * dv) / incr - cy;
		theta  = myarctan(x,y);
		radius = sqrt(x*x + y*y);
		rnew = slope * radius + thecone.r2;
		
		p.h = sx + (short)(rnew * cos(theta));
		p.v = sy + (short)(rnew * sin(theta));
		if (mu == 0)
			MoveTo(p.h,p.v);
		else
			StdLine(p);
	}
}

pascal void CIRCLEline(p2)
Point p2;
{
	short sx,sy;
	short mu,incr;
	Rect r;
	double x,y,xx,yy,dx,dy,cx,cy,dh,dv,length,radius;
	double theta,degrees,specialangle;
	Point p,p1;
	
	GetPen(&p1);
	
	/* Determine the centre of the window */
	r = outwindow->portRect;
	ClipRect(&r);
	sx = (r.right + r.left) / 2;
	sy = (r.bottom + r.top) / 2;
	
	/* Determine the bounds of the image being transformed */
	r = (*inpicture)->picFrame;
	dx = (r.right - r.left) / 2.0;
	dy = (r.bottom - r.top) / 2.0;
	cx = (r.right + r.left) / 2.0;
	cy = (r.bottom + r.top) / 2.0;
	
	/*
		Calculate the length of the line and hence the resolution
		at which to draw it
	*/
	dh = p2.h - p1.h;
	dv = p2.v - p1.v;
	length = sqrt(dh*dh + dv*dv);
	if (length <= 3)
		incr = 1;
	else if (length < 10)
		incr = 3;
	else if (length < 100)
		incr = 15;
	else
		incr = 30;
	
	for (mu=0;mu<=incr;mu++) {
		x = p1.h + (mu * dh) / incr - cx;
		y = p1.v + (mu * dv) / incr - cy;
		theta  = myarctan(x,y);
		degrees = theta * RTOD;
		radius = sqrt(x*x + y*y);
		
		specialangle = myarctan(dx,dy) * RTOD;
		if (degrees < - 180 + specialangle) {
			xx = x * thecircle.rx * ABS(cos(theta) / dx);
			yy = y * thecircle.ry * ABS(cos(theta) / dx);
		} else if (degrees < -specialangle) {
			xx = x * thecircle.rx * ABS(sin(theta) / dy);
			yy = y * thecircle.ry * ABS(sin(theta) / dy);
		} else if (degrees < specialangle) {
			xx = x * thecircle.rx * ABS(cos(theta) / dx);
			yy = y * thecircle.ry * ABS(cos(theta) / dx);
		} else if (degrees < 180 - specialangle) {
			xx = x * thecircle.rx * ABS(sin(theta) / dy);
			yy = y * thecircle.ry * ABS(sin(theta) / dy);
		} else {
			xx = x * thecircle.rx * ABS(cos(theta) / dx);
			yy = y * thecircle.ry * ABS(cos(theta) / dx);
		}
				
		p.h = sx + (short)xx;
		p.v = sy + (short)yy;
		if (mu == 0)
			MoveTo(p.h,p.v);
		else
			StdLine(p);
	}
}

pascal void PLANEline(p2)
Point p2;
{
	short sx,sy,mu,incr;
	Point p,p1;
	Rect r;
	double length,dh,dv,dx,dy,cx,cy;
	double mux,muy;
	double x,y,x1,y1,x2,y2,x3,y3,x4,y4,mu1,mu2;
	
	GetPen(&p1);
	
	/* Determine the centre of the window */
	r = outwindow->portRect;
	ClipRect(&r);
	sx = (r.right + r.left) / 2;
	sy = (r.bottom + r.top) / 2;
	
	/* Determine the bounds of the image being transformed */
	r = (*inpicture)->picFrame;
	dx = (r.right - r.left) / 2.0;
	dy = (r.bottom - r.top) / 2.0;
	cx = (r.right + r.left) / 2.0;
	cy = (r.bottom + r.top) / 2.0;
	
	/*
		Calculate the length of the line and hence the resolution
		at which to draw it
	*/
	dh = p2.h - p1.h;
	dv = p2.v - p1.v;
	length = sqrt(dh*dh + dv*dv);
	if (length <= 3)
		incr = 1;
	else if (length < 10)
		incr = 3;
	else if (length < 100)
		incr = 15;
	else
		incr = 30;

	for (mu=0;mu<=incr;mu++) {
		x = p1.h + mu * dh / incr - r.left;
		y = p1.v + mu * dv / incr - r.top;

		mux = (x - r.left) / (double)(r.right - r.left);
		muy = (y - r.bottom) / (double)(r.top - r.bottom);
	
		x1 = theplane.p1.h + mux * (theplane.p4.h - theplane.p1.h);
		y1 = theplane.p1.v + mux * (theplane.p4.v - theplane.p1.v);
		
		x2 = theplane.p2.h + mux * (theplane.p3.h - theplane.p2.h);
		y2 = theplane.p2.v + mux * (theplane.p3.v - theplane.p2.v);
		
		x3 = theplane.p1.h + muy * (theplane.p2.h - theplane.p1.h);
		y3 = theplane.p1.v + muy * (theplane.p2.v - theplane.p1.v);
		
		x4 = theplane.p4.h + muy * (theplane.p3.h - theplane.p4.h);
		y4 = theplane.p4.v + muy * (theplane.p3.v - theplane.p4.v);
	
		if (!lineintersect(x1,y1,x2,y2,x3,y3,x4,y4,&mu1,&mu2))
			return;
	
		p.h = x1 + mu1 * (x2 - x1);
		p.v = y1 + mu1 * (y2 - y1);
		
		if (mu == 0)
			MoveTo(p.h,p.v);
		else 
			StdLine(p);
	}
}

pascal void PARABOLAline(p2)
Point p2;
{
	short sx,sy,mu,incr;
	Point p,p1;
	Rect r;
	double intersect,scale;
	double length,dh,dv,dx,dy,cx,cy;
	double x,y;
	
	GetPen(&p1);
	
	/* Determine the centre of the window */
	r = outwindow->portRect;
	ClipRect(&r);
	sx = (r.right + r.left) / 2;
	sy = (r.bottom + r.top) / 2;
	
	/* Determine the bounds of the image being transformed */
	r = (*inpicture)->picFrame;
	dx = (r.right - r.left) / 2.0;
	dy = (r.bottom - r.top) / 2.0;
	cx = (r.right + r.left) / 2.0;
	cy = (r.bottom + r.top) / 2.0;
	
	/*
		Calculate the length of the line and hence the resolution
		at which to draw it
	*/
	dh = p2.h - p1.h;
	dv = p2.v - p1.v;
	length = sqrt(dh*dh + dv*dv);
	if (length <= 3)
		incr = 1;
	else if (length < 10)
		incr = 3;
	else if (length < 100)
		incr = 15;
	else
		incr = 30;

	for (mu=0;mu<=incr;mu++) {
		x = p1.h + (mu * dh) / incr - cx;
		x *= (theparabola.b / dx);
		y = p1.v + (mu * dv) / incr - cy;
		
		intersect = y * theparabola.a / dy;
		scale = (y * sy / dy - intersect) / (theparabola.b * theparabola.b);
		
		p.h = sx + x;
		p.v = sy + scale * x * x + intersect;
		
		if (mu == 0)
			MoveTo(p.h,p.v);
		else 
			StdLine(p);
	}
}

pascal void RECTONICALline(p2)
Point p2;
{
	short sx,sy;
	short mu,incr;
	Rect r;
	double x,y,dx,dy,cx,cy,dh,dv,length,slopex,slopey;
	Point p,p1;
	
	GetPen(&p1);
	
	/* Determine the centre of the window */
	r = outwindow->portRect;
	ClipRect(&r);
	sx = (r.right + r.left) / 2;
	sy = (r.bottom + r.top) / 2;
	
	/* Determine the bounds of the image being transformed */
	r = (*inpicture)->picFrame;
	dx = (r.right - r.left) / 2.0;
	dy = (r.bottom - r.top) / 2.0;
	cx = (r.right + r.left) / 2.0;
	cy = (r.bottom + r.top) / 2.0;
	
	/*
		Calculate the length of the line and hence the resolution
		at which to draw it
	*/
	dh = p2.h - p1.h;
	dv = p2.v - p1.v;
	length = sqrt(dh*dh + dv*dv);
	if (length <= 3)
		incr = 1;
	else if (length < 10)
		incr = 3;
	else if (length < 100)
		incr = 15;
	else
		incr = 30;
	
	slopex = (therectonical.x2 - therectonical.x1) / dx;
	slopey = (therectonical.y2 - therectonical.y1) / dy;
	
	for (mu=0;mu<=incr;mu++) {
		x = p1.h + (mu * dh) / incr - cx;
		y = p1.v + (mu * dv) / incr - cy;
		
		if (x >= 0)
			p.h = sx + (short)(x * slopex + therectonical.x1);
		else
			p.h = sx + (short)((x + dx) * slopex - therectonical.x2);

		if (y >= 0)
			p.v = sy + (short)(y * slopey + therectonical.y1);
		else
			p.v = sy + (short)((y + dy) * slopey - therectonical.y2);
		
		if (mu == 0)
			MoveTo(p.h,p.v);
		else
			StdLine(p);
	}
}

