Beispiel #1
0
        //http://geomalgorithms.com/

//https://stackoverflow.com/questions/1073336/circle-line-segment-collision-detection-algorithm
        public static bool TestRayCircle(LVector2 cPos, LFloat cR, LVector2 rB, LVector2 rDir, ref LFloat t)
        {
            var d            = rDir;
            var f            = rB - cPos;
            var a            = LVector2.Dot(d, d);
            var b            = 2 * LVector2.Dot(f, d);
            var c            = LVector2.Dot(f, f) - cR * cR;
            var discriminant = b * b - 4 * a * c;

            if (discriminant < 0)
            {
                // no intersection
                return(false);
            }
            else
            {
                discriminant = LMath.Sqrt(discriminant);
                var t1 = (-b - discriminant) / (2 * a);
                var t2 = (-b + discriminant) / (2 * a);
                if (t1 >= 0)
                {
                    t = t1;
                    return(true);
                }

                if (t2 >= 0)
                {
                    t = t2;
                    return(true);
                }

                return(false);
            }
        }
Beispiel #2
0
    /// <summary>
    /// 判断是否包围了原点
    /// <para>如果没有包含,且点数超过2时,只保留连线离原点最近的两个点</para>
    /// </summary>
    /// <returns></returns>
    public bool DoSimplex2D()
    {
        bool certain = false;

        if (count == 1 ||
            count == 2)
        {
            certain = false;
        }
        else if (count == 3)
        {
            LVector2 p02 = LGeometryUtil2D.GetPerpendicular2D(vertics[0].p, vertics[2].p, vertics[1].p);
            if (LVector2.Dot(-vertics[0].p, p02) >= 0)
            {
                LVector2 p12 = LGeometryUtil2D.GetPerpendicular2D(vertics[1].p, vertics[2].p, vertics[0].p);
                if (LVector2.Dot(-vertics[1].p, p12) >= 0)
                {
                    certain = true;
                }
                else
                {
                    RemoveIndex(0);
                }
            }
            else
            {
                RemoveIndex(1);
            }
        }
        return(certain);
    }
