赞
踩
目录
已知点P(x,y),以及直线上的两点A(x1,y1)、B(x2,y2),可以通过计算向量AP与向量AB的叉乘是否等于0来计算点P是否在直线AB上
知识点:叉乘
- /// <summary>
- /// 2D叉乘
- /// </summary>
- /// <param name="v1">点1</param>
- /// <param name="v2">点2</param>
- /// <returns></returns>
- public static float CrossProduct2D(Vector2 v1,Vector2 v2)
- {
- //叉乘运算公式 x1*y2 - x2*y1
- return v1.x * v2.y - v2.x * v1.y;
- }
-
-
- /// <summary>
- /// 点是否在直线上
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static bool IsPointOnLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- float value = CrossProduct2D(point - lineStart, lineEnd - lineStart);
- return Mathf.Abs(value) <0.0003 /* 使用 Mathf.Approximately(value,0) 方式,在斜线上好像无法趋近为0*/;
- }
已知点P(x,y),以及线段A(x1,y1),B(x2,y2)。
1)方法一
可以进行下面两部来判断点P是否在线段AB上:
(1)点是否在线段AB所在的直线上(点是否在直线上)
(2)点是否在以线段AB为对角线的矩形上,来忽略点在线段AB延长线上
- /// <summary>
- /// 2D叉乘
- /// </summary>
- /// <param name="v1">点1</param>
- /// <param name="v2">点2</param>
- /// <returns></returns>
- public static float CrossProduct2D(Vector2 v1,Vector2 v2)
- {
- //叉乘运算公式 x1*y2 - x2*y1
- return v1.x * v2.y - v2.x * v1.y;
- }
-
-
- /// <summary>
- /// 点是否在直线上
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static bool IsPointOnLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- float value = CrossProduct2D(point - lineStart, lineEnd - lineStart);
- return Mathf.Abs(value) <0.0003 /* 使用 Mathf.Approximately(value,0) 方式,在斜线上好像无法趋近为0*/;
- }
-
-
- /// <summary>
- /// 点是否在线段上
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static bool IsPointOnSegment(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- //1.先通过向量的叉乘确定点是否在直线上
- //2.在拍段点是否在指定线段的矩形范围内
- if (IsPointOnLine(point,lineStart,lineEnd))
- {
- //点的x值大于最小,小于最大x值 以及y值大于最小,小于最大
- if (point.x >= Mathf.Min(lineStart.x, lineEnd.x) && point.x <= Mathf.Max(lineStart.x, lineEnd.x) &&
- point.y >= Mathf.Min(lineStart.y, lineEnd.y) && point.y <= Mathf.Max(lineStart.y, lineEnd.y))
- return true;
- }
- return false;
- }
-
2)方法二
计算向量AP的长度加上向量BP的长度是否等于向量AB的长度,来确定点P是否在线段AB上
- /// <summary>
- /// 点是否在线段上
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static bool IsPointOnSegment2(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- return Mathf.Approximately(Mathf.Abs((lineStart - point).magnitude) + Mathf.Abs((lineEnd - point).magnitude),
- Mathf.Abs((lineEnd - lineStart).magnitude));
- }
已知点P(x,y),与直线上A(x1,y1),B(x2,y2)两点,通过向量AP与BP的叉乘返回的结果,即可确定点在直线的位置关系。
判断依据:1)等于0:点在直线上;2)小于0:点在直线的左侧;3)大于0:点在直线的右侧
- /// <summary>
- /// 2D叉乘
- /// </summary>
- /// <param name="v1">点1</param>
- /// <param name="v2">点2</param>
- /// <returns></returns>
- public static float CrossProduct2D(Vector2 v1,Vector2 v2)
- {
- //叉乘运算公式 x1*y2 - x2*y1
- return v1.x * v2.y - v2.x * v1.y;
- }
-
-
- /// <summary>
- /// 点与线的位置关系
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns>==0:点在线上 <0:点在线的左侧 >0:点在线的右侧</returns>
- public static int IsPointToLinePosition(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- float crossValue = CrossProduct2D(point - lineStart, lineEnd - lineStart);
- if (crossValue < 0) return -1;
- if (crossValue > 0) return 1;
- return 0;
- }
已知点P(x,y),与直线上两点A(x1,y1),B(x2,2),求P点在直线AB上的投影
知识点:通过向量投影公式(点乘),即可获得点P在直线AB投影点。
- /// <summary>
- /// 2D叉乘
- /// </summary>
- /// <param name="v1">点1</param>
- /// <param name="v2">点2</param>
- /// <returns></returns>
- public static float CrossProduct2D(Vector2 v1,Vector2 v2)
- {
- //叉乘运算公式 x1*y2 - x2*y1
- return v1.x * v2.y - v2.x * v1.y;
- }
-
-
- /// <summary>
- /// 点是否在直线上
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static bool IsPointOnLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- float value = CrossProduct2D(point - lineStart, lineEnd - lineStart);
- return Mathf.Abs(value) <0.0003 /* 使用 Mathf.Approximately(value,0) 方式,在斜线上好像无法趋近为0*/;
- }
-
-
- /// <summary>
- /// 点到直线上的投影坐标
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static Vector2 Point2LineProject(Vector2 point,Vector2 lineStart,Vector2 lineEnd)
- {
- if (IsPointOnLine(point,lineStart,lineEnd))
- return point;
- Vector2 v = point - lineStart;
- Vector2 u = lineEnd - lineStart;
- //求出u'的长度
- float u1Length = Vector2.Dot(u, v) / u.magnitude;
- return u1Length * u.normalized + lineStart;
- }
已点P(x,y),与直线上两点A(x1,y1),B(x2,y2),求点P到直线AB的距离
1)方法1:
先求出点P在直线AB上的投影点P’,求出点P与点P’的距离即可。
- /// <summary>
- /// 2D叉乘
- /// </summary>
- /// <param name="v1">点1</param>
- /// <param name="v2">点2</param>
- /// <returns></returns>
- public static float CrossProduct2D(Vector2 v1,Vector2 v2)
- {
- //叉乘运算公式 x1*y2 - x2*y1
- return v1.x * v2.y - v2.x * v1.y;
- }
-
- /// <summary>
- /// 点是否在直线上
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static bool IsPointOnLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- float value = CrossProduct2D(point - lineStart, lineEnd - lineStart);
- return Mathf.Abs(value) <0.0003 /* 使用 Mathf.Approximately(value,0) 方式,在斜线上好像无法趋近为0*/;
- }
-
- /// <summary>
- /// 点到直线上的投影坐标
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static Vector2 Point2LineProject(Vector2 point,Vector2 lineStart,Vector2 lineEnd)
- {
- if (IsPointOnLine(point,lineStart,lineEnd))
- return point;
- Vector2 v = point - lineStart;
- Vector2 u = lineEnd - lineStart;
- //求出u'的长度
- float u1Length = Vector2.Dot(u, v) / u.magnitude;
- return u1Length * u.normalized + lineStart;
- }
-
- /// <summary>
- /// 点到直线的距离
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static float Point2LineDistance(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- return Vector2.Distance(point, Point2LineProject(point, lineStart, lineEnd));
- }
2)方法2:
通过海伦公式+底x高三角形面积公式,就可求得点P到直线AB的距离。
海伦公式:知道三角形3条边长,求三角形面积。链接:海伦公式
底x高三角形面积公式:底x高=2倍的三角形面积
-
- /// <summary>
- /// 2D叉乘
- /// </summary>
- /// <param name="v1">点1</param>
- /// <param name="v2">点2</param>
- /// <returns></returns>
- public static float CrossProduct2D(Vector2 v1,Vector2 v2)
- {
- //叉乘运算公式 x1*y2 - x2*y1
- return v1.x * v2.y - v2.x * v1.y;
- }
-
- /// <summary>
- /// 点是否在直线上
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static bool IsPointOnLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- float value = CrossProduct2D(point - lineStart, lineEnd - lineStart);
- return Mathf.Abs(value) <0.0003 /* 使用 Mathf.Approximately(value,0) 方式,在斜线上好像无法趋近为0*/;
- }
-
- /// <summary>
- /// 点到直线的距离
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static float Point2LineDistance(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- //先判断点是否在线上
- if (IsPointOnLine(point, lineStart, lineEnd)) return 0;
- //通过海伦公式求得三角形面积,然后面积除以底,得到高度
- //point 简写为p lineStart简写为s lineEnd简写为e
- float se = Vector2.Distance(lineStart, lineEnd);
- float sp = Vector2.Distance(lineStart, point);
- float ep = Vector2.Distance(lineEnd, point);
-
- //海伦公式 + 底x高面积公式
- //半周长
- float p = (se + sp + ep) / 2;
- //求面积
- float s = Mathf.Sqrt(p * (p - se) * (p - sp) * (p - ep));
- //面积除以底得高度
- return 2 * s / se;
- }
已知点P(x,y),与线段A(x1,y1),B(x2,y2),计算点到线段的距离
思路:先求出点到直线AB(包括线段AB的延长线)的投影点,在判断点是否在线段AB的矩形区间内,在计算两点的距离即可。
- /// <summary>
- /// 2D叉乘
- /// </summary>
- /// <param name="v1">点1</param>
- /// <param name="v2">点2</param>
- /// <returns></returns>
- public static float CrossProduct2D(Vector2 v1,Vector2 v2)
- {
- //叉乘运算公式 x1*y2 - x2*y1
- return v1.x * v2.y - v2.x * v1.y;
- }
-
- /// <summary>
- /// 点是否在直线上
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static bool IsPointOnLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- float value = CrossProduct2D(point - lineStart, lineEnd - lineStart);
- return Mathf.Abs(value) <0.0003 /* 使用 Mathf.Approximately(value,0) 方式,在斜线上好像无法趋近为0*/;
- }
-
- /// <summary>
- /// 点到直线上的投影坐标
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static Vector2 Point2LineProject(Vector2 point,Vector2 lineStart,Vector2 lineEnd)
- {
- if (IsPointOnLine(point,lineStart,lineEnd))
- return point;
- Vector2 v = point - lineStart;
- Vector2 u = lineEnd - lineStart;
- //求出u'的长度
- float u1Length = Vector2.Dot(u, v) / u.magnitude;
- return u1Length * u.normalized + lineStart;
- }
-
- /// <summary>
- /// 点到线段的距离
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns></returns>
- public static float Point2SegmentDistance(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- Vector2 projectPoint = Point2LineProject(point,lineStart,lineEnd);
- if (projectPoint.x >= Mathf.Min(lineStart.x, lineEnd.x) &&
- projectPoint.x <= Mathf.Max(lineStart.x, lineEnd.x) &&
- projectPoint.y >= Mathf.Min(lineStart.y, lineEnd.y) && projectPoint.y <= Mathf.Max(lineStart.y, lineEnd.y))
- return Vector2.Distance(point, projectPoint);
- return float.MaxValue;
- }
凸(凹)多边形 计算方法
已知多边形的逆时针顶点序列,依次判断相邻两个线段走向是否一致即可。
(点与线段位置关系,因为规定为逆时针顶点序列,所以只要两个相邻线段的叉乘都小于0则该多边形为凸多边形)
- /// <summary>
- /// 2D叉乘
- /// </summary>
- /// <param name="v1">点1</param>
- /// <param name="v2">点2</param>
- /// <returns></returns>
- public static float CrossProduct2D(Vector2 v1,Vector2 v2)
- {
- //叉乘运算公式 x1*y2 - x2*y1
- return v1.x * v2.y - v2.x * v1.y;
- }
-
-
- /// <summary>
- /// 点与线的位置关系
- /// </summary>
- /// <param name="point"></param>
- /// <param name="lineStart"></param>
- /// <param name="lineEnd"></param>
- /// <returns>==0:点在线上 <0:点在线的左侧 >0:点在线的右侧</returns>
- public static int IsPointToLinePosition(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
- {
- float crossValue = CrossProduct2D(point - lineStart, lineEnd - lineStart);
- if (crossValue < 0) return -1;
- if (crossValue > 0) return 1;
- return 0;
- }
-
-
- /// <summary>
- /// 是否为凸多边形
- /// </summary>
- /// <param name="points">逆时针点序列</param>
- /// <returns></returns>
- public static bool IsConvexPolygon(List<Vector2> points)
- {
- //计算每个顶点的转向,如果有不一致的转向,则表示该多边形不是凸多边形
- if (points.Count < 3) return false;
- bool isConvex = true;
- for (int i = 1; i < points.Count; i++)
- {
- Vector2 point = points[i];
- //上一个点
- Vector2 point1 = points[i - 1];
- //下一个点,如果超出当前点集合,则需要获取第一个点
- int nextIndex = i + 1;
- if (nextIndex >= points.Count) nextIndex = 0;
- Vector2 point2 = points[nextIndex];
- //计算朝向,因为点集合为逆时针点序列,如果点在线段右侧,则表示该角大于180 该多边形为凹多边形
- float value = IsPointToLinePosition(point1, point,point2);
- if (value > 0)
- {
- isConvex = false;
- break;
- }
- }
- return isConvex;
- }
思路:
1)先判断两条线段是否平行,即两条线段的叉积等于0
2)在判断两条线段是否共线,即线段1一个点在线段2的延长线上
- /// <summary>
- /// 线段与线段是否共线
- /// </summary>
- /// <param name="segment1Start"></param>
- /// <param name="segment1End"></param>
- /// <param name="segment2Start"></param>
- /// <param name="segment2End"></param>
- /// <returns></returns>
- public static bool IsSegmentCollineation(Vector2 segment1Start, Vector2 segment1End, Vector2 segment2Start,
- Vector2 segment2End)
- {
- //1.判断两个向量是否平行
- float value = CrossProduct2D(segment1End - segment1Start, segment2End - segment2Start);
- if (Mathf.Abs(value)<0.0003f)
- {
- // 平行,则判断一个线上的点是否在另一线上
- if (IsPointOnLine(segment2Start, segment2End , segment2Start))
- return true;
- }
- return false;
- }
1)判断两条线段必须共线
2)然后片段判断线段A的起终点是否在线段B,以及线段B的起终点,是否在线段A上,只要有一个条件成立,则可以认为两条线段是重合的
或
1)判断两条线段是否共线
2)对两条线段的4个定点进行排序,如果1,3 或 1,4 为为同一条线段上的点,则可以任务两条线段是否重合的
- /// <summary>
- /// 线段与线段是否重合(全部重合或局部重合)
- /// </summary>
- /// <param name="segment1Start"></param>
- /// <param name="segment1End"></param>
- /// <param name="segment2Start"></param>
- /// <param name="segment2End"></param>
- /// <returns></returns>
- public static bool IsSegmentCoincide(Vector2 segment1Start, Vector2 segment1End, Vector2 segment2Start,
- Vector2 segment2End)
- {
- //先判断两条线段是否在同一条线上
- if (!IsSegmentCollineation(segment1Start,segment1End,segment2Start,segment2End))
- return false;
-
- //如果是相同的起终点
- if (segment1Start == segment2Start && segment1End == segment2End) return true;
- //判断检测点是否在另一条线段上
- if (IsPointOnSegment2(segment1Start, segment2Start, segment2End) ||
- IsPointOnSegment2(segment1End, segment2Start, segment2End) ||
- IsPointOnSegment2(segment2Start, segment1Start, segment1End) ||
- IsPointOnSegment2(segment2End, segment1Start, segment1End))
- return true;
- return false;
- }

