protected void HandleEndpointIntersectionSplit(BspSegment splitter, BspSegment segmentToSplit, Endpoint endpoint) { // We know that the endpoint argument is the vertex that was // intersected by the splitter. This means the other endpoint is // on the left or the right side of the splitter, so we'll use // that 'opposite' endpoint to check the side we should place the // segment on. BspVertex oppositeVertex = segmentToSplit.Opposite(endpoint); Rotation side = splitter.ToSide(oppositeVertex); Debug.Assert(side != Rotation.On, "Ambiguous split, segment too small to determine splitter side"); if (side == Rotation.Right) { States.RightSegments.Add(segmentToSplit); } else { States.LeftSegments.Add(segmentToSplit); } BspVertex vertex = segmentToSplit.VertexFrom(endpoint); States.CollinearVertices.Add(vertex); }
private static List <SubsectorEdge> CreateSubsectorEdges(ConvexTraversal convexTraversal, Rotation rotation) { List <ConvexTraversalPoint> traversal = convexTraversal.Traversal; Debug.Assert(traversal.Count >= 3, "Traversal must yield at least a triangle in size"); List <SubsectorEdge> subsectorEdges = new List <SubsectorEdge>(); ConvexTraversalPoint firstTraversal = traversal.First(); Vec2D startPoint = firstTraversal.Vertex; foreach (ConvexTraversalPoint traversalPoint in traversal) { BspSegment segment = traversalPoint.Segment; Vec2D endingPoint = segment.Opposite(traversalPoint.Endpoint).Struct(); bool traversedFrontSide = CheckIfTraversedFrontSide(traversalPoint, rotation); SubsectorEdge edge = new SubsectorEdge(startPoint, endingPoint, segment.Line.Value, traversedFrontSide); subsectorEdges.Add(edge); Debug.Assert(startPoint != endingPoint, "Traversal produced the wrong endpoint indices"); startPoint = endingPoint; } Debug.Assert(subsectorEdges.Count == traversal.Count, "Added too many subsector edges in traversal"); return(subsectorEdges); }
public void Execute() { Debug.Assert(ValidExecutionState(), "Called convex checker execution in an invalid state"); if (States.CurrentSegment == null) { throw new NullReferenceException("Forgot to load the segments in, current segment is null"); } States.State = ConvexState.Traversing; // We traverse around the suspected enclosed polygon with each of // the following rules: // - NextSeg is the next attached segment in the cycle iteration // - CurrentSeg and NextSeg share a 'pivot' vertex // - CurrentEndpoint is the endpoint on the current segment that // is not the pivot vertex // - The third vertex is the vertex on the NextSeg that is not // the pivot // // This is summed up by this image (assuming clockwise traversal): // // Current endpoint Pivot (aka: Opposite endpoint) // (0)-----[CurrentSeg]-----(1) // | // |NextSeg // | // (2) Third vertex // // Each number is the vertex in the rotation order. BspSegment currentSeg = States.CurrentSegment; Vec2D firstVertex = currentSeg[States.CurrentEndpoint].Struct(); Vec2D secondVertex = currentSeg.Opposite(States.CurrentEndpoint).Struct(); int pivotIndex = currentSeg.OppositeIndex(States.CurrentEndpoint); // Since we know there are exactly two lines at each endpoint, we // can select the next segment by whichever of the two is not the // current segment. List <ConvexTraversalPoint> linesAtPivot = VertexMap[pivotIndex]; Debug.Assert(linesAtPivot.Count == 2, "Expected two lines for every endpoint"); BspSegment nextSeg = linesAtPivot[0].Segment; if (ReferenceEquals(currentSeg, nextSeg)) { nextSeg = linesAtPivot[1].Segment; } Endpoint nextSegPivotEndpoint = nextSeg.EndpointFrom(pivotIndex); Vec2D thirdVertex = nextSeg.Opposite(nextSegPivotEndpoint).Struct(); Rotation rotation = Seg2D.GetRotation(firstVertex, secondVertex, thirdVertex); if (rotation != Rotation.On) { if (States.Rotation == Rotation.On) { States.Rotation = rotation; } else if (States.Rotation != rotation) { States.State = ConvexState.FinishedIsSplittable; return; } } States.ConvexTraversal.AddTraversal(currentSeg, States.CurrentEndpoint); States.CurrentSegment = nextSeg; States.CurrentEndpoint = nextSegPivotEndpoint; States.SegsVisited++; if (!CompletedTraversalCycle(nextSeg)) { return; } // If we never rotated, it's a straight degenerate line (and not a single // convex polygon). if (States.Rotation == Rotation.On) { States.State = ConvexState.FinishedIsDegenerate; return; } bool isConvex = (States.SegsVisited == States.TotalSegs); States.State = (isConvex ? ConvexState.FinishedIsConvex : ConvexState.FinishedIsSplittable); }