Beispiel #1
0
        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);
        }