/// <summary> /// Classifies an edge w.r.t a plane, adding it to inFrontEdges or behindEdges. If the plane intersects the edge, it's split, /// and the two resulting edges are added to inFrontEdges or behindEdges instead /// </summary> private static void ClassifyEdge( Plane2 plane, Edge edge, ICollection< Edge > inFrontEdges, ICollection< Edge > behindEdges ) { PlaneClassification startClass = plane.ClassifyPoint( edge.Start, OnPlaneTolerance ); PlaneClassification endClass = plane.ClassifyPoint( edge.End, OnPlaneTolerance ); if ( startClass == PlaneClassification.On ) { startClass = endClass; } if ( endClass == PlaneClassification.On ) { endClass = startClass; } if ( startClass == endClass ) { // Edge endpoints on the same side of the splitter plane - no split required if ( startClass == PlaneClassification.Behind ) { AddEdge( behindEdges, edge ); } else if ( startClass == PlaneClassification.InFront ) { AddEdge( inFrontEdges, edge ); } // Don't care about edges that are on the splitter plane return; } Point2 midPt = Intersections2.GetLinePlaneIntersection( edge.Start, edge.End, plane ).IntersectionPosition; Edge startToMid = new Edge( edge.Start, midPt, edge.IsDoubleSided, edge.SourceEdge ); Edge midToEnd = new Edge( midPt, edge.End, edge.IsDoubleSided, edge.SourceEdge ); if ( startClass == PlaneClassification.Behind ) { AddEdge( behindEdges, startToMid ); AddEdge( inFrontEdges, midToEnd ); } else { AddEdge( inFrontEdges, startToMid ); AddEdge( behindEdges, midToEnd ); } }
/// <summary> /// Splits a source polygon along a plane, returning the sub-poly behind the plane in "behind" /// and the sub-poly in-front of the plane in "inFront" /// </summary> public void Split( Plane2 plane, Polygon source, out Polygon behind, out Polygon inFront ) { float tolerance = 0.001f; int firstDefiniteClassIndex = -1; PlaneClassification[] classifications = new PlaneClassification[ source.Indices.Length ]; for ( int index = 0; index < source.Indices.Length; ++index ) { classifications[ index ] = plane.ClassifyPoint( m_Points[ source.Indices[ index ] ], tolerance ); if ( ( firstDefiniteClassIndex == -1 ) && ( classifications[ index ] != PlaneClassification.On ) ) { firstDefiniteClassIndex = index; } } if ( firstDefiniteClassIndex > 1 ) { // The first two points are on the split plane. This means that we // can easily classify the polygon as either behind or in front depending on the first // definite class if ( classifications[ firstDefiniteClassIndex ] == PlaneClassification.Behind ) { behind = new Polygon( source.Indices ); inFront = null; } else { behind = null; inFront = new Polygon( source.Indices ); } return; } int lastPtIndex = firstDefiniteClassIndex; int curPtIndex = ( lastPtIndex + 1 ) % source.Indices.Length; Point2 lastPt = m_Points[ source.Indices[ lastPtIndex ] ]; PlaneClassification lastClass = classifications[ lastPtIndex ]; List< int > behindPoints = new List< int >( source.Indices.Length + 2 ); List< int > inFrontPoints = new List< int >( source.Indices.Length + 2 ); for ( int count = 0; count < source.Indices.Length; ++count ) { Point2 curPt = m_Points[ source.Indices[ curPtIndex ] ]; PlaneClassification curClass = classifications[ curPtIndex ]; if ( curClass == PlaneClassification.On ) { curClass = lastClass; } if ( curClass != lastClass ) { // Split line on plane Line2Intersection intersection = Intersections2.GetLinePlaneIntersection( lastPt, curPt, plane ); int newPtIndex = AddPoint( intersection.IntersectionPosition ); behindPoints.Add( newPtIndex ); inFrontPoints.Add( newPtIndex ); } if ( curClass == PlaneClassification.Behind ) { behindPoints.Add( source.Indices[ curPtIndex ] ); } else { inFrontPoints.Add( source.Indices[ curPtIndex ] ); } lastClass = curClass; lastPt = curPt; curPtIndex = ( curPtIndex + 1 ) % source.Indices.Length; } behind = ( behindPoints.Count == 0 ) ? null : new Polygon( behindPoints.ToArray( ) ); inFront = ( inFrontPoints.Count == 0 ) ? null : new Polygon( inFrontPoints.ToArray( ) ); }