예제 #1
0
        /// <summary>
        /// Slicing function used for earthquake puzzles.
        /// c should be geodesic (orthogonal to the disk boundary).
        /// </summary>
        public static void SlicePolygonWithHyperbolicGeodesic(Polygon p, CircleNE c, double thickness, out List <Polygon> output)
        {
            Geometry g = Geometry.Hyperbolic;

            Segment seg = null;

            if (c.IsLine)
            {
                Vector3D p1, p2;
                Euclidean2D.IntersectionLineCircle(c.P1, c.P2, new Circle(), out p1, out p2);
                seg = Segment.Line(p1, p2);
            }
            else
            {
                // Setup the two slicing circles.
                // These are cuts equidistant from the passed in geodesic.
                Vector3D closestToOrigin = H3Models.Ball.ClosestToOrigin(new Circle3D()
                {
                    Center = c.Center, Radius = c.Radius, Normal = new Vector3D(0, 0, 1)
                });

                Vector3D p1, p2;
                Euclidean2D.IntersectionCircleCircle(c, new Circle(), out p1, out p2);
                seg = Segment.Arc(p1, closestToOrigin, p2);
            }

            Circle c1 = H3Models.Ball.EquidistantOffset(g, seg, thickness / 2);
            Circle c2 = H3Models.Ball.EquidistantOffset(g, seg, -thickness / 2);

            CircleNE c1NE = c.Clone(), c2NE = c.Clone();

            c1NE.Center = c1.Center; c2NE.Center = c2.Center;
            c1NE.Radius = c1.Radius; c2NE.Radius = c2.Radius;
            SlicePolygonHelper(p, c1NE, c2NE, out output);
        }
예제 #2
0
        /// <summary>
        /// Reflect a point in us.
        /// ZZZ - This method is confusing in that it is opposite the above (we aren't reflecting ourselves here).
        /// </summary>
        /// <param name="p"></param>
        public Vector3D ReflectPoint(Vector3D p)
        {
            if (this.IsLine)
            {
                return(Euclidean2D.ReflectPointInLine(p, P1, P2));
            }
            else
            {
                // Handle infinities.
                Vector3D infinityVector = Infinity.InfinityVector;
                if (p.Compare(Center))
                {
                    return(infinityVector);
                }
                if (p == infinityVector)
                {
                    return(Center);
                }

                Vector3D v = p - Center;
                double   d = v.Abs();
                v.Normalize();
                return(Center + v * (Radius * Radius / d));
            }
        }
예제 #3
0
        /// <summary>
        /// Checks to see if two points are ordered on this segment, that is:
        /// P1 -> test1 -> test2 -> P2 returns true.
        /// P1 -> test2 -> test1 -> P2 returns false;
        /// Also returns false if test1 or test2 are equal, not on the segment, or are an endpoint.
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns></returns>
        public bool Ordered(Vector3D test1, Vector3D test2)
        {
            if (test1.Compare(test2))
            {
                Debug.Assert(false);
                return(false);
            }
            if (!IsPointOn(test1) || !IsPointOn(test2))
            {
                Debug.Assert(false);
                return(false);
            }
            if (test1.Compare(P1) || test1.Compare(P2) ||
                test2.Compare(P1) || test2.Compare(P2))
            {
                return(false);
            }

            if (SegmentType.Arc == Type)
            {
                Vector3D t1 = P1 - Center;
                Vector3D t2 = test1 - Center;
                Vector3D t3 = test2 - Center;
                double   a1 = Clockwise ? Euclidean2D.AngleToClock(t1, t2) : Euclidean2D.AngleToCounterClock(t1, t2);
                double   a2 = Clockwise ? Euclidean2D.AngleToClock(t1, t3) : Euclidean2D.AngleToCounterClock(t1, t3);
                return(a1 < a2);
            }
            else
            {
                double d1 = (test1 - P1).MagSquared();
                double d2 = (test2 - P1).MagSquared();
                return(d1 < d2);
            }
        }
예제 #4
0
        public static Vector3D SpiralToIsometric(Vector3D v, int p, int m, int n)
        {
            Complex vc = v.ToComplex();

            v = new Vector3D(Math.Log(vc.Magnitude), vc.Phase);

            Vector3D e1 = new Vector3D(0, 1);
            Vector3D e2;

            switch (p)
            {
            case 3:
                e2 = new Vector3D(); break;

            case 4:
                e2 = new Vector3D(); break;

            case 6:
                e2 = new Vector3D(); break;

            default:
                throw new System.ArgumentException();
            }

            double scale = Math.Sqrt(m * m + n * n);
            double a     = Euclidean2D.AngleToClock(new Vector3D(0, 1), new Vector3D(m, n));

            v.RotateXY(a);          // Rotate
            v *= scale;             // Scale

            v *= Math.Sqrt(2) * Geometry2D.EuclideanHypotenuse / (2 * Math.PI);
            v.RotateXY(Math.PI / 4);
            return(v);
        }
