public static void Main(string[] args) { var graph = new SimpleGraph <bool>(); var node1 = new SimpleGraphNode <bool>(1); var Node1Input1 = new SimpleGraphTerminal <bool>(node1); var Node1Input2 = new SimpleGraphTerminal <bool>(node1); var Node1Output = new SimpleGraphTerminal <bool>(node1); node1.Inputs.Add(Node1Input1); node1.Inputs.Add(Node1Input2); node1.Outputs.Add(Node1Output); var node2 = new SimpleGraphNode <bool>(2); var Node2Input1 = new SimpleGraphTerminal <bool>(node2); var Node2Output = new SimpleGraphTerminal <bool>(node2); node2.Inputs.Add(Node2Input1); node2.Outputs.Add(Node2Output); var node3 = new SimpleGraphNode <bool>(3); var Node3Input1 = new SimpleGraphTerminal <bool>(node3); var Node3Output = new SimpleGraphTerminal <bool>(node3); node3.Inputs.Add(Node3Input1); node3.Outputs.Add(Node3Output); var node4 = new SimpleGraphNode <bool>(4); var Node4Output = new SimpleGraphTerminal <bool>(node4); node4.Outputs.Add(Node4Output); var node5 = new SimpleGraphNode <bool>(5); var Node5Output = new SimpleGraphTerminal <bool>(node5); node5.Outputs.Add(Node5Output); var node6 = new SimpleGraphNode <bool>(6); var Node6Input1 = new SimpleGraphTerminal <bool>(node6); node6.Inputs.Add(Node6Input1); graph.AddNode(node1); graph.AddNode(node2); graph.AddNode(node3); graph.AddNode(node4); graph.AddNode(node5); graph.AddNode(node6); graph.AddEdge(new SimpleGraphEdge <bool>(Node3Output, Node6Input1)); graph.AddEdge(new SimpleGraphEdge <bool>(Node1Output, Node2Input1)); graph.AddEdge(new SimpleGraphEdge <bool>(Node2Output, Node3Input1)); graph.AddEdge(new SimpleGraphEdge <bool>(Node4Output, Node1Input1)); graph.AddEdge(new SimpleGraphEdge <bool>(Node5Output, Node1Input2)); graph.CalculateFromNode(node3); Console.ReadKey(); }
public static bool ValidPolygon(Ring2 <double> outer, RingSet2 <double> inner) { if (outer == null || inner == null) { return(false); } HashSet <Ring2 <double> > ringHash = new HashSet <Ring2 <double> >(); //check for the silly condition of multiple references to the same ring ringHash.Add(outer); Envelope2 <double> outerEnv = outer.Envelope; PlanarChainGraph <double> gr = new PlanarChainGraph <double>(); foreach (Ring2 <double> r in inner.Rings) { if (!ringHash.Add(r)) { return(false); //oops, duplicate reference } if (!Envelope2 <double> .EnvelopeContain(outerEnv, r.Envelope)) //all inner rings must be contained by outer ring, so the envelopes must overlap { return(false); } gr.Add(r); } ringHash.Clear(); ringHash = null; gr.Add(outer); SegmentGroup <double> activeEdges = new SegmentGroup <double>(); IEnumerator <Node <double> > points = gr.GetEnumerator(); //walk through the points in xy sorted order Node <double> nd; LeakyResizableArray <Edge <double> > localEdges; int localCt; int activeCt = 0; Edge <double> localEdge; LineSegment2IntersectionResult <double> intersects; Point2 <double> localStart; Point2 <double> localEnd; Point2 <double> activeStart; Point2 <double> activeEnd; Point2 <double> intPoint; SimpleGraph <object> touchingRings = new SimpleGraph <object>(); HashSet <object> outerRingTouching = new HashSet <object>(); //new point event in the moving front while (points.MoveNext()) { nd = points.Current; localEdges = nd.Edges; //edges connected to this point localCt = (int)localEdges.Count; //compute intersections with other edges in the scan area for (int i = 0; i < localCt; i++) { localEdge = localEdges.Data[i]; localStart = localEdge.Start.Point; localEnd = localEdge.End.Point; activeCt = activeEdges.Edges.Count; foreach (Edge <double> activeEdge in activeEdges.Edges) { if (object.ReferenceEquals(localEdge, activeEdge) || object.ReferenceEquals(localEdge.Start.ParentShape, activeEdge.Start.ParentShape)) { continue; //exiting edge || 2 edges on same ring } activeStart = activeEdge.Start.Point; activeEnd = activeEdge.End.Point; intersects = SegmentUtils.ComputeIntersection(localStart, localEnd, activeStart, activeEnd); if (intersects.IntersectionType != LineIntersectionType.NoIntersection) { if (intersects.IntersectionType == LineIntersectionType.CollinearIntersection) { return(false); // there's a full segment of intersection - must be between outer ring and an inner ring } //ok, we have an intersection that is a point between 2 different rings intPoint = intersects.BasePoint; if (object.ReferenceEquals(localEdge.Start.ParentShape, outer)) //localEdge is on the shell { if (PointUtilsDouble.PointsEqual(intPoint, activeStart)) { //only add the shell touching for segment intersection at segment start point - prevents recounting point if (!PointUtilsDouble.PointsEqual(intPoint, localEnd)) { if (!outerRingTouching.Add(activeEdge.Start.ParentShape)) { return(false); //same ring touches outer ring at multiple non-adjacent points } } if (!RingUtils.PointInteriorToRing(outer, activeEnd)) { return(false); //ring is outside of shell or crosses shell at a vertex } } else if (PointUtilsDouble.PointsEqual(intPoint, activeEnd)) { //only add the shell touching for segment intersection at segment start point - prevents recounting point if (!PointUtilsDouble.PointsEqual(intPoint, localEnd)) { if (!outerRingTouching.Add(activeEdge.Start.ParentShape)) { return(false); //same ring touches outer ring at multiple non-adjacent points } } if (!RingUtils.PointInteriorToRing(outer, activeStart)) { return(false); //ring is outside of shell or crosses shell at a vertex } } else { return(false); //we have a mid-segment intersection between the outer ring and an inner ring } } else if (object.ReferenceEquals(activeEdge.Start.ParentShape, outer)) //activeEdge is on the shell { if (PointUtilsDouble.PointsEqual(intPoint, localStart)) { //only add the shell touching for segment intersection at segment start point - prevents recounting point if (!PointUtilsDouble.PointsEqual(intPoint, activeEnd)) { if (!outerRingTouching.Add(localEdge.Start.ParentShape)) { return(false); //same ring touches outer ring at multiple non-adjacent points } } if (!RingUtils.PointInteriorToRing(outer, localEnd)) { return(false); //ring is outside of shell or crosses shell at a vertex } } else if (PointUtilsDouble.PointsEqual(intPoint, localEnd)) { //only add the shell touching for segment intersection at segment start point - prevents recounting point if (!PointUtilsDouble.PointsEqual(intPoint, activeEnd)) { if (!outerRingTouching.Add(localEdge.Start.ParentShape)) { return(false); //same ring touches outer ring at multiple non-adjacent points } } if (!RingUtils.PointInteriorToRing(outer, localStart)) { return(false); //ring is outside of shell or crosses shell at a vertex } } else { return(false); //we have a mid-segment intersection between the outer ring and an inner ring } } else //both are on inner rings { //since the ringset is valid, we just need to map the connectivity of rings if (!touchingRings.Contains(localEdge.Start.ParentShape)) { touchingRings.AddNode(localEdge.Start.ParentShape); } if (!touchingRings.Contains(activeEdge.Start.ParentShape)) { touchingRings.AddNode(activeEdge.Start.ParentShape); } touchingRings.AddEdge(localEdge.Start.ParentShape, activeEdge.Start.ParentShape); } } //end !nointersection } //end foreach } //end for //remove all exiting segments and add all starting segments //Action gets called exactly twice per edge -- once to add it, once to remove it for (int i = 0; i < localCt; i++) { activeEdges.Action(localEdges.Data[i]); } } //we now know all the rings of the ringset are "legally" connected wrt the shell -- but -- //inner rings may be adjacent to both the shell and other inner rings to form a "path" cutting the shell //any ring COULD be outside the shell -- we did already do the quick envelope check, so just do singular point-in-ring checks //shell cutting test (quick) object[] shellTouchers = outerRingTouching.ToArray(); for (int i = shellTouchers.Length - 1; i > 0; i--) { object adjacentRingA = shellTouchers[i]; if (touchingRings.Contains(adjacentRingA)) { for (int j = 0; j < i; j++) { object adjacentRingB = shellTouchers[j]; if (touchingRings.Contains(adjacentRingB)) { if (HasPath(adjacentRingA, adjacentRingB, touchingRings)) { return(false); //path exists between shell touching inner rings } } } } } //ring inside shell testing foreach (Ring2 <double> innerR in inner.Rings) { if (!(RingUtils.PointInteriorToRing(outer, innerR.Points[0]) || RingUtils.PointInteriorToRing(outer, innerR.Points[1]))) //at least one of 2 adjacent points must be interior { return(false); } } return(true); }