mPlane.cpp

Engine/source/math/mPlane.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "math/mPlane.h"
 26
 27#include "math/mathUtils.h"
 28#include "math/mBox.h"
 29#include "math/mOrientedBox.h"
 30#include "math/mSphere.h"
 31
 32
 33//-----------------------------------------------------------------------------
 34
 35bool PlaneF::intersect( const PlaneF& plane, Point3F& outLinePt, VectorF& outLineDir ) const
 36{
 37   // Compute direction of intersection line.
 38   outLineDir = mCross( *this, plane );
 39
 40   // If d is zero, the planes are parallel (and separated)
 41   // or coincident, so they're not considered intersecting
 42   F32 denom = mDot( outLineDir, outLineDir );
 43   if ( denom < 0.00001f ) 
 44      return false;
 45
 46   // Compute point on intersection line
 47   outLinePt = - mCross( d * plane - plane.d * *this,
 48                         outLineDir ) / denom;
 49
 50   return true;
 51}
 52
 53//-----------------------------------------------------------------------------
 54
 55bool PlaneF::isParallelTo( const PlaneF& plane, F32 epsilon ) const
 56{
 57   F32 val = 1.0f - mFabs( mDot( *this, plane ) );
 58   return ( val > - epsilon ) && ( val < epsilon );
 59}
 60
 61//-----------------------------------------------------------------------------
 62
 63bool PlaneF::isPerpendicularTo( const PlaneF& plane, F32 epsilon ) const
 64{
 65   F32 val = mDot( *this, plane );
 66   return ( val > - epsilon) && ( val < epsilon );   
 67}
 68
 69//-----------------------------------------------------------------------------
 70
 71bool PlaneF::clipSegment( const Point3F& start, const Point3F& end, Point3F& outNewEnd ) const
 72{
 73   // Intersect ray with plane.
 74
 75   F32 dist = intersect( start, end );
 76   if( dist == PARALLEL_PLANE || dist < 0.f || dist > 1.f )
 77      return false;
 78
 79   // Compute distance to point on segment.
 80
 81   Point3F dir = end - start;
 82   dir *= dist;
 83
 84   // Compute new end point.
 85
 86   outNewEnd = start + dir;
 87
 88   return true;
 89}
 90
 91//-----------------------------------------------------------------------------
 92
 93U32 PlaneF::clipPolygon( const Point3F* inVertices, U32 inNumVertices, Point3F* outVertices ) const
 94{
 95   // Find the first vertex that lies on the front of the plane.
 96
 97   S32 start = -1;
 98   for( U32 i = 0; i < inNumVertices; i ++ )
 99   {
100      Side side = whichSide( inVertices[ i ] );
101      if( side == PlaneF::Front )
102      {
103         start = i;
104         break;
105      }
106   }
107
108   // If nothing was in front of the plane, we're done.
109
110   if( start == -1 )
111      return 0;
112
113   Point3F finalPoints[ 128 ];
114   U32  numFinalPoints = 0;
115
116   U32 baseStart = start;
117   U32 end       = ( start + 1 ) % inNumVertices;
118
119   dMemcpy( outVertices, inVertices, inNumVertices * sizeof( Point3F ) );
120
121   while( end != baseStart )
122   {
123      const Point3F& rStartPoint = outVertices[ start ];
124      const Point3F& rEndPoint   = outVertices[ end ];
125
126      PlaneF::Side fSide = whichSide( rStartPoint );
127      PlaneF::Side eSide = whichSide( rEndPoint );
128
129      S32 code = fSide * 3 + eSide;
130      switch( code )
131      {
132         case 4:   // f f
133         case 3:   // f o
134         case 1:   // o f
135         case 0:   // o o
136            // No Clipping required
137            finalPoints[ numFinalPoints ++ ] = outVertices[ start ];
138            start = end;
139            end   = ( end + 1 ) % inNumVertices;
140            break;
141
142
143         case 2:   // f b
144         {
145            // In this case, we emit the front point, Insert the intersection,
146            //  and advancing to point to first point that is in front or on...
147            //
148            finalPoints[ numFinalPoints ++ ] = outVertices[ start ];
149
150            Point3F vector = rEndPoint - rStartPoint;
151            F32 t        = - ( distToPlane( rStartPoint ) / mDot( *this, vector ) );
152
153            Point3F intersection = rStartPoint + ( vector * t );
154            finalPoints[ numFinalPoints ++ ] = intersection;
155
156            U32 endSeek = ( end + 1 ) % inNumVertices;
157            while( whichSide( outVertices[ endSeek ] ) == PlaneF::Back )
158               endSeek = ( endSeek + 1 ) % inNumVertices;
159
160            end   = endSeek;
161            start = ( end + ( inNumVertices - 1 ) ) % inNumVertices;
162
163            const Point3F& rNewStartPoint = outVertices[ start ];
164            const Point3F& rNewEndPoint   = outVertices[ end ];
165
166            vector = rNewEndPoint - rNewStartPoint;
167            t = - ( distToPlane( rNewStartPoint ) / mDot( *this, vector ) );
168
169            intersection = rNewStartPoint + ( vector * t );
170            outVertices[ start ] = intersection;
171         }
172         break;
173
174         case -1:  // o b
175         {
176            // In this case, we emit the front point, and advance to point to first
177            //  point that is in front or on...
178            //
179            finalPoints[ numFinalPoints ++ ] = outVertices[ start ];
180
181            U32 endSeek = ( end + 1 ) % inNumVertices;
182            while( whichSide( outVertices[ endSeek ] ) == PlaneF::Back)
183               endSeek = ( endSeek + 1 ) % inNumVertices;
184
185            end   = endSeek;
186            start = (end + ( inNumVertices - 1 ) ) % inNumVertices;
187
188            const Point3F& rNewStartPoint = outVertices[ start ];
189            const Point3F& rNewEndPoint   = outVertices[ end ];
190
191            Point3F vector = rNewEndPoint - rNewStartPoint;
192            F32 t        = - ( distToPlane( rNewStartPoint ) / mDot( *this, vector ) );
193
194            Point3F intersection = rNewStartPoint + ( vector * t );
195            outVertices[ start ] = intersection;
196         }
197         break;
198
199        case -2:  // b f
200        case -3:  // b o
201        case -4:  // b b
202           // In the algorithm used here, this should never happen...
203           AssertISV(false, "SGUtil::clipToPlane: error in polygon clipper");
204           break;
205
206        default:
207           AssertFatal(false, "SGUtil::clipToPlane: bad outcode");
208           break;
209      }
210
211   }
212
213   // Emit the last point.
214   finalPoints[ numFinalPoints ++ ] = outVertices[ start ];
215   AssertFatal( numFinalPoints >= 3, avar("Error, this shouldn't happen!  Invalid winding in clipToPlane: %d", numFinalPoints ) );
216
217   // Copy the new rWinding, and we're set!
218   //
219   dMemcpy( outVertices, finalPoints, numFinalPoints * sizeof( Point3F ) );
220   AssertISV( numFinalPoints <= 128, "MaxWindingPoints exceeded in scenegraph.  Fatal error.");
221
222   return numFinalPoints;
223}
224