コード例 #1
0
ファイル: IWidePath.cs プロジェクト: lulzzz/Nucleus
        /// <summary>
        /// Generate the left and right edges of the paths in this network,
        /// automatically joining them at shared end nodes.  Nodes should have been
        /// generated for the network prior to calling this function.
        /// </summary>
        /// <typeparam name="TPath"></typeparam>
        /// <param name="paths"></param>
        public static void GenerateNetworkPathEdges <TPath>(this IList <TPath> paths)
            where TPath : IWidePath
        {
            var pathMap = new Dictionary <Guid, TPath>();

            // Generate initial curves + build map:
            foreach (TPath path in paths)
            {
                if (path.Spine != null)
                {
                    pathMap[path.Spine.GUID] = path;
                    path.GenerateInitialPathEdges();
                    path.CurveInitialPathEdges();
                }
            }

            NodeCollection nodes = paths.ExtractNetworkPathNodes();

            // Trim edges at nodes:
            foreach (Node node in nodes)
            {
                if (node.Vertices.Count > 0)
                {
                    // Sort connected vertices by the angle pointing away from the node
                    var angleSorted = new SortedList <double, Vertex>(node.Vertices.Count);
                    foreach (var v in node.Vertices)
                    {
                        if (v.Owner != null && v.Owner is Curve && pathMap.ContainsKey(v.Owner.GUID))
                        {
                            Curve crv = (Curve)v.Owner;
                            if (v.IsStart)
                            {
                                angleSorted.AddSafe(crv.TangentAt(0).Angle, v);
                            }
                            else if (v.IsEnd)
                            {
                                angleSorted.AddSafe(crv.TangentAt(1).Reverse().Angle, v);
                            }
                        }
                    }
                    if (angleSorted.Count > 1)
                    {
                        for (int i = 0; i < angleSorted.Count - 1; i++)
                        {
                            // Reference case is path leading away from node
                            Vertex vR = angleSorted.Values.GetWrapped(i - 1);
                            Vertex v  = angleSorted.Values[i];
                            Vertex vL = angleSorted.Values.GetWrapped(i + 1);

                            Angle a  = new Angle(angleSorted.Keys[i]).NormalizeTo2PI();
                            Angle aR = new Angle(angleSorted.Keys.GetWrapped(i - 1) - a);
                            Angle aL = new Angle(angleSorted.Keys.GetWrapped(i + 1) - a).Explement();

                            TPath pathR = pathMap[vR.Owner.GUID];
                            TPath path  = pathMap[v.Owner.GUID];
                            TPath pathL = pathMap[vL.Owner.GUID];

                            // Work out correct edges to match up based on direction:
                            Vertex edgeVR;
                            Vertex edgeVL;
                            double offsR;
                            double offsL;

                            if (v.IsStart)
                            {
                                // Curve is pointing away from the node
                                edgeVR = path.RightEdge.Start;
                                edgeVL = path.LeftEdge.Start;
                                offsR  = path.RightOffset;
                                offsL  = path.LeftOffset;
                            }
                            else
                            {
                                // Curve is pointing towards the node - flip everything!
                                edgeVR = path.LeftEdge.End;
                                edgeVL = path.RightEdge.End;
                                offsR  = path.LeftOffset;
                                offsL  = path.RightOffset;
                            }

                            Vertex edgeVR2;
                            double offsR2;
                            if (vR.IsStart)
                            {
                                edgeVR2 = pathR.LeftEdge.Start;
                                offsR2  = pathR.LeftOffset;
                            }
                            else
                            {
                                edgeVR2 = pathR.RightEdge.End;
                                offsR2  = pathR.RightOffset;
                            }

                            Vertex edgeVL2;
                            double offsL2;
                            if (vL.IsStart)
                            {
                                edgeVL2 = pathL.RightEdge.Start;
                                offsL2  = pathL.RightOffset;
                            }
                            else
                            {
                                edgeVL2 = pathL.LeftEdge.End;
                                offsL2  = pathL.LeftOffset;
                            }

                            bool canTrimR  = true;
                            bool canTrimR2 = true;
                            if (aR.IsReflex)
                            {
                                if (offsR > offsR2)
                                {
                                    canTrimR = false;
                                }
                                else if (offsR2 > offsR)
                                {
                                    canTrimR2 = false;
                                }
                            }

                            if (!Curve.MatchEnds(edgeVR, edgeVR2, true, canTrimR, canTrimR2))
                            {
                                if (offsR > offsR2)
                                {
                                    Curve.ExtendToLineXY(edgeVR2, node.Position, edgeVR.Position - node.Position);
                                    path.SetEndEdge(edgeVR, new Line(edgeVR.Position, edgeVR2.Position));
                                }
                                else
                                {
                                    Curve.ExtendToLineXY(edgeVR, node.Position, edgeVR2.Position - node.Position);
                                    pathR.SetEndEdge(edgeVR2, new Line(edgeVR2.Position, edgeVR.Position));
                                }

                                /*(Curve crv = Curve.Connect(edgeVR, edgeVR2.Position);
                                 * if (crv != null)
                                 * {
                                 *  if (v.IsStart) path.RightEdge = crv;
                                 *  else path.LeftEdge = crv;
                                 * }*/
                            }


                            bool canTrimL  = true;
                            bool canTrimL2 = true;
                            if (aL.IsReflex)
                            {
                                if (offsL > offsL2)
                                {
                                    canTrimL = false;
                                }
                                else if (offsL2 > offsL)
                                {
                                    canTrimL2 = false;
                                }
                            }

                            if (!Curve.MatchEnds(edgeVL, edgeVL2, true, canTrimL, canTrimL2))
                            {
                                if (offsL > offsL2)
                                {
                                    Curve.ExtendToLineXY(edgeVL2, node.Position, edgeVL.Position - node.Position);
                                    path.SetEndEdge(edgeVL, new Line(edgeVL.Position, edgeVL2.Position));
                                }
                                else
                                {
                                    Curve.ExtendToLineXY(edgeVL, node.Position, edgeVL2.Position - node.Position);
                                    pathL.SetEndEdge(edgeVL2, new Line(edgeVL2.Position, edgeVL.Position));
                                }

                                /*Curve crv = Curve.Connect(edgeVL, edgeVL2.Position);
                                 * if (crv != null)
                                 * {
                                 *  if (v.IsStart) path.LeftEdge = crv;
                                 *  else path.RightEdge = crv;
                                 * }*/
                            }
                        }
                    }
                    else if (angleSorted.Count == 1)
                    {
                        // Close off end:
                        Vertex v    = angleSorted.Values[0];
                        TPath  path = pathMap[v.Owner.GUID];
                        if (v.IsStart)
                        {
                            path.StartCapLeft = new Line(path.LeftEdge.StartPoint, path.RightEdge.StartPoint);
                        }
                        else
                        {
                            path.EndCapLeft = new Line(path.LeftEdge.EndPoint, path.RightEdge.EndPoint);
                        }
                    }
                }
            }
        }
