public static H3.Cell[] CalcCells2( Sphere[] mirrors, H3.Cell[] cells, Settings settings ) { HashSet<Vector3D> completedCellIds = new HashSet<Vector3D>( cells.Select( c => c.ID ).ToArray() ); List<H3.Cell> completedCells = new List<H3.Cell>( cells ); ReflectCellsRecursive2( mirrors, cells, settings, completedCells, completedCellIds ); return completedCells.ToArray(); }
public static void GenImage() { int size = 1000; Bitmap image = new Bitmap( size, size ); ImageSpace i = new ImageSpace( size, size ); double b = 1.1; i.XMin = -b; i.XMax = b; i.YMin = -b; i.YMax = b; Vector3D cen = HoneycombPaper.CellCenBall; cen = H3Models.BallToUHS( cen ); Sphere[] simplex = Simplex( ref cen ); Sphere inSphere = InSphere( simplex ); using( Graphics g = Graphics.FromImage( image ) ) foreach( int[] reflections in AllCells() ) { Sphere clone = inSphere.Clone(); foreach( int r in reflections ) clone.Reflect( simplex[r] ); Sphere ball = new Sphere(); Circle3D inSphereIdealBall = ball.Intersection( clone ); Circle3D inSphereIdealUHS = H3Models.BallToUHS( inSphereIdealBall ); Circle inSphereIdeal = new Circle { Center = inSphereIdealUHS.Center, Radius = inSphereIdealUHS.Radius }; using( Brush brush = new SolidBrush( Color.Blue ) ) DrawUtils.DrawFilledCircle( inSphereIdeal, g, i, brush ); } image.Save( "threefifty.png", ImageFormat.Png ); }
private static void ReflectEdgesRecursive( Sphere[] mirrors, Quad[] quads, List<Quad> allQuads, HashSet<Vector3D> completed ) { if( 0 == quads.Length ) return; List<Quad> newQuads = new List<Quad>(); foreach( Quad quad in quads ) //foreach( Sphere mirror in mirrors ) { Sphere mirror = mirrors[3]; Quad newQuad = quad.Clone(); for( int i = 0; i < newQuad.Verts.Length; i++ ) newQuad.Verts[i] = mirror.ReflectPoint( newQuad.Verts[i] ); if( completed.Add( newQuad.ID ) ) { // Haven't seen this yet, so // we'll need to recurse on it. allQuads.Add( newQuad ); newQuads.Add( newQuad ); } } //ReflectEdgesRecursive( mirrors, newQuads.ToArray(), allQuads, completed ); }
public static void AppendSimplex( Sphere[] facets, Vector3D interiorPoint, int[] include, string fileName ) { using( StreamWriter sw = File.AppendText( fileName ) ) { sw.WriteLine( SimplexFacets( facets, interiorPoint, include ) ); } }
/// <summary> /// Append facets to the end of an existing povray file. /// </summary> public static void AppendFacets( Sphere[] facets, string fileName ) { using( StreamWriter sw = File.AppendText( fileName ) ) { foreach( Sphere sphere in facets ) sw.WriteLine( H3Facet( sphere ) ); } }
/// <summary> /// A version for the fundamental simplex. /// </summary> public static void CreateSimplex( Sphere[] facets, string fileName ) { using( StreamWriter sw = File.CreateText( fileName ) ) { Vector3D dummy = new Vector3D(); sw.WriteLine( SimplexFacets( facets, dummy, new int[] { 0, 1, 2, 3 } ) ); } }
private static Quad[] CalcQuads( Sphere[] mirrors, Quad start ) { List<Quad> allQuads = new List<Quad>(); allQuads.Add( start ); HashSet<Vector3D> completed = new HashSet<Vector3D>( new Vector3D[] { start.ID } ); ReflectEdgesRecursive( mirrors, new Quad[] { start }, allQuads, completed ); return allQuads.ToArray(); }
private static H3.Cell[] GenTruss( Sphere[] simplex, Mesh mesh, Vector3D cen, bool ball ) { // We don't want to include the first mirror (which reflects across cells). Sphere[] mirrors = simplex.Skip( 1 ).ToArray(); Sphere[] allMirrors = simplex.ToArray(); // Simplices will be the "cells" in Recurse.CalcCells. H3.Cell.Facet[] simplexFacets = simplex.Select( m => new H3.Cell.Facet( m ) ).ToArray(); H3.Cell startingCell = new H3.Cell( simplexFacets ); startingCell.Center = cen; //FCOrient( startingCell ); //return null; startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. H3.Cell[] simplices = Recurse.CalcCells( mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball } ); //H3.Cell[] simplices = new H3.Cell[] { startingCell }; // Subsets //return simplices.Where( s => s.Depths[0] == 1 ).ToArray(); //return simplices.ToArray(); List<H3.Cell> final = new List<H3.Cell>(); final.AddRange( simplices ); // Add in other truss cells. Recurse.Settings settings = new Recurse.Settings(); foreach( int[] reflections in TrussReflections() ) foreach( H3.Cell c in simplices ) { H3.Cell clone = c.Clone(); foreach( int r in reflections ) clone.Reflect( allMirrors[r] ); if( Recurse.CellOk( clone, settings ) ) final.Add( clone ); } return final.ToArray(); }
private static string SimplexFacets( Sphere[] facets, Vector3D interiorPoint, int[] include ) { StringBuilder sb = new StringBuilder(); foreach( int idx in include ) { Sphere facet = facets[idx]; bool invert = CheckForInvert( facet, interiorPoint ); sb.Append( string.Format( "{0} material {{ sphereMat2 }} clipped_by {{ ball }}", FormatSphereNoMaterial( facet, invert, false ) ) ); Sphere[] others = facets.Except( new Sphere[] { facet } ).ToArray(); foreach( Sphere otherFacet in others ) { invert = CheckForInvert( otherFacet, interiorPoint ); sb.Append( string.Format( " clipped_by {{ {0} }}", FormatSphereNoMaterial( otherFacet, invert ) ) ); } sb.Append( " }" ); } return sb.ToString(); }
public static Sphere Plane( Vector3D offset, Vector3D normal ) { Sphere result = new Sphere(); result.Center = normal; result.Offset = offset; result.Radius = double.PositiveInfinity; return result; }
public static Edge[] CalcEdges( Sphere[] simplex, Edge[] edges, Settings settings ) { HashSet<Edge> completedEdges = new HashSet<Edge>( edges, new H3.Cell.EdgeEqualityComparer() ); ReflectEdgesRecursive( simplex, completedEdges.ToArray(), settings, completedEdges ); return completedEdges.ToArray(); }
public static void RotateSphere( Sphere s, Vector3D axis, double rotation ) { if( s.IsPlane ) { Vector3D o = s.Offset; o.RotateAboutAxis( axis, rotation ); s.Offset = o; } Vector3D c = s.Center; c.RotateAboutAxis( axis, rotation ); s.Center = c; }
private static void ReflectEdgesRecursive( Sphere[] simplex, Edge[] edges, Settings settings, HashSet<Edge> completedEdges ) { if( 0 == edges.Length ) return; HashSet<Edge> newEdges = new HashSet<Edge>( new H3.Cell.EdgeEqualityComparer() ); foreach( Edge edge in edges ) //foreach( Sphere mirror in simplex ) for( int m=0; m<simplex.Length; m++ ) { Sphere mirror = simplex[m]; if( completedEdges.Count > settings.MaxEdges ) throw new System.Exception( "Maxing out edges - will result in uneven filling." ); Vector3D r1 = mirror.ReflectPoint( edge.Start ); Vector3D r2 = mirror.ReflectPoint( edge.End ); Edge newEdge = new Edge( r1, r2 ); newEdge.CopyDepthsFrom( edge ); if( !EdgeOk( newEdge, settings ) ) continue; // This tracks reflections across the cell facets. newEdge.Depths[m]++; // Edge color. // Make the threshold length black, or the background color. double percentWhite = ( r1.Dist( r2 ) - settings.Threshold ) / 0.015; if( percentWhite < 0 ) percentWhite = 0; if( percentWhite > 1 ) percentWhite = 1; //newEdge.Color = new Vector3D( percentWhite, percentWhite, percentWhite ); newEdge.Color = m_background; newEdge.Color.Z = 0.1 + 0.9 * percentWhite; if( completedEdges.Add( newEdge ) ) { // Haven't seen this edge yet, so // we'll need to recurse on it. newEdges.Add( newEdge ); } } ReflectEdgesRecursive( simplex, newEdges.ToArray(), settings, completedEdges ); }
private static void ReflectCellsRecursive( Sphere[] simplex, H3.Cell[] cells, Settings settings, List<H3.Cell> completedCells, HashSet<Vector3D> completedCellIds ) { if( 0 == cells.Length ) return; List<H3.Cell> newCells = new List<H3.Cell>(); foreach( H3.Cell cell in cells ) //foreach( Sphere mirror in simplex ) for( int m=0; m<simplex.Length; m++ ) { Sphere mirror = simplex[m]; //if( m == 2 ) // continue; //if( completedCellIds.Count > 1000 ) // return; //if( completedCellIds.Count > settings.MaxEdges/5 ) if( completedCellIds.Count > settings.MaxEdges / 20 ) throw new System.Exception( "Maxing out cells - will result in uneven filling." ); H3.Cell newCell = cell.Clone(); newCell.Reflect( mirror ); if( !CellOk( newCell, settings ) ) continue; // This tracks reflections across the cell facets. newCell.Depths[m]++; if( completedCellIds.Add( newCell.ID ) ) { // Haven't seen this cell yet, so // we'll need to recurse on it. newCells.Add( newCell ); completedCells.Add( newCell ); } } ReflectCellsRecursive( simplex, newCells.ToArray(), settings, completedCells, completedCellIds ); }
/// <summary> /// Attempts to calculate approx 1.3M edges when the threshold is a minimum edge length. /// This is required for honeycombs with ideal or ultra-ideal cells /// </summary> public static Edge[] CalcEdgesSmart2( Sphere[] simplex, Edge[] edges ) { Settings s = new Settings(); // I found that log(1/thresh)/log(count) was relatively constant, // so we'll extrapolate that to get close to the right number of edges. double OneOverThresh = 60; s.Threshold = 1 / OneOverThresh; Edge[] result = CalcEdges( simplex, edges, s ); int count1 = result.Length; OneOverThresh = 80; s.Threshold = 1 / OneOverThresh; result = CalcEdges( simplex, edges, s ); int count2 = result.Length; double slope = ( Math.Log( count2 ) - Math.Log( count1 ) ) / ( Math.Log( 80 ) - Math.Log( 60 ) ); // Why 1.3M? We'll get 650k after we half this. double desiredCount = 2e6; //double desiredCount = 3e4; // For testing double logDesiredCount = Math.Log( desiredCount ); double temp = Math.Log( 80 ) + ( logDesiredCount - Math.Log( count2 ) ) / slope; s.Threshold = 1 / Math.Exp( temp ); return CalcEdges( simplex, edges, s ); }
public static void ScaleSphere( Sphere s, double factor ) { if( s.IsPlane ) s.Offset *= factor; s.Center *= factor; s.Radius *= factor; }
/// <summary> /// Finds the intersection (a circle) between us and another sphere. /// Returns null if sphere centers are coincident or no intersection exists. /// Does not currently work for planes. /// </summary> public Circle3D Intersection( Sphere s ) { if( this.IsPlane || s.IsPlane ) throw new System.NotImplementedException(); double r = s.Radius; double R = this.Radius; Vector3D diff = this.Center - s.Center; double d = diff.Abs(); if( Tolerance.Zero( d ) || d > r + R ) return null; double x = ( d*d + r*r - R*R ) / ( 2*d ); double y = Math.Sqrt( r*r - x*x ); Circle3D result = new Circle3D(); diff.Normalize(); result.Normal = diff; result.Center = s.Center + diff * x; result.Radius = y; return result; }
/// <summary> /// Reflect ourselves about another sphere. /// </summary> public void Reflect( Sphere sphere ) { // An interior point used to calculate whether we get inverted. Vector3D interiorPoint; if( IsPlane ) { Debug.Assert( !this.Normal.IsOrigin ); interiorPoint = -this.Normal; } else { // We don't want it to be the center, because that will reflect to infinity. interiorPoint = ( this.Center + new Vector3D( this.Radius / 2, 0 ) ); } if( Invert ) interiorPoint = ReflectPoint( interiorPoint ); Debug.Assert( IsPointInside( interiorPoint ) ); interiorPoint = sphere.ReflectPoint( interiorPoint ); Debug.Assert( !interiorPoint.DNE ); if( this.Equals( sphere ) ) { if( IsPlane ) { //this.Center = -this.Center; // Same as inverting, but we need to do it this way because of Pov-Ray this.Invert = !this.Invert; } else this.Invert = !this.Invert; Debug.Assert( this.IsPointInside( interiorPoint ) ); return; } // Both planes? if( IsPlane && sphere.IsPlane ) { // XXX - not general, but I know the planes I'll be dealing with go through the origin. //if( !sphere.Offset.IsOrigin ) // throw new System.NotImplementedException(); /*Vector3D p1 = this.Normal.Cross( sphere.Normal ); if( !p1.Normalize() ) { this.Center *= -1; return; } Vector3D p2 = p1.Cross( this.Normal ); p2.Normalize(); p1 = sphere.ReflectPoint( p1 ); p2 = sphere.ReflectPoint( p2 ); Vector3D newNormal = p2.Cross( p1 ); if( !newNormal.Normalize() ) throw new System.Exception( "Reflection impl" ); this.Center = newNormal;*/ // Reflect the normal relative to the plane (conjugate with sphere.Offset). Vector3D newNormal = this.Normal + sphere.Offset; newNormal = sphere.ReflectPoint( newNormal ); newNormal -= sphere.Offset; newNormal.Normalize(); this.Center = newNormal; // Calc the new offset (so far we have considered planes through origin). this.Offset = sphere.ReflectPoint( this.Offset ); //Debug.Assert( Offset.IsOrigin ); // XXX - should handle more generality. Debug.Assert( this.IsPointInside( interiorPoint ) ); return; } // We are a plane and reflecting in a sphere. if( IsPlane ) { // Think of 2D case here (circle and line)... Vector3D projected = Euclidean3D.ProjectOntoPlane( this.Normal, this.Offset, sphere.Center ); Vector3D p = sphere.ReflectPoint( projected ); if( Infinity.IsInfinite( p ) ) { // This can happen if we go through sphere.Center. // This reflection does not change our orientation (does not invert us). return; } Center = sphere.Center + ( p - sphere.Center ) / 2; Radius = Center.Dist( sphere.Center ); // Did this invert us? if( !this.IsPointInside( interiorPoint ) ) Invert = !Invert; return; } // Is mirror a plane? if( sphere.IsPlane ) { Vector3D projected = Euclidean3D.ProjectOntoPlane( sphere.Normal, sphere.Offset, Center ); Vector3D diff = Center - projected; Center -= 2 * diff; // Radius remains unchanged. // NOTE: This does not invert us. Debug.Assert( this.IsPointInside( interiorPoint ) ); return; } // // Now sphere reflecting in a sphere. // // Reflecting to a plane? if( IsPointOn( sphere.Center ) ) { // Concentric spheres? if( Center == sphere.Center ) throw new System.Exception(); // Center Vector3D center = Center - sphere.Center; // Offset Vector3D direction = center; direction.Normalize(); Vector3D offset = direction * Radius * 2; offset = sphere.ReflectPoint( offset ); // We are a line now. Center = center; //Offset = offset; // Not working?? Caused issues in old generation code for 435. Radius = double.PositiveInfinity; // Did this invert us? if( !this.IsPointInside( interiorPoint ) ) this.Invert = !this.Invert; Debug.Assert( this.IsPointInside( interiorPoint ) ); return; } // XXX - Could try to share code below with Circle class. // NOTE: We can't just reflect the center. // See http://mathworld.wolfram.com/Inversion.html double a = Radius; double k = sphere.Radius; Vector3D v = Center - sphere.Center; double s = k * k / ( v.MagSquared() - a * a ); Center = sphere.Center + v * s; Radius = Math.Abs( s ) * a; // Did this invert us? if( !this.IsPointInside( interiorPoint ) ) Invert = !Invert; }
/// <summary> /// This is like the GenCell method, but super hacked up for the Catacombs image with Henry. /// </summary> internal static void GenCellCatacombs( Sphere[] simplex, bool ball ) { // We don't want to include the first mirror (which reflects across cells). Sphere[] mirrors = simplex.Skip( 1 ).ToArray(); Sphere[] allMirrors = simplex.ToArray(); // Simplices will be the "cells" in Recurse.CalcCells. H3.Cell.Facet[] simplexFacets = simplex.Select( m => new H3.Cell.Facet( m ) ).ToArray(); // Offset cell boundary ever so slightly, to avoid artifacts of adjacent cells. Sphere toReflectLater = simplexFacets[0].Sphere.Clone(); //simplexFacets[0].Sphere = CoxeterImages.GeodesicOffset( simplexFacets[0].Sphere, ball ? -1e-6 : 1e-7, ball ); H3.Cell startingCell = new H3.Cell( simplexFacets ); startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. Vector3D cen = new Vector3D( 0.05, 0.01, -0.05 ); // 373, 438 //Vector3D cen = new Vector3D( 0.05, 0.01, 100 ); // 637 //cen.RotateXY( Math.PI / 2 ); // only if we also rotate simplex mirrors. XXX - make a setting. startingCell.Center = cen; H3.Cell[] simplices = Recurse.CalcCells( mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball } ); List<H3.Cell> simplicesFinal = new List<H3.Cell>(); List<int[]> reflectionSets = new List<int[]>(); // 1 reflects in x-axis // 3, 1 rotates right // 1, 3 rotates left reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 1, 3 } ); reflectionSets.Add( new int[] { 0, 3, 1, 2, 3, 1, 0, 3, 1, 2, 0, 3 } ); // 2 reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 2, 3, 1 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 2, 3, 1 } ); // 3 //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 0, 3, 1, 2 } ); reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 0, 3, 1, 3, 1, 0, 2 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 2 } ); // 5 //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 1, 2, 3, 1 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 2, 3, 1 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 1, 0, 1, 3 } ); // baby //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2 } ); // maybe //reflectionSets.Add( new int[] { 0, 3, 1, 2, 3, 1, 0, 2, 1, 3 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 2, 3, 1, 0, 3, 1, 2 } ); // not great orientation // reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 2 } ); // big bool ceiling = true; if( ceiling ) simplicesFinal = simplices.ToList(); else { foreach( int[] set in reflectionSets ) { List<H3.Cell> copy = simplices.Select( s => s.Clone() ).ToList(); foreach( int r in set ) { foreach( H3.Cell cell in copy ) cell.Reflect( allMirrors[r] ); } simplicesFinal.AddRange( copy ); } } /* // A second cell. //toReflectLater = simplices[45].Facets[0].Sphere.Clone(); //toReflectLater = simplices.First( s => s.Depth == 2 ).Facets[0].Sphere.Clone(); foreach( H3.Cell cell in simplices ) cell.Reflect( toReflectLater ); // A third cell. toReflectLater = simplices[40].Facets[0].Sphere.Clone(); //toReflectLater = simplices.First( s => s.Depth == 4 ).Facets[0].Sphere.Clone(); foreach( H3.Cell cell in simplices ) cell.Reflect( toReflectLater ); foreach( H3.Cell cell in simplices ) cell.Depths = new int[4]; List<H3.Cell> simplicesFinal = Recurse.CalcCells2( mirrors, simplices ).ToList(); simplicesFinal = simplicesFinal.Where( s => s.Depths[0] % 3 == 1 && s.Depths[1] % 2 == 0 && s.Depths[2] % 2 == 1 ).ToList(); */ /* List<H3.Cell> simplicesFinal = new List<H3.Cell>(); //for( int d = 0; d < 1; d+=2 ) int d = 0; { //Sphere toReflect = simplices.First( s => s.Depth == d ).Facets[0].Sphere.Clone(); //Sphere toReflect = simplices.Where( s => s.Depth == d ).Skip(1).Take(1).First().Facets[0].Sphere.Clone(); List<H3.Cell> reflectionCells = simplices.Where( s => s.Depths[1] == d && s.Depths[0] % 2 == 0 ).Skip(0).Take(1).ToList(); foreach( Sphere toReflect in reflectionCells.Select( c => c.Facets[0].Sphere.Clone() ) ) { List<H3.Cell> thisCell = new List<H3.Cell>(); foreach( H3.Cell cell in simplices ) { H3.Cell clone = cell.Clone(); clone.Reflect( toReflect ); thisCell.Add( clone ); } //Sphere toReflect2 = thisCell.First( s => s.Depth1 == d + 3 && s.Depth0 % 2 == 0 ).Facets[0].Sphere.Clone(); //List<H3.Cell> reflectionCellsTemp = simplices.Where( s => Math.Abs( s.Depths[1] - d ) == 2 && s.Depths[0] % 2 == 0 ).ToList(); List<H3.Cell> reflectionCellsTemp = simplices.Where( s => s.Depths[1] == 2 && s.Depths[1] == s.Depths[0] + s.Depths[2] ).ToList(); List<H3.Cell> reflectionCells2 = reflectionCellsTemp;//.Where( ( x, i ) => i % 3 == 0 ).ToList(); // .Skip( 5 ).Take( 5 ).ToList(); foreach( Sphere toReflect2 in reflectionCells2.Select( c => c.Facets[0].Sphere.Clone() ) ) //Sphere toReflect2 = toReflectLater; { foreach( H3.Cell cell in thisCell ) { H3.Cell clone = cell.Clone(); clone.Reflect( toReflect2 ); simplicesFinal.Add( clone ); } } } }*/ int count = 0; foreach( H3.Cell cell in simplicesFinal ) { count++; //if( count % 2 == 0 ) // continue; /*if( count < 1 ) continue; if( count > 30 ) return; */ //int[] include = new int[] { 0, 1, 2, 3 }; int[] include = new int[] { 0 }; PovRay.AppendSimplex( cell.Facets.Select( f => f.Sphere ).ToArray(), cell.Center, include, "cell.pov" ); } }
private static Sphere InSphere( Sphere[] simplex ) { // The point centered on a face is the closest point of the cell mirror to the origin. Vector3D facePoint = simplex[0].ProjectToSurface( new Vector3D() ); // Reflect it to get 3 more points on our insphere. Vector3D reflected1 = simplex[2].ReflectPoint( facePoint ); Vector3D reflected2 = simplex[1].ReflectPoint( reflected1 ); Vector3D reflected3 = simplex[3].ReflectPoint( reflected2 ); Sphere inSphere = Sphere.From4Points( facePoint, reflected1, reflected2, reflected3 ); return inSphere; }
/// <summary> /// This generates a polyhedron using recursion. It needs to be finite /// (There are not any other breakouts of the recursion, other than all facets having been generated.) /// </summary> public static void GenPolyhedron( Sphere[] mirrors, H3.Cell.Facet[] facets, List<H3.Cell.Facet> completedFacets, HashSet<Vector3D> completedFacetIds ) { if( 0 == facets.Length ) return; List<H3.Cell.Facet> newFacets = new List<H3.Cell.Facet>(); foreach( H3.Cell.Facet facet in facets ) foreach( Sphere mirror in mirrors ) { H3.Cell.Facet newFacet = facet.Clone(); newFacet.Reflect( mirror ); if( completedFacetIds.Add( newFacet.ID ) ) { // Haven't seen this facet yet, so // we'll need to recurse on it. newFacets.Add( newFacet ); completedFacets.Add( newFacet ); } } GenPolyhedron( mirrors, newFacets.ToArray(), completedFacets, completedFacetIds ); }
public static string Sphere( Sphere sphere ) { return string.Format( "sphere {{ {0}, {1:G6} material {{ sphereMat }} }}", FormatVec( sphere.Center ), sphere.Radius ); //return string.Format( "sphere {{ {0}, rad material {{ sphereMat }} }}", // FormatVec( sphere.Center ) ); }
private static void ReflectCellsRecursive2( Sphere[] simplex, H3.Cell[] cells, Settings settings, List<H3.Cell> completedCells, HashSet<Vector3D> completedCellIds ) { if( 0 == cells.Length ) return; List<H3.Cell> newCells = new List<H3.Cell>(); foreach( H3.Cell cell in cells ) //foreach( Sphere mirror in simplex ) for( int m = 0; m < simplex.Length; m++ ) { Sphere mirror = simplex[m]; if( completedCellIds.Count > 250000 ) return; H3.Cell newCell = cell.Clone(); newCell.Reflect( mirror ); //if( !CellOk( newCell, settings ) ) bool cellOk = true; foreach( H3.Cell.Facet f in cell.Facets ) if( f.Sphere.Radius < 0.002 ) cellOk = false; if( !cellOk ) continue; // This tracks reflections across the cell facets. newCell.Depths[m]++; if( completedCellIds.Add( newCell.ID ) ) { // Haven't seen this cell yet, so // we'll need to recurse on it. newCells.Add( newCell ); completedCells.Add( newCell ); } } ReflectCellsRecursive2( simplex, newCells.ToArray(), settings, completedCells, completedCellIds ); }
private static bool CheckForInvert( Sphere facet, Vector3D point ) { System.Diagnostics.Debug.Assert( !facet.IsPointInside( point ) ); if( !facet.IsPlane ) { bool invert = !facet.Invert; // This check doesn't seem like it should be here. //if( facet.IsPointInside( point ) ) // invert = !invert; return invert; } else { return !facet.Invert; } }
///////////////////////////////////////////////////////// // Hacking around. I should remove this or make CalcCells() configurable enough to deal with more cases. public static H3.Cell[] CalcCells2( Sphere[] mirrors, H3.Cell[] cells ) { Settings settings = new Settings(); return CalcCells2( mirrors, cells, settings ); }
private static string FormatSphereNoMaterial( Sphere sphere, bool invert, bool includeClosingBracket = true ) { if( sphere.IsPlane ) { Vector3D offsetOnNormal = Euclidean2D.ProjectOntoLine( sphere.Offset, new Vector3D(), sphere.Normal ); double offset = offsetOnNormal.Abs(); if( offsetOnNormal.Dot( sphere.Normal ) < 0 ) offset *= -1; return string.Format( "plane {{ {0}, {1:G6}{2} {3}", FormatVec( sphere.Normal ), offset, invert ? " inverse" : string.Empty, includeClosingBracket ? "}" : string.Empty ); } else { return string.Format( "sphere {{ {0}, {1:G6}{2} {3}", FormatVec( sphere.Center ), sphere.Radius, invert ? " inverse" : string.Empty, includeClosingBracket ? "}" : string.Empty ); } }
public static Edge[] CalcEdges( Sphere[] simplex, Edge[] edges ) { Settings settings = new Settings(); return CalcEdges( simplex, edges, settings ); }
private static string H3Facet( Sphere sphere ) { if( sphere.IsPlane ) { Vector3D offsetOnNormal = Euclidean2D.ProjectOntoLine( sphere.Offset, new Vector3D(), sphere.Normal ); return string.Format( "plane {{ {0}, {1:G6} material {{ sphereMat }} clipped_by {{ ball }} }}", FormatVec( sphere.Normal ), offsetOnNormal.Abs() ); } else { return string.Format( "sphere {{ {0}, {1:G6} material {{ sphereMat }} clipped_by {{ ball }} }}", FormatVec( sphere.Center ), sphere.Radius ); } }
/// <summary> /// Attempts to calculate approx 1.3M edges when the threshold is a distance from origin in the ball model. /// This works for honeycombs with finite cells. /// </summary> public static Edge[] CalcEdgesSmart( Sphere[] simplex, Edge[] edges ) { Settings s = new Settings(); // The number of cells increase exponentially with hyperbolic distance, // so linear on a log scale. // We'll do to test runs to get the line, then run at the extrapolated value. double hDist = 5; s.Threshold = DonHatch.h2eNorm( hDist ); Edge[] result = CalcEdges( simplex, edges, s ); int count1 = result.Length; hDist = 5.5; s.Threshold = DonHatch.h2eNorm( hDist ); result = CalcEdges( simplex, edges, s ); int count2 = result.Length; double slope = ( Math.Log( count2 ) - Math.Log( count1 ) ) / 0.5; // Why 1.3M? We'll get 650k after we half this. double desiredCount = 1.0e4; // for testing //double desiredCount = 1.3e6; //double desiredCount = 0.4e6; // Mid-range double logDesiredCount = Math.Log( desiredCount ); hDist = 5.5 + ( logDesiredCount - Math.Log( count2 ) ) / slope; s.Threshold = DonHatch.h2eNorm( hDist ); return CalcEdges( simplex, edges, s ); }
/// <summary> /// Find the sphere defined by 3 points on the unit sphere, and orthogonal to the unit sphere. /// Returns null if points are not on the unit sphere. /// </summary> public static Sphere OrthogonalSphere( Vector3D b1, Vector3D b2, Vector3D b3 ) { Sphere unitSphere = new Sphere(); if( !unitSphere.IsPointOn( b1 ) || !unitSphere.IsPointOn( b2 ) || !unitSphere.IsPointOn( b3 ) ) return null; Circle3D c = new Circle3D( b1, b2, b3 ); // Same impl as orthogonal circles now. Vector3D center; double radius; OrthogonalCircle( b1, b1 + ( c.Center - b1 ) * 2, out center, out radius ); Sphere sphere = new Sphere(); if( Infinity.IsInfinite( radius ) ) { // Have the center act as a normal. sphere.Center = c.Normal; sphere.Radius = double.PositiveInfinity; } else { sphere.Center = center; sphere.Radius = radius; } return sphere; }