
/////////////////////////////////////////////////////////////////////////////////////////

//                    geometry.lib header

//                    g.j.hawkesford August 2003
//						modified with 2d & 3d vector methods 2006
//
// This program is released under the BSD license. See the file COPYING for details.
//
/////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifdef WIN32
#pragma warning( disable : 4996 )
#ifndef WINVER
	#define WINVER 0x501
#endif
#endif

#include <math.h>
#include <algorithm>
#include <vector>
#include <list>
#include <iostream>
#include <fstream>
#include <string.h>

using namespace std;


namespace geoff_geometry {

	// offset methods
	enum OFFSET_METHODS {
		NO_ELIMINATION = 0,
		BASIC_OFFSET,
		ROLLINGBALL_OFFSET // unfinished
	};

	enum SPAN_IDS {
		UNMARKED = 0xe0000000,
		ROLL_AROUND,
		INTERSECTION,
		FULL_CIRCLE_KURVE
		};


	class Vector2d;
	class Vector3d;
	class Point;
	class Point3d;
	class CLine;
	class Circle;
	class Span;
	class Kurve;
	class Line;


	enum UNITS_TYPE{
		MM = 0,
		METRES,
		INCHES
	};

	extern int	  UNITS;					// may be enum UNITS_TYPE (MM METRES or INCHES)
	extern double TOLERANCE;				// CAD Geometry resolution (inexact, eg. from import)
	extern double TOLERANCE_SQ;				// tolerance squared for faster coding.
	extern double TIGHT_TOLERANCE;
	extern double UNIT_VECTOR_TOLERANCE;
	extern double SMALL_ANGLE;				// small angle tangency test eg isConvex
	extern double SIN_SMALL_ANGLE;
	extern double COS_SMALL_ANGLE;
	extern double RESOLUTION;				// CNC resolution

	void set_Tolerances(int mode);
	double mm(double value);				// convert to current units from mm

inline bool FEQ(double a, double b, double tolerance = TOLERANCE) {return fabs(a - b) <= tolerance;}
inline bool FNE(double a, double b, double tolerance = TOLERANCE) {return fabs(a - b) > tolerance;}

inline bool FEQZ(double a, double tolerance = TIGHT_TOLERANCE) {return fabs(a) <= tolerance;}
inline bool FNEZ(double a, double tolerance = TIGHT_TOLERANCE) {return fabs(a) > tolerance;}

#define PI 3.1415926535897932384626433832795e0
#define DegreesToRadians (PI / 180.0e0)
#define RadiansToDegrees (180.0e0 / PI)
#define NEARLY_ONE 0.99999999999e0
#define CPTANGENTTOL 1.0e-04			// normalised vector crossproduct tolerance sin A  so A = .0057deg

#define TANTO		-1
#define ANTITANTO	1

#define TANGENT		0

#define NEARINT		1
#define FARINT		-1

#define LEFTINT		1
#define RIGHTINT	-1

#define CFILLET			0	// corner fillet
#define CHAMFER			1	// chamfer

#define GEOFF_LEFT 1
#define NONE 0
#define GEOFF_RIGHT -1


#define LINEAR 0	// linear
#define ACW 1		// anti-clockwise
#define CW -1		// clockwise

	const wchar_t* getMessage(const wchar_t* original);							// dummy
	void FAILURE(const wchar_t* str);
	void FAILURE(const std::wstring& str);

	enum MESSAGE_GROUPS {
		GENERAL_MESSAGES,
		GEOMETRY_ERROR_MESSAGES,
		PARAMSPMP
	};

	enum GENERAL_MESSAGES {
		MES_TITLE = 0,
		MES_UNFINISHEDCODING,
		MES_ERRORFILENAME,
		MES_LOGFILE,
		MES_LOGFILE1,
		MES_P4CMENU,
		MES_P4CMENUHINT
	};

	enum GEOMETRY_ERROR_MESSAGES{	// For geometry.lib
		MES_DIFFSCALE = 1000,
		MES_POINTONCENTRE,
		MES_INVALIDARC,
		MES_LOFTUNEQUALSPANCOUNT,
		MES_EQUALSPANCOUNTFAILED,
		MES_CANNOTTRIMSPAN,
		MES_INDEXOUTOFRANGE,
		MES_BAD_VERTEX_NUMBER,
		MES_BAD_REF_OFFSET,
		MES_BAD_SEC_OFFSET,
		MES_ROLLINGBALL4AXIS_ERROR,
		MES_INPUT_EQUALSPANCOUNT,
		MES_INVALIDPLANE
	};

	// homogenous 4 x 4 Matrix class
	class Matrix{
	protected:
	public:
		double e[16];
		bool m_unit;												// true if unit matrix
		int m_mirrored;												// 1 if mirrored, 0 if not and -1 if unknown

	public:
		// constructors etc...
		Matrix();													// create a unit matrix
		Matrix(double m[16]);										// from an array
		Matrix(const Matrix& m);									// copy constructor

		~Matrix(){};

		//operators
		bool operator==(const Matrix &m)const;
		bool operator!=(const Matrix &m)const { return !(*this == m);}

		// methods
		void	Unit();												// unit matrix
		void	Get(double* p) const;								// get the matrix into p
		void	Put(double*p);										// put p[16] into matrix
		void	Translate(double x, double y, double z=0);			// Translation

		void	Rotate(double sinang, double cosang, Vector3d *rotAxis); // Rotation about rotAxis
		void	Rotate(double angle, Vector3d *rotAxis);			// Rotation about rotAxis

		void	Rotate(double sinang, double cosang, int Axis);			// Rotation with cp & dp
		void	Rotate(double angle, int Axis);						// Rotation with angle

		void	Scale(double scale);								// Scale
		void	Scale(double scalex, double scaley, double scalez);

		void	Multiply(Matrix& m);								// Multiply 2 Matrices
		//	void	Transform(Point& p);
		void	Transform(double p0[3]) const;							// Transform p0 thro' this matrix
		void	Transform(double p0[3], double p1[3]) const;				// Transform p0 to p1 thro' this matrix
		void	Transform2d(double p0[2], double p1[2]) const;			// Transform p0 to p1 thro' this matrix

