unity3d: vector calculation, AOE graphics intersection

Shortest distance from point to line

/// <summary>
        ///The trigonometric function method calculates the square of the shortest vertical distance from X to the straight line x0 as the starting point and u as the unit vector
        /// </summary>
        ///< param name = "x0" > starting point < / param >
        ///< param name = "U" > unit vector of ray < / param >
        /// <param name="x"></param>
        /// <returns></returns>
        public static float StraightPointSqrMinDistanceByDir(Vector2 x0, Vector2 u, Vector2 x)
        {
            float t = Vector2.Dot(x - x0, u);
            return (x - (x0 + Mathf.Abs(t) * u)).sqrMagnitude;
        }

X0 is the starting point and u is the unit vector, then the length of x0t is | x0x|cosa = x0xu / |u | because u is the unit vector and the module length is 1. Then, the coordinate of point t is x - (x0 + Mathf.Abs(t) * u). Because X may be on the left of x0, only the absolute value unit vector of length is calculated, and then the distance between X and t is calculated

Distance from point to segment

The shortest vertical distance is when the point falls between segments, otherwise it is the shortest distance to one of the two endpoints

/// <summary>
        ///Calculate the square distance between the line segment and the point. The point is the vertical distance between the line segments, otherwise it is the distance from the nearest endpoint
        /// </summary>
        /// <param name="x0"></param>
        ///< param name = "U" > the direction of the line segment to the end point is two points subtracted < / param >
        /// <param name="x"></param>
        /// <returns></returns>
        public static float SegmentPointSqrDistance(Vector2 x0, Vector2 u, Vector2 x)
        {
            float t = Vector2.Dot(x - x0, u) / u.sqrMagnitude;
            return (x - (x0 + Mathf.Clamp(t, 0, 1) * u)).sqrMagnitude;
        }

1. First, suppose that two points P1 and P2 on the straight line and a point P3 outside the straight line are known.
2. Let the projection point be P0.
3. Because P0, P1 and P2 are on the same straight line, k (P2 - P1) = P0 - P1 can be obtained
k = |P0-P1|/|P2-P1|. As long as the scale factor K is obtained, the value of P0 can be obtained.
4. Let v1 = P3 - P1, v2 = P2 - P1, v1 and v2 point multiply to obtain: V1v2 = cos (seta) | p3-p1| p2-p1| = | p0-p1| p2-p1|, then
k = |P0-P1|/|P2-P1| = ( (v1v2)/|P2-P1| ) / |P2-P1| = (P3 - P1) * (P2 - P1) / (|P2 - P1| * |P2 - P1|)
Because it is the distance to the line segment, the range of k is [0,1], the projection point coordinate x0 + Mathf.Clamp(t, 0, 1) * u, and u is x1 - x0

Is the point inside the rectangle

Outer product, also known as cross product, is a concept in vector algebra (analytic geometry). Outer product v1 of two vectors v1(x1, y1) and v2(x2, y2) × v2=x1y2-y1x2. If v1 to V2 rotate clockwise, the outer product is negative, otherwise it is positive, and 0 indicates that the two directions are the same (parallel).

//External product. Outer product v1 of two vectors v1(x1, y1) and v2(x2, y2) × v2=x1y2-y1x2. 
        //>0, a in b clockwise < 0, a in b counterclockwise
        public static float Cross(this Vector2 a, Vector2 b)
        {
            return a.x * b.y - b.x * a.y;
        }

        public static bool IsPointInRectangle(Vector2 P, Vector2[] rectCorners)
        {
            return IsPointInRectangle(P, rectCorners[0], rectCorners[1], rectCorners[2], rectCorners[3]);
        }

        //Rectangle 4 points, sorted counterclockwise or clockwise from the first point
        public static bool IsPointInRectangle(Vector2 P, Vector2 A, Vector2 B, Vector2 C, Vector2 D)
        {
            Vector2 AB = A - B;
            Vector2 AP = A - P;
            Vector2 CD = C - D;
            Vector2 CP = C - P;

            Vector2 DA = D - A;
            Vector2 DP = D - P;
            Vector2 BC = B - C;
            Vector2 BP = B - P;

            bool isBetweenAB_CD = AB.Cross(AP) * CD.Cross(CP) > 0;
            bool isBetweenDA_BC = DA.Cross(DP) * BC.Cross(BP) > 0;
            return isBetweenAB_CD && isBetweenDA_BC;
        }

Circle intersects circle

Square of distance between two centers < square of length of two radii

Circle intersects rectangle

