private void Init() { m_tiles = new List <Tile>(); m_equator = new CircleNE(); m_neighborCircle = new CircleNE(); m_cells = new List <Cell>(); }
/// <summary> /// Setup a circle we'll use to color neighbors. /// </summary> private void SetupNeighborCircle(Tile templateTriangle) { Polygon poly = m_tiles.First().Boundary; // Tetrahedral tiling. CircleNE circ = new CircleNE(); circ.Radius = m_shrink; circ.Reflect(poly.Segments[2]); circ.Reflect(templateTriangle.Boundary.Segments[1]); Mobius m = new Mobius(); m.Isometry(Geometry.Spherical, 0, -circ.CenterNE); circ.Transform(m); m_neighborCircle = new CircleNE(); m_neighborCircle.Radius = 1.0 / circ.Radius; m_originalNeighborCircle = m_neighborCircle.Clone(); System.Func <Vector3D, Vector3D> pointTransform = v => { v *= m_neighborCircle.Radius; v = new Vector3D(v.Y, v.X); v.RotateXY(-Math.PI / 2); return(v); }; m_neighborToStandardDisk = CalcMobius(pointTransform); }
private static void SlicePolygonHelper(Polygon p, CircleNE c1, CircleNE c2, out List <Polygon> output) { output = new List <Polygon>(); // ZZZ - alter Clip method to work on Polygons and use that. // Slice it up. List <Polygon> sliced1, sliced2; Slicer.SlicePolygon(p, c1, out sliced1); Slicer.SlicePolygon(p, c2, out sliced2); // Keep the ones we want. foreach (Polygon newPoly in sliced1) { bool outside = !c1.IsPointInsideNE(newPoly.CentroidApprox); if (outside) { output.Add(newPoly); } } foreach (Polygon newPoly in sliced2) { bool inside = c2.IsPointInsideNE(newPoly.CentroidApprox); if (inside) { output.Add(newPoly); } } }
/// <summary> /// Slicing function used for earthquake puzzles. /// c should be geodesic (orthogonal to the disk boundary). /// </summary> public static void SlicePolygonWithHyperbolicGeodesic(Polygon p, CircleNE c, double thickness, out List <Polygon> output) { Geometry g = Geometry.Hyperbolic; Segment seg = null; if (c.IsLine) { Vector3D p1, p2; Euclidean2D.IntersectionLineCircle(c.P1, c.P2, new Circle(), out p1, out p2); seg = Segment.Line(p1, p2); } else { // Setup the two slicing circles. // These are cuts equidistant from the passed in geodesic. Vector3D closestToOrigin = H3Models.Ball.ClosestToOrigin(new Circle3D() { Center = c.Center, Radius = c.Radius, Normal = new Vector3D(0, 0, 1) }); Vector3D p1, p2; Euclidean2D.IntersectionCircleCircle(c, new Circle(), out p1, out p2); seg = Segment.Arc(p1, closestToOrigin, p2); } Circle c1 = H3Models.Ball.EquidistantOffset(g, seg, thickness / 2); Circle c2 = H3Models.Ball.EquidistantOffset(g, seg, -thickness / 2); CircleNE c1NE = c.Clone(), c2NE = c.Clone(); c1NE.Center = c1.Center; c2NE.Center = c2.Center; c1NE.Radius = c1.Radius; c2NE.Radius = c2.Radius; SlicePolygonHelper(p, c1NE, c2NE, out output); }
/// <summary> /// Slices a polygon by a circle with some thickness. /// Input circle may be a line. /// </summary> /// <remarks>The input polygon might get reversed</remarks> public static void SlicePolygon(Polygon p, CircleNE c, Geometry g, double thickness, out List <Polygon> output) { // Setup the two slicing circles. CircleNE c1 = c.Clone(), c2 = c.Clone(); Mobius m = new Mobius(); Vector3D pointOnCircle = c.IsLine ? c.P1 : c.Center + new Vector3D(c.Radius, 0); m.Hyperbolic2(g, c1.CenterNE, pointOnCircle, thickness / 2); c1.Transform(m); m.Hyperbolic2(g, c2.CenterNE, pointOnCircle, -thickness / 2); c2.Transform(m); SlicePolygonHelper(p, c1, c2, out output); }
/// <summary> /// This will return whether we'll be a new tile after reflecting through a segment. /// This allows us to do the check without having to do all the work of reflecting the entire tile. /// </summary> public bool NewTileAfterReflect(Tile t, Segment s, Dictionary <Vector3D, bool> completed) { /* This was too slow! * Polygon newPolyBoundary = t.Boundary.Clone(); * newPolyBoundary.Reflect( s ); * Vector3D testCenter = this.TilingConfig.M.Apply( newPolyBoundary.Center );*/ CircleNE newVertexCircle = t.VertexCircle.Clone(); newVertexCircle.Reflect(s); Vector3D testCenter = this.TilingConfig.M.Apply(newVertexCircle.CenterNE); return(!completed.ContainsKey(testCenter)); }
private bool NewTetAfterReflect(Cell cell, Segment s, HashSet <Vector3D> completed) { foreach (Tile tile in cell.Tiles) { CircleNE newVertexCircle = tile.VertexCircle.Clone(); newVertexCircle.Reflect(s); if (completed.Contains(Infinity.InfinitySafe(newVertexCircle.CenterNE))) { return(false); } } return(true); }
/// <summary> /// Slices a polygon by a circle with some thickness. /// Input circle may be a line. /// </summary> /// <remarks>The input polygon might get reversed</remarks> public static void SlicePolygon(Polygon p, CircleNE c, Geometry g, double thickness, out List <Polygon> output) { output = new List <Polygon>(); // Setup the two slicing circles. CircleNE c1 = c.Clone(), c2 = c.Clone(); Mobius m = new Mobius(); Vector3D pointOnCircle = c.IsLine ? c.P1 : c.Center + new Vector3D(c.Radius, 0); m.Hyperbolic2(g, c1.CenterNE, pointOnCircle, thickness / 2); c1.Transform(m); m.Hyperbolic2(g, c2.CenterNE, pointOnCircle, -thickness / 2); c2.Transform(m); // ZZZ - alter Clip method to work on Polygons and use that. // Slice it up. List <Polygon> sliced1, sliced2; Slicer.SlicePolygon(p, c1, out sliced1); Slicer.SlicePolygon(p, c2, out sliced2); // Keep the ones we want. foreach (Polygon newPoly in sliced1) { bool outside = !c1.IsPointInsideNE(newPoly.CentroidApprox); if (outside) { output.Add(newPoly); } } foreach (Polygon newPoly in sliced2) { bool inside = c2.IsPointInsideNE(newPoly.CentroidApprox); if (inside) { output.Add(newPoly); } } }
/// <summary> /// ZZZ - needs to be part of performance setting? /// Returns true if the tile should be included after a Mobius transformation will be applied. /// If the tile is not be included, this method avoids applying the mobious transform to the entire tile. /// </summary> public bool IncludeAfterMobius(Mobius m) { switch (this.Geometry) { // Spherical tilings are finite, so we can always include everything. case Geometry.Spherical: return(true); case Geometry.Euclidean: return(true); // We'll let the number of tiles specified in the tiling control this.. case Geometry.Hyperbolic: { //Polygon poly = Boundary.Clone(); //poly.Transform( m ); //bool use = (poly.Length > 0.01); // ZZZ - DANGER! Some transforms can cause this to lead to stackoverflow (the ones that scale the tiling up). //bool use = ( poly.Length > 0.01 ) && ( poly.Center.Abs() < 10 ); //bool use = ( poly.Center.Abs() < 0.9 ); // Only disk CircleNE c = VertexCircle; bool use = c.CenterNE.Abs() < 0.9999; /*List<Vector3D> points = poly.GetEdgePoints(); * double maxdist = points.Max( point => point.Abs() ); * bool use = maxdist < 0.97;*/ return(use); } } Debug.Assert(false); return(false); }
public static bool IsPointInsideFast(CircleNE c, Vector3D testPoint) { return(c.IsPointInsideFast(testPoint)); }