/* * 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()); } }); }
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); }