private Tile TemplateTile() { double inRadiusHyp = InRadius; double inRadiusEuclidean = DonHatch.h2eNorm(inRadiusHyp); double faceRadius = FaceRadius(inRadiusEuclidean); // Calc the midpoint, and project to plane. Vector3D midPoint = MidPoint(inRadiusEuclidean, faceRadius); midPoint.Z *= -1; midPoint = Sterographic.SphereToPlane(midPoint); //double midPointSpherical = MidPoint( inRadiusEuclidean, faceRadius ); //double midPoint = Spherical2D.s2eNorm( midPointSpherical ); // Create and scale based on our midpoint. Polygon poly = new Polygon(); poly.CreateRegular(Q, R); double standardMidpointAbs = poly.Segments[0].Midpoint.Abs(); m_shrink = midPoint.Abs() / standardMidpointAbs; poly.Scale(m_shrink); Matrix4D m = Matrix4D.MatrixToRotateinCoordinatePlane(-Math.PI / Q, 0, 1); poly.Rotate(m); return(new Tile(poly, poly.Clone(), Geometry.Hyperbolic)); }
public static void EdgesToStl(H3.Cell.Edge[] edges) { Shapeways mesh = new Shapeways(); int divisions = 25; foreach (H3.Cell.Edge edge in edges) { Segment seg = Segment.Line( Sterographic.R3toS3(edge.Start), Sterographic.R3toS3(edge.End)); Vector3D[] points = seg.Subdivide(divisions); ProjectAndAddS3Points(mesh, points); } for (int i = 0; i < mesh.Mesh.Triangles.Count; i++) { mesh.Mesh.Triangles[i] = new Mesh.Triangle( SphericalModels.StereoToEqualVolume(mesh.Mesh.Triangles[i].a), SphericalModels.StereoToEqualVolume(mesh.Mesh.Triangles[i].b), SphericalModels.StereoToEqualVolume(mesh.Mesh.Triangles[i].c)); } STL.SaveMeshToSTL(mesh.Mesh, @"output.stl"); }
public static Vector3D SinusoidalToStereo(Vector3D v) { double lat = Math.PI / 2 * (1 - v.Y); Vector3D spherical = new Vector3D(1, lat, Math.PI * v.X / Math.Cos(lat - Math.PI / 2)); Vector3D onBall = SphericalCoords.SphericalToCartesian(spherical); return(Sterographic.SphereToPlane(onBall)); }
/// <summary> /// 2-dimensional function. /// http://archive.bridgesmathart.org/2013/bridges2013-217.pdf /// </summary> public static Vector3D MercatorToStereo(Vector3D v) { v *= Math.PI; // Input is [-1,1] double lat = 2 * Math.Atan(Math.Exp(v.Y)) - Math.PI / 2; double inclination = lat + Math.PI / 2; Vector3D spherical = new Vector3D(1, inclination, v.X); Vector3D onBall = SphericalCoords.SphericalToCartesian(spherical); return(Sterographic.SphereToPlane(onBall)); }
public static Vector3D EquirectangularToStereo(Vector3D v) { // 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(Sterographic.SphereToPlane(onBall)); }
/// <summary> /// 2-dimensional function. /// ZZZ - Should make this general. /// </summary> public static Vector3D OrthographicToStereo(Vector3D v) { // We can only do the projection for half of the sphere. double t = v.X * v.X + v.Y * v.Y; if (t > 1) { t = 1; } v.Z = Math.Sqrt(1 - t); return(Sterographic.SphereToPlane(v)); }
private static double EquidistantToStereo(double dist) { if (dist > 1) { throw new System.ArgumentException(); } Vector3D v = new Vector3D(0, -1); v.RotateXY(dist * Math.PI); v = Sterographic.SphereToPlane(new Vector3D(v.X, 0, v.Y)); return(v.Abs()); }
/// <summary> /// https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection /// </summary> private static double EqualAreaToStereo(double dist) { if (dist > 1) { throw new System.ArgumentException(); } // We have dist normalized between 0 and 1, so this formula is slightly // different than on Wikipedia, where dist ranges up to 2. Vector3D v = new Vector3D(1, 2 * Math.Acos(dist), 0); v = Sterographic.SphereToPlane(SphericalCoords.SphericalToCartesian(v)); return(v.Abs()); }
public static void Hypercube() { List <Vector3D> vertices = new List <Vector3D>(); vertices.Add(new Vector3D(1, 1, 1, 1)); vertices.Add(new Vector3D(1, 1, 1, -1)); vertices.Add(new Vector3D(1, 1, -1, 1)); vertices.Add(new Vector3D(1, 1, -1, -1)); vertices.Add(new Vector3D(1, -1, 1, 1)); vertices.Add(new Vector3D(1, -1, 1, -1)); vertices.Add(new Vector3D(1, -1, -1, 1)); vertices.Add(new Vector3D(1, -1, -1, -1)); vertices.Add(new Vector3D(-1, 1, 1, 1)); vertices.Add(new Vector3D(-1, 1, 1, -1)); vertices.Add(new Vector3D(-1, 1, -1, 1)); vertices.Add(new Vector3D(-1, 1, -1, -1)); vertices.Add(new Vector3D(-1, -1, 1, 1)); vertices.Add(new Vector3D(-1, -1, 1, -1)); vertices.Add(new Vector3D(-1, -1, -1, 1)); vertices.Add(new Vector3D(-1, -1, -1, -1)); HashSet <H3.Cell.Edge> edges = new HashSet <H3.Cell.Edge>(new H3.Cell.EdgeEqualityComparer()); foreach (Vector3D v1 in vertices) { foreach (Vector3D v2 in vertices) { if (v1.Dist(v2) == 2) { edges.Add(new H3.Cell.Edge(v1, v2)); } } } // Radial project to S3, then stereographic to R3. foreach (H3.Cell.Edge edge in edges) { edge.Start.Normalize(); edge.Start = Sterographic.S3toR3(edge.Start); edge.End.Normalize(); edge.End = Sterographic.S3toR3(edge.End); } PovRay.WriteEdges(new PovRay.Parameters() { AngularThickness = .05 }, Geometry.Spherical, edges.ToArray(), "433.pov", append: false); }
public static Vector3D StereoToGnomonic(Vector3D p) { Vector3D sphere = Sterographic.PlaneToSphere(p); // We can't only represent the lower hemisphere. if (sphere.Z >= 0) { sphere.Z = 0; sphere.Normalize(); sphere *= Infinity.FiniteScale; return(sphere); } double z = sphere.Z; sphere.Z = 0; return(-sphere * m_gScale / z); }
public static void GenPolyhedron() { Tiling tiling; int p = 3; int q = 6; GetAssociatedTiling(p, q, 5000, out tiling); double overallScale = 12.5; // 2.5 cm = 1 in diameter Shapeways mesh = new Shapeways(); foreach (Tile tile in tiling.Tiles) { foreach (Segment seg in tile.Boundary.Segments) { double tilingScale = 0.75; seg.Scale(new Vector3D(), tilingScale); Vector3D v1 = Sterographic.PlaneToSphereSafe(seg.P1); Vector3D v2 = Sterographic.PlaneToSphereSafe(seg.P2); //if( v1.Dist( v2 ) < 0.01 ) // continue; if (SphericalCoords.CartesianToSpherical(v1).Y < Math.PI / 12 && SphericalCoords.CartesianToSpherical(v2).Y < Math.PI / 12) { continue; } double dist = v1.Dist(v2); int divisions = 2 + (int)(dist * 20); Vector3D[] points = seg.Subdivide(divisions); points = points.Select(v => Sterographic.PlaneToSphereSafe(v)).ToArray(); mesh.AddCurve(points, v => SizeFunc(v, overallScale)); } } mesh.Mesh.Scale(overallScale); string outputFileName = @"d:\temp\" + p + q + ".stl"; STL.SaveMeshToSTL(mesh.Mesh, outputFileName); }
// Maps unit disk to Boy's surface. public static Vector3D MapToBoys(Vector3D v) { // https://en.wikipedia.org/wiki/Boy%27s_surface#Parametrization_of_Boy.27s_surface Complex w = v.ToComplex(); Complex t0 = (Complex.Pow(w, 6) + Complex.Pow(w, 3) * Math.Sqrt(5) - 1); Complex t1 = w * (1 - Complex.Pow(w, 4)) / t0; Complex t2 = w * (1 + Complex.Pow(w, 4)) / t0; Complex t3 = (1 + Complex.Pow(w, 6)) / t0; double g1 = -3 / 2 * t1.Imaginary; double g2 = -3 / 2 * t2.Real; double g3 = t3.Imaginary - 0.5; double denom = g1 * g1 + g2 * g2 + g3 * g3; v = new Vector3D(g1, g2, g3); v /= denom; // The above is actually a map to R^3, but we want a surface in S^3 return(Sterographic.R3toS3(v)); }
/// <summary> /// Inputs and Outputs are in R3 (stereographically projected). /// </summary> public static Vector3D[] GeodesicPoints(Vector3D v1, Vector3D v2) { Vector3D start = Sterographic.R3toS3(v1); Vector3D end = Sterographic.R3toS3(v2); AvoidNorthPole(ref start, end); AvoidNorthPole(ref end, start); int div = 42; //int div = 56; // 343 //int div = 50; // 333 Segment seg = Segment.Line(start, end); Vector3D[] result = seg.Subdivide(div); for (int i = 0; i < result.Length; i++) { result[i].Normalize(); result[i] = Sterographic.S3toR3(result[i]); } return(result); }
public static void DrawElements(HyperbolicModel model, Vector3D[] textureCoords, Vector3D[] textureVerts, int[] elements, Isometry mouseIsometry, double textureScale) { ////////////////////// ZZZ - Use VBOs GL.Begin(BeginMode.Triangles); { double factor = textureScale; int skipped = 0; for (int i = 0; i < elements.Length; i++) { int idx = elements[i]; // In Poincare model. GL.TexCoord2((textureCoords[idx].X * factor + 1) / 2, (textureCoords[idx].Y * factor + 1) / 2); Complex transformed = textureVerts[idx].ToComplex(); if (mouseIsometry != null) { transformed = mouseIsometry.Apply(transformed); } switch (model) { case HyperbolicModel.Poincare: { Vertex(transformed); break; } case HyperbolicModel.Klein: { Vector3D temp = Vector3D.FromComplex(transformed); Vertex(PoincareToKlein(temp)); break; } case HyperbolicModel.Pseudosphere: { Mobius m = new Mobius(); m.UpperHalfPlane(); Complex u = m.Apply(transformed); double x = u.Real; double y = u.Imaginary; double max = 1 * System.Math.PI; double min = -1 * System.Math.PI; if (0 == i % 3 && (x < min - 1 || x > max + 1 || y < 0)) { skipped = 1; continue; } if (skipped > 0 && skipped < 3) { skipped++; continue; } skipped = 0; GL.TexCoord2((textureCoords[idx].X * factor + 1) / 2, (textureCoords[idx].Y * factor + 1) / 2); // Pseudosphere Func <double, Complex> tractrix = new Func <double, Complex>( (t) => { return(new Complex(t - Math.Tanh(t), 1.0 / Math.Cosh(t))); }); //Vector3D temp1 = Vector3D.FromComplex( u ); if (x < min) { x = min; } if (x > max) { x = max; } if (y < 1) { y = 1; } Vector3D temp1 = new Vector3D(x, y); double logy = Math.Log(temp1.Y); Complex tract = tractrix(logy); Vector3D temp2 = new Vector3D( Math.Cos(temp1.X) * tract.Imaginary, Math.Sin(temp1.X) * tract.Imaginary, tract.Real); GL.Vertex3(temp2.X, temp2.Y, temp2.Z); //temp1 = m.Inverse().Apply( temp1 ); //GL.Vertex3( temp1.X, temp1.Y, temp1.Z ); //Vertex( temp1 ); break; } case HyperbolicModel.Hyperboloid: { Vector3D hyper = Sterographic.PlaneToHyperboloid(Vector3D.FromComplex(transformed)); // Hyperboloid GL.Vertex3(hyper.X, hyper.Y, hyper.Z); break; } default: { System.Diagnostics.Debug.Assert(false); break; } } /* // PETALS * int petals = 7; * double newMag = transformed.Magnitude * ( 1 + 0.5 * Math.Sin( transformed.Phase * petals ) ); * double newPhase = transformed.Phase + ( -0.2 * newMag * Math.Pow( Math.Sin( newMag * 3 ), 1 ) * Math.Cos( transformed.Phase * petals ) ); * transformed = Complex.FromPolarCoordinates( newMag, newPhase ); * * Vertex( transformed ); * */ //double mag = System.Math.Pow( transformed.Magnitude, 3 ) / transformed.Magnitude; // nice //double mag = System.Math.Pow( transformed.Magnitude - 3, 2 ) + .0; // looks spherical //double mag = transformed.Magnitude + 0.1* System.Math.Sin( transformed.Magnitude * 15 ); // Fun warping (20 is cool too) //Vertex( transformed * mag ); /*double xmag = 1; * double ymag = transformed.Imaginary + 0.1 * System.Math.Sin( transformed.Imaginary * 15 ); * xmag = System.Math.Abs( xmag ); * ymag = System.Math.Abs( ymag ); * Vertex( new Complex( transformed.Real * xmag, transformed.Imaginary * ymag ) ); */ //Vertex( 2 / System.Math.PI * Complex.Log( ( 1 + transformed ) / ( 1 - transformed ) ) ); // Band model //Vertex( Complex.Pow( transformed, 3 ) / transformed.Magnitude ); // Spikey // Spiral //Complex band = 2 / System.Math.PI * Complex.Log( ( 1 + transformed ) / ( 1 - transformed ) ); //band = new Complex( band.Real, band.Imaginary + 0.3 * System.Math.Sin( band.Real * 2 ) ); //band = new Complex( band.Real * .5, band.Imaginary ); //band += new Complex( 0, .5 ); //Vertex( band ); /* * double x = band.Real; * double y = band.Imaginary; * * double r = System.Math.Exp( x ); * double theta = 3*( x + y/1.75 ); */ //Vertex( new Complex( r * System.Math.Sin( theta ), r * System.Math.Cos( theta ) ) ); // Spiral } } GL.End(); }