线段(向量)的计算(判断线段重叠、相交,合并线段,点与线的关系)

您所在的位置:网站首页 线段交叉有什么规律 线段(向量)的计算(判断线段重叠、相交,合并线段,点与线的关系)

线段(向量)的计算(判断线段重叠、相交,合并线段,点与线的关系)

2023-07-02 00:03| 来源: 网络整理| 查看: 265

主要内容:

判断两线段是否相交计算两线段的交叉点点与直线的位置关系判断两线段重合并计算其重合部分判断合并两条线段

说明全都在注释里了,有的方法可能不是最佳,欢迎大家提出建议~~

public class Line : MonoBehaviour { Vector2 impossiblePoint = -1000 * Vector2.one; // ---------- //判断两线段交叉并计算交叉点,线段AB,线段CD public Vector2 LineCross(Vector2 A, Vector2 B, Vector2 C, Vector2 D) { //可能情况说明: //01 完全交叉,线段AB的端点分别在线段CD的两侧,且线段CD的端点也分别在线段AB的两侧 // pointPosA * pointPosB < 0 && pointPosC * pointPosD < 0 // pointPosA * pointPosB < 0 点AB在线段CD两侧, > 0,点AB在线段同侧, == 0,点AB至少有一个点在线段上 //02 线段一个端点在另一条线段上,且另一个端点不在 // pointPosA == 0 && pointPosB != 0 || pointPosA != 0 && pointPosB == 0 // pointPosC == 0 && pointPosD != 0 || pointPosC != 0 && pointPosD == 0 //计算各端点与线段的关系 float pointPosA, pointPosB, pointPosC, pointPosD; pointPosA = PointPosionOfLine(A, C, D); pointPosB = PointPosionOfLine(B, C, D); pointPosC = PointPosionOfLine(C, A, B); pointPosD = PointPosionOfLine(D, A, B); //01 if (pointPosA * pointPosB < 0 && pointPosC * pointPosD < 0) { return GetCrosPoint(A, B, C, D); } //02 if (IsZero(pointPosA) && !IsZero(pointPosB)) return A; else if (!IsZero(pointPosA) && IsZero(pointPosB)) return B; if (IsZero(pointPosC) && !IsZero(pointPosD)) return C; else if (!IsZero(pointPosC) && IsZero(pointPosD)) return D; //03 若不符合以上条件,则不交叉 return impossiblePoint; } //点与直线的位置,目标点M,直线AB float PointPosionOfLine(Vector2 M, Vector2 A, Vector2 B) { // 返回值 > 0 在右侧, = 0 在线上, < 0 在左侧 return (B.y - M.y) * (A.x - M.x) - (A.y - M.y) * (B.x - M.x); //公式计算过程 //直线公式:a * X + b * Y + c = 0 //将线段端点代入公式 // a * A.x + b * A.y + c = 0 // a * B.x + b * B.y + c = 0 //两式分别相加、相减 // (A.x + B.x) * a + (A.y + B.y) * b + 2c = 0 // (A.x - B.x) * a + (A.y - B.y) * b = 0 //化简得 // b = (B.x - A.x) / (A.y - B.y) * a // c = -a * (A.y * B.x - A.x * B.y) / (A.y - B.y) //原直线公式用a表示为 // a * X + (B.x - A.x) / (A.y - B.y) * a * Y - a * (A.y * B.x - A.x * B.y) / (A.y - B.y) = 0 //公式两边同时除a,直线公式用点A/B表示为 // X + (B.x - A.x) / (A.y - B.y) * Y - (A.y * B.x - A.x * B.y) / (A.y - B.y) = 0 //再次化简 // (A.y - B.y) * X + (B.x - A.x) * Y - (A.y * B.x - A.x * B.y) = 0 //公式左侧==0,点在直线上,公式左侧>0,点在直线右侧,工作左侧 A.y) || (M.y < A.y && M.y > B.y)),化简为: if ((A.y - M.y) * (M.y - B.y) > 0.0f) { return true; } return false; } //在同一水平方向 else if (IsZero(A.y - B.y) && IsZero(A.y - M.y)) { if ((A.x - M.x) * (M.x - B.x) > 0.0f) { return true; } return false; } //线段倾斜,此时线段所在直线存在斜率 else { //点在直线上,MA与MB斜率相等,且有共同点M,此时MA与MB重合,即点M在直线AB上 //(A.y - M.y) / (A.x - M.x) == (M.y - B.y) / (M.x - B.x)) if (IsZero((A.y - M.y) / (A.x - M.x) - (M.y - B.y) / (M.x - B.x))) { //已判定点在直线上,若点在两端点中间,即点在线段上 if (((A.y - M.y) * (M.y - B.y) > 0) && ((A.x - M.x) * (M.x - B.x) > 0)) { return true; } } return false; } } // ---------- //合并两条线段,线段AB,线段CD public Vector2[] LineCombine(Vector2 A, Vector2 B, Vector2 C, Vector2 D) { //与LineCoincide(Vector2 A, Vector2 B, Vector2 C, Vector2 D)相似 //可能情况说明: //01 有一个公共端点,两线段反向,夹角180度 // A == C && AB/CD共线 // A == D && AB/CD共线 // B == C && AB/CD共线 // B == D && AB/CD共线 //02 交错关系,各包含一个端点,比如:线段AB的端点A在线段CD上,线段CD的端点C在线段AB上 // A != C && onLineA && onLineC // A != D && onLineA && onLineD // B != C && onLineB && onLineC // B != D && onLineB && onLineD //03 包含关系,一条线段包含在另一条线段内,比如:线段AB的端点A和端点B都在线段CD上 // onLineA && onLineB // onLineC && onLineD //以上01和02两种情况可以合并如下 //一般情况下,点A在线段CD上,C在AB上,此时AB/CD已经共线,但A/C是同一点的时候特殊考虑,需要验证夹角180度 // onLineA && onLineC && AB/CD共线 // onLineA && onLineD && AB/CD共线 // onLineB && onLineC && AB/CD共线 // onLineB && onLineD && AB/CD共线 //再将以上三种情况合并 //只有两线段共线,才有可能合并 //计算各个端点与线段的关系(点是否在线段上) bool onLineA, onLineB, onLineC, onLineD; onLineA = IsPointOnLine(A, C, D); onLineB = IsPointOnLine(B, C, D); onLineC = IsPointOnLine(C, A, B); onLineD = IsPointOnLine(D, A, B); //01,02,03 if (IsLineDirection(A, B, C, D)) { if (onLineA && onLineC) return new Vector2[] { B, D }; else if (onLineA && onLineD) return new Vector2[] { B, C }; else if (onLineB && onLineC) return new Vector2[] { A, D }; else if (onLineB && onLineD) return new Vector2[] { A, C }; else if (onLineA && onLineB) return new Vector2[] { C, D}; else if (onLineC && onLineD) return new Vector2[] { A, B }; } //若不符合以上条件,则不可合并 return null; } //是否线段共线,线段AB,CD bool IsLineDirection(Vector2 A, Vector2 B, Vector2 C, Vector2 D) { // dotValue == 1 0度 // dotValue == 0 90度 // dotValue == -1 180度 float dotValue = Vector2.Dot((A - B).normalized, (C - D).normalized); if (IsZero(dotValue - 1) || IsZero(dotValue + 1)) return true; else return false; } // ---------- //判断float == 0 bool IsZero(float floatValue) { if (floatValue > -0.00001f & floatValue < 0.00001f) return true; else return false; } }

本文来自博客园,作者:萧然CS,转载请注明原文链接:https://www.cnblogs.com/z-c-s/p/15112998.html



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3