/// <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); /* * 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); * } * } * } * * if(pointsOut.Count == 0) * { * //pointsOut = new List<Vector2>(pointsIn); * } * * var tmp = pointsIn; * pointsIn = pointsOut; * pointsOut = tmp; * } * * if (clipped == null) * { * clipped = new List<Vector2>(); * } * else * { * clipped.Clear(); * } * * clipped.AddRange(pointsIn); * */ }