コード例 #1
0
        /// <summary>
        /// This will trim back the tile using an equidistant curve.
        /// It assumes the tile is at the origin.
        /// </summary>
        internal static void ShrinkTile(ref Tile tile, double shrinkFactor)
        {
            // This code is not correct in non-Euclidean cases!
            // But it works reasonable well for small shrink factors.
            // For example, you can easily use this function to grow a hyperbolic tile beyond the disk.
            Mobius m = new Mobius();

            m.Hyperbolic(tile.Geometry, new Vector3D(), shrinkFactor);
            tile.Drawn.Transform(m);
            return;

            /*
             * // ZZZ
             * // Wow, all the work I did below was subsumed by 4 code lines above!
             * // I can't bring myself to delete it yet.
             *
             * switch( tile.Geometry )
             * {
             *      case Geometry.Spherical:
             *      {
             *              List<Tile> clipped = new List<Tile>();
             *              clipped.Add( tile );
             *
             *              Polygon original = tile.Drawn.Clone();
             *              foreach( Segment seg in original.Segments )
             *              {
             *                      Debug.Assert( seg.Type == SegmentType.Arc );
             *
             *                      if( true )
             *                      {
             *                              // Unproject to sphere.
             *                              Vector3D p1 = Spherical2D.PlaneToSphere( seg.P1 );
             *                              Vector3D p2 = Spherical2D.PlaneToSphere( seg.P2 );
             *
             *                              // Get the poles of the GC, and project them to the plane.
             *                              Vector3D pole1, pole2;
             *                              Spherical2D.GreatCirclePole( p1, p2, out pole1, out pole2 );
             *                              pole1 = Spherical2D.SphereToPlane( pole1 );
             *                              pole2 = Spherical2D.SphereToPlane( pole2 );
             *
             *                              // Go hyperbolic, dude.
             *                              double scale = 1.065;	// ZZZ - needs to be configurable.
             *                              Complex fixedPlus = pole1;
             *                              Mobius hyperbolic = new Mobius();
             *                              hyperbolic.Hyperbolic( tile.Geometry, fixedPlus, scale );
             *                              Vector3D newP1 = hyperbolic.Apply( seg.P1 );
             *                              Vector3D newMid = hyperbolic.Apply( seg.Midpoint );
             *                              Vector3D newP2 = hyperbolic.Apply( seg.P2 );
             *
             *                              Circle trimmingCircle = new Circle();
             *                              trimmingCircle.From3Points( newP1, newMid, newP2 );
             *
             *                              Slicer.Clip( ref clipped, trimmingCircle, true );
             *                      }
             *                      else
             *                      {
             *                              // I think this block has logic flaws, but strangely it seems to work,
             *                              // so I'm leaving it in commented out for posterity.
             *
             *                              Vector3D p1 = seg.P1;
             *                              Vector3D mid = seg.Midpoint;
             *                              Vector3D p2 = seg.P2;
             *
             *                              //double offset = .1;
             *                              double factor = .9;
             *                              double f1 = Spherical2D.s2eNorm( (Spherical2D.e2sNorm( p1.Abs() ) * factor) );
             *                              double f2 = Spherical2D.s2eNorm( (Spherical2D.e2sNorm( mid.Abs() ) * factor) );
             *                              double f3 = Spherical2D.s2eNorm( (Spherical2D.e2sNorm( p2.Abs() ) * factor) );
             *                              p1.Normalize();
             *                              mid.Normalize();
             *                              p2.Normalize();
             *                              p1 *= f1;
             *                              mid *= f2;
             *                              p2 *= f3;
             *
             *                              Circle trimmingCircle = new Circle();
             *                              trimmingCircle.From3Points( p1, mid, p2 );
             *
             *                              Slicer.Clip( ref clipped, trimmingCircle, true );
             *                      }
             *              }
             *
             *              Debug.Assert( clipped.Count == 1 );
             *              tile = clipped[0];
             *              return;
             *      }
             *      case Geometry.Euclidean:
             *      {
             *              double scale = .95;
             *
             *              Mobius hyperbolic = new Mobius();
             *              hyperbolic.Hyperbolic( tile.Geometry, new Vector3D(), scale );
             *
             *              tile.Drawn.Transform( hyperbolic );
             *
             *              return;
             *      }
             *      case Geometry.Hyperbolic:
             *      {
             *              List<Tile> clipped = new List<Tile>();
             *              clipped.Add( tile );
             *
             *              Circle infinity = new Circle();
             *              infinity.Radius = 1.0;
             *
             *              Polygon original = tile.Drawn.Clone();
             *              foreach( Segment seg in original.Segments )
             *              {
             *                      Debug.Assert( seg.Type == SegmentType.Arc );
             *                      Circle segCircle = seg.GetCircle();
             *
             *                      // Get the intersection points with the disk at infinity.
             *                      Vector3D p1, p2;
             *                      int count = Euclidean2D.IntersectionCircleCircle( infinity, segCircle, out p1, out p2 );
             *                      Debug.Assert( count == 2 );
             *
             *                      Vector3D mid = seg.Midpoint;
             *                      //mid *= 0.75;	// ZZZ - needs to be configurable.
             *
             *                      double offset = .03;
             *                      double f1 = DonHatch.h2eNorm( DonHatch.e2hNorm( mid.Abs() ) - offset );
             *                      mid.Normalize();
             *                      mid *= f1;
             *
             *                      Circle trimmingCircle = new Circle();
             *                      trimmingCircle.From3Points( p1, mid, p2 );
             *
             *                      Slicer.Clip( ref clipped, trimmingCircle, false );
             *              }
             *
             *              Debug.Assert( clipped.Count == 1 );
             *              tile = clipped[0];
             *              return;
             *      }
             * }
             */
        }
