Beispiel #1
0
        public void Rotate()
        {           
            V2 expected;
            V2 returned;

            // --- TEST ---

            expected = new V2(0.0f, 1.0f);
            returned = new V2(1.0f, 0.0f);
            returned.Rotate(2f * (Real)Math.PI * 0.25f);

            Assert.AreEqual(expected.X, returned.X, EPSILON);
            Assert.AreEqual(expected.Y, returned.Y, EPSILON);

            // --- TEST ---

            expected = new V2(-1.0f, 0.0f);
            returned = new V2(1.0f, 0.0f);
            returned.Rotate(2f * (Real)Math.PI * 0.5f);

            Assert.AreEqual(expected.X, returned.X, EPSILON);
            Assert.AreEqual(expected.Y, returned.Y, EPSILON);

            // --- TEST ---

            expected = new V2(-1.0f, 0.0f);
            returned = new V2(0.0f, -1.0f);
            returned.Rotate(-2f * (Real)Math.PI * 0.25f);

            Assert.AreEqual(expected.X, returned.X, EPSILON);
            Assert.AreEqual(expected.Y, returned.Y, EPSILON);
        }
Beispiel #2
0
 public MaterialInfo(
     BgfBitmap Texture,
     string TextureName,
     string MaterialName,          
     V2 ScrollSpeed)
 {
     this.Texture = Texture;
     this.TextureName = TextureName;
     this.MaterialName = MaterialName;
     this.ScrollSpeed = ScrollSpeed;
 }
        /// <summary>
        /// Constructor using two initial points.
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        public BoundingBox2D(V2 P1, V2 P2)
        {
            // these initial values make sure
            // any first point will replace them
            this.Min.X = Real.MaxValue;
            this.Min.Y = Real.MaxValue;
            this.Max.X = Real.MinValue;
            this.Max.Y = Real.MinValue;

            ExtendByPoint(P1);
            ExtendByPoint(P2);
        }
Beispiel #4
0
        /// <summary>
        /// Constructor using two initial points.
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        public BoundingBox2D(V2 P1, V2 P2)
        {
            // these initial values make sure
            // any first point will replace them
            this.Min.X = Real.MaxValue;
            this.Min.Y = Real.MaxValue;
            this.Max.X = Real.MinValue;
            this.Max.Y = Real.MinValue;

            ExtendByPoint(P1);
            ExtendByPoint(P2);
        }
Beispiel #5
0
        /// <summary>
        /// Returns a projection of this instance on another vector.
        /// </summary>
        /// <param name="Vector"></param>
        /// <returns></returns>
        public V2 GetProjection(V2 Vector)
        {
            Real denom = Vector.LengthSquared;

            if (denom > 0.0f)
            {
                Real num = this * Vector;
                return(Vector * (num / denom));
            }
            else
            {
                return(V2.ZERO);
            }
        }
Beispiel #6
0
        public void Scale()
        {
            V2 expected;
            V2 returned;

            // --- TEST ---

            expected = new V2(0.0f, 0.0f);
            returned = new V2(0.0f, 0.0f);
            returned.Scale(10f);

            Assert.AreEqual(expected.X, returned.X, EPSILON);
            Assert.AreEqual(expected.Y, returned.Y, EPSILON);

            // --- TEST ---

            expected = new V2(10.0f, 0.0f);
            returned = new V2(1.0f, 0.0f);
            returned.Scale(10f);

            Assert.AreEqual(expected.X, returned.X, EPSILON);
            Assert.AreEqual(expected.Y, returned.Y, EPSILON);

            // --- TEST ---

            expected = new V2(0.0f, -10.0f);
            returned = new V2(0.0f, -1.0f);
            returned.Scale(10f);

            Assert.AreEqual(expected.X, returned.X, EPSILON);
            Assert.AreEqual(expected.Y, returned.Y, EPSILON);

            // --- TEST ---

            expected = new V2(0.0f, 0.0f);
            returned = new V2(1.34f, -5.563f);
            returned.Scale(0.0f);

            Assert.AreEqual(expected.X, returned.X, EPSILON);
            Assert.AreEqual(expected.Y, returned.Y, EPSILON);

            // --- TEST ---

            expected = new V2(EPSILON, EPSILON);
            returned = new V2(1.0f, 1.0f);
            returned.Scale(EPSILON);

            Assert.AreEqual(expected.X, returned.X, EPSILON);
            Assert.AreEqual(expected.Y, returned.Y, EPSILON);
        }
        /// <summary>
        /// Converts V2 direction to radian angle.
        /// </summary>
        /// <param name="Direction">Direction vector</param>
        /// <returns>Value in [0..2PI]</returns>
        public static Real GetRadianForDirection(ref V2 Direction)
        {
            // normalize
            Direction.Normalize();

            // get angle between x-axis and direction in radian.
            Real cosphi = Direction * V2.UNITX;
            Real phi    = (Real)Math.Acos(cosphi);

            // phi is always in [0..PI], not in [0..2PI]
            // this increases to full range [0..2PI]
            if (Direction.Y < 0)
            {
                phi = GeometryConstants.TWOPI - phi;
            }

            return(phi);
        }
Beispiel #8
0
        /// <summary>
        /// Returns the side (-1 or 1) of this (point) instance
        /// for the line given by points P1 and P2.
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        /// <returns></returns>
        public int GetSide(V2 P1, V2 P2)
        {
            Real val = (P2.X - P1.X) * (Y - P1.Y) - (P2.Y - P1.Y) * (X - P1.X);

            if (val >= EPSILON)
            {
                return(1);
            }

            else if (val <= -EPSILON)
            {
                return(-1);
            }

            else
            {
                return(0);
            }
        }
        /// <summary>
        /// Returns a random point within a 2D triangle.
        /// </summary>
        /// <remarks>
        /// See:
        /// http://math.stackexchange.com/questions/18686/uniform-random-point-in-triangle
        /// </remarks>
        /// <param name="A"></param>
        /// <param name="B"></param>
        /// <param name="C"></param>
        /// <returns>Random point</returns>
        public static V2 RandomPointInTriangle(ref V2 A, ref V2 B, ref V2 C)
        {
            // create two randoms within [0,1]
            Real rnd1 = (Real)Random.NextDouble();
            Real rnd2 = (Real)Random.NextDouble();

            // get rootsqrt
            Real sqrt_rnd1 = (Real)Math.Sqrt(rnd1);

            // coefficients
            Real coeff1 = 1 - sqrt_rnd1;
            Real coeff2 = sqrt_rnd1 * (1 - rnd2);
            Real coeff3 = rnd2 * sqrt_rnd1;

            // return random point
            return(new V2(
                       coeff1 * A.X + coeff2 * B.X + coeff3 * C.X,
                       coeff1 * A.Y + coeff2 * B.Y + coeff3 * C.Y));
        }
Beispiel #10
0
 /// <summary>
 /// Adjusts the current min, max accordingly in case
 /// the new point lies outside the current box.
 /// </summary>
 /// <param name="Point"></param>
 public void ExtendByPoint(V2 Point)
 {
     if (Point.X < Min.X)
     {
         Min.X = Point.X;
     }
     if (Point.X > Max.X)
     {
         Max.X = Point.X;
     }
     if (Point.Y < Min.Y)
     {
         Min.Y = Point.Y;
     }
     if (Point.Y > Max.Y)
     {
         Max.Y = Point.Y;
     }
 }
