Home | History | Annotate | Download | only in Imath
      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
     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
    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>
    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>
    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