/// <summary> /// Add a finite (truncated) banana to our mesh. Passed in edge should be in Ball model. /// </summary> public static void AddBanana( Shapeways mesh, Vector3D e1, Vector3D e2, H3.Settings settings ) { Vector3D e1UHS = H3Models.BallToUHS( e1 ); Vector3D e2UHS = H3Models.BallToUHS( e2 ); // Endpoints of the goedesic on the z=0 plane. Vector3D z1, z2; H3Models.UHS.GeodesicIdealEndpoints( e1UHS, e2UHS, out z1, out z2 ); // XXX - Do we want to do a better job worrying about rotation here? // (multiply by complex number with certain imaginary part as well) //Vector3D z3 = ( z1 + z2 ) / 2; //if( Infinity.IsInfinite( z3 ) ) // z3 = new Vector3D( 1, 0 ); Vector3D z3 = new Vector3D( Math.E, Math.PI ); // This should vary the rotations a bunch. // Find the Mobius we need. // We'll do this in two steps. // (1) Find a mobius taking z1,z2 to origin,inf // (2) Deal with scaling e1 to a height of 1. Mobius m1 = new Mobius( z1, z3, z2 ); Vector3D e1UHS_transformed = m1.ApplyToQuaternion( e1UHS ); double scale = 1.0 / e1UHS_transformed.Z; Mobius m2 = Mobius.Scale( scale ); Mobius m = m2 * m1; // Compose them (multiply in reverse order). Vector3D e2UHS_transformed = m.ApplyToQuaternion( e2UHS ); // Make our truncated cone. // For regular tilings, we really would only need to do this once for a given LOD. List<Vector3D> points = new List<Vector3D>(); double logHeight = Math.Log( e2UHS_transformed.Z ); if( logHeight < 0 ) throw new System.Exception( "impl issue" ); int div1, div2; H3Models.Ball.LOD_Finite( e1, e2, out div1, out div2, settings ); double increment = logHeight / div1; for( int i=0; i<=div1; i++ ) { double h = increment * i; // This is to keep different bananas from sharing exactly coincident vertices. double tinyOffset = 0.001; if( i == 0 ) h -= tinyOffset; if( i == div1 ) h += tinyOffset; Vector3D point = new Vector3D( 0, 0, Math.Exp( h ) ); points.Add( point ); } Shapeways tempMesh = new Shapeways(); tempMesh.Div = div2; tempMesh.AddCurve( points.ToArray(), v => H3Models.UHS.SizeFunc( v, settings.AngularThickness ) ); // Unwind the transforms. TakePointsBack( tempMesh.Mesh, m.Inverse(), settings ); mesh.Mesh.Triangles.AddRange( tempMesh.Mesh.Triangles ); }
/// <summary> /// Helper to apply a Mobius to the ball model. /// Vector is taken to UHS, mobius applied, then taken back. /// </summary> public static Vector3D ApplyMobius( Mobius m, Vector3D v ) { v = BallToUHS( v ); v = m.ApplyToQuaternion( v ); return UHSToBall( v ); }
/// <summary> /// A helper for adding a sphere. center should be passed in the ball model. /// The approach is similar to how we do the bananas below. /// </summary> public static void AddSphere( Shapeways mesh, Vector3D center, H3.Settings settings ) { Vector3D centerUHS = H3Models.BallToUHS( center ); // Find the Mobius we need. // We'll do this in two steps. // (1) Find a mobius taking center to (0,0,h). // (2) Deal with scaling to a height of 1. Vector3D flattened = centerUHS; flattened.Z = 0; Mobius m1 = new Mobius( flattened, Complex.One, Infinity.InfinityVector ); Vector3D centerUHS_transformed = m1.ApplyToQuaternion( centerUHS ); double scale = 1.0 / centerUHS_transformed.Z; Mobius m2 = new Mobius( scale, Complex.Zero, Complex.Zero, Complex.One ); Mobius m = m2 * m1; // Compose them (multiply in reverse order). // Add the sphere at the Ball origin. // It will *always* be generated with the same radius. Shapeways tempMesh = new Shapeways(); tempMesh.AddSphere( new Vector3D(), H3Models.Ball.SizeFunc( new Vector3D(), settings.AngularThickness ) ); // Unwind the transforms. for( int i=0; i<tempMesh.Mesh.Triangles.Count; i++ ) { tempMesh.Mesh.Triangles[i] = new Mesh.Triangle( H3Models.BallToUHS( tempMesh.Mesh.Triangles[i].a ), H3Models.BallToUHS( tempMesh.Mesh.Triangles[i].b ), H3Models.BallToUHS( tempMesh.Mesh.Triangles[i].c ) ); } Banana.TakePointsBack( tempMesh.Mesh, m.Inverse(), settings ); mesh.Mesh.Triangles.AddRange( tempMesh.Mesh.Triangles ); }
internal static void TakePointsBack( Mesh mesh, Mobius m, H3.Settings settings ) { for( int i=0; i<mesh.Triangles.Count; i++ ) { mesh.Triangles[i] = new Mesh.Triangle( m.ApplyToQuaternion( mesh.Triangles[i].a ), m.ApplyToQuaternion( mesh.Triangles[i].b ), m.ApplyToQuaternion( mesh.Triangles[i].c ) ); /*if( Infinity.IsInfinite( mesh.Triangles[i].a ) || Infinity.IsInfinite( mesh.Triangles[i].b ) || Infinity.IsInfinite( mesh.Triangles[i].c ) ) System.Diagnostics.Debugger.Break();*/ } // Take all points back to Ball, if needed. if( !settings.Halfspace ) { for( int i=0; i<mesh.Triangles.Count; i++ ) { mesh.Triangles[i] = new Mesh.Triangle( H3Models.UHSToBall( mesh.Triangles[i].a ), H3Models.UHSToBall( mesh.Triangles[i].b ), H3Models.UHSToBall( mesh.Triangles[i].c ) ); } } }