- /// <summary>
- /// 线段是否相交
- /// </summary>
- /// <param name="segment1Start"></param>
- /// <param name="segment1End"></param>
- /// <param name="segment2Start"></param>
- /// <param name="segment2End"></param>
- /// <returns></returns>
- public static bool IsSegmentIntersect(Vector2 segment1Start, Vector2 segment1End, Vector2 segment2Start,
- Vector2 segment2End)
- {
- //快速排斥实验
- if (Mathf.Min(segment1Start.x,segment1End.x) <= Mathf.Max(segment2Start.x,segment2End.x)
- && Mathf.Min(segment2Start.x,segment2End.x) <= Mathf.Max(segment2Start.x,segment2End.x)
- && Mathf.Min(segment1Start.y,segment1End.y)<=Mathf.Max(segment2Start.y,segment2End.y)
- && Mathf.Min(segment2Start.y,segment2End.y) <= Mathf.Max(segment1Start.y,segment1End.y))
- {
- //先判断线段是否重合,重合,则认为也是相交
- if (IsSegmentCoincide(segment1Start, segment1End, segment2Start, segment2End))
- return true;
- //互为跨立的判断 一线的点相对另一线的位置关系,左右 -1 1,之和为 0
- int state = IsPointToLinePosition(segment1Start, segment2Start, segment2End) +
- IsPointToLinePosition(segment1End, segment2Start, segment2End) +
- IsPointToLinePosition(segment2Start, segment1Start, segment1End) +
- IsPointToLinePosition(segment2End, segment1Start, segment1End);
- if (state==0) return true;
- }
- return false;
- }
- /// <summary>
- /// 求直线的交点
- /// </summary>
- /// <param name="line1Start"></param>
- /// <param name="line2End"></param>
- /// <param name="line2Start"></param>
- /// <param name="line2End"></param>
- /// <returns></returns>
- public static Vector2 LineIntersectPoint(Vector2 line1Start, Vector2 line1End, Vector2 line2Start,
- Vector2 line2End)
- {
- //两点式公式
- //x0 = ((x3-x4) * (x2*y1 - x1*y2) - (x1-x2) * (x4*y3 - x3*y4)) / ((x3-x4) * (y1-y2) - (x1-x2) * (y3-y4));
- //y0 = ((y3-y4) * (y2*x1 - y1*x2) - (y1-y2) * (y4*x3 - y3*x4)) / ((y3-y4) * (x1-x2) - (y1-y2) * (x3-x4));
-
- float x1 = line1Start.x, x2 = line1End.x, x3 = line2Start.x, x4 = line2End.x;
- float y1 = line1Start.y, y2 = line1End.y, y3 = line2Start.y, y4 = line2End.y;
-
- Vector2 point = Vector2.zero;
- point.x = ((x3-x4) * (x2*y1 - x1*y2) - (x1-x2) * (x4*y3 - x3*y4)) / ((x3-x4) * (y1-y2) - (x1-x2) * (y3-y4));
- point.y = ((y3-y4) * (y2*x1 - y1*x2) - (y1-y2) * (y4*x3 - y3*x4)) / ((y3-y4) * (x1-x2) - (y1-y2) * (x3-x4));
- return point;
- }
1)先判断线段与线段是否相交。
2)如果相交,则获取直线与直线的交点
其中,需要注意线段平行与重合情况。
平行:无交点
全部重合:返回其中一条线段的起点与终点
部分重合:返回重合部分的起点与终点
- /// <summary>
- /// 线段与线段的交点
- /// </summary>
- /// <param name="segment1Start"></param>
- /// <param name="segment1End"></param>
- /// <param name="segment2Start"></param>
- /// <param name="segment2End"></param>
- /// <param name="points"></param>
- /// <returns></returns>
- public static bool SegmentIntersectPoint(Vector2 segment1Start,Vector2 segment1End,Vector2 segment2Start,Vector2 segment2End,out List<Vector2> points)
- {
- //线段相同情况下 直接返回其中一条线段即可
- if (segment1Start==segment2Start && segment1End== segment2End)
- {
- points = new List<Vector2>(){segment1Start,segment1End};
- return true;
- }
- points = new List<Vector2>();
- //线段平行,且不共线,则无交点
- float value = CrossProduct2D(segment1End - segment1Start, segment2End - segment2Start);
- if (Mathf.Approximately(Mathf.Abs(value), 0))
- {
- //共线判断,一点是否在另一条线段上
- if (!IsPointOnLine(segment1Start,segment2Start,segment2End))
- return false;
- //平行且共线的情况下,需要知道线段是否重合
- if (IsPointOnSegment2(segment1Start, segment2Start, segment2End))
- points.Add(segment1Start);
- if (IsPointOnSegment2(segment1End, segment2Start, segment2End))
- points.Add(segment1End);
- if (IsPointOnSegment2(segment2Start, segment1Start, segment1End))
- points.Add(segment2Start);
- if (IsPointOnSegment2(segment2End, segment1Start, segment1End))
- points.Add(segment2End);
- if (points.Count <= 0) return false;
- return true;
- }
-
- //不平行,且不共线,则需要判断两个线段是否相交
- if (!IsSegmentIntersect(segment1Start, segment1End, segment2Start, segment2End))
- return false;
-
- //计算直线与直线的交点
- Vector2 outPoint = Vector2.zero;
- if (LineIntersectPoint(segment1Start,segment1End,segment2Start,segment2End,out outPoint))
- {
- points.Add(outPoint);
- return true;
- }
-
- /*********用此种方式也可*************************/
- //1.先求交点
- //2.在计算点是否在两线段上
- /*
- if (LineIntersectPoint(segment1Start,segment1End,segment2Start,segment2End,out outPoint))
- {
- if (IsPointOnLine(outPoint,segment1Start,segment1End) && IsPointOnLine(outPoint,segment2Start,segment2End))
- {
- points.Add(outPoint);
- return true;
- }
- }*/
-
- return false;
- }
1)判断射线所在的直线是否相交
2)判断点是否在两条射线上
- /// <summary>
- /// 射线是否相交
- /// </summary>
- /// <param name="ray1Start"></param>
- /// <param name="ray1Dir"></param>
- /// <param name="ray2Start"></param>
- /// <param name="ray2Dir"></param>
- /// <returns></returns>
- public static bool IsRayIntersect(Vector2 ray1Start, Vector2 ray1Dir, Vector2 ray2Start, Vector2 ray2Dir,out Vector2 point)
- {
- //先计算两条直线是否相交
- if (!LineIntersectPoint(ray1Start,ray1Start+ray1Dir * 1,ray2Start,ray2Start+ray2Dir*1,out point))
- return false;
- if (Vector2.Dot((point - ray1Start).normalized, ray1Dir.normalized) < 0) return false;
- if (Vector2.Dot((point - ray2Start).normalized, ray2Dir.normalized) < 0) return false;
- return true;
- }
14、射线与线段是否相交,以及交点
1)所在直线是否相交
2)点是否在射线以及直线上
- /// <summary>
- /// 射线与线段是否相交
- /// </summary>
- /// <param name="rayStart"></param>
- /// <param name="rayDir"></param>
- /// <param name="segmentStart"></param>
- /// <param name="segmentEnd"></param>
- /// <returns></returns>
- public static bool IsRaySegmentIntersect(Vector2 rayStart,Vector2 rayDir,Vector2 segmentStart,Vector2 segmentEnd,out Vector2 point)
- {
- //先计算两条直线是否相交
- if (!LineIntersectPoint(rayStart,rayStart+rayDir * 1,segmentStart,segmentEnd,out point))
- return false;
- //判断交点的位置是否在射线上 方向相同可以确定点在射线上
- if (Vector2.Dot((point - rayStart).normalized, rayDir.normalized) < 0) return false;
- //点是否在线段上
- if (!IsPointOnSegment2(point,segmentStart, segmentEnd)) return false;
- return true;
- }
需要注意的是,需要将角度转为弧度制进行计算(角度与弧度)
- /// <summary>
- /// 点绕另一个点进行旋转
- /// </summary>
- /// <param name="originPoint"></param>
- /// <param name="point"></param>
- /// <param name="angle"></param>
- /// <returns></returns>
- public static Vector2 PointRoationOnPoint(Vector2 originPoint, Vector2 point, float angle)
- {
- if (originPoint == point) return originPoint;
- Vector2 resultPoint = Vector2.zero;
- Vector2 v= (point - originPoint).normalized;
- angle *= Mathf.Deg2Rad;
- resultPoint.x = v.x * Mathf.Cos(angle) - v.y * Mathf.Sin(angle);
- resultPoint.y = v.x * Mathf.Sin(angle) + v.y * Mathf.Cos(angle);
- return resultPoint * Vector2.Distance(originPoint,point) + originPoint ;
- }
-
- /// <summary>
- /// 点集合绕点旋转
- /// </summary>
- /// <param name="points"></param>
- /// <param name="point"></param>
- /// <param name="angle"></param>
- /// <returns></returns>
- public static List<Vector2> PointsRoationOnPoint(List<Vector2> points, Vector2 point, float angle)
- {
- List<Vector2> resultPoints = new List<Vector2>();
- if (points == null) return resultPoints;
- for (int i = 0; i < points.Count; i++)
- {
- Vector2 nPoint = PointRoationOnPoint(point,points[i],angle);
- resultPoints.Add(nPoint);
- }
- return resultPoints;
- }
判断点是否在任意多变内部的几种方法
射线法:
1)求出多边形所在矩形,判断点是否在矩形内
2)点是否在多边形顶点或边上
3)以当前点做一条水平射线,计算该射线与多边形线段的相交数量,如果为奇数则点在多边形内部
- /// <summary>
- /// 点是否在任意多边形内部
- /// </summary>
- /// <param name="point"></param>
- /// <param name="polygon"></param>
- /// <returns>-1:不在多边形内 0:在多边形上 1:多边形内 </returns>
- public static int IsPointInAnyPolygon(Vector2 point, List<Vector2> polygon)
- {
- //顶点数量小于3,则无法形成多边形
- if (polygon.Count < 3) return -1;
-
- //1.先获取多边形所在矩形范围内
-
- Vector2 rectMin = polygon[0], rectMax = polygon[0];
- for (int i = 1; i < polygon.Count; i++)
- {
- if (polygon[i].x < rectMin.x) rectMin.x = polygon[i].x;
- if (polygon[i].y < rectMin.y) rectMin.y = polygon[i].y;
- if (polygon[i].x > rectMax.x) rectMax.x = polygon[i].x;
- if (polygon[i].y > rectMax.y) rectMax.y = polygon[i].y;
- }
- if (point.x < rectMin.x || point.y < rectMin.y || point.x > rectMax.x || point.y > rectMax.y) return -1;
- //2.射线相交点计算
- int intersectCount = 0;
- for (int i = 0; i < polygon.Count; i++)
- {
- int nextIndex = i + 1;
- if (nextIndex >= polygon.Count)
- nextIndex = 0;
- //目标在顶点上
- if (polygon[i] == point || polygon[nextIndex] == point)
- return 0;
- //目标在线段上
- if (IsPointOnSegment2(point, polygon[i], polygon[nextIndex]))
- return 0;
- Vector2 intersectPoint;
- //射线与线段相交
- if (IsRaySegmentIntersect(point,Vector2.right,polygon[i],polygon[nextIndex],out intersectPoint))
- {
- //如果相交为线段的顶点,则需要增加2,因为在同一点进入,又在同一个点出去
- if (intersectPoint == polygon[i] || intersectPoint == polygon[nextIndex])
- intersectCount += 2;
- else
- intersectCount += 1;
- }
- }
- return intersectCount % 2 == 1 ? 1:-1;
- }
如果P(x,y)是否在椭圆内,则小于等于1
焦点在x轴上时,长轴为2a,短轴为2b,圆方程为x^2/a^2+y^2/b^2=1
焦点在y轴上时,长轴为2a,短轴为2b,圆方程为x^2/b^2+y^2/a^2=1
笔误
- /// <summary>
- /// 点是否在椭圆内
- /// </summary>
- /// <param name="point">目标点</param>
- /// <param name="xAxis">长轴半径</param>
- /// <param name="yAxis">短轴半径</param>
- /// <returns></returns>
- private bool PointIsInEllipse(Vector2 point,float xAxis,float yAxis)
- {
- return (point.x * point.x) / (xAxis * xAxis ) + (point.y * point.y) / (yAxis * yAxis )<=1;
- }
- /// <summary>
- /// 线段和椭圆弧的交点
- /// </summary>
- /// <param name="line">线段对象</param>
- /// <param name="ht">存储交点和error信息</param>
- /// <returns>返回交点和error信息</returns>
- internal static Hashtable LineIntersectEllipticArc(Line line, Hashtable ht)
- {
- //线段的终点
- Vector2 LineendPoint = line.endPoint;
- //线段的起点
- Vector2 LinestartPoint = line.startPoint;
- //椭圆弧的长轴的一半
- double maxAxis = 262.39051820125013 / 2;
- //椭圆弧的短轴一半
- double minAxis = 135.76528231694766 / 2;
- //椭圆弧的起点
- //椭圆弧的起始角度
- double startAngle = DegreeToRadian(132.0438345714015);
- //椭圆弧的终点
- //椭圆弧的终止角度 //默认设置为90度对应的弧度
- double endAngle = DegreeToRadian(258.13766538237763);
- //椭圆弧的圆心
- Vector2 center = new Vector2(17.7894639270817, 15.0254309579905);
- //设置原点坐标(0,0)
- Vector2 centerZero = new Vector2(0, 0);
- //椭圆弧的导入角度'
- double angle = DegreeToRadian(191.75357833501226);
- //将直线顺时针旋转angle度
- Vector2[] ve = Anticlockwise(LineendPoint, LinestartPoint, center, angle);
- //假设默认交点坐标
- Vector2 ptInter1 = new Vector2(0, 0);
- Vector2 ptInter2 = new Vector2(0, 0);
- //直线和椭圆的交点坐标
- LineIntersectEllipse(MoveOne(ve[0], center), MoveOne(ve[1], center), maxAxis, minAxis, ref ptInter1, ref ptInter2);
- //用于存储交点
- List<Vector2> node = new List<Vector2>();
- //用于判断是否有交点
- bool judgeNode = false;
- //存储的版本号
- int version = 0;
- double a = NormalizeRadianAngle(startAngle);
- double b = NormalizeRadianAngle(endAngle);
- if (Zero(ptInter1))
- {
- JudgeDotQualified(centerZero, ptInter1, a, b, node);
- if (node.Count == 1)
- {
- if (node[0] != null)
- {
- //表示第一次有一个值
- //将交点逆时针旋转
- Vector2[] ve1 = Anticlockwise(ptInter1, ptInter2, centerZero, angle, false);
- //再将交点平移得到最后真正的交点
- ve1[0] = MoveTwo(ve1[0], center);
- node[0] = ve1[0];
- version = 1;
- }
- }
- }
- if (Zero(ptInter2))
- {
- if (version == 0)
- {
- JudgeDotQualified(centerZero, ptInter2, a, b, node);
- if (node.Count == 1)
- {
- if (node[0] != null)
- {
- //表示第一次没有一个值
- //将交点逆时针旋转
- Vector2[] ve1 = Anticlockwise(ptInter1, ptInter2, centerZero, angle, false);
- //再将交点平移得到最后真正的交点
- ve1[1] = MoveTwo(ve1[1], center);
- node[0] = ve1[1];
- }
- }
- }
- else if (version == 1)
- {
- JudgeDotQualified(centerZero, ptInter2, a, b, node);
- if (node.Count == 2)
- {
- if (node[1] != null)
- {
- //表示第一次有一个值
- //将交点逆时针旋转
- Vector2[] ve1 = Anticlockwise(ptInter1, ptInter2, centerZero, angle, false);
- //再将交点平移得到最后真正的交点
- ve1[1] = MoveTwo(ve1[1], center);
- node[1] = ve1[1];
- }
- }
- }
- }
- ht.Add("node", node);
- return ht;
- }
- /// <summary>
- /// 角度转弧度
- /// </summary>
- /// <param name="angle">角度</param>
- /// <returns>弧度</returns>
- public static double DegreeToRadian(double angle)
- {
- return ((angle * System.Math.PI) / 180.0);
- }
- public const double EPSILON = 1E-12;
- public static bool IsEqual(double x, double y, double epsilon = EPSILON)
- {
- return IsEqualZero(x - y, epsilon);
- }
- public static bool IsEqualZero(double x, double epsilon = EPSILON)
- {
- return (System.Math.Abs(x) < epsilon);
- }
- /// <summary>
- /// 点的绕椭圆弧弧心旋转
- /// </summary>
- /// <param name="LineendPoint">线段终点</param>
- /// <param name="LinestartPoint">线段起点</param>
- /// <param name="center">椭圆弧弧心</param>
- /// <param name="angle">椭圆弧的导入角度'</param>
- /// /// <param name="isClockwise">顺逆旋转,默认为顺时针旋转</param>
- internal static Vector2[] Anticlockwise(Vector2 LineendPoint, Vector2 LinestartPoint, Vector2 center, double angle, bool isClockwise = true)
- {
- Vector2[] ve = new Vector2[2];
- if (isClockwise)
- {
- angle = -angle;
- }
- double cos = System.Math.Cos(angle);
- double sin = System.Math.Sin(angle);
- if (IsEqual(cos, 0))
- {
- cos = 0;
- }
- if (IsEqual(sin, 0))
- {
- sin = 0;
- }
- double x = ((LineendPoint.x - center.x) * cos - (LineendPoint.y - center.y) * sin + center.x);
- double y = ((LineendPoint.x - center.x) * sin + (LineendPoint.y - center.y) * cos + center.y);
- ve[0].x = x;
- ve[0].y = y;
- double x1 = ((LinestartPoint.x - center.x) * cos - (LinestartPoint.y - center.y) * sin + center.x);
- double y1 = ((LinestartPoint.x - center.x) * sin + (LinestartPoint.y - center.y) * cos + center.y);
- ve[1].x = x1;
- ve[1].y = y1;
- return ve;
- }
- /// <summary>
- /// 第一次平移
- /// </summary>
- /// <param name="dot">交点坐标</param>
- /// <param name="center">圆心坐标</param>
- /// <returns>返回平移后的点坐标</returns>
- internal static Vector2 MoveOne(Vector2 dot, Vector2 center)
- {
- Vector2 returnDot = new Vector2();
- if (center.x >= 0 && center.y >= 0)
- {
- //圆心在第一象限
- returnDot.x = dot.x - center.x;
- returnDot.y = dot.y - center.y;
- }
- else if (center.x <= 0 && center.y >= 0)
- {
- //圆心在第二象限
- returnDot.x = dot.x + center.x;
- returnDot.y = dot.y - center.y;
- }
- else if (center.x <= 0 && center.y <= 0)
- {
- //圆心在第三象限
- returnDot.x = dot.x + center.x;
- returnDot.y = dot.y + center.y;
- }
- else if (center.x >= 0 && center.y <= 0)
- { //圆心在第四象限
- returnDot.x = dot.x - center.x;
- returnDot.y = dot.y + center.y;
- }
- return returnDot;
- }
- /// <summary>
- /// 第二次平移
- /// </summary>
- /// <param name="dot">点坐标</param>
- /// <param name="center">圆心坐标</param>
- /// <returns>返回平移后的点</returns>
- internal static Vector2 MoveTwo(Vector2 dot, Vector2 center)
- {
- Vector2 returnDot = new Vector2();
- if (center.x >= 0 && center.y >= 0)
- {
- //圆心在第一象限
- returnDot.x = dot.x + center.x;
- returnDot.y = dot.y + center.y;
- }
- else if (center.x <= 0 && center.y >= 0)
- {
- //圆心在第二象限
- returnDot.x = dot.x - center.x;
- returnDot.y = dot.y + center.y;
- }
- else if (center.x <= 0 && center.y <= 0)
- {
- //圆心在第三象限
- returnDot.x = dot.x - center.x;
- returnDot.y = dot.y - center.y;
- }
- else if (center.x >= 0 && center.y <= 0)
- { //圆心在第四象限
- returnDot.x = dot.x + center.x;
- returnDot.y = dot.y - center.y;
- }
- return returnDot;
- }
- /// <summary>
- /// 判断点是否为(0,0)
- /// </summary>
- /// <param name="dot">交点</param>
- /// <returns>是(0,0)返回false</returns>
- internal static bool Zero(Vector2 dot)
- {
- if (dot.x == 0)
- {
- if (dot.y == 0)
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- else
- {
- return true;
- }
- }
- /// <summary>
- /// 规整化弧度
- /// 返回值范围:[0, 2*PI)
- /// </summary>
- internal static double NormalizeRadianAngle(double rad)
- {
- double value = rad % (2 * System.Math.PI);
- if (value < 0)
- value += 2 * System.Math.PI;
- return value;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。