예제 #5
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);
        }
예제 #6
0
        public bool IsPointOn(Vector3D test)
        {
            if (this.IsLine)
            {
                return(Tolerance.Zero(Euclidean2D.DistancePointLine(test, P1, P2)));
            }

            return(Tolerance.Equal((test - Center).Abs(), Radius));
        }
예제 #7
0
 public Vector3D ReflectPoint(Vector3D input)
 {
     if (SegmentType.Arc == Type)
     {
         Circle c = this.Circle;
         return(c.ReflectPoint(input));
     }
     else
     {
         return(Euclidean2D.ReflectPointInLine(input, P1, P2));
     }
 }
예제 #8
0
        public bool Intersects(Segment s)
        {
            Vector3D i1 = Vector3D.DneVector(), i2 = Vector3D.DneVector();
            int      numInt = 0;

            if (SegmentType.Arc == Type)
            {
                if (SegmentType.Arc == s.Type)
                {
                    numInt = Euclidean2D.IntersectionCircleCircle(Circle, s.Circle, out i1, out i2);
                }
                else
                {
                    numInt = Euclidean2D.IntersectionLineCircle(P1, P2, s.Circle, out i1, out i2);
                }
            }
            else
            {
                if (SegmentType.Arc == s.Type)
                {
                    numInt = Euclidean2D.IntersectionLineCircle(s.P1, s.P2, Circle, out i1, out i2);
                }
                else
                {
                    numInt = Euclidean2D.IntersectionLineLine(P1, P2, s.P1, s.P2, out i1);
                }
            }

            // -1 can denote conincident segments (I'm not consistent in the impls above :/),
            // and we are not going to include those for now.
            if (numInt <= 0)
            {
                return(false);
            }

            if (numInt > 0)
            {
                if (IsPointOn(i1) && s.IsPointOn(i1))
                {
                    return(true);
                }
            }
            if (numInt > 1)
            {
                if (IsPointOn(i2) && s.IsPointOn(i2))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #9
0
        private static bool PointOnArcSegment(Vector3D p, Segment seg)
        {
            double   maxAngle = seg.Angle;
            Vector3D v1       = seg.P1 - seg.Center;
            Vector3D v2       = p - seg.Center;

            Debug.Assert(Tolerance.Equal(v1.Abs(), v2.Abs()));
            double angle = seg.Clockwise ?
                           Euclidean2D.AngleToClock(v1, v2) :
                           Euclidean2D.AngleToCounterClock(v1, v2);

            return(Tolerance.LessThanOrEqual(angle, maxAngle));
        }
예제 #10
0
        // Get the intersection points with a segment.
        // Returns null if the segment is an arc coincident with the circle (infinite number of intersection points).
        public Vector3D[] GetIntersectionPoints(Segment segment)
        {
            Vector3D p1, p2;
            int      result;

            // Are we a line?
            if (this.IsLine)
            {
                if (SegmentType.Arc == segment.Type)
                {
                    Circle tempCircle = segment.Circle;
                    result = Euclidean2D.IntersectionLineCircle(this.P1, this.P2, tempCircle, out p1, out p2);
                }
                else
                {
                    result = Euclidean2D.IntersectionLineLine(this.P1, this.P2, segment.P1, segment.P2, out p1);
                    p2     = Vector3D.DneVector();
                }
            }
            else
            {
                if (SegmentType.Arc == segment.Type)
                {
                    Circle tempCircle = segment.Circle;
                    result = Euclidean2D.IntersectionCircleCircle(tempCircle, this, out p1, out p2);
                }
                else
                {
                    result = Euclidean2D.IntersectionLineCircle(segment.P1, segment.P2, this, out p1, out p2);
                }
            }

            if (-1 == result)
            {
                return(null);
            }

            List <Vector3D> ret = new List <Vector3D>();

            if (result >= 1 && segment.IsPointOn(p1))
            {
                ret.Add(p1);
            }
            if (result >= 2 && segment.IsPointOn(p2))
            {
                ret.Add(p2);
            }

            return(ret.ToArray());
        }
예제 #11
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);
        }
예제 #12
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.
            }
        }
예제 #13
0
        /// <summary>
        /// Maps a point in a rhombus to a point in the unit square, via a simple affine transformation.
        /// b1 and b2 are the two basis vectors of the rhombus.
        /// Does not currently check the input point.
        /// </summary>
        public static Vector3D MapRhombusToUnitSquare(Vector3D b1, Vector3D b2, Vector3D v)
        {
            double a = Euclidean2D.AngleToCounterClock(b1, new Vector3D(1, 0));

            v.RotateXY(a);
            b1.RotateXY(a);
            b2.RotateXY(a);

            // Shear
            v.X -= b2.X * (v.Y / b2.Y);

            // Scale x and y.
            v.X /= b1.X;
            v.Y /= b2.Y;

            return(v);
        }