コード例 #2
0
ファイル: PolyCurve.cs プロジェクト: lulzzz/Nucleus
        /// <summary>
        /// Extract from this PolyCurve a chain of subcurves, starting with the
        /// longest and continuing to select the longest edge until no more can
        /// be added without adding an edge which is within an angle tolerance of
        /// an existing curve within the chain.
        /// </summary>
        /// <returns></returns>
        public PolyCurve ExtractLongCurveChain(Angle maxAngle)
        {
            Curve longest = SubCurves.GetLongest();

            if (longest != null)
            {
                var tangents = new List <Vector>();
                tangents.Add(longest.TangentAt(0.5));
                var  result  = new PolyCurve(longest);
                int  iL      = SubCurves.IndexOf(longest);
                int  i0      = iL - 1;
                int  i1      = iL + 1;
                bool closed  = Closed;
                bool tryPre  = closed || i0 >= 0;
                bool tryPost = closed || i1 < SubCurves.Count;
                while (tryPre || tryPost)
                {
                    Curve pre  = tryPre ? SubCurves.GetWrapped(i0, closed) : null;
                    Curve post = tryPost ? SubCurves.GetWrapped(i1, closed) : null;
                    if (post != null && (pre == null || post.Length > pre.Length))
                    {
                        Vector tang = post.TangentAt(0.5);
                        if (result.SubCurves.Contains(post.GUID) || tangents.MaximumAngleBetween(tang).Abs() > maxAngle)
                        {
                            tryPost = false;
                        }
                        else
                        {
                            result.SubCurves.Add(post);
                            tangents.Add(tang);
                            i1++;
                            if (!closed && i1 >= SubCurves.Count)
                            {
                                tryPost = false;
                            }
                        }
                    }
                    else if (pre != null)
                    {
                        Vector tang = pre.TangentAt(0.5);
                        if (result.SubCurves.Contains(pre.GUID) || tangents.MaximumAngleBetween(tang).Abs() > maxAngle)
                        {
                            tryPre = false;
                        }
                        else
                        {
                            result.SubCurves.Insert(0, pre);
                            tangents.Add(tang);
                            i0--;
                            if (!closed && i0 < 0)
                            {
                                tryPre = false;
                            }
                        }
                    }
                    else
                    {
                        tryPre  = false;
                        tryPost = false;
                    }
                }
                return(result);
            }
            return(null);
        }