		int		IsMirrored();										// true if matrix has a mirror transformation
		int		IsUnit();											// true if matrix is unit matrix
		void	GetTranslate(double& x, double& y, double& z) const;		// get translation from matrix
		void	GetScale(double& sx, double& sy, double& sz) const;		// get scale from matrix
		bool	GetScale(double& sx) const;								// get scale from matrix (true if uniform scale)
		void	GetRotation(double& ax, double& ay, double& az) const;	// get rotation from matrix

		Matrix	Inverse();											// inverts this matrix
	};

	extern Matrix UnitMatrix;		// a Unit Matrix


	// 2d Point class
	class Point {
		friend wostream& operator << (wostream& op, Point& p);

	public:
		bool	ok;																// true if this point is defined correctly	
		double	x;																// x value
		double	y;																// y value

		// constructors etc...
		inline	Point(){ ok=false;};																// Point p1
		inline	Point( double xord, double yord, bool okay = true) {					// Point p1(10,30);
			x = xord; y = yord; ok = okay;}
		inline	Point( const Point& p ) {												// copy constructor  Point p1(p2);
			x = p.x; y = p.y; ok = p.ok;}
				Point( const Point3d& p );												// copy constructor  Point p1(p2);
		Point(const Vector2d& v);

		// operators
		bool operator==(const Point &p)const;
		bool operator!=(const Point &p)const { return !(*this == p);}
		inline	Point	operator+(const Point &p)const{return Point(x + p.x, y + p.y);}		// p0 = p1 + p2;
		inline	Point	operator+=(const Point &p){return Point(x += p.x, y += p.y);}		// p0 += p1;
		Point operator+(const Vector2d &v)const;			// p1 = p0 + v0;

		// destructor
		//~Point(){};

		// methods
		Point	Transform(const Matrix& m);											    // transform point
		double	Dist(const Point& p)const;														// distance between 2 points
		double	DistSq(const Point& p)const;													// distance squared
		double	Dist(const CLine& cl)const;													// distance p to cl
		Point	Mid(const Point& p, double factor=.5)const;									// mid point
		void	get(double xyz[2]) {xyz[0] = x; xyz[1] = y;}						// return to array
	};


#define INVALID_POINT	Point(9.9999999e50, 0, false)
#define INVALID_POINT3D	Point3d(9.9999999e50, 0, 0, false)
#define INVALID_CLINE	CLine(INVALID_POINT, 1, 0, false)
#define INVALID_CIRCLE	Circle(INVALID_POINT, 0)

	// 3d point class
	class Point3d {
		friend wostream& operator <<(wostream& op, Point3d& p);
	public:
//		bool	ok;																// true if this point is defined correctly	
		double	x;																// x value
		double	y;																// y value
		double	z;																// z value

		// constructors
		inline	Point3d(){};// {z=0; /*ok=false;*/};												// Point p1
		inline	Point3d(const double* xyz) {x = xyz[0], y = xyz[1]; z = xyz[2];}
		inline	Point3d( double xord, double yord, double zord = 0/*, bool okay = true*/) {	// Point p1(10,30.5);
			x = xord; y = yord; z = zord;/* ok = okay;*/}
		inline	Point3d( const Point3d& p ) {											// copy constructor  Point p1(p2);
			x = p.x; y = p.y;  z = p.z;/* ok = p.ok;*/}
		inline	Point3d( const Point& p ) {												// copy constructor  Point p1(p2);
			x = p.x; y = p.y;  z = 0; /*ok = p.ok;*/}
		inline	Point3d( const Point& p, double zord ) {								// copy constructor  Point p1(p2, z);
			x = p.x; y = p.y;  z = zord;/* ok = p.ok;*/}
		Point3d(const Vector3d& v);

		// destructor
//		~Point3d();

		// operators
		bool operator==(const Point3d &p)const;
		bool operator!=(const Point3d &p)const { return !(*this == p);}
		Point3d operator+(const Vector3d &v)const;			// p1 = p0 + v0;


		// methods
#ifdef PEPSDLL
		void	ToPeps(int id, bool draw = true);									// copy Point to Peps
#endif
		Point3d Transform(const Matrix& m);
		double Dist(const Point3d& p)const;													// distance between 2 points
		double DistSq(const Point3d& p)const;													// distance squared between 2 points
		Point3d	Mid(const Point3d& p, double factor = 0.5)const;									// midpoint
		void get(double xyz[3]) {xyz[0] = x; xyz[1] = y; xyz[2] = z;}
		double* getBuffer(){return &this->x;};																		// returns ptr to data
		const double* getBuffer()const{return &this->x;};																		// returns ptr to data

	};

	// 2d vector class
	class Vector2d{
		friend wostream& operator <<(wostream& op, Vector2d& v);
	private:
		double dx, dy;		
	public:

		// constructors
		Vector2d() {};
		inline	Vector2d(const Vector2d &v) { dx = v.dx; dy = v.dy;}
				Vector2d(const Vector3d &v);		// careful
		inline	Vector2d(double x, double y) {dx = x, dy = y;}
		inline	Vector2d(const Point& p0, const Point& p1) {dx = p1.x - p0.x; dy = p1.y - p0.y;}
		inline	Vector2d(const Point *p0, const Point *p1) {dx = p1->x - p0->x; dy = p1->y - p0->y;}
		inline	Vector2d(const Point& p) { dx = p.x; dy = p.y;} // from 0,0 to p
		inline	Vector2d(double angle) {dx = cos(angle *= DegreesToRadians); dy = sin(angle);}	// constructs a vector from an angle (0° - 360°)


		// operators
		inline	const	Vector2d& operator=(const Vector2d &v){dx = v.dx; dy = v.dy; return *this;}			// v1 = v2;
		inline			Vector2d operator+(const Vector2d &v)const{return Vector2d(dx + v.dx, dy + v.dy);}	// v2 = v0 + v1;
		inline			Point	operator+(const Point &p)const{return Point(this->dx + p.x, this->dy + p.y);}			// p1 = v0 + p0;
		inline			Vector2d operator+(const double d){ return Vector2d(dx + d, dy + d); };

