public static void Test() { Line2d line1 = new Line2d(); line1.m_point1 = new Vector2L(0, 0); line1.m_point2 = new Vector2L(100, 100); Line2d line2 = new Line2d(); line2.m_point1 = new Vector2L(0, 100); line2.m_point2 = new Vector2L(100, 0); Vector2L intersectionPoint = new Vector2L(); if (Line2dWithLine2d(line1, line2, ref intersectionPoint)) { Debug.Log("双线相交 交点 " + intersectionPoint); } else { Debug.Log("双线没有相交"); } List <Vector2L> pointList = new List <Vector2L> { new Vector2L(-4.5f, -10f), new Vector2L(-4.5f, 10f), new Vector2L(4.5f, 10f), new Vector2L(4.5f, -10f) }; Convex2d convex1 = new Convex2d(new Vector2L(-5, 0), QuaternionL.Euler(Vector3L.zero), pointList); Convex2d convex2 = new Convex2d(new Vector2L(+5, 0), QuaternionL.Euler(Vector3L.zero), pointList); Debug.Log("凸多边形相交测试1 " + (Convex2dWithConvex2d(convex1, convex2, false, true) != null)); Convex2d convex3 = new Convex2d(new Vector2L(+5, 0), QuaternionL.Euler(new Vector3L(0, -90, 0)), pointList); Debug.Log("凸多边形相交测试2 " + (Convex2dWithConvex2d(convex1, convex3, false, true) != null)); Circle2d circle = new Circle2d(new Vector3L(-5, 0), 5); Debug.Log("圆与凸多边形相交测试1 " + (Circle2dWithConvex2d(circle, convex2, false, true) != null)); Debug.Log("圆与凸多边形相交测试2 " + (Circle2dWithConvex2d(circle, convex3, false, true) != null)); }
/// <summary> /// 根据Separating Axis Theorem理论实现 /// https://www.sevenson.com.au/actionscript/sat/ /// https://github.com/sevdanski/SAT_AS3 /// </summary> /// <param name="convex1"></param> /// <param name="convex2"></param> /// <returns></returns> public static CollisionInfo Circle2dWithConvex2d(Circle2d circleA, Convex2d polygonA, bool flip, bool docalc) { CollisionInfo result = new CollisionInfo(); if (flip) { result.shapeA = polygonA; result.shapeB = circleA; } else { result.shapeA = circleA; result.shapeB = polygonA; } result.shapeAContained = true; result.shapeBContained = true; // get the offset Vector2L vOffset = new Vector2L(polygonA.m_pos.x - circleA.m_pos.x, polygonA.m_pos.y - circleA.m_pos.y); // get the vertices List <Vector2L> p1 = polygonA.GetRotateList(); // find the closest point Vector2L closestPoint = new Vector2L(); FloatL minDist = FloatL.MaxValue; foreach (var iter in p1) { FloatL currentDist = (circleA.m_pos - (polygonA.m_pos + iter)).sqrMagnitude; if (currentDist < minDist) { minDist = currentDist; closestPoint = polygonA.m_pos + iter; } } // make a normal of this vector Vector2L vAxis = closestPoint - circleA.m_pos; vAxis.Normalize(); // project polygon A FloatL min0 = Vector2L.Dot(vAxis, p1[0]); FloatL max0 = min0; for (int j = 1; j < p1.Count; ++j) { FloatL t = Vector2L.Dot(vAxis, p1[j]); if (t < min0) { min0 = t; } if (t > max0) { max0 = t; } } // project circle A FloatL min1 = Vector2L.Dot(vAxis, Vector2L.zero); FloatL max1 = min1 + circleA.m_radius; min1 -= circleA.m_radius; // shift polygonA's projected points FloatL sOffset = Vector2L.Dot(vAxis, vOffset); min0 += sOffset; max0 += sOffset; // test for intersections FloatL d0 = min0 - max1; FloatL d1 = min1 - max0; if (d0 > 0 || d1 > 0) { // gap found return(null); } FloatL shortestDist = FloatL.MaxValue; if (docalc) { FloatL distmin = (max1 - min0) * -1; //Math.min(dist0, dist1); if (flip) { distmin *= -1; } FloatL distminAbs = (distmin < 0) ? distmin * -1 : distmin; // check for containment if (!flip) { if (max0 > max1 || min0 < min1) { result.shapeAContained = false; } if (max1 > max0 || min1 < min0) { result.shapeBContained = false; } } else { if (max0 < max1 || min0 > min1) { result.shapeAContained = false; } if (max1 < max0 || min1 > min0) { result.shapeBContained = false; } } // this distance is shorter so use it... result.distance = distmin; result.vector = vAxis; // shortestDist = distminAbs; } // loop through all of the axis on the first polygon for (int i = 0; i < p1.Count; i++) { // find the axis that we will project onto vAxis = GetAxisNormal(p1, i); // project polygon A min0 = Vector2L.Dot(vAxis, p1[0]); max0 = min0; // for (int j = 1; j < p1.Count; j++) { FloatL t = Vector2L.Dot(vAxis, p1[j]); if (t < min0) { min0 = t; } if (t > max0) { max0 = t; } } // project circle A min1 = Vector2L.Dot(vAxis, new Vector2L(0, 0)); max1 = min1 + circleA.m_radius; min1 -= circleA.m_radius; // shift polygonA's projected points sOffset = Vector2L.Dot(vAxis, vOffset); min0 += sOffset; max0 += sOffset; // test for intersections d0 = min0 - max1; d1 = min1 - max0; if (d0 > 0 || d1 > 0) { // gap found return(null); } if (docalc) { // check for containment if (!flip) { if (max0 > max1 || min0 < min1) { result.shapeAContained = false; } if (max1 > max0 || min1 < min0) { result.shapeBContained = false; } } else { if (max0 < max1 || min0 > min1) { result.shapeAContained = false; } if (max1 < max0 || min1 > min0) { result.shapeBContained = false; } } FloatL distmin = (max1 - min0) * -1; if (flip) { distmin *= -1; } FloatL distminAbs = (distmin < 0) ? distmin * -1 : distmin; if (distminAbs < shortestDist) { // this distance is shorter so use it... result.distance = distmin; result.vector = vAxis; // shortestDist = distminAbs; } } } // if you are here then no gap was found return(result); }
/// <summary> /// 根据Separating Axis Theorem理论实现 /// https://www.sevenson.com.au/actionscript/sat/ /// https://github.com/sevdanski/SAT_AS3 /// </summary> /// <param name="convex1"></param> /// <param name="convex2"></param> /// <returns></returns> public static CollisionInfo Convex2dWithConvex2d(Convex2d polygonA, Convex2d polygonB, bool flip, bool docalc) { CollisionInfo result = new CollisionInfo(); result.shapeA = (flip) ? polygonB : polygonA; result.shapeB = (flip) ? polygonA : polygonB; result.shapeAContained = true; result.shapeBContained = true; // get the vertices List <Vector2L> p1 = polygonA.GetRotateList(); List <Vector2L> p2 = polygonB.GetRotateList(); // get the offset Vector2L vOffset = new Vector2L(polygonA.m_pos.x - polygonB.m_pos.x, polygonA.m_pos.y - polygonB.m_pos.y); FloatL shortestDist = FloatL.MaxValue; // loop through all of the axis on the first polygon for (int i = 0; i < p1.Count; ++i) { // find the axis that we will project onto Vector2L vAxis = GetAxisNormal(p1, i); // project polygon A FloatL min0 = Vector2L.Dot(vAxis, p1[0]); FloatL max0 = min0; for (int j = 1; j < p1.Count; ++j) { FloatL t = Vector2L.Dot(vAxis, p1[j]); if (t < min0) { min0 = t; } if (t > max0) { max0 = t; } } // project polygon B FloatL min1 = Vector2L.Dot(vAxis, p2[0]); FloatL max1 = min1; for (int j = 1; j < p2.Count; ++j) { FloatL t = Vector2L.Dot(vAxis, p2[j]); if (t < min1) { min1 = t; } if (t > max1) { max1 = t; } } // shift polygonA's projected points FloatL sOffset = Vector2L.Dot(vAxis, vOffset); min0 += sOffset; max0 += sOffset; // test for intersections FloatL d0 = min0 - max1; FloatL d1 = min1 - max0; if (d0 > 0 || d1 > 0) { // gap found return(null); } if (docalc) { // check for containment if (!flip) { if (max0 > max1 || min0 < min1) { result.shapeAContained = false; } if (max1 > max0 || min1 < min0) { result.shapeBContained = false; } } else { if (max0 < max1 || min0 > min1) { result.shapeAContained = false; } if (max1 < max0 || min1 > min0) { result.shapeBContained = false; } } FloatL distmin = (max1 - min0) * -1; if (flip) { distmin *= -1; } FloatL distminAbs = (distmin < 0) ? distmin * -1 : distmin; if (distminAbs < shortestDist) { // this distance is shorter so use it... result.distance = distmin; result.vector = vAxis; shortestDist = distminAbs; } } } // if you are here then no gap was found return(result); }