/// <summary> /// Calculates a mesh for an RLD surface. /// </summary> private static Mesh SurfaceInternal(out RLD_outputs outputs) { Mesh mesh = new Mesh(); Func <double, double, double, Vector3D[]> oneCircle = (x, o, scale) => { Vector3D normal = Normal(x, o * scale); Vector3D cen = new Vector3D(0, 0, normal.Z); Vector3D radius = new Vector3D(normal.X, 0); return(Shapeways.Disk(cen, new Vector3D(0, 0, 1), radius, m_params.Res)); }; outputs = RLD_Sphere(m_params.K); double s = m_params.Scale; //double s = outputs.scale; // Add in two bands for each segment along the profile, one for +z coords, and one for -z coords. Vector3D[] profile = outputs.profile; for (int i = 0; i < profile.Length - 1; i++) { Vector3D p1 = profile[i]; Vector3D p2 = profile[i + 1]; mesh.AddBand(oneCircle(p1.X, p1.Y, s), oneCircle(p2.X, p2.Y, s)); mesh.AddBand(oneCircle(p1.X, -p1.Y, s), oneCircle(p2.X, -p2.Y, s)); } return(mesh); }
/// <summary> /// Calculates a mesh for a standard euclidean catenoid. /// This will need to be transformed to the various locations later. /// </summary> private static Mesh StandardCatenoid(double waist, double height) { Mesh mesh = new Mesh(); int res = m_params.Res * 2; Func <double, Vector3D[]> oneCircle = z => { double r = waist * Math.Cosh(z / waist); Vector3D cen = new Vector3D(0, 0, z); Vector3D radius = new Vector3D(r, 0); return(Shapeways.Disk(cen, new Vector3D(0, 0, 1), radius, res)); }; double inc = height / (res * 2); for (int i = 0; i < res; i++) { double z1 = inc * i; double z2 = inc * (i + 1); mesh.AddBand(oneCircle(z1), oneCircle(z2)); mesh.AddBand(oneCircle(-z1), oneCircle(-z2)); } return(mesh); }
/// <summary> /// Ball /// </summary> private static void AddEdge(Mesh mesh, Vector3D v1, Vector3D v2) { double quality = v1.Dist(v2) * 8; // roughly 0 to 1. int div = (int)(quality * 16); if (div > 16) { div = 16; } if (div < 6) { div = 6; } div = 50; Vector3D[] points = H3Models.Ball.GeodesicPoints(v1, v2, div); List <Vector3D> ePoints = new List <Vector3D>(); List <double> eRadii = new List <double>(); foreach (Vector3D pNE in points) { Sphere sphere = SphereFuncBall(Geometry.Hyperbolic, pNE, false); ePoints.Add(sphere.Center); eRadii.Add(sphere.Radius); } Shapeways shapeways = new Shapeways(); shapeways.AddCurve(ePoints.ToArray(), eRadii.ToArray()); mesh.Append(shapeways.Mesh); }
/// <summary> /// Create an STL file for a cell. /// Currently only works for cells with both hyperideal vertices and cells. /// </summary> public static void HoneycombHyperidealLegs(HoneycombDef def, int lod, Dictionary <Vector3D, H3.Cell> complete) { int p = def.P; int q = def.Q; int r = def.R; m_div = TextureHelper.SetLevels(lod); bool ball = false; Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: ball); H3.Cell.Edge[] edges; if (ball) { edges = SimplexCalcs.SimplexEdgesBall(p, q, r); } else { edges = SimplexCalcs.SimplexEdgesUHS(p, q, r); } // Two edges of one simplex facet. H3.Cell.Edge e1 = edges[2]; H3.Cell.Edge e2 = edges[3]; Vector3D[] points1, points2; if (ball) { points1 = H3Models.Ball.GeodesicPoints(e1.Start, e1.End, 2 * m_div); points2 = H3Models.Ball.GeodesicPoints(e2.Start, e2.End, 2 * m_div); } else { points1 = H3Models.UHS.GeodesicPoints(e1.Start, e1.End, 2 * m_div); points2 = H3Models.UHS.GeodesicPoints(e2.Start, e2.End, 2 * m_div); } Sphere cellSphere = simplex[0]; Sphere vertexSphere = simplex[3]; // Because one vertex the facet triangle is hyperideal, it will actually look like a square. List <Vector3D[]> allPoints = new List <Vector3D[]>(); for (int i = 0; i < points1.Length; i++) { Vector3D p1 = points1[i]; Vector3D p2 = points2[i]; Vector3D[] arcPoints; if (i == points1.Length - 1) //if( false ) { // NOTE: This arc is not generally geodesic! // Or is it? arcPoints = ball ? H3Models.Ball.GeodesicPoints(p1, p2, m_div) : H3Models.UHS.GeodesicPoints(p1, p2, m_div); /*Circle3D arc = cellSphere.Intersection( vertexSphere ); * double angleTot = (p1 - arc.Center).AngleTo( p2 - arc.Center ); * arcPoints = Shapeways.CalcArcPoints( arc.Center, arc.Radius, p1, arc.Normal, -angleTot, div );*/ } else { Circle3D c = Circle3D.FromCenterAnd2Points(cellSphere.Center, p1, p2); double angleTot = (p1 - c.Center).AngleTo(p2 - c.Center); arcPoints = Shapeways.CalcArcPoints(cellSphere.Center, cellSphere.Radius, p1, c.Normal, -angleTot, m_div); } //Vector3D[] arcPoints = new Vector3D[] { p1, p2 }; allPoints.Add(arcPoints); } // Create the triangles for the patch. Mesh mesh = new Mesh(); for (int i = 0; i < allPoints.Count - 1; i++) { Vector3D[] arc1 = allPoints[i]; Vector3D[] arc2 = allPoints[i + 1]; for (int j = 0; j < arc1.Length - 1; j++) { // Points of (i,j) box; Vector3D p1 = arc1[j]; Vector3D p2 = arc2[j]; Vector3D p3 = arc1[j + 1]; Vector3D p4 = arc2[j + 1]; Mesh.Triangle tri1 = new Mesh.Triangle(p1, p2, p3); Mesh.Triangle tri2 = new Mesh.Triangle(p2, p4, p3); // We need to thicken after reflecting around, otherwise we can't apply a min thickness. /*Sphere normal = cellSphere; * Mesh.Triangle[] thickened1 = Thicken( tri1, normal ); * Mesh.Triangle[] thickened2 = Thicken( tri2, normal ); * mesh.Triangles.AddRange( thickened1 ); * mesh.Triangles.AddRange( thickened2 );*/ mesh.Triangles.Add(tri1); mesh.Triangles.Add(tri2); } } // AuxPoints will be used for multiple things. // - The first two points are for an an that will fill the gap where there is a missing face. // - We'll also store the points for the 4 edges of our fundamental triangle. List <Vector3D> auxPoints = new List <Vector3D>(); { var edge1 = allPoints.First(); var edge2 = allPoints.Last(); List <Vector3D> edge3 = new List <Vector3D>(), edge4 = new List <Vector3D>(); for (int i = 0; i < allPoints.Count; i++) { edge3.Add(allPoints[i][0]); edge4.Add(allPoints[i][allPoints[i].Length - 1]); } edge4.Reverse(); auxPoints.Add(e1.Start); auxPoints.Add(e1.End); auxPoints.AddRange(edge1.Reverse()); auxPoints.AddRange(edge2); auxPoints.AddRange(edge3); auxPoints.AddRange(edge4); } Vector3D cen = HoneycombPaper.InteriorPointBall; /* Reorientation code. Move this elsewhere. * * // Face centered orientation. * bool faceCentered = false; * if( faceCentered ) * SimplexCalcs.PrepForFacetCentering( p, q, simplex, ref cen ); * * Mobius mUHS = SimplexCalcs.FCOrientMobius( p, q ); * Mobius mBall = HoneycombPaper.FCOrientMobius( H3Models.UHSToBall( cellSphere ) ); * * simplex = simplex.Select( s => * { * s = H3Models.UHSToBall( s ); * //H3Models.TransformInBall2( s, mBall ); * return s; * } ).ToArray(); * * * { * for( int i = 0; i < mesh.Triangles.Count; i++ ) * { * Mesh.Triangle tri = mesh.Triangles[i]; * * if( faceCentered ) * { * tri.a = mUHS.ApplyToQuaternion( tri.a ); * tri.b = mUHS.ApplyToQuaternion( tri.b ); * tri.c = mUHS.ApplyToQuaternion( tri.c ); * } * * tri.a = H3Models.UHSToBall( tri.a ); * tri.b = H3Models.UHSToBall( tri.b ); * tri.c = H3Models.UHSToBall( tri.c ); * * if( faceCentered ) * { * tri.a = H3Models.TransformHelper( tri.a, mBall ); * tri.b = H3Models.TransformHelper( tri.b, mBall ); * tri.c = H3Models.TransformHelper( tri.c, mBall ); * } * mesh.Triangles[i] = tri; * } * * if( faceCentered ) * cen = H3Models.TransformHelper( cen, mBall ); * } */ // Now we need to reflect around this fundamental patch. H3.Cell[] simplices = GenCell(simplex, mesh, cen, auxPoints.ToArray(), ball); // Existing cells take precedence. foreach (H3.Cell c in simplices) { Vector3D t = c.Center; H3.Cell dummy; if (!complete.TryGetValue(t, out dummy)) { complete[t] = c; } } }
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 ); }
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"); } }