点到直线的最短距离
/// <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;
}</code></pre></div></div><h2 id="dp24a" name="%E5%9C%86%E4%B8%8E%E5%9C%86%E7%9B%B8%E4%BA%A4">圆与圆相交</h2><p>两圆心距离平方 < 两者半径长平方</p><h2 id="bj5fq" name="%E5%9C%86%E4%B8%8E%E7%9F%A9%E5%BD%A2%E7%9B%B8%E4%BA%A4">圆与矩形相交</h2><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">/// <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;
}</code></pre></div></div><p>圆心在矩形内即相交。圆心在矩形外,比较圆心到每条矩形边线段的距离,只要有一条< 圆的半径即相交</p><h2 id="cv0ht" name="%E7%82%B9%E5%9B%B4%E7%BB%95%E5%8F%A6%E4%B8%80%E7%82%B9%E6%97%8B%E8%BD%AC%E5%90%8E%E5%9D%90%E6%A0%87">点围绕另一点旋转后坐标</h2><p>两个向量夹角</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">float angel = Vector2.Angle(Vector2.right, dirPos);
if (dirPos.y < 0)
{
angel = -angel;
}</code></pre></div></div><p>一个向量与Vector.right的夹角
Vector2.Angle
第一象限:090
第二象限:90180
第三象限:18090
第四象限:900
三四象限要为 负值旋转
旋转后坐标
代码语言: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;
}</code></pre></div></div>