/// <summary>
        ///Whether the circle and rectangle intersect
        /// </summary>
        ///< param name = "CC" > center < / param >
        ///< param name = "R" > circle radius < / param >
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <param name="d"></param>
        /// <returns></returns>
        public static bool IsCicleRectIntersect(Vector2 cc,float r,Vector2 rectA,Vector2 rectB, Vector2 rectC, Vector2 rectD)
        {
            if (IsPointInRectangle(cc, rectA, rectB, rectC, rectD))//The center of the circle is inside the rectangle
            {
                return true;
            }
            else//The center of the circle is outside the rectangle and intersects with any edge
            {
                float sqR = r * r;
                float disA = SegmentPointSqrDistance(rectA, rectB - rectA, cc);
                if (disA < sqR)
                {
                    return true;
                }

                float disB = SegmentPointSqrDistance(rectB, rectC - rectB, cc);
                if (disB < sqR)
                {
                    return true;
                }

                float disC = SegmentPointSqrDistance(rectC, rectD - rectC, cc);
                if (disC < sqR)
                {
                    return true;
                }

                float disD = SegmentPointSqrDistance(rectD, rectA - rectD, cc);
                if (disD < r * r)
                {
                    return true;
                }
            }
            return false;
        }

The center of the circle intersects in the rectangle. The center of the circle is outside the rectangle. Compare the distance from the center of the circle to each rectangular edge segment. As long as there is a radius < circle, it will intersect

Coordinates after a point rotates around another point

Angle between two vectors

float angel = Vector2.Angle(Vector2.right, dirPos);

			if (dirPos.y < 0)
			{
				angel = -angel;
			}

The angle between a vector and Vector.right
Vector2.Angle
First quadrant: 0 ~ 90
Second quadrant: 90 ~ 180
Quadrant 3: 180 ~ 90
Quadrant 4: 90 ~ 0
The third and fourth quadrants should be rotated with negative values
Coordinates after rotation

public static Vector2 RotatePoint(Vector2 origin, float angle, Vector2 point)
{

	// Translate point back to origin;

	Vector2 temp = new Vector2(point.x -= origin.x, point.y -= origin.y);

	// Roate the point

	float xNew = Mathf.Cos(angle * Mathf.Deg2Rad) * (point.x) - Mathf.Sin(angle * Mathf.Deg2Rad) * (point.y);

	float yNew = Mathf.Cos(angle * Mathf.Deg2Rad) * (point.y) + Mathf.Sin(angle * Mathf.Deg2Rad) * (point.x);

	temp.x = xNew + origin.x;

	temp.y = yNew + origin.y;

	return temp;
}

The circle intersects the facing rectangle

First use rect's rectangle, and then rotate rect's four vertices toward the vector according to the rectangle

// No rotation towards rectangle ----- > the server's rectangle centered on the selection point, the client's selection point is at the edge of the rectangle, and rect in unit cannot use the direction
Rect effRange = new Rect(selectedPos.x, selectedPos.y - rectHigh * .5f, rectWidth, rectHigh);
Vector2 pos1 = HXUtility.RotatePoint(selectedPos, angel, effRange.min);
Vector2 pos2 = HXUtility.RotatePoint(selectedPos, angel, effRange.min + new Vector2(effRange.width, 0));
Vector2 pos3 = HXUtility.RotatePoint(selectedPos, angel, effRange.min + new Vector2(0, effRange.height));
Vector2 pos4 = HXUtility.RotatePoint(selectedPos, angel, effRange.max);

Then judge whether the point intersects the rectangle

The circle intersects the facing sector

// Fan and disk intersection test
        // a sector center
        // u sector direction (unit vector)
        // theta sector sweep half angle 
        // l sector side length
        // c center of disc
        // r radius of disc
        public static bool IsCicleSectorIntersect(
            Vector2 a, Vector2 u, float theta, float l,
            Vector2 c, float r)
        {
            // 1. If the direction of the sector center and the disc center can be separated, the two shapes do not intersect
            Vector2 d = c - a;
            float rsum = l + r;
            if (d.sqrMagnitude > rsum * rsum)
                return false;

            // 2. Calculate the p of fan-shaped local space
            float px = Vector2.Dot(d, u);
            float py = Mathf.Abs(Vector2.Dot(d, new Vector2(-u.y, u.x)));//Sector unit direction vector rotates 90 degrees counterclockwise

            // 3. If p_ X > | P | cos theta, two shapes intersect
            if (px > d.magnitude * Mathf.Cos(theta * Mathf.Deg2Rad))
                return true;

            // 4. Find out whether the left line segment intersects with the disc
            Vector2 q = l * new Vector2(Mathf.Cos(theta * Mathf.Deg2Rad), Mathf.Sin(theta * Mathf.Deg2Rad));
            Vector2 p = new Vector2(px, py);
            return SegmentPointSqrDistance(Vector2.zero, q, p) <= r * r;
        }

Tags: Unity3d linear algebra

Posted on Wed, 08 Sep 2021 00:58:38 -0400 by ranam