//
//	Copyright © 2005 Nemetschek North America 
//	All Rights Reserved.
//
// Created by Vladislav Stanev

#ifndef VECTORWORKS_POLYGON_3D__H
#define VECTORWORKS_POLYGON_3D__H

#pragma once

namespace VWFC
{
	namespace Math
	{
		class VWPolygon3D
		{
		public:
								VWPolygon3D();
								VWPolygon3D(const VWPolygon3D& src);
								VWPolygon3D(const VWPolygon2D& src, double z =0);
								VWPolygon3D(const TSTLPoints3DArray& src);
								VWPolygon3D(const TSTLPoints3DVWArray& src);
								// create 3d polygon by three points (a plane)
								VWPolygon3D(const VWPoint3D& a, const VWPoint3D& b, const VWPoint3D& c);
								VWPolygon3D(const VWTransformMatrix& plane);
			virtual				~VWPolygon3D();

			VWPolygon3D&		operator=(const VWPolygon3D& src);
			VWPolygon3D&		operator=(const VWPolygon2D& src);
			VWPolygon3D&		operator=(const TSTLPoints3DArray& src);
			VWPolygon3D&		operator=(const TSTLPoints3DVWArray& src);


		public:
			// setting polygon
			void				SetPolygon(const TSTLPoints3DArray& src);
			void				SetPolygon(const TSTLPoints3DVWArray& src);
			void				GetPolygon(TSTLPoints3DArray& out) const;
			void				GetPolygon(TSTLPoints3DVWArray& out) const;

			// create 3d polygon by three points (a plane)
			void				SetPolygon(const VWPoint3D& a, const VWPoint3D& b, const VWPoint3D& c);
			void				SetPolygon(const VWTransformMatrix& plane);

			void				ClearVertices();
			void				ClearVertex(size_t at);
			void				AddVertex(double x, double y, double z);
			void				AddVertex(const VWPoint3D& pt);
			void				InsertVertex(size_t at, double x, double y, double z);
			void				InsertVertex(size_t at, const VWPoint3D& pt);

			bool				IsEmpty() const;
			size_t				GetVertexCount() const;
			const VWPoint3D&	GetVertexAt(size_t at, bool bLoopVerts=false) const;
			VWPoint3D&			GetVertexAt(size_t at, bool bLoopVerts=false);
			VWLine3D			GetLineAt(size_t at) const;

			bool				IsClosed() const;
			void				SetClosed(bool bClosed);
			
			// reverse the order of the points (if CW to CCW or CCW to CW)
			void				ReversePoints();

			// determine if the polygon is Clock Wise oriented
			bool				IsClockWise() const;

			// return true if the passed polygon has more than 3 different vertices
			bool				IsValidPolygon(double dEpsilon) const;

			// removed all same points in the polygon
			void				CleanUpPolygon(double dEpsilon);

			void				GetPlanarPolygon(VWPolygon2D& out) const;

			void				GetXBounds(double& outMinX, double& outMaxX) const;
			void				GetYBounds(double& outMinY, double& outMaxY) const;
			void				GetZBounds(double& outMinZ, double& outMaxZ) const;

		// mathematics
		public:
			// return the plane equation
			// A*x + B*y + C*z + D
			bool				GetPlaneEquation(double& A, double& B, double& C, double& D) const;
			
			// return transformation which describes this plane
			VWTransformMatrix	GetTransformMatrix() const;
			
			// perpendicular distance from the point to the plane made by the first 3 points
			// the distance is reversed if the polygon is CCW
			double				GetDistance(const VWPoint3D& pt) const;
			// the vertical distance -- what z for the point to be on the plane
			double				GetVerticalDistance(const VWPoint3D& pt) const;
			
			// normal of the plane made by the first 3 points
			VWPoint3D			Normal() const;

			// get geometry center of the polygon
			VWPoint3D			GetCenter() const;
			
			// calculate the area of the polygon
			// positive if polygon is CCW -- negative if CW
			double				GetArea() const;
			
			// intersect the plane made by the first 3 points with a specified line
			//  return false if line is parallel to plane
			bool				Intersect(const VWLine3D& line, VWPoint3D& outIntersPt, double dEpsilon) const;
			// intersect the plane made by the first 3 points with a specified line given by points and direction
			//  return false if line is parallel to plane
			bool				Intersect(const VWPoint3D& startPt, const VWPoint3D& dir, VWPoint3D& outIntersPt, double dEpsilon) const;
			// intersect this plane made by the first 3 points
			// with the specified plane (first 3 points)
			//  return false is planes are parallel
			bool				Intersect(const VWPolygon3D& plane, VWLine3D& outIntersLine, double dEpsilon) const;

			// determines if a point is in the area of the projected polygon (the 2D projection)
			bool				IsPtInProjPoly2D(double ptX, double ptY, double dEpsilon) const;
			bool				IsPtInProjPoly2D(const VWPoint2D& pt, double dEpsilon) const;

			bool				IsPtInOrOnProjPoly2D(double ptX, double ptY, double dEpsilon) const;

			// transform polygon's points
			void				PointsTransform(const VWTransformMatrix& matrix);
			void				InversePointsTransform(const VWTransformMatrix& matrix);
			void				MovePoints(double dx, double dy, double dz);
			void				MovePoints(const VWPoint3D& amount);

		protected:
			TSTLPoints3DArray						farrVertices;
			bool									fbIsClosed;
		};

		// array of polygon defintion
		typedef		std::vector<VWPolygon3D>									TSTLPolygons3DArray;
		typedef		std::vector<VWPolygon3D, std::vwallocator<VWPolygon3D> >	TSTLPolygons3DVWArray;
	}
}

#endif // VECTORWORKS_POLYGON_3D__H