		inline	const	Vector2d& operator+=(const Vector2d &v){dx += v.dx; dy += v.dy; return *this;}		// v1 += v0;
		inline			Vector2d operator-(const Vector2d &v)const{return Vector2d( dx - v.dx, dy - v.dy);}	// v2 = v0 - v1;
		inline	const	Vector2d& operator-=(const Vector2d &v){dx -= v.dx; dy =- v.dy; return *this;}		// v1 -= v0;
		inline			Vector2d operator-(const double d){ return Vector2d(dx - d, dy - d); };

		inline	const	Vector2d operator-(void)const{return Vector2d(-dx, -dy);}							// v1 = -v0;  (unary minus)

		inline	const	double operator*(const Vector2d &v)const{return (dx * v.dx + dy * v.dy);}			// dot product	m0.m1.cos a = v0 * v1
		inline			Vector2d operator*(double c)const{return Vector2d(dx*c, dy*c);}							// scalar product
		inline	const	Vector2d& operator*=(double c){dx *= c; dy *= c; return *this;}						// scalar product
		inline			Vector2d operator*(int c)const{return Vector2d(dx*(double)c, dy*(double)c);}				// scalar product

		inline	const	double operator^(const Vector2d &v)const{return (dx * v.dy - dy * v.dx);}			// cross product m0.m1.sin a = v0 ^ v1
		inline			Vector2d operator~(void)const{return Vector2d(-dy, dx);}							// perp to left

						bool operator==(const Vector2d &v)const;													// v1 == v2
		inline			bool operator!=(const Vector2d &v)const { return !(*this == v);}							// v1 != v2



		// methods
		void get(double xyz[2]) {xyz[0] = dx; xyz[1] = dy;}													// return to array
		inline	double	getx()const{return dx;}
		inline	double	gety()const{return dy;}
		inline	void	putx(double x){dx = x;}
		inline	void	puty(double y){dy = y;}
		double	normalise()
		{double m = magnitude(); if(m < TIGHT_TOLERANCE) {dx=dy=0; return 0;} dx/=m; dy/=m; return m;}				// normalise & returns magnitude
		inline	double	magnitudesqd(void)const{return(dx * dx + dy * dy);}									// magnitude squared
		inline	double	magnitude(void)const{return(sqrt(magnitudesqd()));}									// magnitude
		void	Rotate(double cosa, double sina){															// rotate vector by angle
			double temp = -dy * sina + dx * cosa;
			dy = dx * sina + cosa * dy;
			dx = temp;
		}	
		inline	void	Rotate(double angle) { if(FEQZ(angle) == true) return; Rotate(cos(angle), sin(angle));}
		void Transform( const Matrix& m);																			// transform vector

		// destructor
		//~Vector2d(){}

	};


	// 3d vector class
	class Vector3d{
		friend wostream& operator <<(wostream& op, Vector3d& v);
	private:
		double dx, dy, dz;
	public:

		// constructors
		Vector3d() {};
		Vector3d(const Vector3d &v) { dx = v.dx; dy = v.dy; dz = v.dz;}
		Vector3d(double x, double y, double z = 0) {dx = x, dy = y; dz = z;}
		Vector3d(const double* x) {dx = x[0], dy = x[1]; dz = x[2];}
		Vector3d(const double* x0, const double* x1) {dx = x1[0] - x0[0], dy = x1[1] - x0[1]; dz = x1[2] - x0[2];}
		Vector3d(const Point3d& p0, const Point3d& p1) {dx = p1.x - p0.x; dy = p1.y - p0.y; dz = p1.z - p0.z;}
		Vector3d(const Point3d& p) { dx = p.x; dy = p.y; dz = p.z;} // from 0,0,0 to p
		Vector3d(const Vector2d& v) {dx = v.getx(); dy = v.gety(); dz = 0;}

		// operators
		bool operator==(const Vector3d &v)const { return(FEQ(dx, v.dx, UNIT_VECTOR_TOLERANCE) && FEQ(dy, v.dy, UNIT_VECTOR_TOLERANCE) && FEQ(dz, v.dz, UNIT_VECTOR_TOLERANCE)); }		// v1 == v2 (unit only!)
		bool operator!=(const Vector3d &v)const { return (!(*this == v)); }											// v1 != v2
		const	Vector3d& operator=(const Vector3d &v){dx = v.dx; dy = v.dy; dz = v.dz;return *this;}				// v1 = v2;
		//	const	Vector3d& operator=(const Vector2d &v){dx = v.getx(); dy = v.gety(); dz = 0.0;return *this;}	// v1 = v2;
		inline		Point3d	operator+(const Point3d &p)const{return Point3d(dx + p.x, dy + p.y, dz + p.z);}			// p1 = v0 + p0;
		Vector3d operator+(const Vector3d &v)const{return Vector3d(dx + v.dx, dy + v.dy, dz + v.dz);}				// v2 = v0 + v1;
		const	Vector3d& operator+=(const Vector3d &v){dx += v.dx; dy += v.dy; dz += v.dz; return *this;}			// v1 += v0;
		Vector3d operator-(const Vector3d &v)const{return Vector3d( dx - v.dx, dy - v.dy, dz - v.dz);}				// v2 = v0 - v1;
		const	Vector3d& operator-=(const Vector3d &v){
			dx -= v.dx; dy =- v.dy; dz = -v.dz; return *this;}			// v1 -= v0;

		const	Vector3d operator-(void)const{return Vector3d(-dx, -dy, -dz);}										// v1 = -v0;  (unary minus)

		const	double operator*(const Vector3d &v)const{return (dx * v.dx + dy * v.dy + dz * v.dz);}				// dot product	m0 m1 cos a = v0 * v1

		const Vector3d& operator*=(double c){dx *= c; dy *= c; dz *= c; return *this;}								// scalar products
		friend const Vector3d operator*(const Vector3d &v, double c){return Vector3d(v.dx*c, v.dy*c, v.dz*c);}
		friend const Vector3d operator*(double c, const Vector3d &v){return Vector3d(v.dx*c, v.dy*c, v.dz*c);}
		friend const Vector3d operator/(const Vector3d &v, double c){return Vector3d(v.dx/c, v.dy/c, v.dz/c);}

		const	Vector3d operator^(const Vector3d &v)const{
			return Vector3d(dy * v.dz - dz * v.dy, dz * v.dx - dx * v.dz, dx * v.dy - dy * v.dx);}					// cross product vector

