public MapPoints ( System.Numerics.Complex z1, System.Numerics.Complex z2, System.Numerics.Complex z3 ) : void | ||
z1 | System.Numerics.Complex | |
z2 | System.Numerics.Complex | |
z3 | System.Numerics.Complex | |
Результат | void |
/// <summary> /// This transform will map the z points to the respective w points. /// </summary> public void MapPoints(Complex z1, Complex z2, Complex z3, Complex w1, Complex w2, Complex w3) { Mobius m1 = new Mobius(), m2 = new Mobius(); m1.MapPoints(z1, z2, z3); m2.MapPoints(w1, w2, w3); this = m2.Inverse() * m1; }
private void CalculateFromTwoPolygonsInternal(Polygon home, Polygon boundary, CircleNE homeVertexCircle, Geometry g) { // ZZZ - We have to use the boundary, but that can be projected to infinity for some of the spherical tilings. // Trying to use the Drawn tile produced weird (yet interesting) results. Polygon poly1 = boundary; Polygon poly2 = home; if (poly1.Segments.Count < 3 || poly2.Segments.Count < 3) // Poor poor digons. { Debug.Assert(false); return; } // Same? Vector3D p1 = poly1.Segments[0].P1, p2 = poly1.Segments[1].P1, p3 = poly1.Segments[2].P1; Vector3D w1 = poly2.Segments[0].P1, w2 = poly2.Segments[1].P1, w3 = poly2.Segments[2].P1; if (p1 == w1 && p2 == w2 && p3 == w3) { this.Mobius = Mobius.Identity(); return; } Mobius m = new Mobius(); m.MapPoints(p1, p2, p3, w1, w2, w3); this.Mobius = m; // Worry about reflections as well. if (g == Geometry.Spherical) { // If inverted matches the orientation, we need a reflection. bool inverted = poly1.IsInverted; if (!(inverted ^ poly1.Orientation)) { this.Reflection = homeVertexCircle; } } else { if (!poly1.Orientation) { this.Reflection = homeVertexCircle; } } // Some testing. Vector3D test = this.Apply(boundary.Center); if (test != home.Center) { // ZZZ: What is happening here is that the mobius can project a point to infinity before the reflection brings it back to the origin. // It hasn't been much of a problem in practice yet, but will probably need fixing at some point. //Trace.WriteLine( "oh no!" ); } }
/// <summary> /// Does a circle inversion in an arbitrary, generalized circle. /// IOW, the three points may be collinear, in which case we are talking about a reflection. /// </summary> private void CacheCircleInversion(Complex c1, Complex c2, Complex c3) { Mobius toUnitCircle = new Mobius(); toUnitCircle.MapPoints( c1, c2, c3, new Complex(1, 0), new Complex(-1, 0), new Complex(0, 1)); m_cache1 = toUnitCircle; m_cache2 = m_cache1.Inverse(); }
/// <summary> /// Composition operator. /// </summary>> public static Isometry operator *(Isometry i1, Isometry i2) { // ZZZ - Probably a better way. // We'll just apply both isometries to a canonical set of points, // Then calc which isometry makes that. Complex p1 = new Complex(1, 0); Complex p2 = new Complex(-1, 0); Complex p3 = new Complex(0, 1); Complex w1 = p1, w2 = p2, w3 = p3; // Compose (apply in reverse order). w1 = i2.Apply(w1); w2 = i2.Apply(w2); w3 = i2.Apply(w3); w1 = i1.Apply(w1); w2 = i1.Apply(w2); w3 = i1.Apply(w3); Mobius m = new Mobius(); m.MapPoints(p1, p2, p3, w1, w2, w3); Isometry result = new Isometry(); result.Mobius = m; // Need to reflect at end? bool r1 = i1.Reflection != null; bool r2 = i2.Reflection != null; if (r1 ^ r2) // One and only one reflection. { result.Reflection = new Circle( Vector3D.FromComplex(w1), Vector3D.FromComplex(w2), Vector3D.FromComplex(w3)); } return(result); }
/// <summary> /// This transform will map the z points to the respective w points. /// </summary> public void MapPoints( Complex z1, Complex z2, Complex z3, Complex w1, Complex w2, Complex w3 ) { Mobius m1 = new Mobius(), m2 = new Mobius(); m1.MapPoints( z1, z2, z3 ); m2.MapPoints( w1, w2, w3 ); this = m2.Inverse() * m1; }
private static void AddSymmetryTriangles( Mesh mesh, Tiling tiling, Polygon boundary ) { // Assume template centered at the origin. Polygon template = tiling.Tiles.First().Boundary; List<Triangle> templateTris = new List<Triangle>(); foreach( Segment seg in template.Segments ) { int num = 1 + (int)(seg.Length * m_divisions); Vector3D a = new Vector3D(); Vector3D b = seg.P1; Vector3D c = seg.Midpoint; Vector3D centroid = ( a + b + c ) / 3; Polygon poly = new Polygon(); Segment segA = Segment.Line( new Vector3D(), seg.P1 ); Segment segB = seg.Clone(); segB.P2 = seg.Midpoint; Segment segC = Segment.Line( seg.Midpoint, new Vector3D() ); poly.Segments.Add( segA ); poly.Segments.Add( segB ); poly.Segments.Add( segC ); Vector3D[] coords = TextureHelper.TextureCoords( poly, Geometry.Hyperbolic ); int[] elements = TextureHelper.TextureElements( 3, LOD: 3 ); for( int i = 0; i < elements.Length / 3; i++ ) { int idx1 = i * 3; int idx2 = i * 3 + 1; int idx3 = i * 3 + 2; Vector3D v1 = coords[elements[idx1]]; Vector3D v2 = coords[elements[idx2]]; Vector3D v3 = coords[elements[idx3]]; templateTris.Add( new Triangle( v1, v2, v3 ) ); } /* // Need to shrink a little, so we won't // get intersections among neighboring faces. a = Shrink( a, centroid ); b = Shrink( b, centroid ); c = Shrink( c, centroid ); Vector3D[] list = seg.Subdivide( num * 2 ); list[0] = b; list[list.Length / 2] = c; for( int i = 0; i < list.Length / 2; i++ ) templateTris.Add( new Triangle( centroid, list[i], list[i + 1] ) ); for( int i = num - 1; i >= 0; i-- ) templateTris.Add( new Triangle( centroid, a + (c - a) * (i + 1) / num, a + (c - a) * i / num ) ); for( int i = 0; i < num; i++ ) templateTris.Add( new Triangle( centroid, a + (b - a) * i / num, a + (b - a) * (i + 1) / num ) ); */ } foreach( Tile tile in tiling.Tiles ) { Vector3D a = tile.Boundary.Segments[0].P1; Vector3D b = tile.Boundary.Segments[1].P1; Vector3D c = tile.Boundary.Segments[2].P1; Mobius m = new Mobius(); if( tile.Isometry.Reflected ) m.MapPoints( template.Segments[0].P1, template.Segments[1].P1, template.Segments[2].P1, c, b, a ); else m.MapPoints( template.Segments[0].P1, template.Segments[1].P1, template.Segments[2].P1, a, b, c ); foreach( Triangle tri in templateTris ) { Triangle transformed = new Triangle( m.Apply( tri.a ), m.Apply( tri.b ), m.Apply( tri.c ) ); CheckAndAdd( mesh, transformed, boundary ); } } }
/// <summary> /// Composition operator. /// </summary>> public static Isometry operator *( Isometry i1, Isometry i2 ) { // ZZZ - Probably a better way. // We'll just apply both isometries to a canonical set of points, // Then calc which isometry makes that. Complex p1 = new Complex( 1, 0 ); Complex p2 = new Complex( -1, 0 ); Complex p3 = new Complex( 0, 1 ); Complex w1 = p1, w2 = p2, w3 = p3; // Compose (apply in reverse order). w1 = i2.Apply( w1 ); w2 = i2.Apply( w2 ); w3 = i2.Apply( w3 ); w1 = i1.Apply( w1 ); w2 = i1.Apply( w2 ); w3 = i1.Apply( w3 ); Mobius m = new Mobius(); m.MapPoints( p1, p2, p3, w1, w2, w3 ); Isometry result = new Isometry(); result.Mobius = m; // Need to reflect at end? bool r1 = i1.Reflection != null; bool r2 = i2.Reflection != null; if( r1 ^ r2 ) // One and only one reflection. { result.Reflection = new Circle( Vector3D.FromComplex( w1 ), Vector3D.FromComplex( w2 ), Vector3D.FromComplex( w3 ) ); } return result; }
private void CalculateFromTwoPolygonsInternal( Polygon home, Polygon boundary, CircleNE homeVertexCircle, Geometry g ) { // ZZZ - We have to use the boundary, but that can be projected to infinity for some of the spherical tilings. // Trying to use the Drawn tile produced weird (yet interesting) results. Polygon poly1 = boundary; Polygon poly2 = home; if( poly1.Segments.Count < 3 || poly2.Segments.Count < 3 ) // Poor poor digons. { Debug.Assert( false ); return; } // Same? Vector3D p1 = poly1.Segments[0].P1, p2 = poly1.Segments[1].P1, p3 = poly1.Segments[2].P1; Vector3D w1 = poly2.Segments[0].P1, w2 = poly2.Segments[1].P1, w3 = poly2.Segments[2].P1; if( p1 == w1 && p2 == w2 && p3 == w3 ) { this.Mobius = Mobius.Identity(); return; } Mobius m = new Mobius(); m.MapPoints( p1, p2, p3, w1, w2, w3 ); this.Mobius = m; // Worry about reflections as well. if( g == Geometry.Spherical ) { // If inverted matches the orientation, we need a reflection. bool inverted = poly1.IsInverted; if( !(inverted ^ poly1.Orientation) ) this.Reflection = homeVertexCircle; } else { if( !poly1.Orientation ) this.Reflection = homeVertexCircle; } // Some testing. Vector3D test = this.Apply( boundary.Center ); if( test != home.Center ) { // ZZZ: What is happening here is that the mobius can project a point to infinity before the reflection brings it back to the origin. // It hasn't been much of a problem in practice yet, but will probably need fixing at some point. //Trace.WriteLine( "oh no!" ); } }
/// <summary> /// Does a circle inversion in an arbitrary, generalized circle. /// IOW, the three points may be collinear, in which case we are talking about a reflection. /// </summary> private void CacheCircleInversion( Complex c1, Complex c2, Complex c3 ) { Mobius toUnitCircle = new Mobius(); toUnitCircle.MapPoints( c1, c2, c3, new Complex( 1, 0 ), new Complex( -1, 0 ), new Complex( 0, 1 ) ); m_cache1 = toUnitCircle; m_cache2 = m_cache1.Inverse(); }
/// <summary> /// Using this to move the view around in interesting ways. /// </summary> private Vector3D ApplyTransformation( Vector3D v, double t = 0.0 ) { //v.RotateXY( Math.PI / 4 + 0.01 ); bool applyNone = true; if( applyNone ) return v; Mobius m0 = new Mobius(), m1 = new Mobius(), m2 = new Mobius(), m3 = new Mobius(); Sphere unitSphere = new Sphere(); // self-similar scale for 437 //v*= 4.259171776329806; double s = 6.5; v *= s; v += new Vector3D( s/3, -s/3 ); v = unitSphere.ReflectPoint( v ); v.RotateXY( Math.PI/6 ); //v /= 3; //v.RotateXY( Math.PI ); //v.RotateXY( Math.PI/2 ); return v; //v.Y = v.Y / Math.Cos( Math.PI / 6 ); // 637 repeatable //return v; // 12,12,12 m0.Isometry( Geometry.Hyperbolic, 0, new Complex( .0, .0 ) ); m1 = Mobius.Identity(); m2 = Mobius.Identity(); m3 = Mobius.Identity(); v = (m0 * m1 * m2 * m3).Apply( v ); return v; // i64 m0.Isometry( Geometry.Hyperbolic, 0, new Complex( .5, .5 ) ); m1.UpperHalfPlane(); m2 = Mobius.Scale( 1.333333 ); m3.Isometry( Geometry.Euclidean, 0, new Vector3D( 0, -1.1 ) ); v = (m1 * m2 * m3).Apply( v ); return v; // 464 // NOTE: Also, don't apply rotations during simplex generation. m1.UpperHalfPlane(); m2 = Mobius.Scale( 1.3 ); m3.Isometry( Geometry.Euclidean, 0, new Vector3D( 1.55, -1.1 ) ); v = ( m1 * m2 * m3 ).Apply( v ); return v; // iii m1.Isometry( Geometry.Hyperbolic, 0, new Complex( 0, Math.Sqrt( 2 ) - 1 ) ); m2.Isometry( Geometry.Euclidean, -Math.PI / 4, 0 ); m3 = Mobius.Scale( 5 ); //v = ( m1 * m2 * m3 ).Apply( v ); // Vertical Line /*v = unitSphere.ReflectPoint( v ); m1.MapPoints( new Vector3D(-1,0), new Vector3D(), new Vector3D( 1, 0 ) ); m2 = Mobius.Scale( .5 ); v = (m1*m2).Apply( v ); */ /* m1 = Mobius.Scale( 0.175 ); v = unitSphere.ReflectPoint( v ); v = m1.Apply( v ); * */ // Inversion //v = unitSphere.ReflectPoint( v ); //return v; /*Mobius m1 = new Mobius(), m2 = new Mobius(), m3 = new Mobius(); m1.Isometry( Geometry.Spherical, 0, new Complex( 0, 1 ) ); m2.Isometry( Geometry.Euclidean, 0, new Complex( 0, -1 ) ); m3 = Mobius.Scale( 0.5 ); v = (m1 * m3 * m2).Apply( v );*/ //Mobius m = new Mobius(); //m.Isometry( Geometry.Hyperbolic, 0, new Complex( -0.88, 0 ) ); //m.Isometry( Geometry.Hyperbolic, 0, new Complex( 0, Math.Sqrt(2) - 1 ) ); //m = Mobius.Scale( 0.17 ); //m.Isometry( Geometry.Spherical, 0, new Complex( 0, 3.0 ) ); //v = m.Apply( v ); // 63i, 73i m1 = Mobius.Scale( 6.0 ); // Scale {3,i} to unit disk. m1 = Mobius.Scale( 1.0 / 0.14062592996431983 ); // 73i (constant is abs of midpoint of {3,7} tiling, if we want to calc later for other tilings). m2.MapPoints( Infinity.InfinityVector, new Vector3D( 1, 0 ), new Vector3D() ); // swap interior/exterior m3.UpperHalfPlane(); v *= 2.9; // iii /*m1.MapPoints( new Vector3D(), new Vector3D(1,0), new Vector3D( Math.Sqrt( 2 ) - 1, 0 ) ); m2.Isometry( Geometry.Euclidean, -Math.PI / 4, 0 ); m3 = Mobius.Scale( 0.75 );*/ Mobius m = m3 * m2 * m1; v = m.Inverse().Apply( v ); // Strange that we have to do inverse here. return v; }