點到直線的最短距離
/// <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;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/298820.html
標籤:其他