		// = the vector perp to the plane of the 2 vectors
		// the z component magnitude is m0.m1.sin a 	
		// methods
		inline	void get(double xyz[3])const {xyz[0] = dx; xyz[1] = dy; xyz[2] = dz;}									// return to array
		inline	double getx()const{return dx;}
		inline	double gety()const{return dy;}
		inline	double getz()const{return dz;}
		inline	void putx(double x){dx = x;}
		inline	void puty(double y){dy = y;}
		inline	void putz(double z){dz = z;}
		double normalise(){double m = magnitude(); if(m < 1.0e-09) {dx=dy=dz=0; return 0;} dx/=m; dy/=m; dz/=m;		// normalise & returns magnitude
		return m;}
		inline	double magnitude(void)const{return(sqrt(dx * dx + dy * dy + dz * dz));}								// magnitude
		inline	double magnitudeSq(void)const{return(dx * dx + dy * dy + dz * dz);}								    // magnitude squared
		void Transform( const Matrix& m);																					// transform vector
		void arbitrary_axes(Vector3d& x, Vector3d& y);
		int setCartesianAxes(Vector3d& b, Vector3d& c);
		double* getBuffer(){return &this->dx;};																		// returns ptr to data
		const double* getBuffer()const{return &this->dx;};																		// returns ptr to data

		// destructor
		//~Vector3d(){}

	};

#define ORIGIN Point3d(0,0,0)
#define NULL_VECTOR Vector3d(0,0,0)
#define Z_VECTOR Vector3d(0,0,1)
#define Y_VECTOR Vector3d(0,1,0)
#define X_VECTOR Vector3d(1,0,0)

	// 2D cline x = x0 + t * dx;    y = y0 + t * dy
	class CLine{
		friend wostream& operator <<(wostream& op, CLine& cl);
	public:
		bool ok;
		Point p;
		Vector2d v;

		// constructors
		inline	CLine()	{ok = false;};
		inline	CLine(const Point& p0, double dx, double dy, bool normalise = true){ p = p0; v = Vector2d(dx, dy); if(normalise) Normalise();};
		inline	CLine(const Point& p0, const Vector2d& v0, bool normalise = true) {p = p0; v = v0; if(normalise) Normalise();};
		inline	CLine( const CLine& s ) {p = s.p; v = s.v;};				// copy constructor  CLine s1(s2);
		inline	CLine(const Point& p0, const Point& p1) {p = p0; v = Vector2d(p0, p1); Normalise();};
		CLine(const Span& sp);	

		// operators
		const	CLine operator~(void);// perp to left
		const	CLine operator=(const Point& p0){p.x=p0.x; p.y=p0.y; return *this;};				// s = p;

		// methods
		double c();																// returns c
		void Normalise();														// normalise dx,dy
#ifdef PEPSDLL
		void ToPeps(int id, bool draw = true);									// to Peps
		void DelPeps(int id);													// delete Peps CLine
#endif
		CLine Transform(Matrix& m);												// transform a CLine
		Point Intof(const CLine& s);													// intersection of 2 clines
		Point Intof(int NF, const Circle& c);											// intersection of cline & circle 
		Point Intof(int NF, const Circle& c, Point& otherInters);	double Dist(const Point& p1)const;	//  ditto & other intersection												
		CLine Bisector(const CLine& s);												// Bisector of 2 Clines

		// destructor
//		~CLine();
	};

#define HORIZ_CLINE CLine(geoff_geometry::Point(0,0), 1.0, 0.0, true)


	// 2D circle 
	class Circle{
		friend wostream& operator <<(wostream& op, Circle& c);
	public:
		bool ok;
		Point pc;
		double	radius;

		// constructors etc...
		inline	Circle() {ok = false;};
		Circle( const Point& p, double r);										// Circle  c1(Point(10,30), 20);
		Circle( const Point& p, const Point& pc);								// Circle  c1(p[222], p[223]);
		Circle( const Circle& c ){*this = c;}									// copy constructor  Circle c1(c2);
		Circle( const Span& sp);														// constructor

		// methods
#ifdef PEPSDLL
		void ToPeps(int id, bool draw = true);									// to Peps
		void DelPeps(int id);													// delete Peps Circle
#endif
		bool operator==(const Circle &c)const;									// c == cc
		bool operator!=(const Circle &c)const { return !(*this == c);}
		Circle Transform(Matrix& m);											// transform a Circle
		Point	Intof(int LR, const Circle& c1);										// intof 2 circles
		Point	Intof(int LR, const Circle& c1, Point& otherInters);					// intof 2 circles, (returns the other intersection)
		int		Intof(const Circle& c1, Point& leftInters, Point& rightInters);		// intof 2 circles (returns number of intersections & left/right inters)
		CLine	Tanto(int AT,  double angle, const CLine& s0)const;			// a cline tanto this circle at angle
	//	~Circle();																// destructor
	};

	// 2d box class
	class Box{
	public:
		Point min;
		Point max;
		bool ok;

		Box() { min.x = min.y = 1.0e61; max.x = max.y = -1.0e61; ok = false;};
		Box(Point& pmin, Point& pmax) { min = pmin; max = pmax; ok = true;};

		bool outside(const Box& b)const;		// returns true if box is outside box
		void combine(const Box& b);		// combines this with b
	};

	// 3d box class
	class Box3d{
	public:
		Point3d min;
		Point3d max;
		bool ok;

		Box3d() { min.x = min.y = min.z = 1.0e61; max.x = max.y = max.z = -1.0e61; ok = false;};
		Box3d(const Point3d& pmin, const Point3d& pmax) { min = pmin; max = pmax; ok = true;};

		bool outside(const Box3d& b)const;		// returns true if box is outside box
		void combine(const Box3d& b);		// combines this with b
	};

	inline void MinMax(const Point& p, Point& pmin, Point& pmax) {
		if(p.x > pmax.x) pmax.x = p.x;
		if(p.y > pmax.y) pmax.y = p.y;
		if(p.x < pmin.x) pmin.x = p.x;
		if(p.y < pmin.y) pmin.y = p.y;
	};