Beispiel #3
0
        public static bool TestAABBOBB(LVector2 posA, LFloat rA, LVector2 sizeA, LVector2 posB, LFloat rB, LVector2 sizeB,
                                       LVector2 upB)
        {
            var diff      = posA - posB;
            var allRadius = rA + rB;

            //circle 判定
            if (diff.sqrMagnitude > allRadius * allRadius)
            {
                return(false);
            }

            var absUPX = LMath.Abs(upB.x); //abs(up dot aabb.right)
            var absUPY = LMath.Abs(upB.y); //abs(right dot aabb.right)

            {
                //轴 投影 AABBx
                var distX = absUPX * sizeB.y + absUPY * sizeB.x;
                if (LMath.Abs(diff.x) > distX + sizeA.x)
                {
                    return(false);
                }

                //轴 投影 AABBy
                //absUPX is abs(right dot aabb.up)
                //absUPY is abs(up dot aabb.up)
                var distY = absUPY * sizeB.y + absUPX * sizeB.x;
                if (LMath.Abs(diff.y) > distY + sizeA.y)
                {
                    return(false);
                }
            }

            {
                var right     = new LVector2(upB.y, -upB.x);
                var diffPObbX = LVector2.Dot(diff, right);
                var diffPObbY = LVector2.Dot(diff, upB);

                //absUPX is abs(aabb.up dot right )
                //absUPY is abs(aabb.right dot right)
                //轴 投影 OBBx
                var distX = absUPX * sizeA.y + absUPY * sizeA.x;
                if (LMath.Abs(diffPObbX) > distX + sizeB.x)
                {
                    return(false);
                }

                //absUPX is abs(aabb.right dot up )
                //absUPY is abs(aabb.up dot up)
                //轴 投影 OBBy
                var distY = absUPY * sizeA.y + absUPX * sizeA.x;
                if (LMath.Abs(diffPObbY) > distY + sizeB.y)
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #4
0
    /// <summary>
    /// 计算v1v2的垂线,pointTo决定垂线的指向(返回向量未归一化)
    /// </summary>
    /// <param name="v1"></param>
    /// <param name="v2"></param>
    /// <param name="pointTo"></param>
    public static LVector2 GetPerpendicular2D(LVector2 v1, LVector2 v2, LVector2 pointTo)
    {
        LVector2 v12  = v1 - v2;
        LVector2 dir  = new LVector2(-v12.y, v12.x);
        int      sign = LVector2.Dot(dir, pointTo - v1) > 0 ? 1 : -1;

        dir *= sign;
        return(dir);
    }
Beispiel #5
0
    /// <summary>
    /// 判断找到Support点是是否是沿找寻的方向
    /// <para>如果是相反的方向,说明不会包含原点,退出GJK</para>
    /// </summary>
    /// <returns></returns>
    public bool IsSameDirectionWithOrigin(SimplexPoint2D sp, LVector2 direction)
    {
        bool certain = false;

        if (count == 0)
        {
            certain = true;
        }
        else if (count == 1 ||
                 count == 2)
        {
            certain = LVector2.Dot(sp.p, direction) >= 0;
        }
        return(certain);
    }
Beispiel #6
0
    internal override LVector2 GetFurtherPointInDirection(LVector2 direction)
    {
        LVector2 fp    = mVertics[0];
        LFloat   fpdot = LVector2.Dot(fp, direction);

        for (int i = mVertics.Length - 1; i >= 1; i--)
        {
            LFloat vdot = LVector2.Dot(mVertics[i], direction);
            if (vdot > fpdot)
            {
                fp    = mVertics[i];
                fpdot = vdot;
            }
        }
        return(fp);
    }
Beispiel #7
0
 /// <summary>
 /// 引入一个新的support point,删除使得此点看不见原点的edge,将删除的edge的点保存在list中
 /// 剔除list中的重复点,用list中的每个点与sp构建新的edge
 /// </summary>
 /// <param name="v1"></param>
 /// <param name="v2"></param>
 /// <param name="sp"></param>
 public void ImportNewSupportPoint(SimplexPoint2D sp)
 {
     for (int i = faces.Count - 1; i >= 0; i--)
     {
         if (LVector2.Dot(sp.p - faces[i].sp1.p, faces[i].direction) > 0)
         {
             AddExpiredEdgePoint(faces[i].sp1);
             AddExpiredEdgePoint(faces[i].sp2);
             faces.RemoveAt(i);
         }
     }
     for (int i = points.Count - 1; i >= 0; i--)
     {
         faces.Add(new EPAFace2D(sp, points[i]));
     }
     points.Clear();
 }
Beispiel #8
0
    private void TestLVector2()
    {
        LVector2 v1 = new LVector2(3.3d, 1.2d);
        LVector2 v2 = new LVector2(1.2d, 3.3d);

        AssertTrue(v1 != v2);
        AssertFalse(v1 == v2);
        AssertTrue(v1 + v2 == new LVector2(4.5d, 4.5d));
        AssertTrue(v1 - v2 == new LVector2(2.1d, -2.1d));
        AssertTrue(v1 * 2 == new LVector2(6.6d, 2.4d));
        AssertTrue(v1 / 3 == new LVector2(1.1d, 0.4d));
        AssertTrue(LVector2.zero.normalized == LVector2.zero);
        AssertTrue(LVector2.Dot(v1, v2) == 7.92d);
        Debug.Log(v1.sqrMagnitude);
        Debug.Log(v1.magnitude);
        Debug.Log(v1.normalized);
        Debug.Log(LVector2.Cross(v1, v2));
        Debug.Log("----------------------");
    }
Beispiel #9
0
        public static bool TestCircleOBB(LVector2 posA, LFloat rA, LVector2 posB, LFloat rB, LVector2 sizeB,
                                         LVector2 up)
        {
            var diff      = posA - posB;
            var allRadius = rA + rB;

//circle 判定CollisionHelper
            if (diff.sqrMagnitude > allRadius * allRadius)
            {
                return(false);
            }

//空间转换
            var absX   = LMath.Abs(LVector2.Dot(diff, new LVector2(up.y, -up.x)));
            var absY   = LMath.Abs(LVector2.Dot(diff, up));
            var size   = sizeB;
            var radius = rA;
            var x      = LMath.Max(absX - size.x, LFloat.zero);
            var y      = LMath.Max(absY - size.y, LFloat.zero);

            return(x * x + y * y < radius * radius);
        }
Beispiel #10
0
        //http://www.kevlindev.com/geometry/2D/intersections/index.htm
        //http://www.kevlindev.com/geometry/2D/intersections/index.htm
        //https://bitlush.com/blog/circle-vs-polygon-collision-detection-in-c-sharp
        public static bool TestCirclePolygon(LVector2 c, LFloat r, LVector2 *_points, int vertexCount)
        {
            var radiusSquared   = r * r;
            var circleCenter    = c;
            var nearestDistance = LFloat.MaxValue;
            int nearestVertex   = -1;

            for (var i = 0; i < vertexCount; i++)
            {
                LVector2 axis     = circleCenter - _points[i];
                var      distance = axis.sqrMagnitude - radiusSquared;
                if (distance <= 0)
                {
                    return(true);
                }

                if (distance < nearestDistance)
                {
                    nearestVertex   = i;
                    nearestDistance = distance;
                }
            }

            LVector2 GetPoint(int index)
            {
                if (index < 0)
                {
                    index += vertexCount;
                }
                else if (index >= vertexCount)
                {
                    index -= vertexCount;
                }

                return(_points[index]);
            }

            var vertex = GetPoint(nearestVertex - 1);

            for (var i = 0; i < 2; i++)
            {
                var nextVertex        = GetPoint(nearestVertex + i);
                var edge              = nextVertex - vertex;
                var edgeLengthSquared = edge.sqrMagnitude;
                if (edgeLengthSquared != 0)
                {
                    LVector2 axis = circleCenter - vertex;
                    var      dot  = LVector2.Dot(edge, axis);
                    if (dot >= 0 && dot <= edgeLengthSquared)
                    {
                        LVector2 projection = vertex + (dot / edgeLengthSquared) * edge;
                        axis = projection - circleCenter;
                        if (axis.sqrMagnitude <= radiusSquared)
                        {
                            return(true);
                        }
                        else
                        {
                            if (edge.x > 0)
                            {
                                if (axis.y > 0)
                                {
                                    return(false);
                                }
                            }
                            else if (edge.x < 0)
                            {
                                if (axis.y < 0)
                                {
                                    return(false);
                                }
                            }
                            else if (edge.y > 0)
                            {
                                if (axis.x < 0)
                                {
                                    return(false);
                                }
                            }
                            else
                            {
                                if (axis.x > 0)
                                {
                                    return(false);
                                }
                            }
                        }
                    }
                }

                vertex = nextVertex;
            }

            return(true);
        }
Beispiel #11
0
        public static bool TestOBBOBB(LVector2 posA, LFloat rA, LVector2 sizeA, LVector2 upA, LVector2 posB,
                                      LFloat rB,
                                      LVector2 sizeB,
                                      LVector2 upB)
        {
            var diff      = posA - posB;
            var allRadius = rA + rB;

//circle 判定
            if (diff.sqrMagnitude > allRadius * allRadius)
            {
                return(false);
            }

            var rightA = new LVector2(upA.y, -upA.x);
            var rightB = new LVector2(upB.y, -upB.x);

            {
//轴投影到 A.right
                var BuProjAr   = LMath.Abs(LVector2.Dot(upB, rightA));
                var BrProjAr   = LMath.Abs(LVector2.Dot(rightB, rightA));
                var DiffProjAr = LMath.Abs(LVector2.Dot(diff, rightA));
                var distX      = BuProjAr * sizeB.y + BrProjAr * sizeB.x;
                if (DiffProjAr > distX + sizeA.x)
                {
                    return(false);
                }

//轴投影到 A.up
                var BuProjAu   = LMath.Abs(LVector2.Dot(upB, upA));
                var BrProjAu   = LMath.Abs(LVector2.Dot(rightB, upA));
                var DiffProjAu = LMath.Abs(LVector2.Dot(diff, upA));
                var distY      = BuProjAu * sizeB.y + BrProjAu * sizeB.x;
                if (DiffProjAu > distY + sizeA.y)
                {
                    return(false);
                }
            }
            {
//轴投影到 B.right
                var AuProjBr   = LMath.Abs(LVector2.Dot(upA, rightB));
                var ArProjBr   = LMath.Abs(LVector2.Dot(rightA, rightB));
                var DiffProjBr = LMath.Abs(LVector2.Dot(diff, rightB));
                var distX      = AuProjBr * sizeA.y + ArProjBr * sizeA.x;
                if (DiffProjBr > distX + sizeB.x)
                {
                    return(false);
                }

//轴投影到 B.right
                var AuProjBu   = LMath.Abs(LVector2.Dot(upA, upB));
                var ArProjBu   = LMath.Abs(LVector2.Dot(rightA, upB));
                var DiffProjBu = LMath.Abs(LVector2.Dot(diff, upB));
                var distY      = AuProjBu * sizeA.y + ArProjBu * sizeA.x;
                if (DiffProjBu > distY + sizeB.x)
                {
                    return(false);
                }
            }
            return(true);
        }
Beispiel #12
0
        /// <summary>
        /// 测试圆和多边形是否相交
        /// </summary>
        /// <param name="c"></param>
        /// <param name="r"></param>
        /// <param name="_points"></param>
        /// <param name="vertextCount">多边形顶点数量</param>
        /// <returns></returns>
        public static bool TestCirclePolygon(LVector2 c, LFloat r, LVector2 *_points, int vertextCount)
        {
            //圆形的半径平方
            var radiusSquared = r * r;
            //圆的中心点
            var circleCenter = c;
            // 记录最近的距离
            var nearestDistance = LFloat.MaxValue;
            // 记录最近的顶点
            int nearestVertex = -1;

            for (int i = 0; i < vertextCount; i++)
            {
                LVector2 axix = circleCenter - _points[i];
                // 多边形的任何顶点在圆的范围内  说明相交
                var distance = axix.sqrMagnitude - radiusSquared;
                if (distance <= 0)
                {
                    return(true);
                }
                if (distance < nearestDistance)
                {
                    nearestVertex   = i;
                    nearestDistance = distance;
                }
            }

            // 获取点
            LVector2 GetPoint(int index)
            {
                if (index < 0)
                {
                    index += vertextCount;
                }
                else if (index >= vertextCount)
                {
                    index -= vertextCount;
                }
                return(_points[index]);
            }

            var vertex = GetPoint(nearestVertex - 1);

            for (int i = 0; i < 2; i++)
            {
                LVector2 nextVertex        = GetPoint(nearestVertex + 1);
                LVector2 edge              = nextVertex - vertex;
                LFloat   edgeLengthSquared = edge.sqrMagnitude;
                if (edgeLengthSquared != 0)
                {
                    LVector2 axis = circleCenter - vertex;
                    LFloat   dot  = LVector2.Dot(edge, axis);
                    if (dot >= 0 && dot <= edgeLengthSquared)
                    {
                        //   (dot / edgeLengthSquare ) *  edge   是求 向量的投影
                        //  两向量 a'  b'  夹角β
                        //  a·b = |a'||b'|cosβ
                        //
                        LVector2 projection = vertex + (dot / edgeLengthSquared) * edge;
                        axis = projection - circleCenter;
                        if (axis.sqrMagnitude <= radiusSquared)
                        {
                            return(true);
                        }
                        else
                        {
                            if (edge.x > 0)
                            {
                                if (axis.y > 0)
                                {
                                    return(false);
                                }
                                else if (edge.x < 0)
                                {
                                    if (axis.y < 0)
                                    {
                                        return(false);
                                    }
                                    else if (edge.y > 0)
                                    {
                                        if (axis.x < 0)
                                        {
                                            return(false);
                                        }
                                        else
                                        if (axis.x > 0)
                                        {
                                            return(false);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                vertex = nextVertex;
            }
            return(true);
        }
Beispiel #13
0
 public LFloat Dot(LVector2 v)
 {
     return(LVector2.Dot(this, v));
 }
Beispiel #14
0
 public static LFloat Angle(LVector2 lhs, LVector2 rhs)
 {
     lhs.Normalize();
     rhs.Normalize();
     return(LMath.Acos(lhs.Dot(rhs)) * LMath.RadToDeg);
 }
Beispiel #15
0
 public static LVector2 Project(LVector2 vec, LVector2 on)
 {
     return(vec.Dot(on) / on.sqrMagnitude * on);
 }