Class with some hackish methods for dealing with points projected to infinite.
Beispiel #1
0
        /// <summary>
        /// Reflect a point in us.
        /// </summary>
        public Vector3D ReflectPoint(Vector3D p)
        {
            if (IsPlane)
            {
                // We used to call ProjectOntoPlane, but optimized it away.
                // This is faster because we already know our normal is normalized,
                // and it avoids some extra Vector3D operations.
                double   dist   = Euclidean3D.DistancePointPlane(this.Normal, this.Offset, p);
                Vector3D offset = this.Normal * dist * -2;
                return(p + offset);
            }
            else
            {
                if (p == Center)
                {
                    return(Infinity.InfinityVector);
                }
                if (Infinity.IsInfinite(p))
                {
                    return(Center);
                }

                Vector3D v = p - Center;
                double   d = v.Abs();
                v.Normalize();
                return(Center + v * (Radius * Radius / d));
            }
        }
Beispiel #2
0
        public static double GetNormalizedCircumRadius(int p, double q)
        {
            double hypot = GetTriangleHypotenuse(p, q);

            switch (Geometry2D.GetGeometry(p, q))
            {
            case Geometry.Spherical:
                return(Spherical2D.s2eNorm(hypot) * DiskRadius);

            case Geometry.Euclidean:
                return(EuclideanHypotenuse);

            case Geometry.Hyperbolic:
            {
                if (Infinity.IsInfinite(hypot))
                {
                    return(DiskRadius);
                }

                return(DonHatch.h2eNorm(hypot) * DiskRadius);
            }
            }

            Debug.Assert(false);
            return(1);
        }
Beispiel #3
0
        /// <summary>
        /// Reflect a point in us.
        /// </summary>
        public Vector3D ReflectPoint(Vector3D p)
        {
            if (IsPlane)
            {
                //Debug.Assert( !Infinity.IsInfinite( p ) );
                Vector3D v = Euclidean3D.ProjectOntoPlane(this.Normal, this.Offset, p);
                v = p + (v - p) * 2;
                return(v);
            }
            else
            {
                if (p == Center)
                {
                    return(Infinity.InfinityVector);
                }
                if (Infinity.IsInfinite(p))
                {
                    return(Center);
                }

                Vector3D v = p - Center;
                double   d = v.Abs();
                v.Normalize();
                return(Center + v * (Radius * Radius / d));
            }
        }
Beispiel #4
0
        /// <summary>
        /// Construct a circle from 3 points
        /// </summary>
        /// <returns>false if the construction failed (if we are a line).</returns>
        public bool From3Points(Vector3D p1, Vector3D p2, Vector3D p3)
        {
            Reset();

            // Check for any infinite points, in which case we are a line.
            // I'm not sure these checks are smart, since our IsInfinite check is so inclusive,
            // but Big Chop puzzle doesn't work if we don't do this.
            // ZZZ - Still, I need to think on this more.
            if (Infinity.IsInfinite(p1))
            {
                this.From2Points(p2, p3);
                return(false);
            }
            else if (Infinity.IsInfinite(p2))
            {
                this.From2Points(p1, p3);
                return(false);
            }
            else if (Infinity.IsInfinite(p3))
            {
                this.From2Points(p1, p2);
                return(false);
            }

            /* Some links
             * http://mathforum.org/library/drmath/view/54323.html
             * http://delphiforfun.org/Programs/Math_Topics/circle_from_3_points.htm
             * There is lots of info out there about solving via equations,
             * but as with other code in this project, I wanted to use geometrical constructions. */

            // Midpoints.
            Vector3D m1 = (p1 + p2) / 2;
            Vector3D m2 = (p1 + p3) / 2;

            // Perpendicular bisectors.
            Vector3D b1 = (p2 - p1) / 2;
            Vector3D b2 = (p3 - p1) / 2;

            b1.Normalize();
            b2.Normalize();
            b1.Rotate90();
            b2.Rotate90();

            Vector3D newCenter;
            int      found = Euclidean2D.IntersectionLineLine(m1, m1 + b1, m2, m2 + b2, out newCenter);

            Center = newCenter;
            if (0 == found)
            {
                // The points are collinear, so we are a line.
                From2Points(p1, p2);
                return(false);
            }

            Radius = (p1 - Center).Abs();
            Debug.Assert(Tolerance.Equal(Radius, (p2 - Center).Abs()));
            Debug.Assert(Tolerance.Equal(Radius, (p3 - Center).Abs()));
            return(true);
        }