	inline void MinMax(const Point3d& p, Point3d& pmin, Point3d& pmax) {
		if(p.x > pmax.x) pmax.x = p.x;
		if(p.y > pmax.y) pmax.y = p.y;
		if(p.z > pmax.z) pmax.z = p.z;
		if(p.x < pmin.x) pmin.x = p.x;
		if(p.y < pmin.y) pmin.y = p.y;
		if(p.z < pmin.z) pmin.z = p.z;
	};




	// 2D line arc span
	class Span{
		friend wostream& operator <<(wostream& op, Span& span);
	public:
		Point p0;			// start
		Point p1;			// end
		Point pc;			// centre
		int	  dir;			// arc direction (CW or ACW or 0 for straight)
		int	ID;				// ID (for offset in wire - stores spanID etc. from original kurve)
		bool ok;

		bool	returnSpanProperties;	// set if properties below are set
		Vector2d vs;			// direction at start or for straight
		Vector2d ve;			// direction at span end

		double length;		// span length
		double radius;		// arc radius
		double angle;		// included arc angle  ( now arc is parameterised start -> start + angle

		Box box;			// span box

		bool	NullSpan;	// true if small span

		// methods
		void SetProperties(bool returnProperties);									// set span properties
		Span Offset(double offset);													// offset span method
		int Split(double tolerance);												// returns number of splits
		void SplitMatrix(int num_vectors, Matrix* matrix);							// returns incremental matrix from split
		void minmax(Box& box, bool start = true);									// minmax of span
		void minmax(Point& pmin, Point& pmax, bool start = true);					// minmax of span
		int Intof(const Span& sp, Point& pInt1, Point& pInt2, double t[4])const;
		void Transform(const Matrix& m, bool setprops = true);
		Point Near(const Point& p)const;														// returns the near point to span from p (on or off)
		Point NearOn(const Point& p)const;														// returns the near point to span from p (on span)
		Point	Mid()const;																// midpoint of a span
		Point MidPerim(double d)const;													// interior point of Span (param 0 - d)
		Point MidParam(double param)const;												// interior point of Span (param 0 - 1)
		bool OnSpan(const Point& p)const;														//  tests if p is on sp *** FAST TEST p MUST LIE on unbounded span
		bool OnSpan(const Point& p, double* t)const;											//  tests if p is on sp *** FAST TEST p MUST LIE on unbounded span
		bool	JoinSeparateSpans(Span& sp);
		Span BlendTwoSpans(Span& sp2, double radius, double maxt);					// Blends 2 Spans
		bool isJoinable(const Span& sp)const;													// is this & sp joinable to 1 span?
		Vector2d GetVector(double fraction)const; // the direction along the span, 0.0 for start, 1.0 for end

		// constructor
		Span() {ID = 0; ok = false;};
		Span(int spandir, const Point& pn, const Point& pf, const Point& c) { dir = spandir; p0 = pn, p1 = pf, pc = c; ID = 0; SetProperties(true); ok = p0.ok;};

		// operators
		//	bool operator==(const Span &sp)const;
		//	bool operator!=(const Span &sp)const { return !(*this == sp);}	
	};

	// general
	double	atn360(double dx, double dy);									// angle 0 to 2pi

	// distance functions
	//double Dist(double px, double py, double p1x, double p1y);				// diatance between 2 points (2d)
	//double Dist(Point& p0, Point& p1);										// distance between 2 points (3d)
	//double Dist(CLine& s, Point& p1);											// distance between cline & point

	double Dist(const Point3d *p, const Vector3d *vl, const Point3d *pf);							// distance from line (p, vl) and pf
	double DistSq(const Point3d *p, const Vector3d *vl, const Point3d *pf);						// distance squared from line (p, vl) and pf
	double Dist(const Circle& c, const Point& p);											// distance between c & p
	double Dist(const Point& p0, const Circle& c, const Point& p1);								// clockwise distance around c from p0 to p1
	double Dist(const CLine& s, const Circle& c);											// distance between line and circle
	double Dist(const Circle& c0, const Circle& c1);										// distance between 2 circles
	double IncludedAngle(const Vector2d& v0, const Vector2d& v1, int dir = 1);				// angle between 2 vectors
	double IncludedAngle(const Vector3d& v0, const Vector3d& v1, const Vector3d& normal, int dir = 1);
	inline	double IncludedAngle(const CLine& s0, const CLine& s1, int dir = 1) {			// angle between 2 Clines
		return IncludedAngle(s0.v, s1.v, dir);
	}


	// point definitions
	Point	Mid(const Point& p0, const Point& p1, double factor = 0.5);					//// midpoint
	Point	Mid(const Span& sp);													//// midpoint of a span
	Point	Rel(const Point& p, double x, double y);								// relative point
	Point	Polar(const Point& p, double angle, double r);						// polar from this point
	Point	AtAngle(const Circle& c, double angle);								// Point at angle on a circle
	Point	XonCLine(const CLine& s, double xval);								// returns point that has X on this line
	Point	YonCLine(const CLine& s, double yval);								// returns point that has Y on this line
	Point	Intof(const CLine& s0, const CLine& s1);									//// intof 2 clines
	Point	Intof(int NF, const CLine& s, const Circle& c);								//// intof of circle & a cline
	Point	Intof(int NF, const CLine& s, const Circle& c, Point& otherInters);			//// intof of circle & a cline (returns the other intersection)
	Point	Intof(int LR, const Circle& c0, const Circle& c1);							//// intof 2 circles
	Point	Intof(int LR, const Circle& c0, const Circle& c1, Point& otherInters);		//// intof 2 circles, (returns the other intersection)
	int		Intof(const Circle& c0, const Circle& c1, Point& pLeft, Point& pRight);		////    ditto
	Point	Along(const CLine& s, double d);										// distance along Cline
	Point	Along(const CLine& s, double d, const Point& p);								// distance along Cline from point
	Point	Around(const Circle& c, double d, const Point& p);								// distance around a circle from point
	Point	On(const CLine& s,  const Point& p);											// returns a point on s nearest to p
	Point	On(const Circle& c, const Point& p);											// returns a point on c nearest to p

	// cline definitons

