public void R3toS3() { for (int i = 0; i < Verts.Length; i++) { Verts[i] = Sterographic.R3toS3(Verts[i]); } }
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()); }
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 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); }
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 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); }
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();*/ }