当前位置:网站首页>unity3d:向量计算,AOE图形相交
unity3d:向量计算,AOE图形相交
2022-07-23 05:45:00 【四夕立羽】
点到直线的最短距离
/// <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两点距离
点到线段的距离
点落在线段之间为最短的垂直距离,否则为到两个端点之一的最短距离
/// <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表示二者方向相同(平行)。
//外积。两个向量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;
}
圆与圆相交
两圆心距离平方 < 两者半径长平方
圆与矩形相交
/// <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;
}
圆心在矩形内即相交。圆心在矩形外,比较圆心到每条矩形边线段的距离,只要有一条< 圆的半径即相交
点围绕另一点旋转后坐标
两个向量夹角
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
三四象限要为 负值旋转
旋转后坐标
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的四个顶点
// 无旋转朝向矩形----->服务器以选重点为中心的矩形,客户端选中点在矩形边缘,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);
再判断点与矩形相交
圆与朝向扇形相交
// 扇形与圆盘相交测试
// 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;
}
边栏推荐
猜你喜欢
随机推荐
Doubts about using the incluxdb database
鋼結構基本原理複習
Redis——配置及应用
Prometheus
1. Ten principles of Economics
*offer--2
OSI开放系统互联模型和TCP/IP模型
博客搭建一:框架选择
博客搭建三:评论系统选择
The CUDA version of pytorch installed by anconda is inconsistent with the CUDA version of the system
合成中文识别数据集的相关repo
obs插件基础
Problems encountered in configuring the historical version of detectron
Anconda安装的pytorch依赖的cuda版本和系统cuda版本不一致问题
堆的实现与堆排序实现
主机字节序的判定
《Kubernetes in Action》第二章笔记
关于如何排查vpn服务器无法转发的问题
动态规划——“换硬币问题”
Redis——基础概念








