/////////////////////////////////////////////////////////////////////////////////////////
//                    geometry.lib header
//					  modified with 2d & 3d vector methods 2006
/////////////////////////////////////////////////////////////////////////////////////////

/*==============================
Copyright (c) 2006 g.j.hawkesford 

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
==============================*/

#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, int messageGroup, int stringID);
	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, false)

	// 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, bool okay = true);							// 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, double t[4]);

	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




