private static Vector3D Transform(Vector3D v) { //v *= 1.35; //v *= 2; v = H3Models.UHSToBall(v); return(v); }
/// <summary> /// Calculates the point of our simplex that is at the middle of a face. /// </summary> private static Vector3D FaceCenterBall(int p, int q, int r) { Geometry cellGeometry = Geometry2D.GetGeometry(p, q); switch (cellGeometry) { case Geometry.Spherical: { Vector3D cellCenter = CellCenterBall(p, q, r); Sphere[] mirrors = Mirrors(p, q, r, moveToBall: true); return(mirrors[0].ProjectToSurface(cellCenter)); } case Geometry.Euclidean: { Sphere[] mirrors = Mirrors(p, q, r, moveToBall: false); Vector3D faceCenterUHS = mirrors[0].Center; faceCenterUHS.Z += mirrors[0].Radius; return(H3Models.UHSToBall(faceCenterUHS)); } case Geometry.Hyperbolic: { throw new System.NotImplementedException(); } } throw new System.ArgumentException(); }
public static Vector3D[] VertsEuclidean() { int p = 4; int q = 3; //int r = 4; // Get a {q,p} tiling on the z=0 plane. Segment[] baseTileSegments = BaseTileSegments(q, p); // These will be unit length. Vector3D pFaceDirection = H3Models.UHSToBall(baseTileSegments.First().P1); Vector3D pMidEdgeDirection = H3Models.UHSToBall(baseTileSegments.First().Midpoint); Vector3D pVertexDirection = new Vector3D(0, 0, -1); // Order is same as facets (these are the points opposite facets). List <Vector3D> verts = new List <Vector3D>(); verts.Add(new Vector3D()); verts.Add(pFaceDirection * m_eScale); verts.Add(pMidEdgeDirection * Math.Sqrt(2) * m_eScale); verts.Add(pVertexDirection * Math.Sqrt(3) * m_eScale); // Apply rotations. double rotation = Math.PI / 2; Vector3D zAxis = new Vector3D(0, 0, 1); for (int i = 0; i < 4; i++) { verts[i].RotateAboutAxis(zAxis, rotation); } return(verts.ToArray()); }
/// <summary> /// Calculates the point of our simplex that is at a vertex. /// </summary> public static Vector3D VertexPointBall(int p, int q, int r) { Geometry vertexGeometry = Geometry2D.GetGeometry(q, r); if (vertexGeometry == Geometry.Hyperbolic) { // Outside the ball, and not in a good way. Use the Klein version. //throw new System.NotImplementedException(); return(new Vector3D(0, 0, -1)); } // Get in UHS first. Sphere cellFacet = Mirrors(p, q, r, moveToBall: false).First(); double rSquared = Math.Pow(cellFacet.Radius, 2); double cSquared = Math.Pow(cellFacet.Center.Abs(), 2); Vector3D uhs; if (Tolerance.Equal(rSquared, cSquared)) // e.g. 363 { uhs = new Vector3D(); } else { double height = Math.Sqrt(rSquared - cSquared); uhs = new Vector3D(0, 0, height); } return(H3Models.UHSToBall(uhs)); }
private static H3.Cell.Edge[] ParameterizedFibers(Complex z) { List <H3.Cell.Edge> fibers = new List <H3.Cell.Edge>(); double scale = 0.1; Vector3D v1 = new Vector3D(0, -1); // -i Vector3D v2 = Vector3D.FromComplex(z); int count = (int)Math.Round(Math.Sqrt(NumFibers), 0); for (int i = -count / 2; i < count / 2; i++) { for (int j = 1; j < count; j++) // dilations should remain positive. { double t1 = scale * i; double t2 = scale * j; // Apply the dilation first. Vector3D _v1 = v1; Vector3D _v2 = v2; _v1 *= t2; _v2 *= t2; _v1.X += t1; _v2.X += t1; fibers.Add(new H3.Cell.Edge( H3Models.UHSToBall(_v1), H3Models.UHSToBall(_v2))); } } return(fibers.ToArray()); }
private Vector3D ApplyTransformationToSphere(Vector3D v, double t) { v = H3Models.BallToUHS(v); // 437 (hyperbolic) //v *= Math.Pow( 4.259171776329806, t*10-5 ); // 36i (parabolic) //v += new Vector3D( Math.Cos( Math.PI / 6 ), Math.Sin( Math.PI / 6 ) ) * t; // iii (loxodromic) //Complex c = v.ToComplex(); //double x = Math.Sqrt( 2 ) - 1; //Mobius m = new Mobius( new Complex( x, 0 ), Complex.One, new Complex( -x, 0 ) ); // 12,12,12 loxodromic //m = new Mobius( new Complex( 0, 1 ), Complex.One, new Complex( 0, -1 ) ); /* * c = m.Apply( c ); * c *= Complex.Exp( new Complex( 2.5, 4 * Math.PI ) * t ); * c = m.Inverse().Apply( c ); * v = Vector3D.FromComplex( c ); */ // Center cell head in KolorEyes. Mobius m = new Mobius(); m.UpperHalfPlane(); v = m.Inverse().Apply(v); return(H3Models.UHSToBall(v)); }
/// <summary> /// Gets fibers for the only fibration with parallel (vs. ultraparallel) fibers. /// Returns result in the ball model. /// </summary> private static H3.Cell.Edge[] ParallelFibers() { List <H3.Cell.Edge> fibers = new List <H3.Cell.Edge>(); double scale = 0.3; // Just a grid of vertical fibers. // We could do any kind of grid we want here really (square, hexagonal, random...) // Each would likely produce different results. // It'd be nice to figure out how to space out the results near the north pole. int count = (int)Math.Round(Math.Sqrt(NumFibers), 0); for (int i = -count / 2; i < count / 2; i++) { for (int j = -count / 2; j < count / 2; j++) { //double off1 = Math.Pow( scale*i, 3 ); //double off2 = Math.Pow( scale*j, 3 ); double off1 = scale * i; double off2 = scale * j; Vector3D v1 = new Vector3D(off1, off2); Vector3D v2 = new Vector3D(double.PositiveInfinity, 1); // Don't use Infinity.InfinityVector, because we want to distiguish this point as being on the boundary. fibers.Add(new H3.Cell.Edge( H3Models.UHSToBall(v1), H3Models.UHSToBall(v2))); } } return(fibers.ToArray()); }
private static List <H3.Cell.Edge> CopyAndProject(List <H3.Cell.Edge> regionEdges, Tiling tiling, double scale, Vector3D offset) { HashSet <H3.Cell.Edge> newEdges = new HashSet <H3.Cell.Edge>(new H3.Cell.EdgeEqualityComparer()); //foreach( Tile tile in tiling.Tiles ) // Needed for doing full ball (rather than just half of it) Tile tile = tiling.Tiles.First(); { foreach (H3.Cell.Edge edge in regionEdges) { // Translation // The isometry is necessary for the 363, but seems to mess up 636 Vector3D start = tile.Isometry.Apply(edge.Start) + offset; Vector3D end = tile.Isometry.Apply(edge.End) + offset; //Vector3D start = edge.Start + tile.Center + offset; //Vector3D end = edge.End + tile.Center + offset; // Scaling start *= scale; end *= scale; // Projections start = H3Models.UHSToBall(start); end = H3Models.UHSToBall(end); H3.Cell.Edge transformed = new H3.Cell.Edge(start, end); if (EdgeOkBall(transformed)) { newEdges.Add(transformed); } } } return(newEdges.ToList()); }
private static H3.Cell.Edge CalcFiber(Vector3D boundaryPointBall) { bool parallel = false; if (parallel) { Vector3D v2 = new Vector3D(0, 0, -1); // Really we can pick any boundary point. return(new H3.Cell.Edge(boundaryPointBall, v2)); } else { // If the point is above the real line, it will have been connected to z. // If below the real line, it will have been connected to -i // If on the real line, it's degenerate. Vector3D pUHS = H3Models.BallToUHS(boundaryPointBall); if (Tolerance.Equal(pUHS.Y, 0)) { return(null); } Vector3D z = Vector3D.FromComplex(ZParam); Vector3D minusi = new Vector3D(0, -1); double dilation = double.NaN; double translation = double.NaN; if (pUHS.Y > 0) { dilation = pUHS.Y / z.Y; z *= dilation; translation = pUHS.X - z.X; z.X += translation; if (H3Models.UHSToBall(z) != boundaryPointBall) { throw new System.Exception(); } minusi *= dilation; minusi.X += translation; return(new H3.Cell.Edge(H3Models.UHSToBall(minusi), boundaryPointBall)); //return null; } else { dilation = pUHS.Y / -1; minusi *= dilation; translation = pUHS.X - minusi.X; minusi.X += translation; if (H3Models.UHSToBall(minusi) != boundaryPointBall) { throw new System.Exception(); } z *= dilation; z.X += translation; return(new H3.Cell.Edge(boundaryPointBall, H3Models.UHSToBall(z))); //return null; } } }
public static void Cell633() { TilingConfig config = new TilingConfig(6, 3, maxTiles: 20000); Tiling tiling = new Tiling(); tiling.GenerateInternal(config, Polytope.Projection.VertexCentered); double edgeLength = Honeycomb.EdgeLength(6, 3, 3); double z = 0.25; double offset = H3Models.UHS.ToEHorizontal(edgeLength, z); double scale = offset / tiling.Tiles.First().Boundary.Segments.First().Length; foreach (Tile tile in tiling.Tiles) { tile.Transform(Mobius.Scale(scale)); } Vector3D dummy; double radius; H3Models.UHS.Geodesic(new Vector3D(0, 0, z), new Vector3D(scale, 0, z), out dummy, out radius); Vector3D midradius = H3Models.UHSToBall(new Vector3D(0, 0, radius)); double temp = midradius.Z; double temp2 = (1 - temp) / 2; double temp3 = temp + temp2; double temp4 = temp3; Vector3D circumradius = H3Models.UHSToBall(new Vector3D(0, 0, z)); temp = circumradius.Z; temp2 = (1 - temp) / 2; temp3 = temp + temp2; temp4 = temp3; // Checking /* * Vector3D test = new Vector3D( offset, 0, z ); * test = H3Models.UHSToBall( test ); * double edgeLength2 = DonHatch.e2hNorm( test.Abs() ); * edgeLength2 += 0; */ HashSet <H3.Cell.Edge> edges = new HashSet <H3.Cell.Edge>(); foreach (Tile tile in tiling.Tiles) { foreach (Segment seg in tile.Boundary.Segments) { H3.Cell.Edge edge = new H3.Cell.Edge( H3Models.UHSToBall(seg.P1 + new Vector3D(0, 0, z)), H3Models.UHSToBall(seg.P2 + new Vector3D(0, 0, z))); edges.Add(edge); } } PovRay.WriteH3Edges(new PovRay.Parameters(), edges.ToArray(), "edges.pov"); }
/// <summary> /// Returns the 6 simplex edges in the Ball model. /// </summary> public static H3.Cell.Edge[] SimplexEdgesBall(int p, int q, int r) { H3.Cell.Edge[] edges = SimplexEdgesUHS(p, q, r); foreach (H3.Cell.Edge e in edges) { e.Start = H3Models.UHSToBall(e.Start); e.End = H3Models.UHSToBall(e.End); } return(edges); }
void CalcFibers(Vector3D[] basePoints, List <H3.Cell.Edge> fibers, double t) { foreach (Vector3D v in basePoints) { H3.Cell.Edge e = CalcFiberFromBase(v); if (e != null) { e.Color = Color(Transform(H3Models.UHSToBall(v), t)); } fibers.Add(Transform(e, t)); } }
public static Vector3D EdgeMidpointSpherical(int p, int q, int r) { // Get a {q,p} tiling on the z=0 plane. Segment[] baseTileSegments = BaseTileSegments(q, p); Vector3D direction = H3Models.UHSToBall(baseTileSegments.First().Midpoint); direction.Normalize(); double midRadius = Spherical2D.s2eNorm(Honeycomb.MidRadius(p, q, r)); return(direction * midRadius); }
public static void Create(HoneycombDef def, string filename) { int p = def.P; int q = def.Q; int r = def.R; double scale = 5.0; Vector3D cen = HoneycombPaper.InteriorPointBall; Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: false); // Apply transformations. simplex = simplex.Select(s => { Sphere.ScaleSphere(s, scale); return(H3Models.UHSToBall(s)); }).ToArray(); for (int i = 0; i < 4; i++) { if (simplex[i].IsPointInside(cen)) { simplex[i].Invert = true; } } Sphere[] simplexForColorScale = SimplexCalcs.Mirrors(p, q, r, moveToBall: true); CoxeterImages.Settings temp = HoneycombPaper.AutoCalcScale(def, simplexForColorScale); int maxDepth = (int)temp.ColorScaling; bool ball = true; bool dual = false; H3.Cell[] simplicesFinal = HoneycombPaper.GenCell(simplex, null, cen, ball, dual); simplicesFinal = simplicesFinal.Where(s => s.Depths[0] < 1).ToArray(); //simplicesFinal = simplicesFinal.Where( s => s.) // Output the facets. using (StreamWriter sw = File.CreateText(filename)) // We need to reuse this StreamWriter (vs. calling AppendSimplex) for performance. { sw.WriteLine("#include \"hyper_ball.pov\""); int[] include = new int[] { 0 }; foreach (H3.Cell cell in simplicesFinal) { Sphere[] facets = cell.Facets.Select(f => f.Sphere).ToArray(); int depth = cell.Depths[0] + 1; Color c = Coloring.ColorAlongHexagon(maxDepth, depth); PovRay.AddSimplex(sw, facets, cell.Center, include, filename, Coloring.ToVec(c)); } } }
public static Vector3D FaceCenterSpherical(int p, int q, int r) { // Get a {q,p} tiling on the z=0 plane. Segment[] baseTileSegments = BaseTileSegments(q, p); // This will be unit length. Vector3D pFaceDirection = H3Models.UHSToBall(baseTileSegments.First().P1); // In-radius is in conformal model double inRadius = Spherical2D.s2eNorm(Honeycomb.InRadius(p, q, r)); return(pFaceDirection * inRadius); }
/// <summary> /// XXX - Need to make this a function of clock, so it probably needs to not be static. /// </summary> /// <param name="basePointUHS"></param> /// <returns>A base point in the disk, possibly transformed.</returns> Vector3D Transform(Vector3D basePointUHS, double t) { if (!Ball) { return(basePointUHS); } Vector3D basePointDisk = H3Models.UHSToBall(basePointUHS); // Apply transformations. // XXX - make this a mobius we pass in, so we can edit it on the outside. //basePointDisk.RotateAboutAxis( new Vector3D( 0, 1, 0 ), 2 * Math.PI * t ); return(basePointDisk); }
/// <summary> /// Get a distribution of points on a sphere. /// The points are the vertices of a geodesic dome. /// </summary> private static Vector3D[] SpherePoints() { List <Vector3D> spherePoints = new List <Vector3D>(); TilingConfig config = new TilingConfig(3, 5); Tiling tiling = new Tiling(); tiling.GenerateInternal(config); Tile baseTile = tiling.Tiles.First(); Vector3D[] templateTextureCoords = TextureHelper.TextureCoords(baseTile.Boundary, Geometry.Spherical, doGeodesicDome: true); foreach (Tile tile in tiling.Tiles) { Isometry isom = new Isometry(); isom.CalculateFromTwoPolygons(baseTile, tile, Geometry.Spherical); Vector3D[] textureCoords = Isometry.TransformVertices(templateTextureCoords, isom.Inverse()); spherePoints.AddRange(textureCoords); } return(spherePoints.Select(p => H3Models.UHSToBall(p)).Distinct().ToArray()); }
public static Sphere[] MirrorsEuclidean() { int p = 4; int q = 3; //int r = 4; // Get a {q,p} tiling on the z=0 plane. Segment[] baseTileSegments = BaseTileSegments(q, p); // This will be unit length. Vector3D pFaceDirection = H3Models.UHSToBall(baseTileSegments.First().P1); // NOTES: // Center is the plane normal. // Cell face is only one with an offset // This is constructed already in the ball. Sphere cellBoundary = new Sphere() { Center = -pFaceDirection, Offset = pFaceDirection * m_eScale, Radius = double.PositiveInfinity }; Sphere[] interior = InteriorMirrors(p, q); interior = interior.Select(s => H3Models.UHSToBall(s)).ToArray(); Sphere[] surfaces = new Sphere[] { cellBoundary, interior[0], interior[1], interior[2] }; // Apply rotations. bool applyRotations = false; if (applyRotations) { double rotation = Math.PI / 2; foreach (Sphere s in surfaces) { RotateSphere(s, rotation); } } return(surfaces); }
/// <summary> /// Calculates the point of our simplex that is at the middle of an edge. /// </summary> private static Vector3D MidEdgePointBall(int p, int q, int r) { // We need the mid-radius, but we have to do the calculation // with our Euclidean simplex mirrors (to avoid infinities that happen in the formulas). Circle3D edge = HoneycombEdgeUHS(p, q, r); if (edge.Radius == 0) { return(edge.Center); } Geometry cellGeometry = Geometry2D.GetGeometry(p, q); switch (cellGeometry) { case Geometry.Spherical: { Sphere sphereInBall = H3Models.UHSToBall(new Sphere() { Center = edge.Center, Radius = edge.Radius }); Vector3D mid = sphereInBall.ProjectToSurface(new Vector3D()); // Project origin to sphere. return(mid); } case Geometry.Euclidean: { Vector3D mid = H3Models.UHSToBall(edge.Center + new Vector3D(0, 0, edge.Radius)); return(mid); } case Geometry.Hyperbolic: { throw new System.NotImplementedException(); } } throw new System.ArgumentException(); }
/// <summary> /// Mirrors for Spherical geometry, in the ball model. /// </summary> public static Sphere[] MirrorsSpherical(int p, int q, int r) { // Get a {q,p} tiling on the z=0 plane. Segment[] baseTileSegments = BaseTileSegments(q, p); // This will be unit length. Vector3D pFaceDirection = H3Models.UHSToBall(baseTileSegments.First().P1); // In-radius is in conformal model double inRadius = Spherical2D.s2eNorm(Honeycomb.InRadius(p, q, r)); double centerOfSphereNE = (1 - inRadius) / (1 + inRadius); Vector3D center; double radius; H3Models.Ball.DupinCyclideSphere(-pFaceDirection * centerOfSphereNE, 1.0 /*geodesic circle*/, Geometry.Spherical, out center, out radius); Sphere cellBoundary = new Sphere() { Center = center, Radius = radius, Invert = true }; Sphere[] interior = InteriorMirrors(p, q); interior = interior.Select(s => H3Models.UHSToBall(s)).ToArray(); Sphere[] surfaces = new Sphere[] { cellBoundary, interior[0], interior[1], interior[2] }; // Apply rotations. bool applyRotations = false; if (applyRotations) { double rotation = Math.PI / 2; foreach (Sphere s in surfaces) { RotateSphere(s, rotation); } } return(surfaces); }
/// <summary> /// This allows us to change the model we have on the plane. /// We usually want UHS, but for Pov-Ray mapping these images to a sphere, we need to have it be an equirectangular projection /// NOTE: The bounds should be set to 1.0 for this to work! v.X and v.Y must be in-between -1 and 1. (also, don't rotate simplex mirrors, for POV-Ray anyway) /// </summary> private Vector3D PlaneModelToBall(Vector3D v, double t = 0.0) { bool equirectangular = false; if (!equirectangular) { // Normal UHS (sterographic projection). return(H3Models.UHSToBall(v)); } else { // If you want output to have twice the width. double xScale = 2; v.X /= xScale; // http://mathworld.wolfram.com/EquirectangularProjection.html // y is the latitude // x is the longitude // Assume inputs go from -1 to 1. Vector3D spherical = new Vector3D(1, Math.PI / 2 * (1 - v.Y), v.X * Math.PI); Vector3D onBall = SphericalCoords.SphericalToCartesian(spherical); return(ApplyTransformationToSphere(onBall, t)); } }
private static void HoneycombFiniteVertexFig(HoneycombDef def, int lod, Dictionary <Vector3D, H3.Cell> complete) { int p = def.P; int q = def.Q; int r = def.R; double scale = 1.0; Vector3D vUHS = H3Models.BallToUHS(SimplexCalcs.VertexPointBall(p, q, r)); if (Geometry2D.GetGeometry(q, r) != Geometry.Hyperbolic) // Vertex-centered if possible { scale = 1.0 / vUHS.Z; } System.Func <Vector3D, Vector3D> trans = v => { v = H3Models.BallToUHS(v); v *= scale; v = H3Models.UHSToBall(v); return(v); }; bool ball = true; Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: ball); simplex = simplex.Select(s => { s = H3Models.BallToUHS(s); Sphere.ScaleSphere(s, scale); s = H3Models.UHSToBall(s); return(s); }).ToArray(); H3.Cell.Edge[] edges = SimplexCalcs.SimplexEdgesBall(p, q, r); // Two edges of the simplex facet. // NOTE: This contruction only works for material triangles, and matches the construction in the TextureHelper. m_div = TextureHelper.SetLevels(lod); int[] elementIndices = TextureHelper.TextureElements(1, lod); List <Vector3D> points = new List <Vector3D>(); H3.Cell.Edge e1 = edges[2]; H3.Cell.Edge e2 = edges[3]; Vector3D p1 = trans(e1.Start), p2 = trans(e1.End), p3 = trans(e2.End); Vector3D[] points1 = H3Models.Ball.GeodesicPoints(p2, p1, m_div); Vector3D[] points2 = H3Models.Ball.GeodesicPoints(p3, p1, m_div); for (int i = 0; i < m_div; i++) { points.AddRange(H3Models.Ball.GeodesicPoints(points1[i], points2[i], m_div - i)); } points.Add(p1); Mesh mesh = new Mesh(); for (int i = 0; i < elementIndices.Length / 3; i++) { int idx1 = i * 3; int idx2 = i * 3 + 1; int idx3 = i * 3 + 2; Vector3D v1 = points[elementIndices[idx1]]; Vector3D v2 = points[elementIndices[idx2]]; Vector3D v3 = points[elementIndices[idx3]]; mesh.Triangles.Add(new Mesh.Triangle(v1, v2, v3)); } // AuxPoints will be used for multiple things. // - The first is a definition point for a face, so we can check for duplicates. // - We'll also store the points for the 3 edges of our fundamental triangle. List <Vector3D> auxPoints = new List <Vector3D>(); { auxPoints.Add((p1 + p2 + p3) / 3); auxPoints.AddRange(points1); auxPoints.AddRange(points2.Reverse()); auxPoints.AddRange(H3Models.Ball.GeodesicPoints(points2[0], points1[0], m_div)); } Vector3D cen = HoneycombPaper.InteriorPointBall; H3.Cell[] simplices = GenCell(simplex, mesh, cen, auxPoints.ToArray(), ball); // Existing cells take precedence. foreach (H3.Cell c in simplices) { Vector3D t = c.AuxPoints[0]; H3.Cell dummy; if (!complete.TryGetValue(t, out dummy)) { complete[t] = c; } } }
internal static Sphere SphereFuncUHS(Vector3D v) { return(H3Models.BallToUHS(SphereFuncBall(Geometry.Hyperbolic, H3Models.UHSToBall(v)))); }
/// <summary> /// This generates a honeycomb by reflecting in 4 mirrors of the fundamental simplex. /// This "new" method is now old. /// </summary> public static void OneHoneycombNew(HoneycombDef imageData) { int p = imageData.P; int q = imageData.Q; int r = imageData.R; double thickness = 0.05; double thicknessSpherical = Spherical2D.s2eNorm(thickness); double thicknessHyperbolic = R3.Math.DonHatch.h2eNorm(thickness); double threshold = 1; H3.Cell.Edge[] edges = null; H3.Cell[] cellsToHighlight = null; Sphere[] simplex = null; Vector3D vertex = new Vector3D(); Geometry g = Util.GetGeometry(p, q, r); if (g == Geometry.Spherical) { thickness = thicknessSpherical /*.07 for 333*/ /* 0.05for 433*/ /*.025 for 533,335*/; threshold = 10000; simplex = SimplexCalcs.MirrorsSpherical(p, q, r); vertex = SimplexCalcs.VertexSpherical(p, q, r); // Ugly special casing for 333, since it has a vertex project to infinity. if (p == 3 && q == 3 && r == 3) { SpecialCase333(); } } else if (g == Geometry.Euclidean) { thickness = thickness / 2; threshold = 1 /*20*/; //SimplexCalcs.CalcEScale(); simplex = SimplexCalcs.MirrorsEuclidean(); Vector3D[] verts = SimplexCalcs.VertsEuclidean(); vertex = verts[2]; } else { thickness = thicknessHyperbolic; threshold = 0.01; simplex = SimplexCalcs.Mirrors(p, q, r); Vector3D[] verts = SimplexCalcs.VertsBall(p, q, r); vertex = verts[2]; //Vector3D[] simplexVerts = SimplexCalcs.VertsBall( p, q, r ); //H3.Cell.Edge edge = new H3.Cell.Edge( simplexVerts[2], simplexVerts[3] ); //H3.Cell.Edge edge = SimplexCalcs.HoneycombEdgeBall( p, q, r ); //H3.Cell.Edge[] startingEdges = new H3.Cell.Edge[] { edge }; //H3.Cell.Edge[] edges = Recurse.CalcEdgesSmart2( simplex, startingEdges ); // Vertex Centered. bool vertexCentered = false; if (vertexCentered) { Vector3D v = SimplexCalcs.VertexPointBall(p, q, r); v = H3Models.BallToUHS(v); double scale = 1.0 / v.Abs(); edges = edges.Select(e => { Vector3D start = H3Models.UHSToBall(H3Models.BallToUHS(e.Start) * scale); Vector3D end = H3Models.UHSToBall(H3Models.BallToUHS(e.End) * scale); return(new H3.Cell.Edge(start, end)); }).ToArray(); } // Code to show endpoints of 535 /*using( StreamWriter sw = File.CreateText( "535_points.pov" ) ) * { * HashSet<Vector3D> verts = new HashSet<Vector3D>(); * foreach( H3.Cell.Edge e in edges ) * { * verts.Add( Sterographic.SphereToPlane( e.Start ) ); * verts.Add( Sterographic.SphereToPlane( e.End ) ); * } * * foreach( Vector3D vert in verts ) * if( !Infinity.IsInfinite( vert ) ) * sw.WriteLine( PovRay.Sphere( new Sphere() { Center = vert, Radius = 0.01 } ) ); * }*/ } // Recurse bool dual = false; { H3.Cell.Edge[] startingEdges = null; if (dual) { startingEdges = new H3.Cell.Edge[] { SimplexCalcs.DualEdgeBall(simplex) } } ; else { //startingEdges = new H3.Cell.Edge[] { SimplexCalcs.HoneycombEdgeBall( simplex, vertex ) }; Vector3D[] verts = SimplexCalcs.VertsEuclidean(); Vector3D v1 = verts[0] + 2 * verts[2]; // adjacent cube center Vector3D corner = verts[3]; startingEdges = new H3.Cell.Edge[] { new H3.Cell.Edge(v1, corner) }; } edges = Recurse.CalcEdges(simplex, startingEdges, new Recurse.Settings() { G = g, Threshold = threshold }); edges = edges.Where(e => { int sum = e.Depths.Count(d => d == 0); return(true); }).ToArray(); //CullHalfOfEdges( ref edges ); // No need to cull edges in spherical case. // This was just to generate some images for 350-cell paper. //edges = Cull120Cell( edges ); Simplex tet = new Simplex(); tet.Facets = simplex; if (dual) { H3.Cell.Edge[] oneDualCell = edges.Where(e => e.Depths[2] == 0).ToArray(); simplex = simplex.Skip(1).ToArray(); edges = Recurse.CalcEdges(simplex, oneDualCell, new Recurse.Settings() { G = g, Threshold = threshold }); int[] polyMirrors = new int[] { 0, 1, 3 }; H3.Cell startingCell = HoneycombGen.PolyhedronToHighlight(g, polyMirrors, tet, new Vector3D()); cellsToHighlight = Recurse.CalcCells(simplex, new H3.Cell[] { startingCell }); //cellsToHighlight = new H3.Cell[] { startingCell }; //cellsToHighlight = cellsToHighlight.Skip( 7 ).ToArray(); } else { int[] polyMirrors = new int[] { 1, 2, 3 }; H3.Cell startingCell = HoneycombGen.PolyhedronToHighlight(g, polyMirrors, tet, vertex); //cellsToHighlight = Recurse.CalcCells( simplex, new H3.Cell[] { startingCell } ); cellsToHighlight = new H3.Cell[] { startingCell }; } // Include just one cell? bool includeOne = false; if (includeOne) { edges = edges.Where(e => e.Depths[0] == 0).ToArray(); //cellsToHighlight = cellsToHighlight.Where( c => c.Depths[0] == 0 ).ToArray(); } } // Rotate bool rotate = false; if (rotate) { CompoundOfFive24Cells(ref edges); } // Write the file bool pov = true; if (pov) { string filename = string.Format("{0}{1}{2}.pov", p, q, r); PovRay.WriteEdges(new PovRay.Parameters() { AngularThickness = thickness }, g, edges, filename, append: false); //File.Delete( filename ); //PovRay.AppendFacets( cellsToHighlight, filename ); HashSet <Vector3D> verts = new HashSet <Vector3D>(); foreach (H3.Cell.Edge e in edges) { verts.Add(e.Start); verts.Add(e.End); } /*foreach( Vector3D v in verts ) * { * Vector3D t = v; * t.Normalize(); * t *= 0.9; * System.Diagnostics.Trace.WriteLine( string.Format( "light_source {{ <{0},{1},{2}> White*.2 }}", t.X, t.Y, t.Z ) ); * }*/ /* * // Include the standard pov stuff, so we can batch this. * string fileName = imageData.FormatFilename( string.Empty ); * using( StreamWriter sw = File.CreateText( fileName + ".pov" ) ) * { * sw.WriteLine( "#include \"C:\\Users\\hrn\\Documents\\roice\\povray\\paper\\H3.pov\"" ); * } * * bool dummy = true; // Doesn't matter for Pov-Ray, just Shapeways meshes. * H3.SaveToFile( fileName, edges, dummy, append: true ); */ } else { if (g == Geometry.Spherical) { edges = edges.Where(e => e.Start.Valid() && e.End.Valid() && !Infinity.IsInfinite(e.Start) && !Infinity.IsInfinite(e.End)).ToArray(); S3.EdgesToStl(edges); } else { throw new System.NotImplementedException(); } } }
private static void CreateCellPovRay(HoneycombDef def, string filename, double t = 0) { int p = def.P; int q = def.Q; int r = def.R; //Vector3D trans = new Vector3D( 1.0/3, 0 ) * (2 + 2 * Math.Sin( Math.PI / 6 )) * t; //double scale = 1.8; Vector3D trans = new Vector3D(); double scale = 1.0; Vector3D[] sVerts = null; // SimplexCalcs.VertsBall( p, q, r ); Vector3D vUHS = H3Models.BallToUHS(SimplexCalcs.VertexPointBall(p, q, r)); // Just did this for everything. Non-general position working better and will make all heads consistent. scale = 2.0; if (Geometry2D.GetGeometry(q, r) != Geometry.Hyperbolic) // Vertex-centered if possible { scale = 1.0 / vUHS.Z; } //else if( Geometry2D.GetGeometry( p, q ) == Geometry.Hyperbolic ) // Make the biggest head somewhat smaller. // scale = 2.0; Vector3D cen = InteriorPointBall; /*var kleinVerts = sVerts.Select( v => HyperbolicModels.PoincareToKlein( v ) ); * Vector3D avg = new Vector3D(); * foreach( Vector3D v in kleinVerts ) * avg += v; * avg /= kleinVerts.Count(); * Vector3D cen = HyperbolicModels.KleinToPoincare( avg );*/ cen = H3Models.BallToUHS(cen); cen += trans; //cen *= scale; cen = H3Models.UHSToBall(cen); Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: false); // Apply transformations. simplex = simplex.Select(s => { Sphere.TranslateSphere(s, trans); Sphere.ScaleSphere(s, scale); return(H3Models.UHSToBall(s)); }).ToArray(); for (int i = 0; i < 4; i++) { if (simplex[i].IsPointInside(cen)) { simplex[i].Invert = true; } } Sphere[] simplexForColorScale = SimplexCalcs.Mirrors(p, q, r, moveToBall: true); CoxeterImages.Settings temp = AutoCalcScale(def, simplexForColorScale); int maxDepth = (int)temp.ColorScaling; //Random rand = new Random( p+q+r ); //int randOffset = rand.Next( maxDepth ); bool ball = true; bool dual = false; H3.Cell[] simplicesFinal = GenCell(simplex, null, cen, ball, dual); using (StreamWriter sw = File.CreateText(filename)) // We need to reuse this StreamWriter (vs. calling AppendSimplex) for performance. { sw.WriteLine("#include \"hyper_ball.pov\""); //int[] include = new int[] { 0, 1, 2, 3 }; int[] include = new int[] { 0 }; if (dual) { include = new int[] { 3 } } ; // Output the facets. foreach (H3.Cell cell in simplicesFinal) { Sphere[] facets = cell.Facets.Select(f => f.Sphere).ToArray(); if (m_toKlein) { facets = facets.Select(s => H3Models.BallToKlein(s)).ToArray(); } int depth = cell.Depths[0] + 1; Color c = Coloring.ColorAlongHexagon(maxDepth, depth); if (cell.Depths.Sum() % 2 == 0) { c = Coloring.Inverse(c); } PovRay.AddSimplex(sw, facets, cell.Center, include, filename, Coloring.ToVec(c)); } /*include = new int[] { 1, 2, 3 }; * foreach( H3.Cell cell in simplicesFinal ) * { * Sphere[] facets = cell.Facets.Select( f => f.Sphere ).ToArray(); * Color c = Color.Red; * Vector3D cv = Coloring.ToVec( c ); * cv.W = 0.9; * PovRay.AddSimplex( sw, facets, cell.Center, include, filename, cv ); * }*/ } // Output the edges/verts. bool includeEdges = false; if (includeEdges) { sVerts = sVerts.Select(v => { v = H3Models.BallToUHS(v); v += trans; v *= scale; return(H3Models.UHSToBall(v)); }).ToArray(); H3.Cell.Edge[] edges = Recurse.CalcEdges(simplex.Skip(1).ToArray(), new H3.Cell.Edge[] { new H3.Cell.Edge(sVerts[2], sVerts[3], order: false) }, new Recurse.Settings() { Threshold = 0.01 }); PovRay.WriteH3Edges(new PovRay.Parameters { AngularThickness = 0.01 }, edges, filename, append: true); HashSet <Vector3D> verts = new HashSet <Vector3D>(); foreach (H3.Cell.Edge e in edges) { verts.Add(e.End); } PovRay.WriteVerts(new PovRay.Parameters { AngularThickness = 0.02 }, Geometry.Hyperbolic, verts.ToArray(), filename, append: true); } }
/// <summary> /// This will return an altered facet to create true apparent 2D tilings (proper bananas) on the boundary. /// Notes: /// The input simplex must be in the ball model. /// The first mirror of the simplex (the one that mirrors across cells) is the one we end up altering. /// </summary> public static Sphere AlteredFacetForTrueApparent2DTilings(Sphere[] simplex) { //Sphere m = H3Models.BallToUHS( simplex[0] ); //Sphere t = new Sphere() { Center = m.Center, Radius = m.Radius*100 }; //return H3Models.UHSToBall( t ); // We first need to find the size of the apparent 2D disk surrounding the leg. // This is also the size of the apparent cell head disk of the dual. // So we want to get the midsphere (insphere would also work) of the dual cell with that head, // then calculate the intersection of that with the boundary. Sphere cellMirror = simplex[0]; if (cellMirror.IsPlane) { throw new System.NotImplementedException(); } // The point centered on a face is the closest point of the cell mirror to the origin. // This will be the point centered on an edge on the dual cell. Vector3D facePoint = cellMirror.ProjectToSurface(new Vector3D()); // Reflect it to get 3 more points on our midsphere. Vector3D reflected1 = simplex[1].ReflectPoint(facePoint); Vector3D reflected2 = simplex[2].ReflectPoint(reflected1); Vector3D reflected3 = simplex[0].ReflectPoint(reflected2); Sphere midSphere = Sphere.From4Points(facePoint, reflected1, reflected2, reflected3); // Get the ideal circles of the cell mirror and midsphere. // Note: The midsphere is not geodesic, so we can't calculate it the same. Sphere cellMirrorUHS = H3Models.BallToUHS(cellMirror); Circle cellMirrorIdeal = H3Models.UHS.IdealCircle(cellMirrorUHS); Sphere ball = new Sphere(); Circle3D midSphereIdealBall = ball.Intersection(midSphere); // This should exist because we've filtered for honeycombs with hyperideal verts. Circle3D midSphereIdealUHS = H3Models.BallToUHS(midSphereIdealBall); Circle midSphereIdeal = new Circle { Center = midSphereIdealUHS.Center, Radius = midSphereIdealUHS.Radius }; // The intersection point of our cell mirror and the disk of the apparent 2D tiling // gives us "ideal" points on the apparent 2D boundary. These points will be on the new cell mirror. Vector3D i1, i2; if (2 != Euclidean2D.IntersectionCircleCircle(cellMirrorIdeal, midSphereIdeal, out i1, out i2)) { //throw new System.ArgumentException( "Since we have hyperideal vertices, we should have an intersection with 2 points." ); // Somehow works in the euclidean case. // XXX - Make this better. return(H3Models.UHSToBall(new Sphere() { Center = Vector3D.DneVector(), Radius = double.NaN })); } double bananaThickness = 0.025; //bananaThickness = 0.15; bananaThickness = 0.05; // Transform the intersection points to a standard Poincare disk. // The midsphere radius is the scale of the apparent 2D tilings. double scale = midSphereIdeal.Radius; Vector3D offset = midSphereIdeal.Center; i1 -= offset; i2 -= offset; i1 /= scale; i2 /= scale; Circle3D banana = H3Models.Ball.OrthogonalCircle(i1, i2); Vector3D i3 = H3Models.Ball.ClosestToOrigin(banana); i3 = Hyperbolic2D.Offset(i3, -bananaThickness); // Transform back. i1 *= scale; i2 *= scale; i3 *= scale; i1 += offset; i2 += offset; i3 += offset; // Construct our new simplex mirror with these 3 points. Circle3D c = new Circle3D(i1, i2, i3); Sphere result = new Sphere() { Center = c.Center, Radius = c.Radius }; return(H3Models.UHSToBall(result)); }
private static Sphere[] MoveToBall(Sphere[] surfaces, ref Vector3D cellCenter) { Sphere[] result = surfaces.Select(s => H3Models.UHSToBall(s)).ToArray(); cellCenter = H3Models.UHSToBall(cellCenter); return(result); }