unity3d:向量计算,AOE图形相交

2023-08-24 15:34:00 浏览数 (2)

点到直线的最短距离

代码语言:javascript复制
/// <summary>
        /// 三角函数法求x到直线x0为起点,u为单位向量的垂直最短距离平方
        /// </summary>
        /// <param name="x0">起点</param>
        /// <param name="u">射线的单位向量</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为起点,u为单位向量,则x0t的长度为 |x0x|cosa = x0xu / |u|,因为u为单位向量,模长为1。然后得到t点坐标为x - (x0 Mathf.Abs(t) * u),因为x可能在x0的左边,所以只算长度的绝对值单位向量,然后算x,t两点距离

点到线段的距离

点落在线段之间为最短的垂直距离,否则为到两个端点之一的最短距离

代码语言:javascript复制
/// <summary>
        /// 计算线段与点的平方距离,点在线段之间是垂直距离,否则是与最近端点距离
        /// </summary>
        /// <param name="x0"></param>
        /// <param name="u">线段方向至末端点,为两点相减</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、首先假设已知直线上两点P1、P2、以及直线外一点P3。 2、令投影点为P0。 3、因为P0、P1、P2都在同一条直线上,所以可得k (P2 - P1) = P0 - P1 k = |P0-P1|/|P2-P1|。 只要求出比例因子k,便可求出P0的值。 4、令v1 = P3 - P1 , v2 = P2 - P1,v1与v2进行点乘得:v1v2=cos(seta)|P3-P1||P2-P1|=|P0-P1||P2-P1|,于是 k = |P0-P1|/|P2-P1| = ( (v1v2)/|P2-P1| ) / |P2-P1| = (P3 - P1) * (P2 - P1) / (|P2 - P1| * |P2 - P1|) 因为是到线段的距离,所以k的范围为[0,1], 投影点坐标 x0 Mathf.Clamp(t, 0, 1) * u ,u为 x1 - x0

点是否在矩形内

外积,又称叉积,是向量代数(解析几何)中的一个概念。两个向量v1(x1, y1)和v2(x2, y2)的外积v1×v2=x1y2-y1x2。如果由v1到v2是顺时针转动,外积为负,反之为正,为0表示二者方向相同(平行)。

代码语言:javascript复制
//外积。两个向量v1(x1, y1)和v2(x2, y2)的外积v1×v2=x1y2-y1x2。
        //>0,a在b顺时针方向    <0,a在b逆时针
        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]);
        }

        //矩形4个点,从第一个点开始逆时针或者顺时针排序
        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;
        }

圆与圆相交

两圆心距离平方 < 两者半径长平方

圆与矩形相交

代码语言:javascript复制
/// <summary>
        /// 圆与矩形是否相交
        /// </summary>
        /// <param name="cc">圆心</param>
        /// <param name="r">圆半径</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))//圆心在矩形内部
            {
                return true;
            }
            else//圆心在矩形外部,与任意一条边相交,即相交
            {
                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;
        }

圆心在矩形内即相交。圆心在矩形外,比较圆心到每条矩形边线段的距离,只要有一条< 圆的半径即相交

点围绕另一点旋转后坐标

两个向量夹角

代码语言:javascript复制
float angel = Vector2.Angle(Vector2.right, dirPos);

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

一个向量与Vector.right的夹角 Vector2.Angle 第一象限:0~90 第二象限:90~180 第三象限:180~90 第四象限:90~0 三四象限要为 负值旋转 旋转后坐标

代码语言:javascript复制
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;
}

圆与朝向矩形相交

先是使用rect的矩形,然后根据矩形朝向向量旋转rect的四个顶点

代码语言:javascript复制
// 无旋转朝向矩形----->服务器以选重点为中心的矩形,客户端选中点在矩形边缘,unity中rect无法使用方向
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);

再判断点与矩形相交

圆与朝向扇形相交

代码语言:javascript复制
// 扇形与圆盘相交测试
        // a 扇形圆心
        // u 扇形方向(单位矢量)
        // theta 扇形扫掠半角 
        // l 扇形边长
        // c 圆盘圆心
        // r 圆盘半径
        public static bool IsCicleSectorIntersect(
            Vector2 a, Vector2 u, float theta, float l,
            Vector2 c, float r)
        {
            // 1. 如果扇形圆心和圆盘圆心的方向能分离,两形状不相交
            Vector2 d = c - a;
            float rsum = l   r;
            if (d.sqrMagnitude > rsum * rsum)
                return false;

            // 2. 计算出扇形局部空间的 p
            float px = Vector2.Dot(d, u);
            float py = Mathf.Abs(Vector2.Dot(d, new Vector2(-u.y, u.x)));//扇形单位方向向量逆时针转90度

            // 3. 如果 p_x > ||p|| cos theta,两形状相交
            if (px > d.magnitude * Mathf.Cos(theta * Mathf.Deg2Rad))
                return true;

            // 4. 求左边线段与圆盘是否相交
            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;
        }

0 人点赞