Пример #1
0
        protected List <Vertex2D> GetSpinePoints(Chord2D chord)
        {
            var points = new List <Vertex2D>();

            GetSpinePointsRoutine(points, chord, null);
            return(points);
        }
Пример #2
0
        // triangles are divided at the spine
        protected void Subdivide(Chord2D root)
        {
            var rTriangles = new List <Triangle2D>();
            var rSegments  = new List <Segment2D>();

            SubdivideRoutine(rTriangles, rSegments, root, null);
            rTriangles.ForEach(t => triangulation.RemoveTriangle(t));
            rSegments.ForEach(s => triangulation.RemoveTriangle(s));
        }
Пример #3
0
 protected void GetSpinePointsRoutine(List <Vertex2D> points, Chord2D current, Chord2D from)
 {
     if (!current.Pruned)
     {
         points.Add(current.Src);
     }
     current.Connection.ForEach(to =>
     {
         if (to != from)
         {
             GetSpinePointsRoutine(points, to, current);
         }
     });
 }
Пример #4
0
        protected 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));

            SewRoutine(triangles, flags, sews, chord, null, division);
        }
Пример #5
0
        protected List <Chord2D> Traverse(Chord2D cur, Chord2D from, Func <Chord2D, bool> check)
        {
            var chords = new List <Chord2D>();

            if (check(cur))
            {
                chords.Add(cur);
            }

            cur.Connection.ForEach(to => {
                if (to != from)
                {
                    chords.AddRange(Traverse(to, cur, check));
                }
            });

            return(chords);
        }
Пример #6
0
        List <Vertex2D> GetSpinePoints(Chord2D chord)
        {
            var points = new List <Vertex2D>();
            Action <Chord2D, Chord2D> Recursion;

            Recursion = (Chord2D current, Chord2D from) => {
                if (!current.Pruned)
                {
                    points.Add(current.Src);
                }
                current.Connection.ForEach(to => {
                    if (to != from)
                    {
                        Recursion(to, current);
                    }
                });
            };
            Recursion(chord, null);
            return(points);
        }
Пример #7
0
        /*
         * The chordal axis is obtained by connecting the midpoints of the internal edges.
         */
        protected Chord2D GetChordalAxis(Face2D external, List <Face2D> faces)
        {
            var t = external.Triangle;

            Vertex2D  src, dst;
            Segment2D dstEdge;

            bool e0 = ExternalSegment(t.s0);
            bool e1 = ExternalSegment(t.s1);
            bool e2 = ExternalSegment(t.s2);

            if (e0 && e1)
            {
                src     = t.s0.HasPoint(t.s1.a) ? t.s1.a : t.s1.b;
                dst     = triangulation.CheckAndAddVertex(t.s2.Midpoint());
                dstEdge = t.s2;
            }
            else if (e1 && e2)
            {
                src     = t.s1.HasPoint(t.s2.a) ? t.s2.a : t.s2.b;
                dst     = triangulation.CheckAndAddVertex(t.s0.Midpoint());
                dstEdge = t.s0;
            }
            else
            {
                src     = t.s2.HasPoint(t.s0.a) ? t.s0.a : t.s0.b;
                dst     = triangulation.CheckAndAddVertex(t.s1.Midpoint());
                dstEdge = t.s1;
            }

            var chord = new Chord2D(src, dst, external);

            chord.SetDstEdge(dstEdge);

            var connection = new Connection2D(faces);

            ChordalAxisRoutine(chord, connection);

            return(chord);
        }
Пример #8
0
        void Init(Triangulation2D triangulation)
        {
            contourSegments = BuildContourSegments(triangulation);

            var triangles = triangulation.Triangles.ToList();

            faces = Categorize(triangles);

            var terminal = faces.Find(f => f.Type == Face2DType.Terminal);

            chord = GetChordalAxis(terminal, faces);

            var terminalChords = Traverse(chord, null, (Chord2D c) => {
                return(c.Face.Type == Face2DType.Terminal);
            });

            var convergence = new List <Vertex2D>();

            terminalChords.ForEach(c => {
                Prune(c, convergence);
            });

            Subdivide(chord);

            // var spine = GetSpinePoints(chord);
            var networkTable = BuildTable(triangulation);

            networks = BuildNetworks(triangulation, networkTable);
            Elevate(networks);

            heightTable = new Dictionary <Vertex2D, float>();
            foreach (Vertex2D v in networkTable.Keys)
            {
                heightTable.Add(v, networkTable[v].Height);
            }

            Sew(triangulation, chord, heightTable, 3);
        }
Пример #9
0
        protected void SewRoutine(List <Triangle2D> triangles, Dictionary <Triangle2D, bool> flags, Dictionary <Triangle2D, List <Triangle2D> > sews, Chord2D current, Chord2D from, int division)
        {
            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(flags, sews, t, segments, division);
                });
            }

            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(flags, sews, t, segments, division);
                });
            }

            next.ForEach(to =>
            {
                SewRoutine(triangles, flags, sews, to, current, division);
            });
        }