Beispiel #11
0
        /// <summary>
        /// Tests whether this V2 instance lies on a line segment
        /// given by points P1 and P2.
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        /// <returns></returns>
        public bool IsOnLineSegment(V2 P1, V2 P2)
        {
            // the point is not even on the infinite line given by P1P2
            if (GetSide(P1, P2) != 0)
            {
                return(false);
            }

            // if on infinite line, must also be in boundingbox
            V2 min, max;

            min.X = Math.Min(P1.X, P2.X);
            min.Y = Math.Min(P1.Y, P2.Y);
            max.X = Math.Max(P1.X, P2.X);
            max.Y = Math.Max(P1.Y, P2.Y);

            return
                (min.X <= X && X <= max.X &&
                 min.Y <= Y && Y <= max.Y);
        }
        /// <summary>
        /// Calculates the FIRST (entry) intersection point of a line and a circle.
        /// </summary>
        /// <remarks>
        /// http://stackoverflow.com/questions/1073336/circle-line-collision-detection
        /// </remarks>
        /// <param name="LineStart"></param>
        /// <param name="LineEnd"></param>
        /// <param name="CircleCenter"></param>
        /// <param name="Radius"></param>
        /// <param name="Intersect"></param>
        /// <returns>True if interesction, false if none.</returns>
        public static bool IntersectLineCircle(ref V2 LineStart, ref V2 LineEnd, ref V2 CircleCenter, Real Radius, out V2 Intersect)
        {
            // default output param
            Intersect.X = 0;
            Intersect.Y = 0;

            // returnval
            bool intersects = false;

            V2 d = LineEnd - LineStart;
            V2 f = LineStart - CircleCenter;

            Real a            = d * d;
            Real b            = 2 * (f * d);
            Real c            = (f * f) - (Radius * Radius);
            Real discriminant = b * b - 4 * a * c;

            if (discriminant >= 0)
            {
                discriminant = (Real)Math.Sqrt(discriminant);

                Real t1 = (-b - discriminant) / (2 * a);
                Real t2 = (-b + discriminant) / (2 * a);

                if (t1 >= 0 && t1 <= 1)
                {
                    intersects = true;
                    Intersect  = LineStart + (t1 * d);
                }
                else if (t2 >= 0 && t2 <= 1)
                {
                    intersects = true;
                    Intersect  = LineStart + (t2 * d);
                }
            }

            return(intersects);
        }
        /// <summary>
        /// True if infinite lines represented by P1P2 and Q1Q2 intersect.
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        /// <param name="Q1"></param>
        /// <param name="Q2"></param>
        /// <param name="Intersect"></param>
        /// <returns></returns>
        public static bool IntersectInfiniteLines(ref V2 P1, ref V2 P2, ref V2 Q1, ref V2 Q2, out V2 Intersect)
        {
            // variant 2
            Real denom = (P1.X - P2.X) * (Q1.Y - Q2.Y) - (P1.Y - P2.Y) * (Q1.X - Q2.X);

            // parallel
            if (denom > -0.001f && denom < 0.001f)
            {
                Intersect.X = 0.0f;
                Intersect.Y = 0.0f;
                return(false);
            }

            Real num;

            num         = (P1.X * P2.Y - P1.Y * P2.X) * (Q1.X - Q2.X) - (P1.X - P2.X) * (Q1.X * Q2.Y - Q1.Y * Q2.X);
            Intersect.X = num / denom;

            num         = (P1.X * P2.Y - P1.Y * P2.X) * (Q1.Y - Q2.Y) - (P1.Y - P2.Y) * (Q1.X * Q2.Y - Q1.Y * Q2.X);
            Intersect.Y = num / denom;

            return(true);
        }
        /// <summary>
        /// Checks for intersection of finite line segment and a circle.
        /// Returns true if there is an intersection, or if line is fully inside circle.
        /// </summary>
        /// <remarks>
        /// http://stackoverflow.com/questions/1073336/circle-line-collision-detection
        /// </remarks>
        /// <param name="LineStart"></param>
        /// <param name="LineEnd"></param>
        /// <param name="CircleCenter"></param>
        /// <param name="Radius"></param>
        /// <returns>True if interesction, false if none.</returns>
        public static bool IntersectOrInsideLineCircle(ref V2 LineStart, ref V2 LineEnd, ref V2 CircleCenter, Real Radius)
        {
            V2 d = LineEnd - LineStart;
            V2 f = LineStart - CircleCenter;

            Real a            = d * d;
            Real b            = 2 * (f * d);
            Real c            = (f * f) - (Radius * Radius);
            Real discriminant = b * b - 4 * a * c;

            if (discriminant <= 0 || a == 0)
            {
                return(false);
            }

            discriminant = (Real)Math.Sqrt(discriminant);
            Real t1 = (-b - discriminant) / (2 * a);
            Real t2 = (-b + discriminant) / (2 * a);

            return((t1 >= 0 && t1 <= 1) ||
                   (t2 >= 0 && t2 <= 1) ||
                   (t1 <= 0 && t2 >= 1));
        }
Beispiel #15
0
        /// <summary>
        /// Checks two finite line segments for intersection.
        /// </summary>
        /// <param name="P1">First point of first line segment</param>
        /// <param name="P2">Second point of first line segment</param>
        /// <param name="Q1">First point of second line segment</param>
        /// <param name="Q2">Second point of second line segment</param>
        /// <param name="Intersect">Intersection point</param>
        /// <returns>True if interesction, false if none.</returns>
        public static bool IntersectLineLine(V2 P1, V2 P2, V2 Q1, V2 Q2, out V2 Intersect)
        {
            Intersect.X = 0.0f;
            Intersect.Y = 0.0f;

            V2   b         = P2 - P1;
            V2   d         = Q2 - Q1;
            Real bDotDPerp = b.X * d.Y - b.Y * d.X;

            // if b dot d == 0, it means the lines are parallel/collapse
            // so have infinite intersection points or none
            if (bDotDPerp == 0)
            {
                return(false);
            }

            V2   c = Q1 - P1;
            Real t = (c.X * d.Y - c.Y * d.X) / bDotDPerp;

            if (t < 0.0f || t > 1.0f)
            {
                return(false);
            }

            Real u = (c.X * b.Y - c.Y * b.X) / bDotDPerp;

            if (u < 0.0f || u > 1.0f)
            {
                return(false);
            }

            b.Scale(t);
            Intersect = P1 + b;

            return(true);
        }
Beispiel #16
0
        protected void DrawWall(Graphics G, RooWall Wall, Pen Pen, bool Infinite, Pen PenInfinite)
        {
            V2 p1p2;

            // transform points to match world of pixeldrawing
            float transx1 = (float)(Wall.P1.X - boxMin.X) * ZoomInv;
            float transy1 = (float)(Wall.P1.Y - boxMin.Y) * ZoomInv;
            float transx2 = (float)(Wall.P2.X - boxMin.X) * ZoomInv;
            float transy2 = (float)(Wall.P2.Y - boxMin.Y) * ZoomInv;

            // draw extensions of line
            if (Infinite)
            {
                V2 p1 = new V2(transx1, transy1);
                V2 p2 = new V2(transx2, transy2);
                p1p2 = p2 - p1;

                p2 += 1000f * p1p2;
                p1 -= 1000f * p1p2;

                G.DrawLine(PenInfinite, (float)p1.X, (float)p1.Y, (float)p2.X, (float)p2.Y);
            }

            // check if this is an issue line (almost horizontal or vertical, but not fully)
            p1p2 = Wall.GetP1P2();
            if (chkVertHortLines.Checked && p1p2.X != 0.0f && p1p2.Y != 0.0f)
            {
                Real m = (Real)(p1p2.Y / p1p2.X);

                if ((m > -0.125f && m < 0.125f) ||
                    (m > 8.0f || m < -8.0f))
                        Pen = penRed2;
            }
            
            // draw line
            G.DrawLine(Pen, transx1, transy1, transx2, transy2);           
        }