	CLine	AtAngle(double angle, const Point& p, const CLine& s = HORIZ_CLINE);		// cline at angle to line thro' point
	CLine	Tanto(int AT, const Circle& c,  double angle, const CLine& s0 = HORIZ_CLINE);//// cline tanto circle at angle to optional cline
	CLine	Tanto(int AT, const Circle& c, const Point& p);								// cline tanto circle thro' a point
	CLine	Tanto(int AT0, const Circle& c0, int AT1, const Circle& c1);					// cline tanto 2 circles
	CLine	Normal(const CLine& s);													// noirmal to cline
	CLine	Normal(const CLine& s, const Point& p);										// normal to cline thro' p
	CLine	Parallel(int LR, const CLine& s, double distance);						// parallel to cline by distance
	CLine	Parallel(const CLine& cl, const Point& p);										// parallel to cline thro' a point


	// circle definitions
	Circle	Thro(const Point& p0, const Point& p1);										// circle thro 2 points (diametric)
	Circle	Thro(const Point& p0, const Point& p1, const Point& p2);							// circle thro 3 points
	Circle	Tanto(int NF, const CLine& s0, const Point& p, double rad);					// circle tanto a CLine thro' a point with radius
	Circle	Thro(int LR, const Point& p0, const Point& p1, double rad);					// circle thro' 2 points with radius
	Circle	Tanto(int AT1, const CLine& s1, int AT2, const CLine& s2, double rad);		// circle tanto 2 clines with radius
	Circle	Tanto(int AT1, const CLine& s1, int AT2, const CLine& s2, int AT3, const CLine& s3);	// circle tanto 3 clines
	Circle	Tanto(int LR, int AT, const Circle& c, const Point& p, double rad);			// circle tanto circle & thro' a point
	Circle	Tanto(int NF, int AT0, const CLine& s0, int AT1, const Circle& c1, double rad);// circle tanto cline & circle with radius
	Circle	Tanto(int LR, int AT0, const Circle& c0, int AT1, const Circle& c1, double rad);// circle tanto 2 circles with radius
	Circle	Tanto(int LR, int AT1 , const Circle& c1 , int AT2 , const Circle& c2, int AT3 , const Circle c3); // tanto 3 circles
	int		apolloniusProblem(int AT1 , const Circle& c1 , int AT2 , const Circle& c2, int AT3 , const Circle& c3, Circle& Solution1, Circle& Solution2);
	int		apolloniusProblem(int AT1 , const Circle& c1 , int AT2 , const Circle& c2, int AT3 , const CLine& cl3, Circle& Solution1, Circle& Solution2);
	int		apolloniusProblem(int AT1 , const Circle& c1 , int AT2 , const CLine& cl2, int AT3 , const CLine& cl3, Circle& Solution1, Circle& Solution2);

	//		Circle	Tanto(int AT0, int NF, int AT1, CLine s1, int AT2, CLine s2);	// circle tanto circle, and 2 clines
	Circle	Parallel(int LR, const Circle& c, double distance);					// parallel to circle by a distance


	// misc
	inline double Radians(double degrees) {return degrees * PI / 180;}
	inline double Degrees(double radians) { return radians * 180 / PI;}
	int quadratic(double a, double b, double c, double& x0, double& x1);	// solve quadratic

	int corner(const Vector2d& v0, const Vector2d& v1, double cpTol = CPTANGENTTOL);	// corner (TANGENT, LEFT, RIGHT)
	inline	int corner(const Span& span, const Span& next, double cpTol = CPTANGENTTOL) {
		return corner((Vector2d)span.ve, (Vector2d)next.vs, cpTol);}

	Line IsPtsLine(const double* a, int n, double tolerance, double* deviation);
//	Span3d IsPtsSpan3d(const double* a, int n, double tolerance, double* deviation);

	class Plane {
		friend wostream& operator <<(wostream& op, Plane& pl);

	public:						// ax + by + cz + d = 0
		bool ok;
		double d;				// distance of plane to origin
		Vector3d normal;				// normal to plane a = n.dx, b = n.dy, c = n.dz
		// constructors
		Plane(){ok = false;};
		Plane(double dist, const Vector3d& n);
		Plane(const Point3d& p0, const Point3d& p1, const Point3d& p2);
		Plane(const Point3d& p0, const Vector3d& n, bool normalise = true);

		// methods
		double Dist(const Point3d& p)const;							// signed distance of point to plane
		bool Intof(const Line& l, Point3d& intof, double& t)const;		// intersection of plane & line (0 >= t <= 1 if intersect within line) 
		bool Intof(const Plane& pl, Line& intof)const;					// intersection of 2 planes
		bool Intof(const Plane& pl0, const Plane& pl1, Point3d& intof)const;	// intersection of 3 planes
		Point3d Near(const Point3d& p)const;							// returns near point to p on the plane
		void Mirrored(Matrix* m);										// returns a matrix for a mirror about this	
	};




#define SPANSTORAGE 32			// lessens number of object pointers

	class spVertex {
		friend wostream& operator <<(wostream& op, spVertex& sp);

	public:
		int type;
		int spanid;
		Point p;
		Point pc;
		spVertex(){};
		spVertex(int t, const Point& point, const Point& centre): type(t), spanid(0), p(point), pc(centre){};

		bool operator==(spVertex &spv){
			// vertex == spvertex (vertex check - doesn't check spannid!)
			if(this->type != spv.type) return false;
			if(this->p != spv.p) return false;
			if(this->type != LINEAR) {
				if(this->pc != spv.pc) return false;
			}
			return true;
		}

		bool operator!=(spVertex &spv){ return !(*this == spv);}

	};


	class SpanDataObject {
		// holds everything needed for Post-Processing/Simulation
	public:
		int method;	// holds method type

		SpanDataObject(int meth){method = meth;};
		SpanDataObject(const SpanDataObject* obj){method = obj->method;};
	};

	class SpanVertex{
	public:
		int type[SPANSTORAGE];							// LINEAR CW or ACW																// 0 straight (cw = -1 (T)   acw = 1 (A) )
		int spanid[SPANSTORAGE];						// identification (eg wire offset span info)
		const SpanDataObject* index[SPANSTORAGE];					// other - pointer to 
		double x[SPANSTORAGE], y[SPANSTORAGE];			// vertex
		double xc[SPANSTORAGE], yc[SPANSTORAGE];		// centre of arc
	public:
		// methods
		void	Add(int offset, int type, const Point& p0, const Point& pc, int ID = UNMARKED);
		const SpanDataObject* GetIndex(int offset)const;
		void	AddSpanID(int offset, int ID);
		SpanVertex();
		~SpanVertex();
		const SpanVertex& operator= (const SpanVertex& spv );

