コード例 #1
0
ファイル: Teddy.cs プロジェクト: zj831007/unity-teddy
        /*
         * BUG
         * 既にPrune済みのJunctionを再度Pruneしてしまうバグ
         */
        protected void Prune(Chord2D chord, List <Vertex2D> convergence, Chord2D from = null, List <Chord2D> past = null)
        {
            if (chord.Face.Type == Face2DType.Junction)
            {
                past.Add(chord);

                var centroid = chord.Face.Centroid();

                var points  = new List <Vertex2D>();
                var ignores = new List <Vertex2D>();

                for (int i = 0, n = past.Count - 1; i < n; i++)
                {
                    var c0 = past[i];
                    var c1 = past[i + 1];
                    points.Add(c0.Face.GetUncommonPoint(c1.Face));
                }

                var      t           = chord.Face.Triangle;
                Vertex2D dividePoint = null;

                if (!chord.Face.Pruned)
                {
                    points.Add(t.a); points.Add(t.b); points.Add(t.c);

                    var coord = chord.Src.Coordinate;
                    if (coord == (t.a.Coordinate + t.b.Coordinate) * 0.5f)
                    {
                        dividePoint = t.c;
                    }
                    else if (coord == (t.b.Coordinate + t.c.Coordinate) * 0.5f)
                    {
                        dividePoint = t.a;
                    }
                    else
                    {
                        dividePoint = t.b;
                    }
                }
                else
                {
                    points.Add(t.a); points.Add(t.b); points.Add(t.c);

                    var        divides = chord.Face.Divides;
                    Triangle2D t0 = divides[0], t1 = divides[1];
                    Vertex2D[] ps0 = t0.ExcludePoint(centroid), ps1 = t1.ExcludePoint(centroid);
                    if (chord.Dst.Coordinate == (ps0[0].Coordinate + ps0[1].Coordinate) * 0.5f)
                    {
                        triangulation.RemoveTriangle(t0);
                        if (t.a != ps0[0] && t.a != ps0[1])
                        {
                            ignores.Add(t.a);
                        }
                        else if (t.b != ps0[0] && t.b != ps0[1])
                        {
                            ignores.Add(t.b);
                        }
                        else
                        {
                            ignores.Add(t.c);
                        }
                    }
                    else if (chord.Dst.Coordinate == (ps1[0].Coordinate + ps1[1].Coordinate) * 0.5f)
                    {
                        triangulation.RemoveTriangle(t1);
                        if (t.a != ps1[0] && t.a != ps1[1])
                        {
                            ignores.Add(t.a);
                        }
                        else if (t.b != ps1[0] && t.b != ps1[1])
                        {
                            ignores.Add(t.b);
                        }
                        else
                        {
                            ignores.Add(t.c);
                        }
                    }
                    else
                    {
                        // Debug.LogWarning("error!");
                        return;
                    }
                }

                var vertices = points.OrderBy(p => Angle(centroid, p.Coordinate)).ToList();
                var cv       = triangulation.CheckAndAddVertex(centroid);

                var newTriangles = new List <Triangle2D>();
                for (int i = 0, n = vertices.Count; i < n; i++)
                {
                    Vertex2D a = cv, b = vertices[i], c = vertices[(i + 1) % n];
                    if (ignores.Contains(b) || ignores.Contains(c))
                    {
                        continue;
                    }
                    var nt = triangulation.AddTriangle(a, b, c);
                    newTriangles.Add(nt);
                }

                if (!chord.Face.Pruned && dividePoint != null)
                {
                    var divides = newTriangles.FindAll(nt => nt.HasPoint(dividePoint));
                    chord.Face.SetDivides(divides.ToList());
                }

                // finish current loop
                convergence.Add(cv);
                Prune(past);

                return;
            }

            Segment2D diameter;

            if (chord.Face.Type == Face2DType.Terminal)
            {
                var t = chord.Face.Triangle;
                if (!ExternalSegment(t.s0))
                {
                    diameter = t.s0;
                }
                else if (!ExternalSegment(t.s1))
                {
                    diameter = t.s1;
                }
                else
                {
                    diameter = t.s2;
                }
            }
            else
            {
                var segments = chord.Face.GetUncommonSegments(from.Face);
                if (!ExternalSegment(segments[0]))
                {
                    diameter = segments[0];
                }
                else
                {
                    diameter = segments[1];
                }
            }

            if (past == null)
            {
                past = new List <Chord2D>();
            }
            past.Add(chord);

            Vector2 center = diameter.Midpoint();
            float   radius = Vector2.Distance(center, diameter.a.Coordinate);

            var found = past.Find(ch => {
                var t     = ch.Face.Triangle;
                Vector2 a = t.a.Coordinate, b = t.b.Coordinate, c = t.c.Coordinate;
                return
                ((!diameter.HasPoint(a) && Vector2.Distance(a, center) - radius > float.Epsilon) ||
                 (!diameter.HasPoint(b) && Vector2.Distance(b, center) - radius > float.Epsilon) ||
                 (!diameter.HasPoint(c) && Vector2.Distance(c, center) - radius > float.Epsilon));
            });

            if (found != null)
            {
                var points = new List <Vertex2D>();

                for (int i = 0, n = past.Count - 1; i < n; i++)
                {
                    var c0 = past[i];
                    var c1 = past[i + 1];
                    points.Add(c0.Face.GetUncommonPoint(c1.Face));
                }
                points.Add(chord.Face.GetUncommonPoint(diameter));

                var basis    = diameter.a.Coordinate;
                var vertices = points.OrderBy(p => Angle(center, basis, p.Coordinate)).ToList();
                vertices.Insert(0, diameter.a);
                vertices.Add(diameter.b);

                var cv = triangulation.CheckAndAddVertex(center);
                for (int i = 0, n = vertices.Count - 1; i < n; i++)
                {
                    Vertex2D a = cv, b = vertices[i], c = vertices[i + 1];
                    triangulation.AddTriangle(a, b, c);
                }

                convergence.Add(cv);
                Prune(past);
                return;
            }

            chord.Connection.ForEach(to => {
                if (to != from)
                {
                    Prune(to, convergence, chord, past.ToList());
                }
            });
        }