コード例 #2
0
        public static void CatenoidBasedSurface()
        {
            RLD_outputs outputs;

            SurfaceInternal(out outputs);
            double scale = m_params.Scale;

            // Map a point for a given k/m from the hemihypersphere to the complex plane.
            // You can also pass in -1 for k to get a point on the equator of the hemihypersphere.
            double mInc = Math.PI * 2 / m_params.M;
            Func <RLD_outputs, int, int, Vector3D> onPlane = (o, k, m) =>
            {
                double theta = k == -1 ? 0 : outputs.x_i[k];
                theta += Math.PI / 2;
                return
                    (Sterographic.SphereToPlane(
                         SphericalCoords.SphericalToCartesian(
                             new Vector3D(1, theta, m * mInc)
                             )
                         ));
            };

            // Setup texture coords on fundamental triangle.
            // We'll use a fundamental triangle in the southern hemisphere,
            // with stereographically projected coords at (0,0), (1,0), and CCW on the unit circle depending on M.
            Polygon p = new Polygon();

            p.Segments.Add(Segment.Line(new Vector3D(), new Vector3D(1, 0)));
            p.Segments.Add(Segment.Arc(new Vector3D(1, 0), onPlane(outputs, 1, 1), onPlane(outputs, -1, 1)));
            p.Segments.Add(Segment.Line(onPlane(outputs, -1, 1), new Vector3D()));
            int levels = 9;

            TextureHelper.SetLevels(levels);
            Vector3D[] coords         = TextureHelper.TextureCoords(p, Geometry.Spherical, doGeodesicDome: true);
            int[]      elementIndices = TextureHelper.TextureElements(1, levels);

            // Setup a nearTree for the catenoid locations (on the plane).
            NearTree nearTree = new NearTree(Metric.Spherical);

            for (int k = 1; k < outputs.x_i.Length; k++)
            {
                for (int m = 0; m <= 1; m++)
                {
                    Vector3D loc = onPlane(outputs, k, m);
                    nearTree.InsertObject(new NearTreeObject()
                    {
                        ID = k, Location = loc
                    });
                }
            }

            // Given a point on the plane, find the nearest catenoid center and calculate the height of the surface based on that.
            // This also calculates the locking of the point.
            Func <Vector3D, Tuple <double, Vector3D, Vector3D> > heightAndLocking = coord =>
            {
                NearTreeObject closest;
                if (!nearTree.FindNearestNeighbor(out closest, coord, double.MaxValue))
                {
                    throw new System.Exception();
                }

                Vector3D locked = new Vector3D();
                if (p.Segments[0].IsPointOn(coord) ||
                    p.Segments[2].IsPointOn(coord))
                {
                    locked = new Vector3D(1, 1, 0, 0);
                }
                //if( p.Segments[1].IsPointOn( v ) )		// Not working right for some reason, but line below will work.
                if (Tolerance.Equal(coord.Abs(), 1))
                {
                    locked = new Vector3D(1, 1, 1, 0);
                }

                Vector3D vSphere = Sterographic.PlaneToSphere(coord);
                Vector3D cSphere = Sterographic.PlaneToSphere(closest.Location);
                double   dist    = vSphere.AngleTo(cSphere);

                int    k          = (int)closest.ID;
                double waist      = outputs.t_i[k];
                double rld_height = outputs.phi_i[k];

                double h      = waist * 3.5 * 2;                                        // height where catenoid will meet rld_height.
                double factor = scale * rld_height * 2 / h;                             // Artifical scaling so we can see things.
                dist /= factor;

                double z = double.NaN;
                if (dist >= waist)
                {
                    z = waist * DonHatch.acosh(dist / waist);
                }
                else if (dist >= 0.7 * waist)
                {
                    z = 0;

                    // Move the coord to the thinnest waist circle.
                    Mobius m = new Mobius();
                    m.Hyperbolic(Geometry.Spherical, coord.ToComplex(), waist / dist);
                    coord = m.Apply(coord);
                }

                if (dist < waist * 20)
                {
                    locked = new Vector3D(1, 1, 1, 1);
                }

                return(new Tuple <double, Vector3D, Vector3D>(z * factor, locked, coord));
            };

            // Calculate all the coordinates.
            Vector3D[] locks = new Vector3D[coords.Length];
            for (int i = 0; i < coords.Length; i++)
            {
                Vector3D coord = coords[i];
                var      hl    = heightAndLocking(coord);
                locks[i]  = hl.Item2;
                coord     = hl.Item3;
                coords[i] = Normal(Sterographic.PlaneToSphere(coord), (double)hl.Item1);
            }

            // Relax it.
            Relax(coords, elementIndices, locks);

            Mesh   mesh = new Mesh();
            Sphere s    = new Sphere();

            for (int i = 0; i < elementIndices.Length; i += 3)
            {
                Vector3D a = coords[elementIndices[i]];
                Vector3D b = coords[elementIndices[i + 1]];
                Vector3D c = coords[elementIndices[i + 2]];
                if (a.DNE || b.DNE || c.DNE)
                {
                    continue;
                }

                for (int m = 0; m <= 0; m++)
                {
                    mesh.Triangles.Add(new Mesh.Triangle(a, b, c));
                    mesh.Triangles.Add(new Mesh.Triangle(
                                           s.ReflectPoint(a),
                                           s.ReflectPoint(b),
                                           s.ReflectPoint(c)));
                    a.RotateXY(mInc);
                    b.RotateXY(mInc);
                    c.RotateXY(mInc);
                }
            }

            PovRay.WriteMesh(mesh, "RLD.pov");
        }