1///////////////////////////////////////////////////////////////////////////////////////////////////
2// OpenGL Mathematics Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net)
3///////////////////////////////////////////////////////////////////////////////////////////////////
4// Created : 2007-04-03
5// Updated : 2009-01-20
6// Licence : This source is under MIT licence
7// File    : glm/gtx/intersect.inl
8///////////////////////////////////////////////////////////////////////////////////////////////////
9
10#include "../geometric.hpp"
11#include <cfloat>
12#include <limits>
13
14namespace glm
15{
16	template <typename genType>
17	GLM_FUNC_QUALIFIER bool intersectRayPlane
18	(
19		genType const & orig, genType const & dir,
20		genType const & planeOrig, genType const & planeNormal,
21		typename genType::value_type & intersectionDistance
22	)
23	{
24		typename genType::value_type d = glm::dot(dir, planeNormal);
25		typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
26
27		if(d < Epsilon)
28		{
29			intersectionDistance = glm::dot(planeOrig - orig, planeNormal) / d;
30			return true;
31		}
32
33		return false;
34	}
35
36	template <typename genType>
37	GLM_FUNC_QUALIFIER bool intersectRayTriangle
38	(
39		genType const & orig, genType const & dir,
40		genType const & v0, genType const & v1, genType const & v2,
41		genType & baryPosition
42	)
43	{
44		genType e1 = v1 - v0;
45		genType e2 = v2 - v0;
46
47		genType p = glm::cross(dir, e2);
48
49		typename genType::value_type a = glm::dot(e1, p);
50
51		typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
52		if(a < Epsilon)
53			return false;
54
55		typename genType::value_type f = typename genType::value_type(1.0f) / a;
56
57		genType s = orig - v0;
58		baryPosition.x = f * glm::dot(s, p);
59		if(baryPosition.x < typename genType::value_type(0.0f))
60			return false;
61		if(baryPosition.x > typename genType::value_type(1.0f))
62			return false;
63
64		genType q = glm::cross(s, e1);
65		baryPosition.y = f * glm::dot(dir, q);
66		if(baryPosition.y < typename genType::value_type(0.0f))
67			return false;
68		if(baryPosition.y + baryPosition.x > typename genType::value_type(1.0f))
69			return false;
70
71		baryPosition.z = f * glm::dot(e2, q);
72
73		return baryPosition.z >= typename genType::value_type(0.0f);
74	}
75
76	//template <typename genType>
77	//GLM_FUNC_QUALIFIER bool intersectRayTriangle
78	//(
79	//	genType const & orig, genType const & dir,
80	//	genType const & vert0, genType const & vert1, genType const & vert2,
81	//	genType & position
82	//)
83	//{
84	//	typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
85	//
86	//	genType edge1 = vert1 - vert0;
87	//	genType edge2 = vert2 - vert0;
88	//
89	//	genType pvec = cross(dir, edge2);
90	//
91	//	float det = dot(edge1, pvec);
92	//	if(det < Epsilon)
93	//		return false;
94	//
95	//	genType tvec = orig - vert0;
96	//
97	//	position.y = dot(tvec, pvec);
98	//	if (position.y < typename genType::value_type(0) || position.y > det)
99	//		return typename genType::value_type(0);
100	//
101	//	genType qvec = cross(tvec, edge1);
102	//
103	//	position.z = dot(dir, qvec);
104	//	if (position.z < typename genType::value_type(0) || position.y + position.z > det)
105	//		return typename genType::value_type(0);
106	//
107	//	position.x = dot(edge2, qvec);
108	//	position *= typename genType::value_type(1) / det;
109	//
110	//	return typename genType::value_type(1);
111	//}
112
113	template <typename genType>
114	GLM_FUNC_QUALIFIER bool intersectLineTriangle
115	(
116		genType const & orig, genType const & dir,
117		genType const & vert0, genType const & vert1, genType const & vert2,
118		genType & position
119	)
120	{
121		typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
122
123		genType edge1 = vert1 - vert0;
124		genType edge2 = vert2 - vert0;
125
126		genType pvec = cross(dir, edge2);
127
128		float det = dot(edge1, pvec);
129
130		if (det > -Epsilon && det < Epsilon)
131			return false;
132		float inv_det = typename genType::value_type(1) / det;
133
134		genType tvec = orig - vert0;
135
136		position.y = dot(tvec, pvec) * inv_det;
137		if (position.y < typename genType::value_type(0) || position.y > typename genType::value_type(1))
138			return false;
139
140		genType qvec = cross(tvec, edge1);
141
142		position.z = dot(dir, qvec) * inv_det;
143		if (position.z < typename genType::value_type(0) || position.y + position.z > typename genType::value_type(1))
144			return false;
145
146		position.x = dot(edge2, qvec) * inv_det;
147
148		return true;
149	}
150
151	template <typename genType>
152	GLM_FUNC_QUALIFIER bool intersectRaySphere
153	(
154		genType const & rayStarting, genType const & rayNormalizedDirection,
155		genType const & sphereCenter, const typename genType::value_type sphereRadiusSquered,
156		typename genType::value_type & intersectionDistance
157	)
158	{
159		typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
160		genType diff = sphereCenter - rayStarting;
161		typename genType::value_type t0 = dot(diff, rayNormalizedDirection);
162		typename genType::value_type dSquared = dot(diff, diff) - t0 * t0;
163		if( dSquared > sphereRadiusSquered )
164		{
165			return false;
166		}
167		typename genType::value_type t1 = sqrt( sphereRadiusSquered - dSquared );
168		intersectionDistance = t0 > t1 + Epsilon ? t0 - t1 : t0 + t1;
169		return intersectionDistance > Epsilon;
170	}
171
172	template <typename genType>
173	GLM_FUNC_QUALIFIER bool intersectRaySphere
174	(
175		genType const & rayStarting, genType const & rayNormalizedDirection,
176		genType const & sphereCenter, const typename genType::value_type sphereRadius,
177		genType & intersectionPosition, genType & intersectionNormal
178	)
179	{
180		typename genType::value_type distance;
181		if( intersectRaySphere( rayStarting, rayNormalizedDirection, sphereCenter, sphereRadius * sphereRadius, distance ) )
182		{
183			intersectionPosition = rayStarting + rayNormalizedDirection * distance;
184			intersectionNormal = (intersectionPosition - sphereCenter) / sphereRadius;
185			return true;
186		}
187		return false;
188	}
189
190	template <typename genType>
191	GLM_FUNC_QUALIFIER bool intersectLineSphere
192	(
193		genType const & point0, genType const & point1,
194		genType const & sphereCenter, typename genType::value_type sphereRadius,
195		genType & intersectionPoint1, genType & intersectionNormal1,
196		genType & intersectionPoint2, genType & intersectionNormal2
197	)
198	{
199		typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
200		genType dir = normalize(point1 - point0);
201		genType diff = sphereCenter - point0;
202		typename genType::value_type t0 = dot(diff, dir);
203		typename genType::value_type dSquared = dot(diff, diff) - t0 * t0;
204		if( dSquared > sphereRadius * sphereRadius )
205		{
206			return false;
207		}
208		typename genType::value_type t1 = sqrt( sphereRadius * sphereRadius - dSquared );
209		if( t0 < t1 + Epsilon )
210			t1 = -t1;
211		intersectionPoint1 = point0 + dir * (t0 - t1);
212		intersectionNormal1 = (intersectionPoint1 - sphereCenter) / sphereRadius;
213		intersectionPoint2 = point0 + dir * (t0 + t1);
214		intersectionNormal2 = (intersectionPoint2 - sphereCenter) / sphereRadius;
215		return true;
216	}
217}//namespace glm
218