Beispiel #17
0
        public void MinDistanceToLineSegment()
        {
            Real expected;
            Real returned;
            V2 s;
            V2 p1, p2;

            // --- TEST ---
            // p1=p2=s=0

            s = new V2(0.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(0.0f, 0.0f);
            expected = 0.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s on p1

            s = new V2(0.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 0.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s on p2

            s = new V2(1.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 0.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s in mid of p1p2

            s = new V2(0.0f, 0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 0.5f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // p1=p2

            s = new V2(0.0f, 0.0f);
            p1 = new V2(1.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 1.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s on extension p1p2, closest p2

            s = new V2(2.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 1.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s on extension p2p1, closest p1

            s = new V2(-1.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 1.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s perpendicular, mid p1p2 closest

            s = new V2(0.5f, 0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 0.5f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s perpendicular, p1 closest +

            s = new V2(0.0f, 1.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 1.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s perpendicular, p1 closest -

            s = new V2(0.0f, -1.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 1.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s perpendicular, p2 closest +

            s = new V2(1.0f, 1.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 1.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s perpendicular, p2 closest -

            s = new V2(1.0f, -1.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = 1.0f;
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s 45° to p2 closest +

            s = new V2(2.0f, 1.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = (Real)Math.Sqrt(2.0f);
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);

            // --- TEST ---
            // s 45° to p2 closest -

            s = new V2(2.0f, -1.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 0.0f);
            expected = (Real)Math.Sqrt(2.0f);
            returned = s.MinDistanceToLineSegment(p1, p2);

            Assert.AreEqual(expected, returned, EPSILON);
        }
        /// <summary>
        /// Checks a finite line segment for intersection with infinite line.
        /// </summary>
        /// <param name="P1">First point of finite line segment</param>
        /// <param name="P2">Second point of finite line segment</param>
        /// <param name="Q1">First point in infinte line</param>
        /// <param name="Q2">Second point in infinite line</param>
        /// <param name="Intersect"></param>
        /// <returns></returns>
        public static LineInfiniteLineIntersectionType IntersectLineInfiniteLine(V2 P1, V2 P2, V2 Q1, V2 Q2, out V2 Intersect)
        {
            Intersect.X = 0.0f;
            Intersect.Y = 0.0f;

            /*****************************************************************/

            int sideP1 = P1.GetSide(Q1, Q2);
            int sideP2 = P2.GetSide(Q1, Q2);

            // case (a): no intersection
            // both finite line endpoints are on the same side of the infinite line
            if (sideP1 == sideP2 && sideP1 != 0)
            {
                return(LineInfiniteLineIntersectionType.NoIntersection);
            }

            // case (b): real intersection (not only touch)
            // both finite line endpoints are on different sides
            if (sideP1 != sideP2 && sideP1 != 0 && sideP2 != 0)
            {
                // variant 2
                Real denom = (P1.X - P2.X) * (Q1.Y - Q2.Y) - (P1.Y - P2.Y) * (Q1.X - Q2.X);
                Real num;

                num         = (P1.X * P2.Y - P1.Y * P2.X) * (Q1.X - Q2.X) - (P1.X - P2.X) * (Q1.X * Q2.Y - Q1.Y * Q2.X);
                Intersect.X = num / denom;

                num         = (P1.X * P2.Y - P1.Y * P2.X) * (Q1.Y - Q2.Y) - (P1.Y - P2.Y) * (Q1.X * Q2.Y - Q1.Y * Q2.X);
                Intersect.Y = num / denom;

                return(LineInfiniteLineIntersectionType.OneIntersection);
            }

            // case (c): fully coincide
            // both finite line endpoints are on the infinite line
            if (sideP1 == 0 && sideP2 == 0)
            {
                Intersect.X = P1.X;
                Intersect.Y = P1.Y;

                return(LineInfiniteLineIntersectionType.FullyCoincide);
            }

            // case (d):
            // finite line endpoint P1 touches infinite line
            if (sideP1 != sideP2 && sideP1 == 0)
            {
                Intersect.X = P1.X;
                Intersect.Y = P1.Y;

                return(LineInfiniteLineIntersectionType.OneBoundaryPoint);
            }

            // case (d):
            // finite line endpoint P2 touches infinite line
            if (sideP1 != sideP2 && sideP2 == 0)
            {
                Intersect.X = P2.X;
                Intersect.Y = P2.Y;

                return(LineInfiniteLineIntersectionType.OneBoundaryPoint);
            }

            // huh? something wrong?
            throw new Exception("Unknown intersection");
        }
Beispiel #19
0
 /// <summary>
 /// Returns the scalar crossproduct of this vector
 /// and the parameter vector.
 /// </summary>
 /// <remarks>
 /// http://stackoverflow.com/questions/243945/calculating-a-2d-vectors-cross-product
 /// </remarks>
 /// <param name="v"></param>
 /// <returns></returns>
 public Real CrossProduct(V2 v)
 {
     return((X * v.Y) - (Y * v.X));
 }
Beispiel #20
0
 /// <summary>
 /// See and prefer the variant with ref params!
 /// </summary>
 /// <param name="p1"></param>
 /// <param name="p2"></param>
 /// <returns></returns>
 public int GetSide(V2 p1, V2 p2)
 {
     return(GetSide(ref p1, ref p2));
 }
Beispiel #21
0
        /// <summary>
        /// Returns the squared distance to another point
        /// </summary>
        /// <param name="Destination"></param>
        /// <returns></returns>
        public Real DistanceToSquared(V2 Destination)
        {
            V2 diff = Destination - this;

            return(diff.LengthSquared);
        }
 protected void HandleMove(MoveMessage Message)
 {
     RoomObject roomObject = RoomObjects.GetItemByID(Message.ObjectID);
     if (roomObject != null)
     {
         // create destination from values
         V2 destination = new V2(Message.NewCoordinateX, Message.NewCoordinateY);
                        
         // initiate movement
         roomObject.StartMoveTo(destination, (byte)Message.MovementSpeed);                            
     }
 }
        /// <summary>
        /// Update Viewer dependent properties on RoomObjects
        /// based on ViewerPosition in DataController
        /// </summary>
        protected void ProcessViewerAngle()
        {
            // get 2D position of viewer
            V2 position = new V2(ViewerPosition.X, ViewerPosition.Z);

            // update roomobjects
            foreach (RoomObject obj in RoomObjects)
                obj.UpdateViewerAngle(position);

            // update projectiles
            foreach (Projectile obj in Projectiles)
                obj.UpdateViewerAngle(position);
        }
Beispiel #24
0
        /// <summary>
        /// Checks if this wall blocks a
        /// move between Start and End
        /// </summary>
        /// <param name="Start">A 3D location</param>
        /// <param name="End">A 2D location</param>
        /// <param name="PlayerHeight">Height of the player for ceiling collisions</param>
        /// <returns></returns>
        public bool IsBlockingMove(V3 Start, V2 End, Real PlayerHeight)
        {          
            // get distance of end to finite line segment
            Real distEnd = End.MinSquaredDistanceToLineSegment(P1, P2);

            // end is far enough away, no block
            if (distEnd >= GeometryConstants.WALLMINDISTANCE2)
                return false;

            /*************************************************************************/
            // end is too 'too' close to wall
            
            V2 start2D      = new V2(Start.X, Start.Z);
            int startside   = start2D.GetSide(P1, P2);
            int endside     = End.GetSide(P1, P2);
            Real endheight;
            ushort bgfbmp;

            /*************************************************************************/
            // allow moving away from wall

            if (startside == endside)
            { 
                Real distStart = start2D.MinSquaredDistanceToLineSegment(P1, P2);

                if (distEnd > distStart)
                    return false;
            }

            /*************************************************************************/
            // prevent moving through non-passable side

            if ((startside < 0 && LeftSide != null && !LeftSide.Flags.IsPassable) ||
                (startside > 0 && RightSide != null && !RightSide.Flags.IsPassable))
                return true;         

            /*************************************************************************/
            // check step-height

            endheight = 0.0f;

            if (startside >= 0)
            {
                endheight = (LeftSector != null) ? LeftSector.CalculateFloorHeight(End.X, End.Y, true) : 0.0f;
                bgfbmp = (RightSide != null) ? RightSide.LowerTexture : (ushort)0;
            }
            else
            {
                endheight = (RightSector != null) ? RightSector.CalculateFloorHeight(End.X, End.Y, true) : 0.0f;
                bgfbmp = (LeftSide != null) ? LeftSide.LowerTexture : (ushort)0;
            }

            if (bgfbmp > 0 && (endheight - Start.Y > GeometryConstants.MAXSTEPHEIGHT))
                return true;
            
            /*************************************************************************/
            // check head collision with ceiling

            endheight = 0.0f;

            if (startside >= 0)
            {
                endheight = (LeftSector != null) ? LeftSector.CalculateCeilingHeight(End.X, End.Y) : 0.0f;
                bgfbmp = (RightSide != null) ? RightSide.UpperTexture : (ushort)0;
            }
            else
            {
                endheight = (RightSector != null) ? RightSector.CalculateCeilingHeight(End.X, End.Y) : 0.0f;
                bgfbmp = (LeftSide != null) ? LeftSide.UpperTexture : (ushort)0;
            }

            if (bgfbmp > 0 && (endheight < Start.Y + PlayerHeight))
                return true;

            /*************************************************************************/

            return false;
        }
Beispiel #25
0
        public void GetSide()
        {
            int expected;
            int returned;
            V2 s;
            V2 p1, p2;

            /**************************************************/

            // --- TEST ---
            // p1=p2=s=0, no line

            s = new V2(0.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(0.0f, 0.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // p1=s

            s = new V2(0.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(0.0f, 1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // p2=s

            s = new V2(0.0f, 1.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(0.0f, 1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            /**************************************************/

            // --- TEST ---
            // s is somewhere on line

            s = new V2(0.5f, 0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is somewhere on line

            s = new V2(-0.5f, -0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(-1.0f, -1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is somewhere on line

            s = new V2(-0.5f, 0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(-1.0f, 1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is somewhere on line

            s = new V2(0.5f, -0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, -1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            /**************************************************/

            // --- TEST ---
            // s is not on line segment, but on same infinite line

            s = new V2(2.0f, 2.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is not on line segment, but on same infinite line

            s = new V2(-2.0f, -2.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is not on line segment, but very far on same infinite line

            s = new V2(-2000000.0f, -2000000.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is left of line, but close (in bbox)

            s = new V2(0.45f, 0.55f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = 1;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is left of line and far away (outside bbox)

            s = new V2(0.0f, 1000.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = 1;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is on line

            s = new V2(14304f, 32512f);
            p1 = new V2(15872f, 32512f);
            p2 = new V2(3433.6f, 32512f);
            expected = 0;
            returned = s.GetSide(p1, p2);

            Assert.AreEqual(expected, returned);

        }
 /// <summary>
 /// Adjusts the current min, max accordingly in case
 /// the new point lies outside the current box.
 /// </summary>
 /// <param name="Point"></param>
 public void ExtendByPoint(V2 Point)
 {
     if (Point.X < Min.X) Min.X = Point.X;
     if (Point.X > Max.X) Max.X = Point.X;
     if (Point.Y < Min.Y) Min.Y = Point.Y;
     if (Point.Y > Max.Y) Max.Y = Point.Y;
 }
Beispiel #27
0
 /// <summary>
 /// Typed equals
 /// </summary>
 /// <param name="obj"></param>
 /// <returns></returns>
 public bool Equals(V2 obj)
 {
     return
         (Math.Abs(obj.X - X) <= EPSILON &&
          Math.Abs(obj.Y - Y) <= EPSILON);
 }
 /// <summary>
 /// Converts V2 direction to M59 angle.
 /// </summary>
 /// <example>
 ///    V2           M59
 /// -------------------------
 /// (1,   0)      = 0
 /// (1,   1)      = 512
 /// (0,   1)      = 1024
 /// (-1,  1)      = 1536
 /// (-1,  0)      = 2048
 /// (-1, -1)      = 2560
 /// (0,  -1)      = 3072
 /// (1,  -1)      = 3584
 /// (1,  -0.0001) = 4096
 /// </example>
 /// <param name="Direction">Direction vector</param>
 /// <returns>Value in [0..4096]</returns>
 public static ushort GetAngleForDirection(ref V2 Direction)
 {
     return(RadianToBinaryAngle(
                GetRadianForDirection(ref Direction)));
 }
Beispiel #29
0
        /// <summary>
        /// Returns the distance to another point
        /// </summary>
        /// <param name="Destination"></param>
        /// <returns></returns>
        public Real DistanceTo(V2 Destination)
        {
            V2 diff = Destination - this;

            return(diff.Length);
        }
Beispiel #30
0
        public static List<Tuple<RooSubSector, V2, float>> FindVertexMismatches(V2 Vertex)
        {
            const float CLOSE = 2;

            List<Tuple<RooSubSector, V2, float>> list = new List<Tuple<RooSubSector, V2, float>>();

            foreach (RooSubSector s in Room.BSPTreeLeaves)
            {
                foreach (V2 v in s.Vertices)
                {
                    float absdx = (float)Math.Abs(v.X - Vertex.X);
                    float absdy = (float)Math.Abs(v.Y - Vertex.Y);

                    // must be very close but not same pos
                    if (absdx <= CLOSE && absdy <= CLOSE && (absdx > 0 || absdy > 0))
                        list.Add(new Tuple<RooSubSector, V2, float>(s, v, Math.Max(absdx, absdy)));
                }
            }

            return list;
        }
Beispiel #31
0
 /// <summary>
 /// See and prefer variant with ref params!
 /// </summary>
 /// <param name="P1"></param>
 /// <param name="P2"></param>
 /// <returns></returns>
 public bool IsOnLineSegment(V2 P1, V2 P2)
 {
     return(IsOnLineSegment(ref P1, ref P2));
 }
Beispiel #32
0
        protected void Calculate(
            ObjectBase Data,
            BgfBitmap MainFrame,
            bool UseViewerFrame = true,
            bool ApplyYOffset = true,
            byte RootHotspotIndex = 0,
            Real Quality = DEFAULTQUALITY,
            bool ScalePow2 = false,
            uint Width = 0,
            uint Height = 0,
            bool CenterVertical = false,
            bool CenterHorizontal = false)
        {
            BgfBitmap mainFrame = MainFrame;
            BgfFile mainResource = Data.Resource;
            byte mainColor = Data.ColorTranslation;
            BgfBitmap subOvFrame;
            BgfBitmapHotspot subOvHotspot;
            SubOverlay subOvParent;
            BgfBitmap subOvParentFrame;
            BgfBitmapHotspot subOvParentHotspot;
            bool rootSpotFound = false;

            // use custom compose root (suboverlay=mainoverlay)
            // if it's not found, fallback to full compose
            if (RootHotspotIndex > 0)
            {
                SubOverlay subOv = Data.GetSubOverlayByHotspot(RootHotspotIndex);

                if (subOv != null)
                {
                    rootSpotFound = true;

                    if (UseViewerFrame)
                        mainFrame = subOv.ViewerFrame;
                    else
                        mainFrame = subOv.FrontFrame;

                    mainResource = subOv.Resource;
                    mainColor = subOv.ColorTranslation;
                }
            }

            if (mainFrame != null && mainResource != null)
            {
                Bgf = mainFrame;
                BgfColor = mainColor;
                size.X = (Real)mainFrame.Width / (Real)mainResource.ShrinkFactor;
                size.Y = (Real)mainFrame.Height / (Real)mainResource.ShrinkFactor;
                origin.X = (Real)mainFrame.XOffset / (Real)mainResource.ShrinkFactor;
                origin.Y = (Real)mainFrame.YOffset / (Real)mainResource.ShrinkFactor;
                MaxShrink = mainResource.ShrinkFactor;

                // used to calculate the boundingbox
                V2 min = new V2(Origin.X, Origin.Y);
                V2 max = (ApplyYOffset) ? 
                    new V2(Size.X, Size.Y) : 
                    new V2(Origin.X + Size.X, Origin.Y + Size.Y);

                Real x, y;

                // walk suboverlay structure
                foreach (SubOverlay subOv in Data.CurrentSubOverlays)
                {
                    if (UseViewerFrame)
                    {
                        subOvFrame = subOv.ViewerFrame;
                        subOvHotspot = subOv.ViewerHotspot;
                        subOvParent = subOv.ViewerParent;
                    }
                    else
                    {
                        subOvFrame = subOv.FrontFrame;
                        subOvHotspot = subOv.FrontHotspot;
                        subOvParent = subOv.FrontParent;
                    }

                    bool isSubRoot = (subOvParent != null && subOvParent.HotSpot == RootHotspotIndex);

                    if (subOv.Resource != null &&
                        subOvFrame != null &&
                        subOvHotspot != null &&
                        (RootHotspotIndex <= 0 || !rootSpotFound || isSubRoot))
                    {
                        SubOverlay.RenderInfo subOvInfo = new SubOverlay.RenderInfo();
                        
                        // save subov & bitmap
                        subOvInfo.SubOverlay = subOv;
                        subOvInfo.Bgf = subOvFrame;

                        // calculate the size of this suboverlay
                        subOvInfo.Size.X = (Real)subOvFrame.Width / (Real)subOv.Resource.ShrinkFactor;
                        subOvInfo.Size.Y = (Real)subOvFrame.Height / (Real)subOv.Resource.ShrinkFactor;

                        // update maxshrink if greater
                        if (subOv.Resource.ShrinkFactor > MaxShrink)
                            MaxShrink = subOv.Resource.ShrinkFactor;

                        // CASE 1: SubOverlay on mainoverlay
                        if (subOvParent == null || isSubRoot)
                        {
                            // calculate the origin of this suboverlay on the mainoverlay
                            subOvInfo.Origin.X = mainFrame.XOffset
                                + ((Real)subOvHotspot.X)
                                + ((Real)subOvFrame.XOffset);

                            subOvInfo.Origin.Y = mainFrame.YOffset
                                + ((Real)subOvHotspot.Y)
                                + ((Real)subOvFrame.YOffset);

                            subOvInfo.Origin.X /= mainResource.ShrinkFactor;
                            subOvInfo.Origin.Y /= mainResource.ShrinkFactor;

                            // determine type of hotspot
                            if (subOvHotspot.Index < 0)
                                subOvInfo.HotspotType = HotSpotType.HOTSPOT_UNDER;
                            else
                                subOvInfo.HotspotType = HotSpotType.HOTSPOT_OVER;
                        }

                        // CASE 2: SubOverlay on SubOverlay on MainOverlay
                        else
                        {
                            if (UseViewerFrame)
                            {
                                subOvParentFrame = subOvParent.ViewerFrame;
                                subOvParentHotspot = subOvParent.ViewerHotspot;
                            }
                            else
                            {
                                subOvParentFrame = subOvParent.FrontFrame;
                                subOvParentHotspot = subOvParent.FrontHotspot;
                            }

                            if (subOvParentHotspot != null &&
                                subOvParentFrame != null &&
                                subOvParent.Resource != null)
                            {
                                // calculate the origin of this suboverlay on the suboverlay on the mainoverlay
                                subOvInfo.Origin.X = 
                                    (mainFrame.XOffset +
                                    (Real)subOvParentHotspot.X +
                                    (Real)subOvParentFrame.XOffset) / (Real)mainResource.ShrinkFactor;

                                subOvInfo.Origin.X +=
                                    ((Real)subOvHotspot.X +
                                    (Real)subOvFrame.XOffset) / (Real)subOvParent.Resource.ShrinkFactor;

                                subOvInfo.Origin.Y = 
                                    (mainFrame.YOffset +
                                    (Real)subOvParentHotspot.Y +
                                    (Real)subOvParentFrame.YOffset) / (Real)mainResource.ShrinkFactor;

                                subOvInfo.Origin.Y +=
                                    ((Real)subOvHotspot.Y +
                                    (Real)subOvFrame.YOffset) / (Real)subOvParent.Resource.ShrinkFactor;

                                // determine type of nested hotspot
                                if (subOvParentHotspot.Index > 0 && subOvHotspot.Index > 0)
                                    subOvInfo.HotspotType = HotSpotType.HOTSPOT_OVEROVER;

                                else if (subOvParentHotspot.Index > 0 && subOvHotspot.Index < 0)
                                    subOvInfo.HotspotType = HotSpotType.HOTSPOT_OVERUNDER;

                                else if (subOvParentHotspot.Index < 0 && subOvHotspot.Index > 0)
                                    subOvInfo.HotspotType = HotSpotType.HOTSPOT_UNDEROVER;

                                else if (subOvParentHotspot.Index < 0 && subOvHotspot.Index < 0)
                                    subOvInfo.HotspotType = HotSpotType.HOTSPOT_UNDERUNDER;
                            }
                        }

                        // update max boundingbox
                        if (subOvInfo.Origin.X < min.X)
                            min.X = subOvInfo.Origin.X;

                        if (subOvInfo.Origin.Y < min.Y)
                            min.Y = subOvInfo.Origin.Y;

                        x = subOvInfo.Origin.X + subOvInfo.Size.X;
                        y = subOvInfo.Origin.Y + subOvInfo.Size.Y;

                        if (x > max.X)
                            max.X = x;

                        if (y > max.Y)
                            max.Y = y;

                        // save info for this suboverlay
                        SubBgf.Add(subOvInfo);
                    }
                }

                // get dimension from boundingbox
                dimension.X = Math.Abs(max.X - min.X);
                dimension.Y = Math.Abs(max.Y - min.Y);

                // move all origins so minimum hits 0/0
                // preparation for drawing (pixel origin is 0/0)
                Translate(-min);

                // get the center of the dimension box
                // this is also the center of our image after the translate above
                V2 bbCenter = dimension * 0.5f;

                // get the center of the main overlay
                V2 mainOriginCenter = Origin + (Size * 0.5f);

                // move the x center of the main overlay to the x center of dimensionbox
                V2 centerMove = new V2(bbCenter.X - mainOriginCenter.X, 0.0f);
                Translate(centerMove);

                // since this moves a part outside the dimension box
                // we need to add this size of the move to the dimension, 
                // to the right AND left side, so our centering above stays centered
                // then we remove to the center.
                V2 center = new V2(Math.Abs(centerMove.X), 0.0f);
                dimension.X += center.X * 2.0f;
                Translate(center);

                // scale so highest resolution resource has 1:1 ratio (no downscale)
                // and apply custom quality level
                Scale((Real)MaxShrink);

                // scale up to pow2 if set
                if (ScalePow2)
                {
                    Real maxQuality = Quality * QUALITYBASE;
                    Real ratioX = maxQuality / dimension.X;
                    Real ratioY = maxQuality / dimension.Y;

                    if (ratioX <= ratioY && ratioX < 1.0f)
                        Scale(ratioX);
                    else if (ratioX > ratioY && ratioY < 1.0f)
                        Scale(ratioY);

                    // get next power of 2 size
                    V2 pow2Size = new V2(
                        MathUtil.NextPowerOf2((uint)dimension.X),
                        MathUtil.NextPowerOf2((uint)dimension.Y));

                    // scale so we use at least all pixels either from upscaled width or height
                    ScaleToBox(pow2Size, CenterHorizontal, CenterVertical);
                }
                else if (Width > 0 && Height > 0)
                {
                    // use user given size
                    V2 userSize = new V2(Width, Height);

                    // scale so we use at least all pixels either from upscaled width or height
                    ScaleToBox(userSize, CenterHorizontal, CenterVertical);
                }
            }
        }
Beispiel #33
0
 /// <summary>
 /// Returns the side (-1 or 1) of this (point) instance
 /// for the line given by points P1 and P2.
 /// </summary>
 /// <param name="P1"></param>
 /// <param name="P2"></param>
 /// <returns></returns>
 public int GetSide(V2 P1, V2 P2)
 {
     return(Math.Sign((P2.X - P1.X) * (Y - P1.Y) - (P2.Y - P1.Y) * (X - P1.X)));
 }
Beispiel #34
0
        /// <summary>
        /// Moves the origins by given translation.
        /// </summary>
        /// <param name="Translation"></param>
        protected void Translate(V2 Translation)
        {
            origin.X += Translation.X;
            origin.Y += Translation.Y;

            foreach (SubOverlay.RenderInfo subInfo in SubBgf)
            {
                subInfo.Origin.X += Translation.X;
                subInfo.Origin.Y += Translation.Y;
            }
        }
Beispiel #35
0
 /// <summary>
 /// Typed equals
 /// </summary>
 /// <param name="obj"></param>
 /// <returns></returns>
 public bool Equals(V2 obj)
 {
     return(obj.X == X && obj.Y == Y);
 }
 /// <summary>
 /// Modifies a 2D vector to slide along this wall
 /// Based on projection.
 /// </summary>
 /// <param name="Begin"></param>
 /// <param name="End"></param>
 /// <returns></returns>
 public V2 SlideAlong(V2 Begin, V2 End)
 {
     V2 diff = End - Begin;
     V2 projection = diff.GetProjection(GetP1P2());
     return Begin + projection;
 }
        /// <summary>
        /// Checks two finite line segments for intersection.
        /// </summary>
        /// <param name="P1">First point of first line segment</param>
        /// <param name="P2">Second point of first line segment</param>
        /// <param name="Q1">First point of second line segment</param>
        /// <param name="Q2">Second point of second line segment</param>
        /// <param name="Intersect">Intersection point</param>
        /// <returns>LineLineIntersectionType</returns>
        public static LineLineIntersectionType IntersectLineLine(ref V2 P1, ref V2 P2, ref V2 Q1, ref V2 Q2, out V2 Intersect)
        {
            Intersect.X = 0.0f;
            Intersect.Y = 0.0f;

            /*****************************************************************/

            // fully coincide, lines are equal
            if ((P1 == Q1 && P2 == Q2) || (P1 == Q2 && P2 == Q1))
            {
                // use one point as intersection
                Intersect.X = P1.X;
                Intersect.Y = P1.Y;

                return(LineLineIntersectionType.FullyCoincide);
            }

            /*****************************************************************/

            V2   b         = P2 - P1;
            V2   d         = Q2 - Q1;
            Real bDotDPerp = b.X * d.Y - b.Y * d.X;

            /******************************************************************
            *                 SPECIAL CASE: b dot d == 0                     *
            ******************************************************************/

            // three subcases:
            // (a) no intersect: parallel or on same infinite line but don't overlap
            // (b) partially coincide with many intersections
            // (c) touch each other at one endpoint
            if (bDotDPerp == 0.0f)
            {
                bool isP1onQ1Q2 = P1.IsOnLineSegment(ref Q1, ref Q2);
                bool isP2onQ1Q2 = P2.IsOnLineSegment(ref Q1, ref Q2);
                bool isQ1onP1P2 = Q1.IsOnLineSegment(ref P1, ref P2);
                bool isQ2onP1P2 = Q2.IsOnLineSegment(ref P1, ref P2);

                // subcase (a): p1p2 and q1q2 don't share a point
                if (!isP1onQ1Q2 && !isP2onQ1Q2 && !isQ1onP1P2 && !isQ2onP1P2)
                {
                    return(LineLineIntersectionType.NoIntersection);
                }

                // subcase (b): P1P2 fully inside Q1Q2
                if (isP1onQ1Q2 && isP2onQ1Q2)
                {
                    // use p1 for intersection
                    Intersect.X = P1.X;
                    Intersect.Y = P1.Y;

                    return(LineLineIntersectionType.PartiallyCoincide);
                }

                // subcase (b): Q1Q2 fully inside P1P2
                if (isQ1onP1P2 && isQ2onP1P2)
                {
                    // use p1 for intersection
                    Intersect.X = Q1.X;
                    Intersect.Y = Q1.Y;

                    return(LineLineIntersectionType.PartiallyCoincide);
                }

                // subcase (c): touch at P1
                if (isP1onQ1Q2 && !isP2onQ1Q2)
                {
                    // use p1 for intersection
                    Intersect.X = P1.X;
                    Intersect.Y = P1.Y;

                    return(LineLineIntersectionType.OneBoundaryPoint);
                }

                // subcase (c): touch at P2
                if (!isP1onQ1Q2 && isP2onQ1Q2)
                {
                    // use p1 for intersection
                    Intersect.X = P2.X;
                    Intersect.Y = P2.Y;

                    return(LineLineIntersectionType.OneBoundaryPoint);
                }

                // subcase (c): touch at Q1
                if (isQ1onP1P2 && !isQ2onP1P2)
                {
                    // use p1 for intersection
                    Intersect.X = Q1.X;
                    Intersect.Y = Q1.Y;

                    return(LineLineIntersectionType.OneBoundaryPoint);
                }

                // subcase (c): touch at Q2
                if (!isQ1onP1P2 && isQ2onP1P2)
                {
                    // use p1 for intersection
                    Intersect.X = Q2.X;
                    Intersect.Y = Q2.Y;

                    return(LineLineIntersectionType.OneBoundaryPoint);
                }
            }

            /******************************************************************
            *             DEFAULT CASE: INFINITE LINES CROSS                 *
            ******************************************************************/

            V2   c = Q1 - P1;
            Real t = (c.X * d.Y - c.Y * d.X) / bDotDPerp;

            if (t < 0.0f || t > 1.0f)
            {
                return(LineLineIntersectionType.NoIntersection);
            }

            Real u = (c.X * b.Y - c.Y * b.X) / bDotDPerp;

            if (u < 0.0f || u > 1.0f)
            {
                return(LineLineIntersectionType.NoIntersection);
            }

            // -- finite line segments cross or boundary point! --

            b.Scale(t);
            Intersect = P1 + b;

            // if the intersection point is also the endpoint of
            // one of the finite lines, it's a boundary point
            if (Intersect == P1 || Intersect == P2 || Intersect == Q1 || Intersect == Q2)
            {
                return(LineLineIntersectionType.OneBoundaryPoint);
            }

            // true intersection
            return(LineLineIntersectionType.OneIntersection);
        }
        /// <summary>
        /// Checks if this wall blocks a
        /// move between Start and End
        /// </summary>
        /// <param name="Start">A 3D location</param>
        /// <param name="End">A 2D location</param>
        /// <param name="PlayerHeight">Height of the player for ceiling collisions</param>
        /// <returns></returns>
        public bool IsBlocking(V3 Start, V2 End, Real PlayerHeight)
        {
            V2 Start2D = new V2(Start.X, Start.Z);

            // calculate the sides of the points (returns -1, 0 or 1)
            int startside = Start2D.GetSide(P1, P2);
            int endside = End.GetSide(P1, P2);

            // if points are not on same side
            // the infinite lines cross
            if (startside != endside)
            {
                // verify also the finite line segments cross
                V2 intersect;

                LineLineIntersectionType intersecttype =
                    MathUtil.IntersectLineLine(Start2D, End, P1, P2, out intersect);

                if (intersecttype == LineLineIntersectionType.OneIntersection ||
                    intersecttype == LineLineIntersectionType.OneBoundaryPoint ||
                    intersecttype == LineLineIntersectionType.FullyCoincide ||
                    intersecttype == LineLineIntersectionType.PartiallyCoincide)
                {
                    // verify the side we've crossed is flaggged as "nonpassable"
                    // if so, we actually have a collision
                    if ((startside < 0 && LeftSide != null && !LeftSide.Flags.IsPassable) ||
                        (startside > 0 && RightSide != null && !RightSide.Flags.IsPassable))
                    {
                        return true;
                    }

                    // still check the stepheight from oldheight to new floor if passable
                    // for too high steps
                    Real endheight = 0.0f;
                    Real diff;

                    if (endside <= 0 && LeftSector != null)
                        endheight = LeftSector.CalculateFloorHeight((int)End.X, (int)End.Y, true);

                    else if (endside > 0 && RightSector != null)
                        endheight = RightSector.CalculateFloorHeight((int)End.X, (int)End.Y, true);

                    diff = endheight - Start.Y;

                    // diff is bigger than max. step height, we have a collision
                    if (diff > GeometryConstants.MAXSTEPHEIGHT)
                        return true;

                    // check the ceiling heights
                    if (endside <= 0 && LeftSector != null)
                        endheight = LeftSector.CalculateCeilingHeight((int)End.X, (int)End.Y);

                    else if (endside > 0 && RightSector != null)
                        endheight = RightSector.CalculateCeilingHeight((int)End.X, (int)End.Y);

                    // diff is bigger than max. step height, we have a collision
                    if (endheight < Start.Y + PlayerHeight)
                        return true;
                }
            }

            return false;
        }
Beispiel #39
0
 /// <summary>
 /// Typed equals
 /// </summary>
 /// <param name="obj"></param>
 /// <returns></returns>
 public bool Equals(V2 obj)
 {
     return 
         Math.Abs(obj.X-X) <= EPSILON && 
         Math.Abs(obj.Y-Y) <= EPSILON;
 }
Beispiel #40
0
        public void IsOnLineSegment()
        {
            bool expected;
            bool returned;
            V2 s, p1, p2;

            /**************************************************/

            // --- TEST ---
            // p1=p2=s=0, no line

            s = new V2(0.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(0.0f, 0.0f);
            expected = true;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // p1=s

            s = new V2(0.0f, 0.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(0.0f, 1.0f);
            expected = true;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // p2=s

            s = new V2(0.0f, 1.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(0.0f, 1.0f);
            expected = true;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            /**************************************************/

            // --- TEST ---
            // s is somewhere on line
            
            s = new V2(0.5f, 0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = true;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is somewhere on line
            
            s = new V2(-0.5f, -0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(-1.0f, -1.0f);
            expected = true;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is somewhere on line
            
            s = new V2(-0.5f, 0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(-1.0f, 1.0f);
            expected = true;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is somewhere on line

            s = new V2(0.5f, -0.5f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, -1.0f);
            expected = true;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            /**************************************************/

            // --- TEST ---
            // s is not on line segment, but on same infinite line

            s = new V2(2.0f, 2.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = false;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is not on line segment, but on same infinite line

            s = new V2(-2.0f, -2.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = false;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);


            // --- TEST ---
            // s is not on line, but close aside of it (in bbox)

            s = new V2(0.45f, 0.55f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = false;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is not on line and far (outside bbox)

            s = new V2(0.0f, 1000.0f);
            p1 = new V2(0.0f, 0.0f);
            p2 = new V2(1.0f, 1.0f);
            expected = false;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);

            // --- TEST ---
            // s is on line

            s = new V2(14304f, 32512f);
            p1 = new V2(15872f, 32512f);
            p2 = new V2(3433.6f, 32512f);
            expected = true;
            returned = s.IsOnLineSegment(p1, p2);

            Assert.AreEqual(expected, returned);
        }
Beispiel #41
0
        /// <summary>
        /// Returns the distance to another point
        /// </summary>
        /// <param name="Destination"></param>
        /// <returns></returns>
        public Real DistanceTo(V2 Destination)
        {
            V2 diff = Destination - this;

            return diff.Length;
        }
Beispiel #42
0
        /// <summary>
        /// Returns the squared distance to another point
        /// </summary>
        /// <param name="Destination"></param>
        /// <returns></returns>
        public Real DistanceToSquared(V2 Destination)
        {
            V2 diff = Destination - this;

            return diff.LengthSquared;
        }
 /// <summary>
 /// Returns true if P lies inside the boundingbox defines by S and E
 /// </summary>
 /// <param name="S"></param>
 /// <param name="E"></param>
 /// <param name="P"></param>
 /// <param name="Epsilon"></param>
 /// <returns></returns>
 public static bool IsInBoundingBox(ref V2 S, ref V2 E, ref V2 P, Real Epsilon)
 {
     return
         (Min(S.X, E.X) - Epsilon <= P.X && P.X <= Max(S.X, E.X) + Epsilon &&
          Min(S.Y, E.Y) - Epsilon <= P.Y && P.Y <= Max(S.Y, E.Y) + Epsilon);
 }
Beispiel #44
0
        /// <summary>
        /// Returns the minimum squared distance of this instance to a
        /// line segment given by points P1, P2.
        /// Note: line segment != infinite line
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        /// <returns></returns>
        public Real MinSquaredDistanceToLineSegment(V2 P1, V2 P2)
        {
            V2 diff = P2 - P1;
            Real l2 = diff.LengthSquared;

            if (l2 == 0.0f)
                return DistanceToSquared(P1);

            Real t = ((this - P1) * (P2 - P1)) / l2;

            if (t < 0.0f)
                return DistanceToSquared(P1);

            else if (t > 1.0f)
                return DistanceToSquared(P2);

            diff.Scale(t);
            V2 projection = P1 + diff;

            return DistanceToSquared(projection);
        }
        /// <summary>
        /// Recalculates the ViewerAngle property based on a viewer's position.
        /// </summary>
        /// <param name="ViewerPosition"></param>
        public void UpdateViewerAngle(V2 ViewerPosition)
        {
            V2 direction = TargetObject.Position2D - Position2D;
            direction.Normalize();

            ushort angle = MathUtil.GetAngleForDirection(direction);

            // update viewer angle
            ViewerAngle = MathUtil.GetAngle(ViewerPosition, Position2D, angle);

            // mark for possible appearance change
            appearanceChanged = true;
        }
Beispiel #46
0
        /// <summary>
        /// Returns the side (-1 or 1) of this (point) instance
        /// for the line given by points P1 and P2.
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        /// <returns></returns>
        public int GetSide(V2 P1, V2 P2)
        {
            Real val = (P2.X - P1.X) * (Y - P1.Y) - (P2.Y - P1.Y) * (X - P1.X);

            if (val >= EPSILON)
                return 1;

            else if (val <= -EPSILON)
               return -1;

            else
                return 0;
        }
Beispiel #47
0
        /// <summary>
        /// Scales the renderinfo with respect to width/height ratio.
        /// Only one side will fit the given Dimension exactly afterwards.
        /// </summary>
        /// <param name="Dimension"></param>
        /// <param name="CenterHorizontal"></param>
        /// <param name="CenterVertical"></param>
        protected void ScaleToBox(V2 Dimension, bool CenterHorizontal = false, bool CenterVertical = false)
        {
            // get scales for both axis
            Real hScale = Dimension.X / this.Dimension.X;
            Real vScale = Dimension.Y / this.Dimension.Y;

            // use the smaller factor so the other side "still fits"
            // into given dimension
            if (hScale >= vScale)
            {
                // apply scale from y-side
                Scale(vScale);

                if (CenterHorizontal)
                {
                    Real stride = (Dimension.X - this.Dimension.X) / 2.0f;
                    Real strideratio = stride / Dimension.X;

                    Translate(new V2(stride, 0.0f));

                    uvstart.X = 0.0f + strideratio;
                    uvend.X = 1.0f - strideratio;
                }
                else
                {
                    // adjust UVEnd on x-side                     
                    uvend.X = 1.0f * (this.Dimension.X / Dimension.X);
                }
            }
            else
            {
                // apply scale from x-side
                Scale(hScale);

                if (CenterVertical)
                {
                    Real stride = (Dimension.Y - this.Dimension.Y) / 2.0f;
                    Real strideratio = stride / Dimension.Y;

                    Translate(new V2(0.0f, stride));

                    uvstart.Y = 0.0f + strideratio;
                    uvend.Y = 1.0f - strideratio;
                }
                else
                {
                    // adjust UVEnd on y-side
                    uvend.Y = 1.0f * (this.Dimension.Y / Dimension.Y);
                }
            }

            this.Dimension = Dimension;
        }
Beispiel #48
0
        /// <summary>
        /// Tests whether this V2 instance lies on a line segment
        /// given by points P1 and P2.
        /// </summary>
        /// <param name="P1"></param>
        /// <param name="P2"></param>
        /// <returns></returns>
        public bool IsOnLineSegment(V2 P1, V2 P2)
        {
            // the point is not even on the infinite line given by P1P2
            if (GetSide(P1, P2) != 0)
                return false;

            // if on infinite line, must also be in boundingbox
            V2 min, max;
            min.X = Math.Min(P1.X, P2.X);
            min.Y = Math.Min(P1.Y, P2.Y);
            max.X = Math.Max(P1.X, P2.X);
            max.Y = Math.Max(P1.Y, P2.Y);

            return
                min.X <= X && X <= max.X &&
                min.Y <= Y && Y <= max.Y;
        }
        protected Real zz3; /* height of top of upper wall */

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Constructor by values
        /// </summary>
        /// <param name="RooVersion"></param>
        /// <param name="ServerID">Sometimes also called UserID, used to reference wall by server.</param>
        /// <param name="RightSideNum">Num of the right side of the wall (1=first, 0=unset)</param>
        /// <param name="LeftSideNum">Num of the left side of the wall (1=first, 0=unset)</param>
        /// <param name="P1">2D coordinates of startpoint, must be in 1:1024 units</param>
        /// <param name="P2">2D coordinates of endpoint, must be in 1:1024 units</param>
        /// <param name="RightXOffset"></param>
        /// <param name="LeftXOffset"></param>
        /// <param name="RightYOffset"></param>
        /// <param name="LeftYOffset"></param>
        /// <param name="RightSectorNum">Num of the sector right to the wall (1=first, 0=unset)</param>
        /// <param name="LeftSectorNum">Num of the sector left to the wall (1=first, 0=unset)</param>
        public RooWall(
            uint RooVersion,
            short ServerID, 
            ushort RightSideNum, 
            ushort LeftSideNum, 
            V2 P1, 
            V2 P2, 
            short RightXOffset, 
            short LeftXOffset, 
            short RightYOffset, 
            short LeftYOffset,
            ushort RightSectorNum, 
            ushort LeftSectorNum)
        {
            this.RooVersion = RooVersion;
            this.NextWallNumInPlane = ServerID;
            this.RightSideNum = RightSideNum;
            this.LeftSideNum = LeftSideNum;
            this.P1 = P1;
            this.P2 = P2;

            // set clientlength stored in 1:64 units (convert from 1:1024)
            this.ClientLength = (P1-P2).Length * 0.0625f;

            this.RightXOffset = RightXOffset;
            this.LeftXOffset = LeftXOffset;
            this.RightYOffset = RightYOffset;
            this.LeftYOffset = LeftYOffset;
            this.RightSectorNum = RightSectorNum;
            this.LeftSectorNum = LeftSectorNum;

            this.BowtieFlags = new BowtieFlags();
        }
Beispiel #50
0
        /// <summary>
        /// Returns a projection of this instance on another vector.
        /// </summary>
        /// <param name="Vector"></param>
        /// <returns></returns>
        public V2 GetProjection(V2 Vector)
        {
            Real denom = Vector.LengthSquared;

            if (denom > 0.0f)
            {
                Real num = this * Vector;
                return Vector * (num / denom);
            }
            else
                return V2.ZERO;
        }
        /// <summary>
        /// Splits this wall into two using infinite line given by Q1Q2.
        /// </summary>
        /// <param name="Q1"></param>
        /// <param name="Q2"></param>
        /// <returns>Item1: P1 to I. Item2: I to P2</returns>
        public Tuple<RooWall, RooWall> Split(V2 Q1, V2 Q2)
        {
            V2 intersect;

            // intersect this wall (finite line) with the infinite line given by Q1Q2
            LineInfiniteLineIntersectionType intersecttype =
                MathUtil.IntersectLineInfiniteLine(P1, P2, Q1, Q2, out intersect);

            // must have a real intersection, not only boundarypoint or even coincide
            if (intersecttype != LineInfiniteLineIntersectionType.OneIntersection)
                return null;

            /*****************************************************************/

            // 1) Piece from P1 to intersection
            RooWall wall1 = new RooWall(
                RooVersion,
                NextWallNumInPlane,
                RightSideNum,
                LeftSideNum,
                P1,
                intersect,
                RightXOffset,  // readjust below
                LeftXOffset,   // readjust below
                RightYOffset,  // readjust below
                LeftYOffset,   // readjust below
                RightSectorNum,
                LeftSectorNum
                );

            // also keep references of old wall
            wall1.RightSector = RightSector;
            wall1.LeftSector = LeftSector;
            wall1.RightSide = RightSide;
            wall1.LeftSide = LeftSide;
            wall1.BowtieFlags = BowtieFlags;
            wall1.CalculateWallSideHeights();

            /*****************************************************************/

            // 2) Piece from intersection to P2
            RooWall wall2 = new RooWall(
                RooVersion,
                NextWallNumInPlane,
                RightSideNum,
                LeftSideNum,
                intersect,
                P2,
                RightXOffset,  // readjust below
                LeftXOffset,   // readjust below
                RightYOffset,  // readjust below
                LeftYOffset,   // readjust below
                RightSectorNum,
                LeftSectorNum
                );

            // also keep references of old wall
            wall2.RightSector = RightSector;
            wall2.LeftSector = LeftSector;
            wall2.RightSide = RightSide;
            wall2.LeftSide = LeftSide;
            wall2.BowtieFlags = BowtieFlags;
            wall2.CalculateWallSideHeights();

            /*****************************************************************/

            // 3) Readjust texture offsets to accoutn for split

            // RightSide
            if (wall1.RightSide != null && wall1.RightSide.Flags.IsBackwards)
                wall1.RightXOffset += (short)wall2.ClientLength;
            else wall2.RightXOffset += (short)wall1.ClientLength;

            // LeftSide (Do this backwards, because client exchanges vertices of negative walls)
            if (wall1.LeftSide != null && wall1.LeftSide.Flags.IsBackwards)
                wall2.LeftXOffset += (short)wall1.ClientLength;
            else wall1.LeftXOffset += (short)wall2.ClientLength;

            /*****************************************************************/

            return new Tuple<RooWall, RooWall>(wall1, wall2);
        }
Beispiel #52
0
 /// <summary>
 /// Returns the scalar crossproduct of this vector
 /// and the parameter vector.
 /// </summary>
 /// <remarks>
 /// http://stackoverflow.com/questions/243945/calculating-a-2d-vectors-cross-product
 /// </remarks>
 /// <param name="v"></param>
 /// <returns></returns>
 public Real CrossProduct(V2 v)
 {
     return (X * v.Y) - (Y * v.X);
 }
        /// <summary>
        /// Checks if this wall blocks
        /// a view ray from Start to End
        /// </summary>
        /// <param name="Start"></param>
        /// <param name="End"></param>
        /// <returns>True if blocked, false if OK</returns>
        public bool IsBlockingSight(V3 Start, V3 End)
        {
            // 2D
            V2 Start2D = new V2(Start.X, Start.Z);
            V2 End2D = new V2(End.X, End.Z);

            // calculate the sides of the points (returns -1, 0 or 1)
            int startside = Start2D.GetSide(P1, P2);
            int endside = End2D.GetSide(P1, P2);

            // if points are not on same side
            // the infinite lines cross
            if (startside != endside)
            {
                // verify also the finite line segments cross
                V2 intersect;
                LineLineIntersectionType intersecttype =
                    MathUtil.IntersectLineLine(Start2D, End2D, P1, P2, out intersect);

                if (intersecttype == LineLineIntersectionType.OneIntersection ||
                    intersecttype == LineLineIntersectionType.OneBoundaryPoint ||
                    intersecttype == LineLineIntersectionType.FullyCoincide ||
                    intersecttype == LineLineIntersectionType.PartiallyCoincide)
                {
                    // the vector/ray between start and end
                    V3 diff = End - Start;

                    // solve 3d linear equation to get rayheight R2
                    // (height of possible intersection)
                    //
                    // ( R1 )   (P1)            (Q1)
                    // ( R2 ) = (P2) + lambda * (Q2)
                    // ( R3 )   (P3)            (Q3)
                    //
                    // using:
                    // R = intersect
                    // P = Start
                    // Q = diff (Direction)

                    // get lambda scale
                    Real lambda = 1.0f;
                    if (diff.X != 0)
                        lambda = (intersect.X - Start.X) / diff.X;

                    else if (diff.Z != 0)
                        lambda = (intersect.Y - Start.Z) / diff.Z;

                    // calculate the rayheight based on linear 3d equation
                    Real rayheight = Start.Y + lambda * diff.Y;

                    // compare height with wallheights
                    // use average of both endpoints (in case its sloped)
                    // do not care about the sides
                    Real h3 = (z3 + zz3) / 2.0f;
                    Real h2 = (z2 + zz2) / 2.0f;
                    Real h1 = (z1 + zz1) / 2.0f;
                    Real h0 = (z0 + zz0) / 2.0f;
                    bool a, b;

                    // test upper part
                    a = (startside <= 0 && LeftSide != null && LeftSide.ResourceUpper != null && (LeftSide.Flags.IsNoLookThrough || !LeftSide.Flags.IsTransparent));
                    b = (startside >= 0 && RightSide != null && RightSide.ResourceUpper != null && (RightSide.Flags.IsNoLookThrough || !RightSide.Flags.IsTransparent));
                    if ((a || b) &&
                        rayheight < h3 &&
                        rayheight > h2)
                        return true;

                    // test middle part
                    a = (startside <= 0 && LeftSide != null && LeftSide.ResourceMiddle != null && (LeftSide.Flags.IsNoLookThrough || !LeftSide.Flags.IsTransparent));
                    b = (startside >= 0 && RightSide != null && RightSide.ResourceMiddle != null && (RightSide.Flags.IsNoLookThrough || !RightSide.Flags.IsTransparent));
                    if ((a || b) &&
                        rayheight < h2 &&
                        rayheight > h1)
                        return true;

                    // test lower part (nolookthrough)
                    a = (startside <= 0 && LeftSide != null && LeftSide.ResourceLower != null);
                    b = (startside >= 0 && RightSide != null && RightSide.ResourceLower != null);
                    if ((a || b) &&
                        rayheight < h1 &&
                        rayheight > h0)
                        return true;
                }
            }

            return false;
        }
Beispiel #54
0
 /// <summary>
 /// Checks whether a point is inside the boundingbox
 /// </summary>
 /// <param name="P">Point to check</param>
 /// <param name="Extent"></param>
 /// <returns></returns>
 public bool IsInside(V2 P, Real Extent = 0.0f)
 {
     return
         (P.X + Extent >= Min.X && P.X - Extent <= Max.X &&
          P.Y + Extent >= Min.Y && P.Y - Extent <= Max.Y);
 }