1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
4 // Digital Ltd. LLC
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
10 // met:
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 // * Neither the name of Industrial Light & Magic nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34
35
36
37 #ifndef INCLUDED_IMATHLINEALGO_H
38 #define INCLUDED_IMATHLINEALGO_H
39
40 //------------------------------------------------------------------
41 //
42 // This file contains algorithms applied to or in conjunction
43 // with lines (Imath::Line). These algorithms may require
44 // more headers to compile. The assumption made is that these
45 // functions are called much less often than the basic line
46 // functions or these functions require more support classes
47 //
48 // Contains:
49 //
50 // bool closestPoints(const Line<T>& line1,
51 // const Line<T>& line2,
52 // Vec3<T>& point1,
53 // Vec3<T>& point2)
54 //
55 // bool intersect( const Line3<T> &line,
56 // const Vec3<T> &v0,
57 // const Vec3<T> &v1,
58 // const Vec3<T> &v2,
59 // Vec3<T> &pt,
60 // Vec3<T> &barycentric,
61 // bool &front)
62 //
63 // V3f
64 // closestVertex(const Vec3<T> &v0,
65 // const Vec3<T> &v1,
66 // const Vec3<T> &v2,
67 // const Line3<T> &l)
68 //
69 // V3f
70 // rotatePoint(const Vec3<T> p, Line3<T> l, float angle)
71 //
72 //------------------------------------------------------------------
73
74 #include "ImathLine.h"
75 #include "ImathVecAlgo.h"
76 #include "ImathFun.h"
77
78 namespace Imath {
79
80
81 template <class T>
82 bool
closestPoints(const Line3<T> & line1,const Line3<T> & line2,Vec3<T> & point1,Vec3<T> & point2)83 closestPoints
84 (const Line3<T>& line1,
85 const Line3<T>& line2,
86 Vec3<T>& point1,
87 Vec3<T>& point2)
88 {
89 //
90 // Compute point1 and point2 such that point1 is on line1, point2
91 // is on line2 and the distance between point1 and point2 is minimal.
92 // This function returns true if point1 and point2 can be computed,
93 // or false if line1 and line2 are parallel or nearly parallel.
94 // This function assumes that line1.dir and line2.dir are normalized.
95 //
96
97 Vec3<T> w = line1.pos - line2.pos;
98 T d1w = line1.dir ^ w;
99 T d2w = line2.dir ^ w;
100 T d1d2 = line1.dir ^ line2.dir;
101 T n1 = d1d2 * d2w - d1w;
102 T n2 = d2w - d1d2 * d1w;
103 T d = 1 - d1d2 * d1d2;
104 T absD = abs (d);
105
106 if ((absD > 1) ||
107 (abs (n1) < limits<T>::max() * absD &&
108 abs (n2) < limits<T>::max() * absD))
109 {
110 point1 = line1 (n1 / d);
111 point2 = line2 (n2 / d);
112 return true;
113 }
114 else
115 {
116 return false;
117 }
118 }
119
120
121 template <class T>
122 bool
intersect(const Line3<T> & line,const Vec3<T> & v0,const Vec3<T> & v1,const Vec3<T> & v2,Vec3<T> & pt,Vec3<T> & barycentric,bool & front)123 intersect
124 (const Line3<T> &line,
125 const Vec3<T> &v0,
126 const Vec3<T> &v1,
127 const Vec3<T> &v2,
128 Vec3<T> &pt,
129 Vec3<T> &barycentric,
130 bool &front)
131 {
132 //
133 // Given a line and a triangle (v0, v1, v2), the intersect() function
134 // finds the intersection of the line and the plane that contains the
135 // triangle.
136 //
137 // If the intersection point cannot be computed, either because the
138 // line and the triangle's plane are nearly parallel or because the
139 // triangle's area is very small, intersect() returns false.
140 //
141 // If the intersection point is outside the triangle, intersect
142 // returns false.
143 //
144 // If the intersection point, pt, is inside the triangle, intersect()
145 // computes a front-facing flag and the barycentric coordinates of
146 // the intersection point, and returns true.
147 //
148 // The front-facing flag is true if the dot product of the triangle's
149 // normal, (v2-v1)%(v1-v0), and the line's direction is negative.
150 //
151 // The barycentric coordinates have the following property:
152 //
153 // pt = v0 * barycentric.x + v1 * barycentric.y + v2 * barycentric.z
154 //
155
156 Vec3<T> edge0 = v1 - v0;
157 Vec3<T> edge1 = v2 - v1;
158 Vec3<T> normal = edge1 % edge0;
159
160 T l = normal.length();
161
162 if (l != 0)
163 normal /= l;
164 else
165 return false; // zero-area triangle
166
167 //
168 // d is the distance of line.pos from the plane that contains the triangle.
169 // The intersection point is at line.pos + (d/nd) * line.dir.
170 //
171
172 T d = normal ^ (v0 - line.pos);
173 T nd = normal ^ line.dir;
174
175 if (abs (nd) > 1 || abs (d) < limits<T>::max() * abs (nd))
176 pt = line (d / nd);
177 else
178 return false; // line and plane are nearly parallel
179
180 //
181 // Compute the barycentric coordinates of the intersection point.
182 // The intersection is inside the triangle if all three barycentric
183 // coordinates are between zero and one.
184 //
185
186 {
187 Vec3<T> en = edge0.normalized();
188 Vec3<T> a = pt - v0;
189 Vec3<T> b = v2 - v0;
190 Vec3<T> c = (a - en * (en ^ a));
191 Vec3<T> d = (b - en * (en ^ b));
192 T e = c ^ d;
193 T f = d ^ d;
194
195 if (e >= 0 && e <= f)
196 barycentric.z = e / f;
197 else
198 return false; // outside
199 }
200
201 {
202 Vec3<T> en = edge1.normalized();
203 Vec3<T> a = pt - v1;
204 Vec3<T> b = v0 - v1;
205 Vec3<T> c = (a - en * (en ^ a));
206 Vec3<T> d = (b - en * (en ^ b));
207 T e = c ^ d;
208 T f = d ^ d;
209
210 if (e >= 0 && e <= f)
211 barycentric.x = e / f;
212 else
213 return false; // outside
214 }
215
216 barycentric.y = 1 - barycentric.x - barycentric.z;
217
218 if (barycentric.y < 0)
219 return false; // outside
220
221 front = ((line.dir ^ normal) < 0);
222 return true;
223 }
224
225
226 template <class T>
227 Vec3<T>
closestVertex(const Vec3<T> & v0,const Vec3<T> & v1,const Vec3<T> & v2,const Line3<T> & l)228 closestVertex
229 (const Vec3<T> &v0,
230 const Vec3<T> &v1,
231 const Vec3<T> &v2,
232 const Line3<T> &l)
233 {
234 Vec3<T> nearest = v0;
235 T neardot = (v0 - l.closestPointTo(v0)).length2();
236
237 T tmp = (v1 - l.closestPointTo(v1)).length2();
238
239 if (tmp < neardot)
240 {
241 neardot = tmp;
242 nearest = v1;
243 }
244
245 tmp = (v2 - l.closestPointTo(v2)).length2();
246 if (tmp < neardot)
247 {
248 neardot = tmp;
249 nearest = v2;
250 }
251
252 return nearest;
253 }
254
255
256 template <class T>
257 Vec3<T>
rotatePoint(const Vec3<T> p,Line3<T> l,T angle)258 rotatePoint (const Vec3<T> p, Line3<T> l, T angle)
259 {
260 //
261 // Rotate the point p around the line l by the given angle.
262 //
263
264 //
265 // Form a coordinate frame with <x,y,a>. The rotation is the in xy
266 // plane.
267 //
268
269 Vec3<T> q = l.closestPointTo(p);
270 Vec3<T> x = p - q;
271 T radius = x.length();
272
273 x.normalize();
274 Vec3<T> y = (x % l.dir).normalize();
275
276 T cosangle = Math<T>::cos(angle);
277 T sinangle = Math<T>::sin(angle);
278
279 Vec3<T> r = q + x * radius * cosangle + y * radius * sinangle;
280
281 return r;
282 }
283
284
285 } // namespace Imath
286
287 #endif
288