Summary of Unity interview questions (6) Some commonly used geometric algorithms

Summary of Unity interview questions (6) Some commonly used geometric algorithms

Table of contents

Summary of Unity interview questions (6) Some commonly used geometric algorithms

1. How to judge whether a point is on a straight line

2. Determine whether the point is on the line segment

3. Determine the positional relationship between the point and the line

4. Calculate the projection of a point on a straight line (vector projection)

5. Calculate the distance from a point to a straight line

6. Calculate the distance from a point to a line segment

7. Determine whether the polygon is a convex polygon

8. Determine whether the line segment and the line segment are collinear

9. Determine whether the line segment coincides with the line segment (non-intersecting)

10. Whether the line segment intersects with the line segment

11. Calculate the intersection point of a straight line and a straight line

12. Intersection of line segment and line segment

13. Whether the ray intersects with the ray, and the intersection point

15. A point rotates around another point by a specified angle

16. Whether the point is within any variable

17. Whether the point is inside the ellipse

18. Calculation of the intersection point of a straight line and an ellipse


1. How to judge whether a point is on a straight line

Given the point P(x,y) and the two points A( x1 ,y1) and B(x2,y2) on the line, you can calculate whether the point P is in the on line AB

Knowledge point: cross multiplication

    /// <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*/;
    }

2. Determine whether the point is on the line segment

Known point P(x,y), and line segments A(x1,y1), B(x2,y2).

1) Method one

The following two steps can be performed to determine whether the point P is on the line segment AB:

(1) Whether the point is on the straight line where the line segment AB is located ( 点是否在直线上)
(2) Whether the point is on the rectangle with the line segment AB as the diagonal, to ignore the point on the extension line of the line segment 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) Method 2

Calculate whether APthe length of the vector plus BPthe length of the vector is equal to ABthe length of the vector to determine whether the point P is on the line segment 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));
    }

3. Determine the positional relationship between the point and the line

Known point P(x,y), and two points A(x1,y1) and B(x2,y2) on the line, through the result returned by the cross product of vector AP and BP, the positional relationship of the point on the line can be determined .

Judgment basis: 1) equal to 0: the point is on the straight line; 2) less than 0: the point is on the left side of the straight line; 3) greater than 0: the point is on the right side of the straight line

    /// <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;
    }

4. Calculate the projection of a point on a straight line (vector projection)

Known point P(x,y), and two points A(x1,y1), B(x2,2) on the line, find the projection of point P on the line AB

Knowledge point: Through the vector projection formula (dot multiplication), the projection point of point P on straight line AB can be obtained.

    /// <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;
    }

5. Calculate the distance from a point to a straight line

Point P(x,y) and two points A(x1,y1) and B(x2,y2) on the line, find the distance from point P to line AB

1) Method 1:
First find the projected point P' of the point P on the straight line AB, and find the distance between the point P and the point 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) Method 2:
The distance from point P to straight line AB can be obtained by Heron's formula + base x height triangle area formula.
Heron's formula: Know the lengths of the three sides of a triangle, find the area of ​​the triangle. Link: Helen's Formula
Base x Height Triangle Area Formula: Base x Height = 2 Times the Area of ​​a Triangle


    /// <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;
    }

6. Calculate the distance from a point to a line segment

Known point P(x,y), and line segment A(x1,y1), B(x2,y2), calculate the distance from the point to the line segment

Idea: First find the projection point from the point to the straight line AB (including the extension line of the line segment AB), and then calculate the distance between the two points when judging whether the point is within the rectangular interval of the line segment 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;
    }

7. Determine whether the polygon is a convex polygon

Convex (concave) polygon calculation method
Knowing the counterclockwise vertex sequence of the polygon, it is enough to judge whether the direction of two adjacent line segments is consistent.

(The positional relationship between points and line segments is specified as a counterclockwise vertex sequence, so as long as the cross product of two adjacent line segments is less than 0, the polygon is a convex polygon)

    /// <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;
    }

8. Determine whether the line segment and the line segment are collinear

Ideas:

1) First judge whether the two line segments are parallel, that is, the cross product of the two line segments is equal to 0
2) After judging whether the two line segments are collinear, that is, a point on line segment 1 is on the extension line of line segment 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;
    }

9. Determine whether the line segment coincides with the line segment (non-intersecting)

1) Judging that the two line segments must be collinear
2) Then the segment judges whether the start and end points of line segment A are on line segment B, and whether the start and end points of line segment B are on line segment A. As long as one condition is true, the two line segments can be considered to be Coincident
or
1) Determine whether two line segments are collinear
2) Sort the 4 fixed points of the two line segments, if 1, 3 or 1, 4 are points on the same line segment, you can check whether the two line segments are coincident of

    /// <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;
    }

10. Whether the line segment intersects with the line segment

Whether a line segment intersects a line segment 1
Whether a line segment intersects a line segment 2

    /// <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;
    }

11. Calculate the intersection point of a straight line and a straight line

Derived formula

    /// <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;
    }

12. Intersection of line segment and line segment

1) First judge whether the line segment intersects with the line segment.
2) If they intersect, obtain the intersection point between the straight line and the straight line
Among them, it is necessary to pay attention to the parallelism and coincidence of the line segments.
Parallel: No intersection
All coincident: Returns the start and end points of one of the line segments
Partially coincident: Returns the start and end points of the coincident portion

    /// <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;
    }

13. Whether the ray intersects with the ray, and the intersection point

1) Determine whether the straight line where the ray is located intersects
2) Determine whether the point is on two rays

    /// <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. Whether the ray intersects the line segment, and whether the intersection point
1) whether the straight line intersects
2) whether the point is on the ray and the straight line

    /// <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;
    }

15. A point rotates around another point by a specified angle

2D vector rotation

It should be noted that the angle needs to be converted to radians for calculation ( angle and radian )

    /// <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;
    }

16. Whether the point is within any variable

Several methods for judging whether a point is inside any changeable interior
Ray method:
1) Find out the rectangle where the polygon is located, and judge whether the point is inside the rectangle
2) Whether the point is on the vertex or side of the polygon
3) Make a horizontal ray with the current point and calculate The number of intersections of this ray with the polygon line segment, if it is an odd number, the point is inside the polygon

    /// <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;
    }

17. Whether the point is inside the ellipse

c# realizes whether a point is in a plane

Less than or equal to 1 if P(x,y) is inside the ellipse

When the focus is on the x-axis, the long axis is 2a, the short axis is 2b, and the circle equation is x^2/a^2+y^2/b^2=1 When the focus is on the y-axis, the long axis is 2a, and the
short The axis is 2b, the circle equation is x^2/b^2+y^2/a^2=1
typo

    /// <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;
    }

18. Calculation of the intersection point of a straight line and an ellipse

Line and ellipse intersect to find intersection point

  /// <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;
        }

Guess you like

Origin blog.csdn.net/u014361280/article/details/128148129