private bool IsProperlyConnectedEndpoint(BspSegment segment, Endpoint endpoint) { if (Traversal.Empty()) { return(true); } ConvexTraversalPoint lastPoint = Traversal.Last(); BspSegment lastSeg = lastPoint.Segment; Endpoint lastEndpoint = lastPoint.Endpoint; if (ReferenceEquals(segment, lastSeg)) { Debug.Assert(false, "Trying to add the same segment twice"); return(false); } // Because our traversal uses the first endpoint we reached, that // means the last segment's opposite endpoint should match this // segment's current endpoint. Graphically, this means: // // LastEndpoint Endpoint // o-----------o------------o // LastSeg Segment // // Notice that the opposite endpoint of LastEndpoint is equal to // the middle vertex labeled Endpoint. This is what we want to make // sure are equal since it is not a valid traversal if they do not // match. if (segment.IndexFrom(endpoint) != lastSeg.OppositeIndex(lastEndpoint)) { Debug.Assert(false, "Expect a tail-to-head connection"); return(false); } return(true); }
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); }