Beispiel #5
0
 public static Vector3D InfinitySafe(Vector3D input)
 {
     if (Infinity.IsInfinite(input))
     {
         return(Infinity.LargeFiniteVector);
     }
     return(input);
 }
Beispiel #6
0
        public static Vector3D PlaneToSphereSafe(Vector3D planePoint)
        {
            if (Infinity.IsInfinite(planePoint))
            {
                return(new Vector3D(0, 0, 1));
            }

            return(PlaneToSphere(planePoint));
        }
Beispiel #7
0
        /// <summary>
        /// https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection
        /// </summary>
        private static double StereoToEqualArea(double dist)
        {
            if (Infinity.IsInfinite(dist))
            {
                return(1);
            }

            double dot = dist * dist;             // X^2 + Y^2 + Z^2
            double w   = (dot - 1) / (dot + 1);

            double r = Math.Sqrt(2 * (1 + w));

            return(r / 2);
        }
Beispiel #8
0
        private static double StereoToEquidistant(double dist)
        {
            if (Infinity.IsInfinite(dist))
            {
                return(1);
            }

            double dot = dist * dist;             // X^2 + Y^2 + Z^2
            double w   = (dot - 1) / (dot + 1);

            double x = Math.Sqrt(1 - w * w);
            double r = Euclidean2D.AngleToCounterClock(new Vector3D(0, -1), new Vector3D(x, w));

            return(r / Math.PI);
        }
