private static Circle3D HoneycombEdgeUHS(int p, int q, int r) { Sphere[] simplex = Mirrors(p, q, r, moveToBall: false); Sphere s1 = simplex[0].Clone(); Sphere s2 = s1.Clone(); s2.Reflect(simplex[1]); Circle3D intersection = s1.Intersection(s2); return(intersection); }
/// <summary> /// NOTE: s must be geodesic! (orthogonal to boundary). /// </summary> public static Sphere UHSToBall( Sphere s ) { Vector3D center; double rad; if( s.IsPlane ) { // Planes through the origin will stay unchanged. if( s.Offset == new Vector3D() ) return s.Clone(); // It must be vertical (because it is orthogonal). Vector3D b1 = H3Models.UHSToBall( Infinity.InfinityVector ); Vector3D b2 = H3Models.UHSToBall( s.Offset ); H3Models.Ball.OrthogonalCircle( b1, b2, out center, out rad ); // Safer to use OrthogonalSphere? } else { Vector3D temp; if( s.Center.IsOrigin ) { temp = new Vector3D( s.Radius, 0, 0 ); } else { temp = s.Center; temp.Normalize(); temp *= s.Radius; } Vector3D centerUhs = s.Center; Vector3D b1 = H3Models.UHSToBall( centerUhs - temp ); Vector3D b2 = H3Models.UHSToBall( centerUhs + temp ); H3Models.Ball.OrthogonalCircle( b1, b2, out center, out rad ); // Safer to use OrthogonalSphere? // Did we project to a plane? if( Infinity.IsInfinite( rad ) ) { temp.RotateXY( Math.PI / 2 ); Vector3D b3 = H3Models.UHSToBall( centerUhs + temp ); center = b1.Cross( b3 ); rad = double.PositiveInfinity; } } return new Sphere() { Center = center, Radius = rad }; }
/// <summary> /// Transform a geodesic sphere in the ball model to the Klein model. /// Output will be a plane. /// </summary> public static Sphere BallToKlein( Sphere s ) { // If we are already a plane, no transformation is needed. if( s.IsPlane ) return s.Clone(); Vector3D closest = Ball.ClosestToOrigin( s ); Vector3D p1 = HyperbolicModels.PoincareToKlein( closest ); // Ideal points are the same in the Klein/Poincare models, so grab // two more plane points from the ideal circle. Vector3D p2, p3, dummy; Ball.IdealPoints( s, out p2, out dummy, out p3 ); Vector3D offset = p1; Vector3D normal = (p2 - p1).Cross( p3 - p1 ); normal.Normalize(); if( !s.Invert ) normal *= -1; return Sphere.Plane( offset, normal ); }
/// <summary> /// This applies the same Mobius transform to all vertical planes through the z axis. /// NOTE: m must therefore be a mobius transform that keeps the imaginary axis constant! /// NOTE: s must be geodesic! (orthogonal to boundary). /// </summary> public static Sphere TransformInBall( Sphere s, Mobius m ) { Vector3D center; double rad; if( s.IsPlane ) { // All planes in the ball go through the origin. if( !s.Offset.IsOrigin ) throw new System.ArgumentException(); // Vertical planes remain unchanged. if( Tolerance.Equal( s.Normal.Z, 0 ) ) return s.Clone(); // Other planes will become spheres. Vector3D pointOnSphere = s.Normal.Perpendicular(); pointOnSphere.Normalize(); Vector3D b1 = H3Models.TransformHelper( pointOnSphere, m ); Vector3D b2 = H3Models.TransformHelper( -pointOnSphere, m ); pointOnSphere.RotateAboutAxis( s.Normal, Math.PI / 2 ); Vector3D b3 = H3Models.TransformHelper( pointOnSphere, m ); return H3Models.Ball.OrthogonalSphere( b1, b2, b3 ); } else { Vector3D s1, s2, s3; H3Models.Ball.IdealPoints( s, out s1, out s2, out s3 ); // Transform the points. Vector3D b1 = H3Models.TransformHelper( s1, m ); Vector3D b2 = H3Models.TransformHelper( s2, m ); Vector3D b3 = H3Models.TransformHelper( s3, m ); return H3Models.Ball.OrthogonalSphere( b1, b2, b3 ); } return new Sphere() { Center = center, Radius = rad }; }
public static Sphere GeodesicOffset( Sphere s, double offset, bool ball = true ) { Sphere offsetSphere; if( ball ) { // Geodesic offset (ball). { // Hyperbolic honeycomb double mag = s.Center.Abs() - s.Radius; mag = s.IsPlane ? DonHatch.h2eNorm( offset ) : DonHatch.h2eNorm( DonHatch.e2hNorm( mag ) - offset ); Vector3D closestPointToOrigin = s.IsPlane ? s.Normal : s.Center; closestPointToOrigin.Normalize(); closestPointToOrigin *= mag; offsetSphere = H3Models.Ball.OrthogonalSphereInterior( closestPointToOrigin ); // There are multiple ultraparallel spheres. // This experiments with picking others. Mobius m = new Mobius(); m.Isometry( Geometry.Hyperbolic, 0, new Vector3D( 0, -0.2 ) ); //H3Models.TransformInBall2( offsetSphere, m ); } { // Spherical honeycomb //offset *= -1; double mag = -s.Center.Abs() + s.Radius; Spherical2D.s2eNorm( Spherical2D.e2sNorm( mag ) + offset ); offsetSphere = s.Clone(); offsetSphere.Radius += offset*10; } } else { // Geodesic offset (UHS). // XXX - not scaled right. offsetSphere = s.Clone(); offsetSphere.Radius += offset; } return offsetSphere; }