/// <summary> /// Returns the center of the circumcircle defined by three points (c0, /// c1 and c2) on its edge. /// </summary> public static Vector2 CircumcircleCenter(Vector2 c0, Vector2 c1, Vector2 c2) { var mp0 = 0.5f * (c0 + c1); var mp1 = 0.5f * (c1 + c2); var v0 = RotateRightAngle(c0 - c1); var v1 = RotateRightAngle(c1 - c2); float m0, m1; Geom.LineLineIntersection(mp0, v0, mp1, v1, out m0, out m1); return(mp0 + m0 * v0); }
/// <summary> /// Clip site of voronoi diagram using polygon (must be convex), /// returning the clipped vertices in clipped list. Modifies neither /// polygon nor diagram, so can be run in parallel for several sites at /// once. /// </summary> public void ClipSite(VoronoiDiagram diag, IList <Vector2> polygon, int site, ref List <Vector2> clipped) { pointsIn.Clear(); pointsIn.AddRange(polygon); int firstEdge, lastEdge; if (site == diag.Sites.Count - 1) { firstEdge = diag.FirstEdgeBySite[site]; lastEdge = diag.Edges.Count - 1; } else { firstEdge = diag.FirstEdgeBySite[site]; lastEdge = diag.FirstEdgeBySite[site + 1] - 1; } for (int ei = firstEdge; ei <= lastEdge; ei++) { pointsOut.Clear(); var edge = diag.Edges[ei]; Vector2 lp, ld; if (edge.Type == VoronoiDiagram.EdgeType.RayCCW || edge.Type == VoronoiDiagram.EdgeType.RayCW) { lp = diag.Vertices[edge.Vert0]; ld = edge.Direction; if (edge.Type == VoronoiDiagram.EdgeType.RayCW) { ld *= -1; } } else if (edge.Type == VoronoiDiagram.EdgeType.Segment) { var lp0 = diag.Vertices[edge.Vert0]; var lp1 = diag.Vertices[edge.Vert1]; lp = lp0; ld = lp1 - lp0; } else if (edge.Type == VoronoiDiagram.EdgeType.Line) { throw new NotSupportedException("Haven't implemented voronoi halfplanes yet"); } else { Debug.Assert(false); return; } for (int pi0 = 0; pi0 < pointsIn.Count; pi0++) { var pi1 = pi0 == pointsIn.Count - 1 ? 0 : pi0 + 1; var p0 = pointsIn[pi0]; var p1 = pointsIn[pi1]; var p0Inside = Geom.ToTheLeft(p0, lp, lp + ld); var p1Inside = Geom.ToTheLeft(p1, lp, lp + ld); if (p0Inside && p1Inside) { pointsOut.Add(p1); } else if (!p0Inside && !p1Inside) { // Do nothing, both are outside } else { var intersection = Geom.LineLineIntersection(lp, ld.normalized, p0, (p1 - p0).normalized); if (p0Inside) { pointsOut.Add(intersection); } else if (p1Inside) { pointsOut.Add(intersection); pointsOut.Add(p1); } else { Debug.Assert(false); } } } var tmp = pointsIn; pointsIn = pointsOut; pointsOut = tmp; } if (clipped == null) { clipped = new List <Vector2>(); } else { clipped.Clear(); } clipped.AddRange(pointsIn); }