Beispiel #9
0
        private bool NewTetAfterReflect(Cell cell, Segment s, HashSet <Vector3D> completed)
        {
            foreach (Tile tile in cell.Tiles)
            {
                CircleNE newVertexCircle = tile.VertexCircle.Clone();
                newVertexCircle.Reflect(s);

                if (completed.Contains(Infinity.InfinitySafe(newVertexCircle.CenterNE)))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #10
0
 public void Reflect(Segment seg)
 {
     foreach (Tile tile in this.Tiles)
     {
         tile.Reflect(seg);
         if (Infinity.IsInfinite(tile.Boundary.Center))
         {
             tile.Boundary.Center = Infinity.LargeFiniteVector;
         }
         if (Infinity.IsInfinite(tile.Drawn.Center))
         {
             tile.Drawn.Center = Infinity.LargeFiniteVector;
         }
     }
 }
Beispiel #11
0
        /// <summary>
        /// Apply a transform to us.
        /// </summary>
        private void TransformInternal <T>(T transform) where T : ITransform
        {
            // NOTES:
            // Arcs can go to lines, and lines to arcs.
            // Rotations may reverse arc directions as well.
            // Arc centers can't be transformed directly.

            // NOTE: We must calc this before altering the endpoints.
            Vector3D mid = Midpoint;

            if (Infinity.IsInfinite(mid))
            {
                mid = Infinity.IsInfinite(P1) ? P2 * Infinity.FiniteScale : P1 * Infinity.FiniteScale;
            }

            P1  = transform.Apply(P1);
            P2  = transform.Apply(P2);
            mid = transform.Apply(mid);

            // Can we make a circle out of the transformed points?
            Circle temp = new Circle();

            if (!Infinity.IsInfinite(P1) && !Infinity.IsInfinite(P2) && !Infinity.IsInfinite(mid) &&
                temp.From3Points(P1, mid, P2))
            {
                Type   = SegmentType.Arc;
                Center = temp.Center;

                // Work out the orientation of the arc.
                Vector3D t1 = P1 - Center;
                Vector3D t2 = mid - Center;
                Vector3D t3 = P2 - Center;
                double   a1 = Euclidean2D.AngleToCounterClock(t2, t1);
                double   a2 = Euclidean2D.AngleToCounterClock(t3, t1);
                Clockwise = a2 > a1;
            }
            else
            {
                // The circle construction fails if the points
                // are colinear (if the arc has been transformed into a line).
                Type = SegmentType.Line;

                // XXX - need to do something about this.
                // Turn into 2 segments?
                //if( isInfinite( mid ) )
                // Actually the check should just be whether mid is between p1 and p2.
            }
        }
Beispiel #12
0
        public static Vector3D R3toS3(Vector3D p)
        {
            if (Infinity.IsInfinite(p))
            {
                return(new Vector3D(0, 0, 0, 1));
            }

            p.W = 0;
            double dot = p.Dot(p);               // X^2 + Y^2 + Z^2

            return(new Vector3D(
                       2 * p.X / (dot + 1),
                       2 * p.Y / (dot + 1),
                       2 * p.Z / (dot + 1),
                       (dot - 1) / (dot + 1)));
        }
Beispiel #13
0
        private static double StereoToEqualVolume(double dist)
        {
            if (Infinity.IsInfinite(dist))
            {
                return(1);
            }

            double dot = dist * dist;             // X^2 + Y^2 + Z^2
            double w   = (dot - 1) / (dot + 1);

            w = -w;             // Because I derived formula from north pole.
            double t = Math.PI / 2 - w * Math.Sqrt(1 - w * w) - Math.Asin(w);
            double r = Math.Pow(t * 3 / 2, 1.0 / 3);

            return(r);
        }
Beispiel #14
0
        private static double Pi_hpq(int p, int q)
        {
            double pi  = Math.PI;
            double pip = PiOverNSafe(p);
            double piq = PiOverNSafe(q);

            double temp = Math.Pow(Math.Cos(pip), 2) + Math.Pow(Math.Cos(piq), 2);
            double hab  = pi / Math.Acos(Math.Sqrt(temp));

            // Infinity safe.
            double pi_hpq = pi / hab;

            if (Infinity.IsInfinite(hab))
            {
                pi_hpq = 0;
            }

            return(pi_hpq);
        }
Beispiel #15
0
        public Vector3D[] CalcEdgePoints(double arcResolution, int minSegs, bool checkForInfinities)
        {
            List <Vector3D> points = new List <Vector3D>();

            for (int i = 0; i < NumSides; i++)
            {
                Segment s = Segments[i];

                // First point.
                // ZZZ - getting lazy
                //Debug.Assert( ! (isInfinite( s.m_p1 ) && isInfinite( s.m_p2 )) );
                Vector3D p1 = checkForInfinities && Infinity.IsInfinite(s.P1) ?
                              s.P2 * Infinity.FiniteScale :
                              s.P1;
                points.Add(p1);

                // For arcs, add in a bunch of extra points.
                if (SegmentType.Arc == s.Type)
                {
                    double   maxAngle    = s.Angle;
                    Vector3D vs          = s.P1 - s.Center;
                    int      numSegments = (int)(maxAngle / (arcResolution));
                    if (numSegments < minSegs)
                    {
                        numSegments = minSegs;
                    }
                    double angle = maxAngle / numSegments;
                    for (int j = 1; j < numSegments; j++)
                    {
                        vs.RotateXY(s.Clockwise ? -angle : angle);
                        points.Add(vs + s.Center);
                    }
                }

                // Last point.
                Vector3D p2 = checkForInfinities && Infinity.IsInfinite(s.P2) ?
                              s.P1 * Infinity.FiniteScale :
                              s.P2;
                points.Add(p2);
            }

            return(points.ToArray());
        }
Beispiel #16
0
        private void ReflectRecursive(int level, List <Cell> cells, HashSet <Vector3D> completed)
        {
            level++;

            // Breadth first recursion.

            if (0 == cells.Count)
            {
                return;
            }

            List <Cell> reflected = new List <Cell>();

            foreach (Cell cell in cells)
            {
                foreach (Segment seg in cell.Segments)
                {
                    // Are we done?
                    if (m_cells.Count >= m_cellCount)
                    {
                        return;
                    }

                    if (!NewTetAfterReflect(cell, seg, completed))
                    {
                        continue;
                    }

                    Cell newBase = cell.Clone();
                    newBase.Level = level;
                    newBase.Reflect(seg);
                    m_cells.Add(newBase);
                    reflected.Add(newBase);
                    foreach (Tile tile in newBase.Tiles)
                    {
                        completed.Add(Infinity.InfinitySafe(tile.VertexCircle.CenterNE));
                    }
                }
            }

            ReflectRecursive(level, reflected, completed);
        }
Beispiel #17
0
        // ZZZ - I wonder if we want to do normalization of lines before comparing.

        public bool Equals(CircleNE c1, CircleNE c2)
        {
            bool radiusEqual =
                Tolerance.Equal(c1.Radius, c2.Radius) ||
                (Infinity.IsInfinite(c1.Radius) && Infinity.IsInfinite(c2.Radius));

            if (c1.IsLine)
            {
                return(c1.P1 == c2.P1 &&
                       c1.P2 == c2.P2 &&
                       radiusEqual);
            }
            else
            {
                return
                    (c1.Center == c2.Center &&
                     c1.CenterNE == c2.CenterNE &&
                     radiusEqual);
            }
        }
Beispiel #18
0
        public Circle3D(Vector3D t1, Vector3D t2, Vector3D t3)
        {
            Vector3D center;
            double   radius;

            From3Points(t1, t2, t3, out center, out radius);

            Center = center;
            Radius = radius;

            Vector3D normal = (t2 - t1).Cross(t3 - t1);

            if (Infinity.IsInfinite(Radius))
            {
                Center = Vector3D.DneVector();
                normal = !t1.IsOrigin ? t1 : !t2.IsOrigin ? t2 : t3;                    // Hacky rep of line.
            }

            normal.Normalize();
            Normal = normal;
        }
Beispiel #19
0
        /// <summary>
        /// Checks to see if a point is inside us, in a non-Euclidean sense.
        /// This works if we are inverted, and even if we are a line!
        /// (if we are a line, half of the plane is still "inside").
        /// </summary>
        public bool IsPointInsideNE(Vector3D testPoint)
        {
            if (this.IsLine)
            {
                // We are inside if the test point is on the same side
                // as the non-Euclidean center.
                return(Euclidean2D.SameSideOfLine(P1, P2, testPoint, CenterNE));
            }
            else
            {
                // Whether we are inside in the Euclidean sense.
                bool pointInside = false;
                if (!Infinity.IsInfinite(testPoint))
                {
                    pointInside = this.IsPointInside(testPoint);
                }

                // And in the Non-Euclidean sense.
                bool inverted = this.Inverted;
                return((!inverted && pointInside) ||
                       (inverted && !pointInside));
            }
        }
Beispiel #20
0
        /// <summary>
        /// Transform a mesh in the Poincare model to Dini's surface.
        /// </summary>
        public static Mesh Dini(Mesh mesh)
        {
            System.Func <Vector3D, Vector3D> transform = v =>
            {
                //v = DiskToUpper( v );
                //v.Y = Math.Log( v.Y );

                //if( v.Y < 1 || v.Y > 10 )
                //	return Infinity.InfinityVector;
                //if( v.X < -Math.PI || v.X > Math.PI )
                //if( v.X < -3*Math.PI || v.X > 3*Math.PI )
                //	return Infinity.InfinityVector;

                //v.Y = Math.Log( v.Y );
                //return v;
                return(Dini(v));
            };

            Mesh result = new Mesh();

            for (int i = 0; i < mesh.Triangles.Count; i++)
            {
                Vector3D a = transform(mesh.Triangles[i].a);
                Vector3D b = transform(mesh.Triangles[i].b);
                Vector3D c = transform(mesh.Triangles[i].c);
                if (Infinity.IsInfinite(a) ||
                    Infinity.IsInfinite(b) ||
                    Infinity.IsInfinite(c))
                {
                    continue;
                }

                result.Triangles.Add(new Mesh.Triangle(a, b, c));
            }

            return(result);
        }
Beispiel #21
0
        /// <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.Offset - 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;
            }
        }