private static Vector3D[] CalcViaProjections(Vector3D p1, Vector3D p2, Vector3D p3, int divisions, Geometry g) { Vector3D h1 = Sterographic.PlaneToHyperboloid(p1); Vector3D h2 = Sterographic.PlaneToHyperboloid(p2); Vector3D h3 = Sterographic.PlaneToHyperboloid(p3); List <Vector3D> temp = new List <Vector3D>(); Segment seg1 = Segment.Line(h1, h2); Segment seg2 = Segment.Line(h3, h2); Vector3D[] s1 = seg1.Subdivide(divisions); Vector3D[] s2 = seg2.Subdivide(divisions); for (int i = 0; i < divisions; i++) { Segment seg = Segment.Line(s1[i], s2[i]); temp.AddRange(seg.Subdivide(divisions - i)); } temp.Add(h2); List <Vector3D> result = new List <Vector3D>(); foreach (Vector3D v in temp) { Vector3D copy = v; Sterographic.NormalizeToHyperboloid(ref copy); result.Add(Sterographic.HyperboloidToPlane(copy)); } return(result.ToArray()); }
public static void Experiment() { TilingConfig config = new TilingConfig(4, 3); Tiling tiling = new Tiling(); tiling.Generate(config); HashSet <H3.Cell.Edge> completed = new HashSet <H3.Cell.Edge>(new H3.Cell.EdgeEqualityComparer()); string fileName = "hopf.pov"; using (StreamWriter sw = File.CreateText(fileName)) { Tile[] tiles = tiling.Tiles.ToArray(); //foreach( Tile t in tiling.Tiles ) foreach (Tile t in new Tile[] { tiles[0] }) { foreach (Segment seg in t.Boundary.Segments) { H3.Cell.Edge e = new H3.Cell.Edge(seg.P1, seg.P2); if (completed.Contains(e)) { continue; } HopfLink(sw, Sterographic.PlaneToSphereSafe(e.Start), Sterographic.PlaneToSphereSafe(e.End), anti: false); completed.Add(e); } } } }
/// <summary> /// Returns a stereographically sphere representing us. /// </summary> public Sphere ToSphere() { // Equatorial sphere? if (Pole == new Vector3D(0, 0, 0, 1)) { return(new Sphere()); } // A plane? Vector3D poleR3 = Sterographic.S3toR3(Pole); if (Tolerance.Equal(poleR3.Abs(), 1)) { return(Sphere.Plane(poleR3)); } // Get 4 points on the sphere. Vector3D e1 = new Vector3D(1, 0, 0, 0); Vector3D e2 = new Vector3D(0, 1, 0, 0); Vector3D e3 = new Vector3D(0, 0, 1, 0); Vector3D e4 = new Vector3D(0, 0, 0, 1); System.Func <Vector3D, Vector3D> one = v => { v = Euclidean3D.ProjectOntoPlane(Pole, new Vector3D(), v); v.Normalize(); return(Sterographic.S3toR3(v)); }; return(Sphere.From4Points(one(e1), one(e2), one(e3), one(e4))); }
public int GetHashCode(Vector3D v) { Vector3D t = m_stereo ? Sterographic.R3toS3(v) : v; t = new Vector3D(Math.Abs(t.X), Math.Abs(t.Y), Math.Abs(t.Z), Math.Abs(t.W)); return(t.GetHashCode()); }
public static GreatSphere[] CalcSpheres(Sphere[] simplex, Vector3D[] poles) { HashSet <Vector3D> completedPoles = new HashSet <Vector3D>(poles, new AntipodeEqualityComparer(stereo: true)); ReflectSpheresRecursive(simplex, completedPoles.ToArray(), completedPoles); return(completedPoles.Select(p => new GreatSphere(Sterographic.R3toS3(p))).ToArray()); }
private H3.Cell.Edge[] GenEdgesInternal(Vector3D v1, Vector3D v2, Vector3D v3, Vector3D v4) { int div = 5; List <H3.Cell.Edge> result = new List <H3.Cell.Edge>(); for (int i = 0; i <= div; i++) { Vector3D start = v1 + (v2 - v1) * i / div; Vector3D end = v3 + (v4 - v3) * i / div; start.Normalize(); end.Normalize(); start = Sterographic.S3toR3(start); end = Sterographic.S3toR3(end); if (Infinity.IsInfinite(start)) { start = end * 10; } if (Infinity.IsInfinite(end)) { end = start * 10; } result.Add(new H3.Cell.Edge(start, end)); } return(result.ToArray()); }
public void R3toS3() { for (int i = 0; i < Verts.Length; i++) { Verts[i] = Sterographic.R3toS3(Verts[i]); } }
private static Vector3D Transform2(Vector3D p, Matrix4D mat) { p.Normalize(); p = mat.RotateVector(p); p = Sterographic.S3toR3(p); p = SphericalModels.StereoToEquidistant(p); return(p); }
private static Vector3D[] OneHopfCircleProjected(Vector3D s2Point, bool anti) { Vector3D[] circlePoints = S3.OneHopfCircle(s2Point, anti); for (int i = 0; i < circlePoints.Length; i++) { circlePoints[i] = Sterographic.S3toR3(circlePoints[i]); } return(circlePoints); }
private static Vector3D Halfway(Vector3D v1, Vector3D v2) { Vector3D v1_ = Sterographic.PlaneToSphereSafe(v1); Vector3D v2_ = Sterographic.PlaneToSphereSafe(v2); Vector3D result = (v1_ + v2_) / 2; result.Normalize(); return(Sterographic.SphereToPlane(result)); }
// https://plus.google.com/u/0/117663015413546257905/posts/BnCEkdNiTZ2 public static void TwinDodecs() { Tiling tiling = new Tiling(); TilingConfig config = new TilingConfig(5, 3); tiling.GenerateInternal(config, Polytope.Projection.VertexCentered); // Vertex-centered makes infinities tricky Dodec dodec = new Dodec(); foreach (Tile tile in tiling.Tiles) { foreach (Segment seg in tile.Boundary.Segments) { Vector3D p1 = seg.P1, p2 = seg.P2; if (Infinity.IsInfinite(p1)) { p1 = Infinity.InfinityVector; } if (Infinity.IsInfinite(p2)) { p2 = Infinity.InfinityVector; } dodec.Verts.Add(p1); dodec.Verts.Add(p2); dodec.Midpoints.Add(Halfway(p1, p2)); } } // Now recursively add more vertices. HashSet <Vector3D> allVerts = new HashSet <Vector3D>(); foreach (Vector3D v in dodec.Verts) { allVerts.Add(v); } RecurseTwins(allVerts, dodec, 0); using (StreamWriter sw = File.CreateText("dual_dodecs_points_sphere.pov")) { foreach (Vector3D vert in allVerts) { Vector3D onSphere = Sterographic.PlaneToSphereSafe(vert); sw.WriteLine(PovRay.Sphere(new Sphere() { Center = onSphere, Radius = 0.01 })); //if( !Infinity.IsInfinite( vert ) ) // sw.WriteLine( PovRay.Sphere( new Sphere() { Center = vert, Radius = 0.01 } ) ); } } }
public static Vector3D[] CalcViaProjections(Vector3D p1, Vector3D p2, Vector3D p3, int divisions, Geometry g) { if (g == Geometry.Euclidean) { throw new System.NotImplementedException(); } Vector3D h1 = new Vector3D(), h2 = new Vector3D(), h3 = new Vector3D(); if (g == Geometry.Hyperbolic) { h1 = Sterographic.PlaneToHyperboloid(p1); h2 = Sterographic.PlaneToHyperboloid(p2); h3 = Sterographic.PlaneToHyperboloid(p3); } else if (g == Geometry.Spherical) { h1 = Sterographic.PlaneToSphereSafe(p1); h2 = Sterographic.PlaneToSphereSafe(p2); h3 = Sterographic.PlaneToSphereSafe(p3); } List <Vector3D> temp = new List <Vector3D>(); Segment seg1 = Segment.Line(h1, h2); Segment seg2 = Segment.Line(h3, h2); Vector3D[] s1 = seg1.Subdivide(divisions); Vector3D[] s2 = seg2.Subdivide(divisions); for (int i = 0; i < divisions; i++) { Segment seg = Segment.Line(s1[i], s2[i]); temp.AddRange(seg.Subdivide(divisions - i)); } temp.Add(h2); List <Vector3D> result = new List <Vector3D>(); foreach (Vector3D v in temp) { Vector3D copy = v; if (g == Geometry.Hyperbolic) { Sterographic.NormalizeToHyperboloid(ref copy); result.Add(Sterographic.HyperboloidToPlane(copy)); } else if (g == Geometry.Spherical) { copy.Normalize(); result.Add(Sterographic.SphereToPlane(copy)); } } return(result.ToArray()); }
public static Vector3D Centroid(Geometry g, Vector3D[] conformalVerts) { if (g == Geometry.Euclidean) { Vector3D result = new Vector3D(); foreach (Vector3D v in conformalVerts) { result += v; } return(result / conformalVerts.Length); } Vector3D[] verts = conformalVerts.Select(v => { switch (g) { case Geometry.Spherical: return(Sterographic.PlaneToSphereSafe(v)); case Geometry.Hyperbolic: return(Sterographic.PlaneToHyperboloid(v)); } throw new System.ArgumentException(); }).ToArray(); // https://math.stackexchange.com/a/2173370/300001 Vector3D sum = new Vector3D(); for (int i = 0; i < verts.Length; i++) { sum += verts[i]; } Vector3D centroid = sum / Math.Sqrt(DotInGeometry(g, sum, sum)); NormalizeInGeometry(g, ref centroid); switch (g) { case Geometry.Spherical: return(Sterographic.SphereToPlane(centroid)); case Geometry.Hyperbolic: return(Sterographic.HyperboloidToPlane(centroid)); } throw new System.ArgumentException(); }
public static void NormalizeInGeometry(Geometry g, ref Vector3D v) { switch (g) { case Geometry.Spherical: v.Normalize(); break; case Geometry.Euclidean: throw new System.NotImplementedException(); case Geometry.Hyperbolic: Sterographic.NormalizeToHyperboloid(ref v); break; } }
public static void ElevenCell() { Graph g = new Graph(); g.SetupCompleteGraph(11); GraphRelaxation relaxer = new GraphRelaxation(); relaxer.Graph = g; relaxer.NodeRepulsion = 0.01; relaxer.EdgeAttraction = 0.0; relaxer.EdgeRepulsion = 0.0; relaxer.Relax(20000); Vector3D northPole = new Vector3D(0, 0, 0, 1); H3.Cell.Edge[] edges = g.Edges.Select(e => { Vector3D v1 = g.Nodes[e.V1].Position.ToVec3D(); Vector3D v2 = g.Nodes[e.V2].Position.ToVec3D(); //if( v1.Compare( northPole, .5 ) || v2.Compare( northPole, 0.5 ) ) // Cull edges near north pole. // return null; v1 = Sterographic.S3toR3(v1); v2 = Sterographic.S3toR3(v2); return(new H3.Cell.Edge(v1, v2)); }).ToArray(); edges = edges.Where(e => e != null).ToArray(); bool povray = false; if (povray) { string filename = "test.pov"; System.IO.File.Delete(filename); using (StreamWriter sw = new StreamWriter(filename)) sw.WriteLine("#include \"C:\\Users\\hrn\\Documents\\roice\\povray\\H3\\horosphere\\633.pov\""); PovRay.WriteEdges(new PovRay.Parameters { AngularThickness = 0.03 }, Geometry.Spherical, edges, filename, append: true); } else { S3.EdgesToStl(edges); } }
public bool Equals(Vector3D v1, Vector3D v2) { if (v1 == v2) { return(true); } Vector3D t1 = m_stereo ? Sterographic.R3toS3(v1) : v1; Vector3D t2 = m_stereo ? Sterographic.R3toS3(v2) : v2; if (t1 == t2 * -1) { return(true); } return(false); }
private static void ProjectAndSave(List <Circle3D> circlesOnUnitSphere) { List <Circle3D> projected = new List <Circle3D>(); foreach (Circle3D c in circlesOnUnitSphere) { Vector3D[] pp = c.RepresentativePoints.Select(p => Sterographic.SphereToPlane(p)).ToArray(); Circle3D cProj = new Circle3D(pp[0], pp[1], pp[2]); if (Infinity.IsInfinite(cProj.Radius)) { continue; } cProj.Color = c.Color; projected.Add(cProj); } SaveToBmp(projected); }
public static Circle3D GeodesicFrom2Points(Vector3D a, Vector3D b) { if (a == b || a == -b) { throw new System.Exception("Geodesic not unique"); } System.Func <Vector3D, Circle3D> lineFunc = p => { Circle3D circ = new Circle3D(); circ.Radius = double.PositiveInfinity; p.Normalize(); circ.Normal = p; // Hacky representation of a line. return(circ); }; if (a.IsOrigin || b.IsOrigin) { Vector3D p = a.IsOrigin ? b : a; return(lineFunc(p)); } double mag1 = a.Abs(), mag2 = b.Abs(); if (Tolerance.Equal(mag1, 1) && Tolerance.Equal(mag2, 1)) { return(new Circle3D(a, b, a * -1)); } // The antipode in S^3 of a or b will give us a 3rd point. Vector3D antipode = Sterographic.S3toR3(Sterographic.R3toS3(a) * -1); // If the antipode is also an an antipode in R3, the points are colinear // (or they are on the equatorial 2-sphere, but that is checked above). if (a == antipode * -1) { return(lineFunc(a)); } return(new Circle3D(a, b, antipode)); }
private static H3.Cell.Edge[] Cull120Cell(H3.Cell.Edge[] edges) { Func <Vector3D, bool> passes = new Func <Vector3D, bool>(v => { //return // Math.Pow( v.Z, 2 ) < 0.13 && // Math.Pow( v.W, 2 ) < 0.13; return(Tolerance.Equal(v.W, 0.0)); }); H3.Cell.Edge[] result = edges.Where(e => { Vector3D start = Sterographic.R3toS3(e.Start); Vector3D end = Sterographic.R3toS3(e.End); return(passes(start) && passes(end)); }).ToArray(); // Now cull valence-2 edges. //result = CullValence2Edges( result ); return(result); }
/// <summary> /// Calculates our pole from a stereographically projected sphere. /// Assume the input sphere is a geodesic sphere in the conformal model. /// </summary> public static GreatSphere FromSphere(Sphere s) { if (s.Center.IsOrigin) { return(new GreatSphere(new Vector3D(0, 0, 0, 1))); } if (s.IsPlane) { // If we are a plane, the pole is is on the unit sphere. Vector3D pole = s.Normal; pole.Normalize(); return(new GreatSphere(Sterographic.R3toS3(pole))); } Vector3D v1 = Sterographic.R3toS3(s.Center + new Vector3D(s.Radius, 0, 0, 0)); Vector3D v2 = Sterographic.R3toS3(s.Center + new Vector3D(0, s.Radius, 0, 0)); Vector3D v3 = Sterographic.R3toS3(s.Center + new Vector3D(0, 0, s.Radius, 0)); Vector3D o = Orthogonal(v1, v2, v3); return(new GreatSphere(o)); }
private static void Relax(Vector3D[] coordsR3, int[] elementIndices, Vector3D[] locks) { int dim = 4; Graph g = new Graph(); for (int i = 0; i < coordsR3.Length; i++) { Vector3D v = coordsR3[i]; GraphNode node = new GraphNode(new VectorND(Sterographic.R3toS3(v)), new VectorND(dim)); node.Lock = new VectorND(locks[i]); g.Nodes.Add(node); } for (int i = 0; i < elementIndices.Length; i += 3) { int a = elementIndices[i]; int b = elementIndices[i + 1]; int c = elementIndices[i + 2]; g.AddEdge(new GraphEdge(a, b)); g.AddEdge(new GraphEdge(b, c)); g.AddEdge(new GraphEdge(c, a)); } GraphRelaxation relaxer = new GraphRelaxation(); relaxer.Graph = g; relaxer.NodeRepulsion = 0; relaxer.EdgeAttraction = 0.5; relaxer.EdgeRepulsion = 0; relaxer.Relax(1000); for (int i = 0; i < coordsR3.Length; i++) { GraphNode node = g.Nodes[i]; coordsR3[i] = Sterographic.S3toR3(node.Position.ToVec3D()); } }
private static void CompoundOfFive24Cells(ref H3.Cell.Edge[] edges) { List <H3.Cell.Edge> allEdges = new List <H3.Cell.Edge>(); Vector3D v600 = Sterographic.R3toS3(SimplexCalcs.VertexSpherical(3, 3, 5)); Vector3D v24 = Sterographic.R3toS3(SimplexCalcs.VertexSpherical(3, 4, 3)); Sphere[] mirrors600 = SimplexCalcs.MirrorsSpherical(3, 3, 5); double a24 = v24.AngleTo(Sterographic.R3toS3(new Vector3D())); double a600 = v600.AngleTo(Sterographic.R3toS3(new Vector3D())); Matrix4D m600 = Matrix4D.MatrixToRotateinCoordinatePlane(a600, 2, 3); Matrix4D m600_ = Matrix4D.MatrixToRotateinCoordinatePlane(-a600, 2, 3); Matrix4D m24 = Matrix4D.MatrixToRotateinCoordinatePlane(a24, 2, 3); Matrix4D m24_ = Matrix4D.MatrixToRotateinCoordinatePlane(-a24, 2, 3); double eLength = 2 * Math.PI / 10; // 600-cell edge length double a_id = Math.Asin(Math.Sin(eLength / 2) / Math.Sin(Math.PI / 3) * Math.Sin(Math.PI / 2)); eLength = 1.0 / Math.Sin(2 * Math.PI / 5); // icosahedron edge length double a_i = Math.Asin(Math.Sin(eLength / 2) / Math.Sin(Math.PI / 3) * Math.Sin(Math.PI / 5)); Func <Vector3D, Vector3D> rot600 = v => { v = Sterographic.R3toS3(v); v = m600.RotateVector(v); v = Sterographic.S3toR3(v); return(v); }; Func <Vector3D, int, Vector3D> rotOne = (v, idx) => { v = Sterographic.R3toS3(v); v = m24.RotateVector(v); v = Sterographic.S3toR3(v); v.RotateAboutAxis(new Vector3D(1, 0, 0), -a_id); // Vertex to cell center. v = Sterographic.R3toS3(v); v = m600_.RotateVector(v); v = Sterographic.S3toR3(v); List <int> reflections = new List <int>(); if (idx == 0) { reflections.Add(2); reflections.Add(1); reflections.Add(2); reflections.Add(0); reflections.Add(1); reflections.Add(2); reflections.Add(1); reflections.Add(2); } if (idx != 0) { reflections.Add(3); } if (idx == 2) { reflections.Add(1); reflections.Add(2); } if (idx == 3) { reflections.Add(2); reflections.Add(1); } if (idx == 4) { reflections.Add(1); reflections.Add(0); reflections.Add(1); reflections.Add(2); reflections.Add(0); reflections.Add(1); reflections.Add(0); reflections.Add(1); } foreach (int reflection in reflections) { v = mirrors600[reflection].ReflectPoint(v); } v = Sterographic.R3toS3(v); v = m600.RotateVector(v); v = Sterographic.S3toR3(v); //v.RotateAboutAxis( new Vector3D( 0, 0, 1 ), Math.PI/3 ); //v.RotateAboutAxis( new Vector3D( 1, 0, 0 ), -a_i*2 ); v = Sterographic.R3toS3(v); //v = m24_.RotateVector( v ); v = Sterographic.S3toR3(v); return(v); }; for (int i = 0; i < 5; i++) { //if( i == 0 ) // continue; allEdges.AddRange(edges.Select(e => { H3.Cell.Edge newEdge = new H3.Cell.Edge(rotOne(e.Start, i), rotOne(e.End, i)); //H3.Cell.Edge newEdge = new H3.Cell.Edge( rot600( e.Start ), rot600( e.End ) ); switch (i) { case 0: newEdge.Color = new Vector3D(1, 0, 0, 1); //newEdge.Color = new Vector3D( 1, 1, 1, 0 ); break; case 1: newEdge.Color = new Vector3D(0, 1, 0, 2); break; case 2: newEdge.Color = new Vector3D(0, 0, 1, 3); break; case 3: newEdge.Color = new Vector3D(1, 0, 1, 4); break; case 4: newEdge.Color = new Vector3D(0, 1, 1, 5); break; } return(newEdge); })); } edges = allEdges.ToArray(); //edges = edges.Where( e => Tolerance.Equal( 1, e.Start.Abs() ) || Tolerance.Equal( 1, e.End.Abs() ) ).ToArray(); HashSet <Vector3D> uniqueVerts = new HashSet <Vector3D>(); foreach (H3.Cell.Edge e in edges) { uniqueVerts.Add(e.Start); uniqueVerts.Add(e.End); } System.Diagnostics.Trace.WriteLine("Number of verts = " + uniqueVerts.Count); /*edges = edges.Where( e => * { * Vector3D v = Tolerance.Equal( 1, e.Start.Abs() ) ? e.End : e.Start; * if( v.Abs() >= 0.8 || v.Abs() <= 0.7 ) * return false; * * if( Tolerance.LessThanOrEqual( v.X, 0 ) || Tolerance.GreaterThanOrEqual( v.Y, 0 ) || Tolerance.GreaterThanOrEqual( v.Z, 0 ) ) * return false; * * return true; * } ).ToArray(); * * edges = edges.OrderBy( e => Tolerance.Equal( 1, e.Start.Abs() ) ? e.End.Abs() : e.Start.Abs() ).ToArray();*/ }
public void Gen(int p, int q, int r) { Geometry g = Util.GetGeometry(p, q, r); if (g != Geometry.Spherical) { throw new System.Exception("Point group code only for spherical geometry."); } Simplex simplex = new Simplex(); simplex.Facets = SimplexCalcs.Mirrors(p, q, r); Vector3D cen = new Vector3D(); Vector3D faceCenter = SimplexCalcs.FaceCenterSpherical(p, q, r); Vector3D edgeMid = SimplexCalcs.EdgeMidpointSpherical(p, q, r); Vector3D vertex = SimplexCalcs.VertexSpherical(p, q, r); List <Vector3D> startingPoles = new List <Vector3D>(); startingPoles.Add(Sterographic.S3toR3(GreatSphere.FromSphere(simplex.Facets[0]).Pole)); GreatSphere[] spheres = CalcSpheres(simplex.Facets, startingPoles.ToArray()); string filename = "point_group.pov"; using (StreamWriter sw = File.CreateText(filename)) { //foreach( var greatSphere in spheres ) //sw.WriteLine( PovRay.Sphere( greatSphere.ToSphere() ) ); } /* * List<H3.Cell.Edge> startingEdges = new List<H3.Cell.Edge>(); * startingEdges.Add( new H3.Cell.Edge( cen, faceCenter ) ); * H3.Cell.Edge[] edges = Recurse.CalcEdges( simplex.Facets, startingEdges.ToArray(), new Recurse.Settings() { G = Geometry.Spherical, Threshold = 0.001 } ); * //edges = edges.Where( e => !( Infinity.IsInfinite( e.Start ) || Infinity.IsInfinite( e.End ) ) ).ToArray(); * * PovRay.WriteEdges( new PovRay.Parameters() { AngularThickness = 0.01 }, Geometry.Spherical, edges, filename, append: true ); */ double minRad = 0; double thick = 0.005; System.Func <Vector3D, Sphere> sizeFunc = v => { Vector3D c; double rad; H3Models.Ball.DupinCyclideSphere(v, thick / 2, g, out c, out rad); return(new Sphere() { Center = c, Radius = Math.Max(rad, minRad) }); }; // All geodesics List <Circle3D> startingCircles = new List <Circle3D>(); startingCircles.Add(GeodesicFrom2Points(cen, edgeMid)); Circle3D[] geodesics = CalcGeodesics(simplex.Facets, startingCircles.ToArray()); Vector3D color = new Vector3D(0, 0, 1); using (StreamWriter sw = File.CreateText(filename)) { Shapeways shapeways = new Shapeways(); foreach (Circle3D geodesic in geodesics) { Vector3D[] points; if (Infinity.IsInfinite(geodesic.Radius)) { double cutoff = 15; Segment seg = Segment.Line(geodesic.Normal * cutoff, geodesic.Normal * -cutoff); points = seg.Subdivide(42); } else { List <Vector3D> tempPoints = geodesic.Subdivide(150).ToList(); tempPoints.Add(tempPoints[0]); tempPoints.Add(tempPoints[1]); points = tempPoints.ToArray(); } List <Vector3D> ePoints = new List <Vector3D>(); List <double> eRadii = new List <double>(); foreach (Vector3D pNE in points) { Sphere sphere = sizeFunc(pNE); ePoints.Add(sphere.Center); eRadii.Add(sphere.Radius); } shapeways.AddCurve(ePoints.ToArray(), eRadii.ToArray()); sw.WriteLine(PovRay.EdgeSphereSweep(points, sizeFunc, color)); } STL.SaveMeshToSTL(shapeways.Mesh, "533.stl"); } }
public static void CatenoidBasedSurface() { RLD_outputs outputs; SurfaceInternal(out outputs); double scale = m_params.Scale; // Map a point for a given k/m from the hemihypersphere to the complex plane. // You can also pass in -1 for k to get a point on the equator of the hemihypersphere. double mInc = Math.PI * 2 / m_params.M; Func <RLD_outputs, int, int, Vector3D> onPlane = (o, k, m) => { double theta = k == -1 ? 0 : outputs.x_i[k]; theta += Math.PI / 2; return (Sterographic.SphereToPlane( SphericalCoords.SphericalToCartesian( new Vector3D(1, theta, m * mInc) ) )); }; // Setup texture coords on fundamental triangle. // We'll use a fundamental triangle in the southern hemisphere, // with stereographically projected coords at (0,0), (1,0), and CCW on the unit circle depending on M. Polygon p = new Polygon(); p.Segments.Add(Segment.Line(new Vector3D(), new Vector3D(1, 0))); p.Segments.Add(Segment.Arc(new Vector3D(1, 0), onPlane(outputs, 1, 1), onPlane(outputs, -1, 1))); p.Segments.Add(Segment.Line(onPlane(outputs, -1, 1), new Vector3D())); int levels = 9; TextureHelper.SetLevels(levels); Vector3D[] coords = TextureHelper.TextureCoords(p, Geometry.Spherical, doGeodesicDome: true); int[] elementIndices = TextureHelper.TextureElements(1, levels); // Setup a nearTree for the catenoid locations (on the plane). NearTree nearTree = new NearTree(Metric.Spherical); for (int k = 1; k < outputs.x_i.Length; k++) { for (int m = 0; m <= 1; m++) { Vector3D loc = onPlane(outputs, k, m); nearTree.InsertObject(new NearTreeObject() { ID = k, Location = loc }); } } // Given a point on the plane, find the nearest catenoid center and calculate the height of the surface based on that. // This also calculates the locking of the point. Func <Vector3D, Tuple <double, Vector3D, Vector3D> > heightAndLocking = coord => { NearTreeObject closest; if (!nearTree.FindNearestNeighbor(out closest, coord, double.MaxValue)) { throw new System.Exception(); } Vector3D locked = new Vector3D(); if (p.Segments[0].IsPointOn(coord) || p.Segments[2].IsPointOn(coord)) { locked = new Vector3D(1, 1, 0, 0); } //if( p.Segments[1].IsPointOn( v ) ) // Not working right for some reason, but line below will work. if (Tolerance.Equal(coord.Abs(), 1)) { locked = new Vector3D(1, 1, 1, 0); } Vector3D vSphere = Sterographic.PlaneToSphere(coord); Vector3D cSphere = Sterographic.PlaneToSphere(closest.Location); double dist = vSphere.AngleTo(cSphere); int k = (int)closest.ID; double waist = outputs.t_i[k]; double rld_height = outputs.phi_i[k]; double h = waist * 3.5 * 2; // height where catenoid will meet rld_height. double factor = scale * rld_height * 2 / h; // Artifical scaling so we can see things. dist /= factor; double z = double.NaN; if (dist >= waist) { z = waist * DonHatch.acosh(dist / waist); } else if (dist >= 0.7 * waist) { z = 0; // Move the coord to the thinnest waist circle. Mobius m = new Mobius(); m.Hyperbolic(Geometry.Spherical, coord.ToComplex(), waist / dist); coord = m.Apply(coord); } if (dist < waist * 20) { locked = new Vector3D(1, 1, 1, 1); } return(new Tuple <double, Vector3D, Vector3D>(z * factor, locked, coord)); }; // Calculate all the coordinates. Vector3D[] locks = new Vector3D[coords.Length]; for (int i = 0; i < coords.Length; i++) { Vector3D coord = coords[i]; var hl = heightAndLocking(coord); locks[i] = hl.Item2; coord = hl.Item3; coords[i] = Normal(Sterographic.PlaneToSphere(coord), (double)hl.Item1); } // Relax it. Relax(coords, elementIndices, locks); Mesh mesh = new Mesh(); Sphere s = new Sphere(); for (int i = 0; i < elementIndices.Length; i += 3) { Vector3D a = coords[elementIndices[i]]; Vector3D b = coords[elementIndices[i + 1]]; Vector3D c = coords[elementIndices[i + 2]]; if (a.DNE || b.DNE || c.DNE) { continue; } for (int m = 0; m <= 0; m++) { mesh.Triangles.Add(new Mesh.Triangle(a, b, c)); mesh.Triangles.Add(new Mesh.Triangle( s.ReflectPoint(a), s.ReflectPoint(b), s.ReflectPoint(c))); a.RotateXY(mInc); b.RotateXY(mInc); c.RotateXY(mInc); } } PovRay.WriteMesh(mesh, "RLD.pov"); }
public static void S3BiHelicoid() { double cutoff = 8.0; int div = 500; Matrix4D mat = Matrix4D.MatrixToRotateinCoordinatePlane(1 * Math.PI / 4, 0, 3); Mesh m1 = S3Helicoid(div, mat, reciprocal: false); //m1.Triangles = m1.Triangles.Where( t => t.a.Abs() < cutoff && t.b.Abs() < cutoff && t.c.Abs() < cutoff ).ToList(); Mesh m2 = S3Helicoid(div, mat, reciprocal: true); //m2.Triangles = m2.Triangles.Where( t => t.a.Abs() < cutoff && t.b.Abs() < cutoff && t.c.Abs() < cutoff ).ToList(); Mesh m3 = new Mesh(); System.Action <bool> addCore = recip => { List <Vector3D> circlePoints = new List <Vector3D>(); double aOffset = 2 * Math.PI / div; for (int i = 0; i <= div; i++) { double x = Math.Sin(aOffset * i); double y = Math.Cos(aOffset * i); circlePoints.Add(recip ? new Vector3D(x, y) : new Vector3D(0, 0, x, y)); } // partial transform to R3 here. circlePoints = circlePoints.Select(p => { p = mat.RotateVector(p); p = Sterographic.S3toR3(p); return(p); }).ToList(); List <Vector3D> ePoints = new List <Vector3D>(); List <double> eRadii = new List <double>(); foreach (Vector3D pNE in circlePoints) { Sphere sphere = SphereFuncBall(Geometry.Spherical, pNE, false); ePoints.Add(sphere.Center); eRadii.Add(sphere.Radius); } Shapeways shapeways = new Shapeways(); shapeways.AddClosedCurve(ePoints.ToArray(), eRadii.ToArray()); m3.Append(shapeways.Mesh); }; addCore(false); addCore(true); for (int i = 0; i < m3.Triangles.Count; i++) { Mesh.Triangle t = m3.Triangles[i]; m3.Triangles[i] = Transform(t, SphericalModels.StereoToEquidistant); } string filename = "helicoid.stl"; File.Delete(filename); using (StreamWriter sw = File.AppendText(filename)) { STL.AppendMeshToSTL(m1, sw); STL.AppendMeshToSTL(m2, sw); STL.AppendMeshToSTL(m3, sw); } //HelicoidHelper( thinMesh, boundaryPoints ); }
private static void SpecialCase333() { /* * HashSet<Vector3D> verts = new HashSet<Vector3D>(); * foreach( H3.Cell.Edge e in edges ) * { * verts.Add( e.Start ); * verts.Add( e.End ); * } * * /// We need to be smart such that the radius does not change too much at each step, * /// and are going to do that by adding multiple edges. * double upperTest = 35.25; // dist where rad ~300 * * System.Func<double, double> locationAtRad = rad => * { * double min = 0; * double max = upperTest; * double current = upperTest / 2; * double searchOffset = ( max - min ) / 4; * * Vector3D cen; * double radTest; * H3Models.Ball.DupinCyclideSphere( verts.First() * current, .07 / 2, g, out cen, out radTest ); * * // iterate to it. * double diff = Math.Abs( rad - radTest ); * int iterations = 1000; * for( int i = 0; i < iterations; i++ ) * { * double t1, t2; * H3Models.Ball.DupinCyclideSphere( verts.First() * ( current + searchOffset ), .07 / 2, g, out cen, out t1 ); * H3Models.Ball.DupinCyclideSphere( verts.First() * ( current - searchOffset ), .07 / 2, g, out cen, out t2 ); * double d1 = Math.Abs( rad - t1 ); * double d2 = Math.Abs( rad - t2 ); * if( d1 == Math.Min( Math.Min( diff, d1 ), d2 ) ) * { * diff = d1; * current += searchOffset; * } * if( d2 == Math.Min( Math.Min( diff, d1 ), d2 ) ) * { * diff = d2; * current -= searchOffset; * } * * if( Tolerance.Equal( diff, 0.0, .0001 ) ) * return current; * * searchOffset /= 2; * } * * throw new System.Exception(); * }; * * List<H3.Cell.Edge> toAdd = new List<H3.Cell.Edge>(); * foreach( Vector3D v in verts ) * { * //toAdd.Add( new H3.Cell.Edge( v, v * 49 ) ); * //toAdd.Add( new H3.Cell.Edge( v * 45, v * 48.5 ) ); // need a lot of resolution here. * toAdd.Add( new H3.Cell.Edge( v, v * 35.25 ) ); * * double maxRad = 300; * double changePerEdge = 5; * double last = 1.0; * for( double rad = changePerEdge; rad < maxRad; rad += changePerEdge ) * { * double loc = locationAtRad( rad ); * //toAdd.Add( new H3.Cell.Edge( v * last, v * loc ) ); * last = loc; * } * } * toAdd.AddRange( edges ); * edges = toAdd.ToArray(); */ // Sphere sweeps just not working - We need to add in clipped tori here. //Vector3D s3 = Sterographic.R3toS3( new Vector3D( 0.7 / 2, 0, 0 ) ); Vector3D s3 = Sterographic.R3toS3(new Vector3D()); s3 += new Vector3D(); // r2 is major radius of torus. // r2 - r1 is minor radius of torus double r1 = .07 / 2; double r2; Vector3D cen; double arbitrary = 0.25; H3Models.Ball.DupinCyclideSphere(new Vector3D(arbitrary, 0, 0), r1, Geometry.Spherical, out cen, out r2); double y = cen.Abs(); double rad = (r2 * r2 - r1 * r1 - y * y) / (2 * r1 - 2 * r2); double x = rad + r1; System.Diagnostics.Trace.WriteLine(x); }