Type TPlane

	Field equation#[4]
	Field origin:TVector
	Field normal:TVector
	Field d# ' dot product of plane
	
	Const PLANE_THICKNESS_EPSILON#=0.0001
	Const POINT_IN_FRONT_OF_PLANE=1
	Const POINT_BEHIND_PLANE=-1
	Const POINT_ON_PLANE=0
	
	Const POLYGON_STRADDLING_PLANE=2
	Const POLYGON_IN_FRONT_OF_PLANE=1
	Const POLYGON_BEHIND_PLANE=-1
	Const POLYGON_COPLANAR_WITH_PLANE=0
	
	Const TRIANGLE_STRADDLING_PLANE=2
	Const TRIANGLE_IN_FRONT_OF_PLANE=1
	Const TRIANGLE_BEHIND_PLANE=-1
	Const TRIANGLE_COPLANAR_WITH_PLANE=0

	' MiniB3D functions
	
	' Internal - not recommended for general use

	Function CreatePlane:TPlane(plane_origin:TVector,plane_normal:TVector)
		Local plane:TPlane=New TPlane
		plane.normal=plane_normal.Copy()
		plane.origin=plane_origin.Copy()
		plane.equation[0] = plane_normal.x
		plane.equation[1] = plane_normal.y
		plane.equation[2] = plane_normal.z
		plane.equation[3] = -(plane_normal.x*plane_origin.x+plane_normal.y*plane_origin.y+plane_normal.z*plane_origin.z)
		plane.d=plane.normal.Dot(plane.origin)
		Return plane
	End Function
	
	Function CreatePlaneFromTriangle:TPlane(p1:TVector,p2:TVector,p3:TVector)
		Local plane:TPlane=New TPlane
		plane.normal = (p2.Subtract(p1)).Cross(p3.Subtract(p1))
		plane.normal.Normalize()
		plane.origin=p1.Copy()
		plane.equation[0] = plane.normal.x
		plane.equation[1] = plane.normal.y
		plane.equation[2] = plane.normal.z
		plane.equation[3] = -(plane.normal.x*plane.origin.x+plane.normal.y*plane.origin.y+plane.normal.z*plane.origin.z)
		plane.d=plane.normal.Dot(plane.origin)
		Return plane
	End Function
	
	Method isFrontFacingTo(direction:TVector)
		Local dot# = normal.Dot(direction)
		Return dot <= 0
	End Method
	
	Method signedDistanceTo!(point:TVector)
		Return (point.Dot(normal)) + equation[3]
	End Method
	
	Method ClassifyPointToPlane(point:TVector)

		Local dist#=signedDistanceTo(point)

		If dist>PLANE_THICKNESS_EPSILON
			Return POINT_IN_FRONT_OF_PLANE
		Else
			If dist<-PLANE_THICKNESS_EPSILON
				Return POINT_BEHIND_PLANE
			Else
				Return POINT_ON_PLANE
			EndIf
		EndIf 

	End Method
	
	Method ClassifyPolygonToPlane(poly:TPolygon)
	
		Local numInFront=0
		Local numBehind=0
		
		Local numVerts=poly.no_verts
		
		For Local i=0 Until numVerts
		
			Local p:TVector=poly.GetVertex(i)
			
			Select ClassifyPointToPlane(p)
				Case POINT_IN_FRONT_OF_PLANE
					numInFront:+1
				Case POINT_BEHIND_PLANE
					numBehind:+1
			End Select
		
		Next
		
		If numBehind<>0 And numInFront<>0 Then Return POLYGON_STRADDLING_PLANE
		If numInFront<>0 Return POLYGON_IN_FRONT_OF_PLANE
		If numBehind<>0 Return POLYGON_BEHIND_PLANE
		
		Return POLYGON_COPLANAR_WITH_PLANE
	
	End Method
	
	Method ClassifyTriangleToPlane(a:TVector,b:TVector,c:TVector)
	
		Local numInFront=0
		Local numBehind=0
		
		If ClassifyPointToPlane(a)=POINT_IN_FRONT_OF_PLANE Then numInFront:+1
		If ClassifyPointToPlane(b)=POINT_IN_FRONT_OF_PLANE Then numInFront:+1
		If ClassifyPointToPlane(c)=POINT_IN_FRONT_OF_PLANE Then numInFront:+1
		
		If ClassifyPointToPlane(a)=POINT_BEHIND_PLANE Then numBehind:+1
		If ClassifyPointToPlane(b)=POINT_BEHIND_PLANE Then numBehind:+1
		If ClassifyPointToPlane(c)=POINT_BEHIND_PLANE Then numBehind:+1
		
		If numBehind<>0 And numInFront<>0 Then Return TRIANGLE_STRADDLING_PLANE
		If numInFront<>0 Return TRIANGLE_IN_FRONT_OF_PLANE
		If numBehind<>0 Return TRIANGLE_BEHIND_PLANE
		
		Return TRIANGLE_COPLANAR_WITH_PLANE
	
	End Method

	Method ClosestPointTo:TVector(p:TVector)

		Local t#=normal.Dot(p)-d ' if plane equation not normalised, append " / normal.Dot(normal)"
		Return p.Subtract(normal.Multiply(t))

	End Method
	
	Function IntersectEdgeAgainstPlane:TVector(a:TVector,b:TVector,p:TPlane)

		' Compute the t value for the directed line ab intersecting the plane
		Local ab:TVector=b.Subtract(a)
		Local t#=(p.d-p.normal.Dot(a))/p.normal.Dot(ab)
	
		' If t in [0..1] compute and return intersection point
		If t>=0.0 And t<=1.0
			Local q:TVector=a.Add(ab.Multiply(t))
			Return q
		EndIf
		
		' Else no intersection
		Return Null

	End Function
	
	Function IntersectSegmentPlane(a:TVector,b:TVector,p:TPlane,t# Var,q:TVector Var)
	
		' Compute the t value for the directed line ab intersecting the plane
		Local ab:TVector=b.Subtract(a)
		t#=(p.d-p.normal.Dot(a))/p.normal.Dot(ab)
	
		' If t in [0..1] compute and return intersection point
		If t>=0.0 And t<=1.0
			q:TVector=a.Add(ab.Multiply(t))
			Return 1
		EndIf
		
		' Else no intersection
		Return 0
	
	End Function

End Type