예제 #14
0
        /// <summary>
        /// Normalize so P1 is closest point to origin,
        /// and direction vector is of unit length.
        /// </summary>
        public void NormalizeLine()
        {
            if (!this.IsLine)
            {
                return;
            }

            Vector3D d = P2 - P1;

            d.Normalize();

            P1 = Euclidean2D.ProjectOntoLine(new Vector3D(), P1, P2);

            // ZZZ - Could probably do something more robust to choose proper direction.
            if (Tolerance.GreaterThanOrEqual(Euclidean2D.AngleToClock(d, new Vector3D(1, 0)), Math.PI))
            {
                d *= -1;
            }

            P2 = P1 + d;
        }
예제 #15
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));
            }
        }
예제 #16
0
        /// <summary>
        /// Returns the 6 simplex edges in the UHS model.
        /// </summary>
        public static H3.Cell.Edge[] SimplexEdgesUHS(int p, int q, int r)
        {
            // Only implemented for honeycombs with hyperideal cells right now.
            if (!(Geometry2D.GetGeometry(p, q) == Geometry.Hyperbolic))
            {
                throw new System.NotImplementedException();
            }

            Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: false);

            Circle[] circles = simplex.Select(s => H3Models.UHS.IdealCircle(s)).ToArray();

            Vector3D[] defPoints = new Vector3D[6];
            Vector3D   dummy;

            Euclidean2D.IntersectionLineCircle(circles[1].P1, circles[1].P2, circles[0], out defPoints[0], out dummy);
            Euclidean2D.IntersectionLineCircle(circles[2].P1, circles[2].P2, circles[0], out defPoints[1], out dummy);
            Euclidean2D.IntersectionLineCircle(circles[1].P1, circles[1].P2, circles[3], out defPoints[2], out dummy);
            Euclidean2D.IntersectionLineCircle(circles[2].P1, circles[2].P2, circles[3], out defPoints[3], out dummy);

            Circle3D c = simplex[0].Intersection(simplex[3]);

            Vector3D normal = c.Normal;

            normal.RotateXY(Math.PI / 2);
            Vector3D intersection;
            double   height, off;

            Euclidean2D.IntersectionLineLine(c.Center, c.Center + normal, circles[1].P1, circles[1].P2, out intersection);
            off            = (intersection - c.Center).Abs();
            height         = Math.Sqrt(c.Radius * c.Radius - off * off);
            intersection.Z = height;
            defPoints[4]   = intersection;

            Euclidean2D.IntersectionLineLine(c.Center, c.Center + normal, circles[2].P1, circles[2].P2, out intersection);
            off            = (intersection - c.Center).Abs();
            height         = Math.Sqrt(c.Radius * c.Radius - off * off);
            intersection.Z = height;
            defPoints[5]   = intersection;

            // Hyperideal vertex too?
            bool order = false;

            H3.Cell.Edge[] edges = null;
            if (Geometry2D.GetGeometry(q, r) == Geometry.Hyperbolic)
            {
                edges = new H3.Cell.Edge[]
                {
                    new H3.Cell.Edge(new Vector3D(), new Vector3D(0, 0, 10)),
                    new H3.Cell.Edge(defPoints[4], defPoints[5], order),
                    new H3.Cell.Edge(defPoints[0], defPoints[4], order),
                    new H3.Cell.Edge(defPoints[1], defPoints[5], order),
                    new H3.Cell.Edge(defPoints[2], defPoints[4], order),
                    new H3.Cell.Edge(defPoints[3], defPoints[5], order),
                };
            }
            else
            {
                Vector3D vPointUHS = H3Models.BallToUHS(VertexPointBall(p, q, r));
                defPoints[0] = defPoints[1] = vPointUHS;
                edges        = new H3.Cell.Edge[]
                {
                    new H3.Cell.Edge(vPointUHS, new Vector3D(0, 0, 10)),
                    new H3.Cell.Edge(defPoints[4], defPoints[5], order),
                    new H3.Cell.Edge(defPoints[0], defPoints[4], order),
                    new H3.Cell.Edge(defPoints[1], defPoints[5], order),
                    new H3.Cell.Edge(defPoints[2], defPoints[4], order),
                    new H3.Cell.Edge(defPoints[3], defPoints[5], order),
                };
            }

            return(edges);
        }
예제 #17
0
        /// <summary>
        /// Reflects a point in a line defined by two points.
        /// </summary>
        public static Vector3D ReflectPointInLine(Vector3D input, Vector3D p1, Vector3D p2)
        {
            Vector3D p = Euclidean2D.ProjectOntoLine(input, p1, p2);

            return(input + (p - input) * 2);
        }