		void	Add(int offset, const SpanDataObject* Index );
		const SpanDataObject*	Get(int offset);
		int		Get(int offset, Point& pe, Point& pc);
		int GetSpanID(int offset);
	};





#ifdef WIN32
#pragma warning(disable:4522)
#endif

	class Kurve : public Matrix{
	friend wofstream& operator << (wofstream& op, Kurve& k);
	friend wifstream& operator >> (wifstream& op, Kurve& k);
		
	protected:
		vector<SpanVertex*> m_spans;
		bool		m_started;
		int			m_nVertices;					// number of vertices in Kurve
		bool		m_isReversed;					// true if get spans reversed

	public:	
		// for comparing kurves
		struct spanCompare {
			int dir;			// LINEAR, CW or ACW
			double length;		// length of the span
			double cp;			// cross-product to next span (sina)
			double dp;
		};
		// constructors etc...
		Kurve()	{
			m_started = false;
			m_nVertices = 0;
			m_isReversed = false;
		};
		Kurve(const Kurve& k0);
		const Kurve& operator= (const Kurve& k );
		const Kurve& operator=(const Matrix &m);

		bool operator==(const Kurve &k)const;									// k == kk (vertex check)
		bool operator!=(const Kurve &k)const { return !(*this == k);}


		// destructor
		~Kurve();

		// methods
		inline int		nSpans(	)const {return (m_nVertices)? m_nVertices - 1 : 0;}				// returns the number of spans
		bool	Closed()const;									// returns true if kurve is closed
		inline bool	Started()const {return m_started;};
		void	FullCircle(int dir, const Point& c, double radius);								// make a full circle
		void	Start();												// start a new kurve
		void	Start(const Point& p);											// start a new kurve with start point
		bool	Add(const spVertex& spv, bool AddNullSpans = true);								// add a vertex
		void	Get(int vertex, spVertex& spv) const;												// get a vertex
		bool	Add(const Span& sp, bool AddNullSpans = true);									// add a span
		bool	Add(int type, const Point& p0, const Point& pc, bool AddNullSpans = true);				// a span
		void	AddSpanID(int ID);
		bool	Add(const Point& p0, bool AddNullSpans = true);									// linear 
		void	Add();					// add a null span
		void	Add(const Kurve* k, bool AddNullSpans = true);									// a kurve
		void	StoreAllSpans(std::vector<Span>& kSpans)const;			// store all kurve spans in array, normally when fast access is reqd
		void	Clear(); // remove all the spans

		void	Replace(int vertexnumber, const spVertex& spv);
		void	Replace(int vertexnumber, int type, const Point& p, const Point& pc, int ID = UNMARKED);
		int		GetSpanID(int spanVertexNumber) const;								// for spanID (wire offset)
		int		Get(int spanVertexNumber, Point& p, Point& pc) const;
		void	Get(std::vector<Span> *all, bool ignoreNullSpans) const;												// get all spans to vector
		int		Get(int spanVertexNumber, Point3d& p, Point3d& pc) const 
		{ Point p2d, pc2d; int d = Get(spanVertexNumber, p2d, pc2d); p = p2d; pc = pc2d; return d;}
		int		Get(int spannumber, Span& sp, bool returnSpanProperties = false, bool transform = false) const;
//		int		Get(int spannumber, Span3d& sp, bool returnSpanProperties = false, bool transform = false) const;
		void	Get(Point &ps,Point &pe) const; // returns the start- and endpoint of the kurve
		const SpanDataObject* GetIndex(int vertexNumber)const;
		inline double GetLength()const{ return Perim();};  // returns the length of a kurve

		void	minmax(Point& pmin, Point& pmax);			// minmax of span
		void	minmax(Box& b);

		Point	NearToVertex(const Point& p, int& nearSpanNumber)const;
		Point	NearToVertex(const Point& p)const { int nearSpanNumber; return NearToVertex(p, nearSpanNumber);};
		Point	Near(const Point& p, int& nearSpanNumber)const;
		Point	Near(const Point& p) const{ int nearSpanNumber; return Near(p, nearSpanNumber);};
		double	Perim()const;									// perimeter of kurve
		double	Area()const;										// area of closed kurve
		void	Reverse();									// reverse kurve direction - obsolete
		bool	Reverse(bool isReversed) {					// reverse kurve direction - later better method
			bool tmp = m_isReversed;
			m_isReversed = isReversed;
			return tmp;
		};
		int		Reduce(double tolerance);					// reduce spans which are in tolerance

		int		Offset(vector <Kurve*> &OffsetKurves, double offset, int direction, int method, int& ret)const;	// offset methods
		int		OffsetMethod1(Kurve& kOffset, double off, int direction,  int method, int& ret)const;
		int		OffsetISOMethod(Kurve& kOffset, double off, int direction, bool BlendAll)const; // special offset (ISO radius - no span elimination)
		int		Intof(const Span& sp, vector<Point>& p)const;			// intof span
		int		Intof(const Kurve&k, vector<Point>& p)const;			// intof kurve
		bool	Compare(const Kurve* k, Matrix* m, bool bAllowMirror = true)const;				// compare 2 Kurves
		void	ChangeStart(const Point *pNewStart, int startSpanno); // change the Kurve's startpoint
		void	ChangeEnd(const Point *pNewEnd, int endSpanno); // change the Kurve's endpoint

	private:
		bool compareKurves(const std::vector<struct spanCompare> &first, const std::vector<struct spanCompare> &second, int &nOffset/*, Kurve *k, Matrix *m*/)const;
		bool calculateMatrix(const Kurve *k, Matrix *m, int nOffset, bool bMirror = false)const;
	public:


		void	AddIndex(int vertexNumber, const SpanDataObject* data);
		bool	Split(double MaximumRadius, double reslution);	// split arcs larger than MaximumRadius to resoultion
		int	IntExtWire( Kurve& kSec, double Ref, double Sec, double height, Kurve* kOut);	// interpolate / extrapolate a mid height kurve (wire)
		void	SetZ(double z) { e[11] = z; if(fabs(z) > 1.0e-6) m_unit = false;}				// assigns kurve to fixed height (wire)

