Пример #1
0
        /*
         * 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());
                }
            });
        }
Пример #2
0
        void Sew(Triangulation2D triangulation, Chord2D chord, Dictionary <Vertex2D, float> heightTable, int division)
        {
            var triangles = triangulation.Triangles.ToList();

            Dictionary <Triangle2D, bool> flags = new Dictionary <Triangle2D, bool>();

            // 既にSew済みのTriangle2Dを再度Sewする必要があるケースが存在する
            //  特定のChord2DのSrcとDstを含むTriangle2Dなのに,それ以外のChord2Dと共通点を持っているがために
            //	Spineと共通エッジを持つ場合のSewの処理がかけられず適切な分割ができていないケース
            Dictionary <Triangle2D, List <Triangle2D> > sews = new Dictionary <Triangle2D, List <Triangle2D> >();

            triangles.ForEach(t => flags.Add(t, false));

            Action <Triangle2D, Segment2D[]> SewTriangle = (Triangle2D t, Segment2D[] segments) => {
                triangulation.RemoveTriangle(t);
                var sewTriangles = Sew(heightTable, triangulation, segments[0], segments[1], division);
                sews.Add(t, sewTriangles);
                flags[t] = true;
            };

            Action <Chord2D, Chord2D> SewRoutine;

            SewRoutine = (Chord2D current, Chord2D from) => {
                if (!current.Pruned)
                {
                    triangles.FindAll(t => {
                        return(t.HasPoint(current.Src) && (t.HasPoint(current.Dst) || !sews.ContainsKey(t)));
                    }).ForEach(t => {
                        Segment2D[] segments;

                        if (sews.ContainsKey(t))
                        {
                            foreach (Triangle2D st in sews[t])
                            {
                                triangulation.RemoveTriangle(st);
                            }
                            sews.Remove(t);
                        }

                        if (t.HasPoint(current.Dst))
                        {
                            Segment2D s = t.CommonSegment(current.Src, current.Dst);
                            segments    = t.ExcludeSegment(s);
                        }
                        else
                        {
                            segments = t.CommonSegments(current.Src);
                        }

                        SewTriangle(t, segments);
                    });
                }

                var next = current.Connection.FindAll(con => con != from);

                // Prune後のSpineで末端にあたる頂点
                bool terminal = next.All(con => con.Pruned);
                if (terminal && !current.Pruned)
                {
                    triangles.FindAll(t => {
                        return(!sews.ContainsKey(t) && t.HasPoint(current.Dst));
                    }).ForEach(t => {
                        var segments = t.CommonSegments(current.Dst);
                        SewTriangle(t, segments);
                    });
                }

                next.ForEach(to => {
                    SewRoutine(to, current);
                });
            };

            SewRoutine(chord, null);
        }