Пример #10
0
        protected void SubdivideRoutine(List <Triangle2D> rTriangles, List <Segment2D> rSegments, Chord2D chord, Chord2D from)
        {
            switch (chord.Face.Type)
            {
            case Face2DType.Sleeve:

                if (!chord.Pruned)
                {
                    Vertex2D  top, lb, rb;
                    Segment2D s0 = chord.SrcEdge, s1 = chord.DstEdge;
                    if (s0.a == s1.a || s0.a == s1.b)
                    {
                        top = s0.a;
                        lb  = s0.b;
                    }
                    else
                    {
                        top = s0.b;
                        lb  = s0.a;
                    }
                    rb = (s1.a == top) ? s1.b : s1.a;

                    Vertex2D tl = chord.Src, tr = chord.Dst, bottom = triangulation.CheckAndAddVertex((lb.Coordinate + rb.Coordinate) * 0.5f);

                    // triangulation.RemoveTriangle(chord.Face.Triangle);
                    rTriangles.Add(chord.Face.Triangle);
                    triangulation.AddTriangle(top, tl, tr);
                    triangulation.AddTriangle(tl, lb, bottom);
                    triangulation.AddTriangle(tr, bottom, rb);
                    triangulation.AddTriangle(tl, bottom, tr);
                }

                break;

            case Face2DType.Junction:

                if (!chord.Pruned)
                {
                    Vertex2D top, lb, rb, bottom;
                    if (chord.SrcEdge != null)
                    {
                        top    = chord.Dst;
                        lb     = chord.SrcEdge.a;
                        rb     = chord.SrcEdge.b;
                        bottom = chord.Src;
                        // triangulation.RemoveTriangle(chord.SrcEdge);
                        rSegments.Add(chord.SrcEdge);
                    }
                    else
                    {
                        top    = chord.Src;
                        lb     = chord.DstEdge.a;
                        rb     = chord.DstEdge.b;
                        bottom = chord.Dst;
                        // triangulation.RemoveTriangle(chord.DstEdge);
                        rSegments.Add(chord.DstEdge);
                    }
                    // triangulation.RemoveTriangle(chord.Face.Triangle);
                    triangulation.AddTriangle(top, lb, bottom);
                    triangulation.AddTriangle(top, rb, bottom);
                }

                break;
            }

            chord.Connection.ForEach(to => {
                if (to != from)
                {
                    SubdivideRoutine(rTriangles, rSegments, to, chord);
                }
            });
        }
Пример #11
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());
                }
            });
        }
Пример #12
0
        protected void ChordalAxisRoutine(Chord2D chord, Connection2D connection)
        {
            var origin    = chord.Face;
            var neighbors = connection.GetNeighbors(origin);

            connection.Remove(origin); // prevent overlaping to traverse

            neighbors.ForEach(neighbor => {
                var face    = neighbor.face;
                var segment = neighbor.joint;

                Vertex2D destination;
                Segment2D destinationEdge = null;

                switch (face.Type)
                {
                case Face2DType.Junction:
                    destination = triangulation.CheckAndAddVertex(face.Centroid());
                    break;

                case Face2DType.Sleeve:
                    var others = face.Triangle.ExcludeSegment(segment);
                    if (!ExternalSegment(others[0]))
                    {
                        destination     = triangulation.CheckAndAddVertex(others[0].Midpoint());
                        destinationEdge = others[0];
                    }
                    else
                    {
                        destination     = triangulation.CheckAndAddVertex(others[1].Midpoint());
                        destinationEdge = others[1];
                    }
                    break;

                // case Face2DType.Terminal:
                default:
                    destination = face.GetUncommonPoint(origin);
                    break;
                }

                Chord2D nextChord;
                if (origin.Type == Face2DType.Junction)
                {
                    var interval = new Chord2D(chord.Dst, triangulation.CheckAndAddVertex(segment.Midpoint()), origin);
                    interval.SetSrcEdge(chord.DstEdge); // maybe null
                    interval.SetDstEdge(segment);

                    nextChord = new Chord2D(interval.Dst, destination, face);
                    nextChord.SetSrcEdge(segment);
                    nextChord.SetDstEdge(destinationEdge); // null or exist

                    chord.Connect(interval);
                    interval.Connect(nextChord);
                }
                else
                {
                    nextChord = new Chord2D(chord.Dst, destination, face);
                    nextChord.SetSrcEdge(chord.DstEdge);
                    nextChord.SetDstEdge(destinationEdge); // null or exist

                    chord.Connect(nextChord);
                }

                ChordalAxisRoutine(nextChord, connection);
            });
        }
Пример #13
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);
        }
Пример #14
0
 public void Disconnect(Chord2D c)
 {
     this.connection.Remove(c);
     c.connection.Remove(this);
 }
Пример #15
0
 public void Connect(Chord2D c)
 {
     this.connection.Add(c);
     c.connection.Add(this);
 }