// Get the distance from this vector to the other one squared. // NJS: note, VC wasn't inlining it correctly in several deeply nested inlines due to being an 'out of line' . // may be able to tidy this up after switching to VC7 vec_t DistToSqr( const Vector2D &vOther ) const { Vector2D delta; delta.x = x - vOther.x; delta.y = y - vOther.y; return delta.LengthSqr(); }
//----------------------------------------------------------------------------- // Computes error between two texcoords; returns false if the error is too great //----------------------------------------------------------------------------- bool CompareTexCoordsFuzzy( const Vector2D &t1, const Vector2D &t2, float &flError ) { Vector2D vecError; vecError[0] = fabs( t2[0] - t1[0] ); vecError[1] = fabs( t2[1] - t1[1] ); flError = vecError.LengthSqr(); return ( flError <= (TEXCOORD_EPSILON * TEXCOORD_EPSILON) ); }
//----------------------------------------------------------------------------- // Computes the closest point to vecTarget no farther than flMaxDist from vecStart //----------------------------------------------------------------------------- void ComputeClosestPoint2D(const Vector2D& vecStart, float flMaxDist, const Vector2D& vecTarget, Vector2D *pResult) { Vector2D vecDelta; Vector2DSubtract(vecTarget, vecStart, vecDelta); float flDistSqr = vecDelta.LengthSqr(); if (flDistSqr <= flMaxDist * flMaxDist) { *pResult = vecTarget; } else { vecDelta /= sqrt(flDistSqr); Vector2DMA(vecStart, flMaxDist, vecDelta, *pResult); } }
// Build a 2D convex hull of the set of points. // This essentially giftwraps the points as it walks around the perimeter. int Convex2D( Vector2D const *pPoints, int nPoints, int *indices, int nMaxIndices ) { int nIndices = 0; bool touched[512]; int indexMap[512]; if( nPoints == 0 ) return 0; // If we don't collapse the points into a unique set, we can loop around forever // and max out nMaxIndices. nPoints = FindUniquePoints( pPoints, nPoints, indexMap, ARRAYSIZE( indexMap ), 0.1f ); memset( touched, 0, nPoints*sizeof(touched[0]) ); // Find the (lower) left side. int i; int iBest = 0; for( i=1; i < nPoints; i++ ) { if( pPoints[indexMap[i]].x < pPoints[indexMap[iBest]].x || (pPoints[indexMap[i]].x == pPoints[indexMap[iBest]].x && pPoints[indexMap[i]].y < pPoints[indexMap[iBest]].y) ) { iBest = i; } } touched[iBest] = true; indices[0] = indexMap[iBest]; nIndices = 1; Vector2D curEdge( 0, 1 ); // Wind around clockwise. while( 1 ) { Vector2D const *pStartPoint = &pPoints[ indices[nIndices-1] ]; float flEdgeAngle = atan2( curEdge.y, curEdge.x ); int iMinAngle = -1; float flMinAngle = 5000; for( i=0; i < nPoints; i++ ) { Vector2D vTo = pPoints[indexMap[i]] - *pStartPoint; float flDistToSqr = vTo.LengthSqr(); if ( flDistToSqr <= 0.1f ) continue; // Get the angle from the edge to this point. float flAngle = atan2( vTo.y, vTo.x ); flAngle = AngleOffset( flEdgeAngle, flAngle ); if( fabs( flAngle - flMinAngle ) < 0.00001f ) { float flDistToTestSqr = pStartPoint->DistToSqr( pPoints[iMinAngle] ); // If the angle is the same, pick the point farthest away. // unless the current one is closing the face loop if ( iMinAngle != indices[0] && flDistToSqr > flDistToTestSqr ) { flMinAngle = flAngle; iMinAngle = indexMap[i]; } } else if( flAngle < flMinAngle ) { flMinAngle = flAngle; iMinAngle = indexMap[i]; } } if( iMinAngle == -1 ) { // Couldn't find a point? Assert( false ); break; } else if( iMinAngle == indices[0] ) { // Finished. break; } else { // Add this point. if( nIndices >= nMaxIndices ) break; for ( int jj = 0; jj < nIndices; jj++ ) { // if this assert hits, this routine is broken and is generating a spiral // rather than a closed polygon - basically an edge overlap of some kind Assert(indices[jj] != iMinAngle ); } indices[nIndices] = iMinAngle; ++nIndices; } curEdge = pPoints[indices[nIndices-1]] - pPoints[indices[nIndices-2]]; } return nIndices; }