		void	Part(int startVertex, int EndVertex, Kurve *part);
		Kurve	Part(int fromSpanno, const Point& fromPt, int toSpanno, const Point& toPt);					// make a Part Kurve
		int	Break(double atParam, const Kurve *secInput, Kurve *refOut, Kurve *secOut);// break kurve perimeter parameterisation with synchronised Kurve (wire)
		void	Part(double fromParam, double toParam, const Kurve *secInput, Kurve *refOut, Kurve *secOut);// part kurve perimeter parameterisation with synchronised Kurve (wire)
		Kurve	Part(double fromParam, double toParam);											// part kurve perimeter parameterisation
		void AddSections(const Kurve* k, bool endOfSection);		// special add kurves for rollingball
		void	AddEllipse(int dir, const Point& pStart, const Point& pEnd, const Point& pCentre, const Vector2d& majorAxis, double majorRadius, double minorRadius, double tolerance);
//		void Kurve::AddEllipse(int dir, Plane *plEllipse, Vector3d *cylAxis, Point3d *cylCentre, double cylradius, Point3d *pStart, Point3d *pEnd, double tolerance);		/// elliptical curve - biarc in tolerance

		void	Spiral(const Point& centre, double startAngle, double startRadius, double radiusRisePerRevolution, double endRadius);
#ifdef PARASOLID
		int ToPKcurve(PK_CURVE_t *curves, PK_INTERVAL_t *ranges, int start_spanno, int n_spans); // Convert to PK Curve

		PK_BODY_t ToPKwire();												// Convert to PK Wire Body
		PK_BODY_t ToPKwire(int start_spanno, int n_spans);

		PK_BODY_t ToPKsheet(			);									// Convert to PK Sheet Body
		PK_BODY_t ToPKextrudedBody(PK_VECTOR1_t path, bool solidbody = true);
		// Convert to PK Body (open kurve >> sheet)
		PK_BODY_t ToPKlofted_sheet_body(Kurve &sec);						// Convert 2 kurves to lofted sheet body
		PK_BODY_t ToPKlofted_thickened_body(Kurve &sec, double thickness);
#endif
	};
#ifdef WIN32
#pragma warning(default:4522)
#endif

	void tangential_arc(const Point &p0, const Point &p1, const Vector2d &v0, Point &c, int &dir);

	int		EqualiseSpanCount(Kurve& k1, Kurve& k2, Kurve& k1equal, Kurve& k2equal, bool equalise_same_span_count);		// span count equalisation
	void	EqualiseSpanCountAfterOffset(Kurve& k1, Kurve&k2, Kurve& k1Out, Kurve& k2Out);// span equalisation after offset
	void	EqualiseSpanCountAfterOffsetFromRollAround(Kurve& k1, Kurve&k2, Kurve& k1Out, Kurve& k2Out/*, double offset, int arc_direction*/);// span equalisation after offset

	Point IntofIso(Span& one, Span& two, Span& three);				// for iso blend radiuses - calc intersection

	inline double CPTOL(double offset, double maxOffset) {
		// this returns a suitable tolerance for a cross product
		// the cp for normalised vectors is the sin of the included angle between the vectors
		//
		// this function takes the machine resolution from RESOLUTION

		offset = fabs(offset);

		if(offset <= RESOLUTION) offset = maxOffset;	// no known offset so guess one from the application

		return RESOLUTION / offset;
	}



	// finite Span routines
	int Intof(const Span& sp0 , const Span& sp1, Point& p0, Point& p1, double t[4]);
	int	LineLineIntof(const Span& L0 , const Span& L1, Point& p, double t[2]);
	int LineArcIntof(const Span& line, const Span& arc, Point& p0, Point& p1, double t[4]);
	int ArcArcIntof(const Span& arc0, const Span& arc1, Point& pLeft, Point& pRight);

	bool OnSpan(const Span& sp, const Point& p);
	bool OnSpan(const Span& sp, const Point& p, bool nearPoints, Point& pNear, Point& pOnSpan);	// function returns true if pNear == pOnSpan
	//			pNear (nearest on unbound span)
	//			pOnSpan (nearest on finite span)


	int Intof(const Line& v0, const Line& v1, Point3d& intof);							// intof 2 lines
	double Dist(const Line& l, const Point3d& p, Point3d& pnear, double& t);			// distance from a point to a line
	Point3d Near(const Line& l, const Point3d& p, double& t );							// near point to a line & t in 0-length range
	double Dist(const Span& sp, const Point& p , Point& pnear );						// distance from p to sp, nearpoint returned as pnear

//	Kurve splineUsingBiarc(CLine& cl0, CLine& cl1, std::vector<pts>);

	int biarc(CLine& cl0, CLine& cl1, Span* sp0, Span* sp1 );

	// 3d line segment
	class Line{
	public:
		Point3d p0;				// start
		Vector3d v;				// vector (not normalised)
		double length;			// line length
		Box3d box;
		bool ok;

		// constructors
		Line() {ok = false;};
		Line(const Point3d& p0, const Vector3d& v0, bool boxed = true);
		Line(const Point3d& p0, const Point3d& p1);
		Line(const Span& sp);

		// methods
		void minmax();
		Point3d Near(const Point3d& p, double& t)const;				// near point to line from point (0 >= t <= 1) in range
		int Intof(const Line& l, Point3d& intof)const {return geoff_geometry::Intof(*this, l, intof);};	// intof 2 lines
		bool atZ(double z, Point3d& p)const;						// returns p at z on line
		bool Shortest(const Line& l2, Line& lshort, double& t1, double& t2)const;	// calculate shortest line between this & l2
	};


class Triangle3d {
		Point3d vert1;    // first vertex
		Point3d vert2;    // second vertex
		Point3d vert3;    // third vertex
		Vector3d v0;      // vector from vert1 to vert2
		Vector3d v1;      // vector from vert1 to vert3
		bool ok;

		Box3d box;        // box around triangle

public:
		// constructor
		Triangle3d(){ ok = false;};
		Triangle3d(const Point3d& vert1, const Point3d& vert2, const Point3d& vert3);

		// methods
		bool Intof(const Line& l, Point3d& intof)const; // returns intersection triangle to line
};



} // End namespace geoff_geometry




