/* ============ idWinding2D::LineIntersection ============ */ bool idWinding2D::LineIntersection( const idVec2 &start, const idVec2 &end ) const { int i, numEdges; int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3]; float d1, d2, epsilon = 0.1f; idVec3 plane, edges[2]; counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0; plane = Plane2DFromPoints( start, end ); for ( i = 0; i < numPoints; i++ ) { d1 = plane.x * p[i].x + plane.y * p[i].y + plane.z; if ( d1 > epsilon ) { sides[i] = SIDE_FRONT; } else if ( d1 < -epsilon ) { sides[i] = SIDE_BACK; } else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; if ( !counts[SIDE_FRONT] ) { return false; } if ( !counts[SIDE_BACK] ) { return false; } numEdges = 0; for ( i = 0; i < numPoints; i++ ) { if ( sides[i] != sides[i+1] && sides[i+1] != SIDE_ON ) { edges[numEdges++] = Plane2DFromPoints( p[i], p[(i+1)%numPoints] ); if ( numEdges >= 2 ) { break; } } } if ( numEdges < 2 ) { return false; } d1 = edges[0].x * start.x + edges[0].y * start.y + edges[0].z; d2 = edges[0].x * end.x + edges[0].y * end.y + edges[0].z; if ( FLOATSIGNBITNOTSET( d1 ) & FLOATSIGNBITNOTSET( d2 ) ) { return false; } d1 = edges[1].x * start.x + edges[1].y * start.y + edges[1].z; d2 = edges[1].x * end.x + edges[1].y * end.y + edges[1].z; if ( FLOATSIGNBITNOTSET( d1 ) & FLOATSIGNBITNOTSET( d2 ) ) { return false; } return true; }
/* ============ idWinding2D::PointInside ============ */ bool idWinding2D::PointInside( const idVec2 &point, const float epsilon ) const { int i; float d; idVec3 plane; for ( i = 0; i < numPoints; i++ ) { plane = Plane2DFromPoints( p[i], p[(i+1) % numPoints] ); d = plane.x * point.x + plane.y * point.y + plane.z; if ( d > epsilon ) { return false; } } return true; }
/* ============ idWinding2D::ExpandForAxialBox ============ */ void idWinding2D::ExpandForAxialBox( const idVec2 bounds[2] ) { int i, j, numPlanes; idVec2 v; idVec3 planes[MAX_POINTS_ON_WINDING_2D], plane, bevel; // get planes for the edges and add bevels for ( numPlanes = i = 0; i < numPoints; i++ ) { j = (i+1) % numPoints; if ( ( p[j] - p[i] ).LengthSqr() < 0.01f ) { continue; } plane = Plane2DFromPoints( p[i], p[j], true ); if ( i ) { if ( GetAxialBevel( planes[numPlanes-1], plane, p[i], bevel ) ) { planes[numPlanes++] = bevel; } } assert( numPlanes < MAX_POINTS_ON_WINDING_2D ); planes[numPlanes++] = plane; } assert( numPlanes < MAX_POINTS_ON_WINDING_2D && numPlanes > 0 ); if ( GetAxialBevel( planes[numPlanes-1], planes[0], p[0], bevel ) ) { planes[numPlanes++] = bevel; } // expand the planes for ( i = 0; i < numPlanes; i++ ) { v.x = bounds[ IEEE_FLT_SIGNBITSET( planes[i].x ) ].x; v.y = bounds[ IEEE_FLT_SIGNBITSET( planes[i].y ) ].y; planes[i].z += v.x * planes[i].x + v.y * planes[i].y; } // get intersection points of the planes for ( numPoints = i = 0; i < numPlanes; i++ ) { if ( Plane2DIntersection( planes[(i+numPlanes-1) % numPlanes], planes[i], p[numPoints] ) ) { numPoints++; } } }
/* ============ idWinding2D::RayIntersection ============ */ bool idWinding2D::RayIntersection( const idVec2 &start, const idVec2 &dir, float &scale1, float &scale2, int *edgeNums ) const { int i, numEdges, localEdgeNums[2]; int sides[MAX_POINTS_ON_WINDING_2D+1], counts[3]; float d1, d2, epsilon = 0.1f; idVec3 plane, edges[2]; scale1 = scale2 = 0.0f; counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0; plane = Plane2DFromVecs( start, dir ); for ( i = 0; i < numPoints; i++ ) { d1 = plane.x * p[i].x + plane.y * p[i].y + plane.z; if ( d1 > epsilon ) { sides[i] = SIDE_FRONT; } else if ( d1 < -epsilon ) { sides[i] = SIDE_BACK; } else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; if ( !counts[SIDE_FRONT] ) { return false; } if ( !counts[SIDE_BACK] ) { return false; } numEdges = 0; for ( i = 0; i < numPoints; i++ ) { if ( sides[i] != sides[i+1] && sides[i+1] != SIDE_ON ) { localEdgeNums[numEdges] = i; edges[numEdges++] = Plane2DFromPoints( p[i], p[(i+1)%numPoints] ); if ( numEdges >= 2 ) { break; } } } if ( numEdges < 2 ) { return false; } d1 = edges[0].x * start.x + edges[0].y * start.y + edges[0].z; d2 = - ( edges[0].x * dir.x + edges[0].y * dir.y ); if ( d2 == 0.0f ) { return false; } scale1 = d1 / d2; d1 = edges[1].x * start.x + edges[1].y * start.y + edges[1].z; d2 = - ( edges[1].x * dir.x + edges[1].y * dir.y ); if ( d2 == 0.0f ) { return false; } scale2 = d1 / d2; if ( idMath::Fabs( scale1 ) > idMath::Fabs( scale2 ) ) { idSwap( scale1, scale2 ); idSwap( localEdgeNums[0], localEdgeNums[1] ); } if ( edgeNums ) { edgeNums[0] = localEdgeNums[0]; edgeNums[1] = localEdgeNums[1]; } return true; }