diff --git a/src/Box2D.NET.Samples/Samples/Collisions/Manifold.cs b/src/Box2D.NET.Samples/Samples/Collisions/Manifold.cs index 4d11b646..63bfde49 100644 --- a/src/Box2D.NET.Samples/Samples/Collisions/Manifold.cs +++ b/src/Box2D.NET.Samples/Samples/Collisions/Manifold.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Erin Catto +// SPDX-FileCopyrightText: 2025 Erin Catto // SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT @@ -305,7 +305,7 @@ public override void Step() B2Transform transform1 = new B2Transform(offset, b2Rot_identity); B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); - B2Manifold m = b2CollidePolygonAndCircle(ref box, transform1, circle, transform2); + B2Manifold m = b2CollidePolygonAndCircle(box, transform1, circle, transform2); DrawSolidPolygon(m_draw, transform1, box.vertices.AsSpan(), box.count, m_round, color1); DrawSolidCircle(m_draw, new B2Transform(circle.center, transform2.q), circle.radius, color2); @@ -346,7 +346,7 @@ public override void Step() B2Transform transform1 = new B2Transform(offset, b2Rot_identity); B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); - B2Manifold m = b2CollidePolygonAndCapsule(ref box, transform1, capsule, transform2); + B2Manifold m = b2CollidePolygonAndCapsule(box, transform1, capsule, transform2); DrawSolidPolygon(m_draw, transform1, box.vertices.AsSpan(), box.count, box.radius, color1); @@ -394,7 +394,7 @@ public override void Step() B2Transform transform1 = new B2Transform(offset, b2Rot_identity); B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); - B2Manifold m = b2CollidePolygons(ref box1, transform1, ref box, transform2); + B2Manifold m = b2CollidePolygons(box1, transform1, box, transform2); DrawSolidPolygon(m_draw, transform1, box1.vertices.AsSpan(), box1.count, box1.radius, color1); DrawSolidPolygon(m_draw, transform2, box.vertices.AsSpan(), box.count, box.radius, color2); @@ -413,7 +413,7 @@ public override void Step() B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); // b2Transform transform2 = {b2Add({0.0f, -0.1f}, offset), {0.0f, 1.0f}}; - B2Manifold m = b2CollidePolygons(ref box1, transform1, ref box, transform2); + B2Manifold m = b2CollidePolygons(box1, transform1, box, transform2); DrawSolidPolygon(m_draw, transform1, box1.vertices.AsSpan(), box1.count, box1.radius, color1); DrawSolidPolygon(m_draw, transform2, box.vertices.AsSpan(), box.count, box.radius, color2); @@ -433,7 +433,7 @@ public override void Step() B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); // b2Transform transform2 = {b2Add({0.0f, -0.1f}, offset), {0.0f, 1.0f}}; - B2Manifold m = b2CollidePolygons(ref box, transform1, ref rox, transform2); + B2Manifold m = b2CollidePolygons(box, transform1, rox, transform2); DrawSolidPolygon(m_draw, transform1, box.vertices.AsSpan(), box.count, box.radius, color1); DrawSolidPolygon(m_draw, transform2, rox.vertices.AsSpan(), rox.count, rox.radius, color2); @@ -453,7 +453,7 @@ public override void Step() // b2Transform transform1 = {{6.48024225f, 2.07872653f}, {-0.938356698f, 0.345668465f}}; // b2Transform transform2 = {{5.52862263f, 2.51146317f}, {-0.859374702f, -0.511346340f}}; - B2Manifold m = b2CollidePolygons(ref rox, transform1, ref rox, transform2); + B2Manifold m = b2CollidePolygons(in rox, transform1, in rox, transform2); DrawSolidPolygon(m_draw, transform1, rox.vertices.AsSpan(), rox.count, rox.radius, color1); DrawSolidPolygon(m_draw, transform2, rox.vertices.AsSpan(), rox.count, rox.radius, color2); @@ -473,7 +473,7 @@ public override void Step() B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); // b2Transform transform2 = {b2Add({-1.44583416f, 0.397352695f}, offset), m_transform.q}; - B2Manifold m = b2CollideSegmentAndPolygon(segment, transform1, ref rox, transform2); + B2Manifold m = b2CollideSegmentAndPolygon(segment, transform1, rox, transform2); B2Vec2 p1 = b2TransformPoint(transform1, segment.point1); B2Vec2 p2 = b2TransformPoint(transform1, segment.point2); @@ -494,7 +494,7 @@ public override void Step() B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); // b2Transform transform2 = {b2Add({0.0f, -0.1f}, offset), {0.0f, 1.0f}}; - B2Manifold m = b2CollidePolygons(ref wox, transform1, ref wox, transform2); + B2Manifold m = b2CollidePolygons(wox, transform1, wox, transform2); DrawSolidPolygon(m_draw, transform1, wox.vertices.AsSpan(), wox.count, wox.radius, color1); DrawSolidPolygon(m_draw, transform1, wox.vertices.AsSpan(), wox.count, 0.0f, color1); @@ -521,7 +521,7 @@ public override void Step() B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); // b2Transform transform2 = {b2Add({0.0f, -0.1f}, offset), {0.0f, 1.0f}}; - B2Manifold m = b2CollidePolygons(ref w1, transform1, ref w2, transform2); + B2Manifold m = b2CollidePolygons(w1, transform1, w2, transform2); DrawSolidPolygon(m_draw, transform1, w1.vertices.AsSpan(), w1.count, w1.radius, color1); DrawSolidPolygon(m_draw, transform1, w1.vertices.AsSpan(), w1.count, 0.0f, color1); @@ -546,7 +546,7 @@ public override void Step() B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); // b2Transform transform2 = {b2Add({0.0f, -0.1f}, offset), {0.0f, 1.0f}}; - B2Manifold m = b2CollidePolygons(ref box, transform1, ref tri, transform2); + B2Manifold m = b2CollidePolygons(box, transform1, tri, transform2); DrawSolidPolygon(m_draw, transform1, box.vertices.AsSpan(), box.count, 0.0f, color1); DrawSolidPolygon(m_draw, transform2, tri.vertices.AsSpan(), tri.count, 0.0f, color2); @@ -611,8 +611,8 @@ public override void Step() B2Transform transform1 = new B2Transform(offset, b2Rot_identity); B2Transform transform2 = new B2Transform(b2Add(m_transform.p, offset), m_transform.q); - B2Manifold m1 = b2CollideChainSegmentAndPolygon(segment1, transform1, ref rox, transform2, ref m_smgroxCache1); - B2Manifold m2 = b2CollideChainSegmentAndPolygon(segment2, transform1, ref rox, transform2, ref m_smgroxCache2); + B2Manifold m1 = b2CollideChainSegmentAndPolygon(segment1, transform1, rox, transform2, ref m_smgroxCache1); + B2Manifold m2 = b2CollideChainSegmentAndPolygon(segment2, transform1, rox, transform2, ref m_smgroxCache2); { B2Vec2 g2 = b2TransformPoint(transform1, segment1.ghost2); diff --git a/src/Box2D.NET.Samples/Samples/Collisions/SmoothManifold.cs b/src/Box2D.NET.Samples/Samples/Collisions/SmoothManifold.cs index 3ea1e166..acf90c38 100644 --- a/src/Box2D.NET.Samples/Samples/Collisions/SmoothManifold.cs +++ b/src/Box2D.NET.Samples/Samples/Collisions/SmoothManifold.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2025 Erin Catto +// SPDX-FileCopyrightText: 2025 Erin Catto // SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT @@ -300,7 +300,7 @@ public override void Draw() { ref readonly B2ChainSegment segment = ref m_segments[i]; B2SimplexCache cache = new B2SimplexCache(); - B2Manifold m = b2CollideChainSegmentAndPolygon(segment, transform1, ref rox, transform2, ref cache); + B2Manifold m = b2CollideChainSegmentAndPolygon(segment, transform1, rox, transform2, ref cache); DrawManifold(m); } } diff --git a/src/Box2D.NET/B2Contacts.cs b/src/Box2D.NET/B2Contacts.cs index 7b5cab7a..5f4c65b0 100644 --- a/src/Box2D.NET/B2Contacts.cs +++ b/src/Box2D.NET/B2Contacts.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 Erin Catto +// SPDX-FileCopyrightText: 2023 Erin Catto // SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT @@ -62,19 +62,19 @@ internal static B2Manifold b2CapsuleManifold(B2Shape shapeA, in B2Transform xfA, internal static B2Manifold b2PolygonAndCircleManifold(B2Shape shapeA, in B2Transform xfA, B2Shape shapeB, in B2Transform xfB, ref B2SimplexCache cache) { B2_UNUSED(cache); - return b2CollidePolygonAndCircle(ref shapeA.us.polygon, xfA, shapeB.us.circle, xfB); + return b2CollidePolygonAndCircle(shapeA.us.polygon, xfA, shapeB.us.circle, xfB); } internal static B2Manifold b2PolygonAndCapsuleManifold(B2Shape shapeA, in B2Transform xfA, B2Shape shapeB, in B2Transform xfB, ref B2SimplexCache cache) { B2_UNUSED(cache); - return b2CollidePolygonAndCapsule(ref shapeA.us.polygon, xfA, shapeB.us.capsule, xfB); + return b2CollidePolygonAndCapsule(shapeA.us.polygon, xfA, shapeB.us.capsule, xfB); } internal static B2Manifold b2PolygonManifold(B2Shape shapeA, in B2Transform xfA, B2Shape shapeB, in B2Transform xfB, ref B2SimplexCache cache) { B2_UNUSED(cache); - return b2CollidePolygons(ref shapeA.us.polygon, xfA, ref shapeB.us.polygon, xfB); + return b2CollidePolygons(shapeA.us.polygon, xfA, shapeB.us.polygon, xfB); } internal static B2Manifold b2SegmentAndCircleManifold(B2Shape shapeA, in B2Transform xfA, B2Shape shapeB, in B2Transform xfB, ref B2SimplexCache cache) @@ -92,7 +92,7 @@ internal static B2Manifold b2SegmentAndCapsuleManifold(B2Shape shapeA, in B2Tran internal static B2Manifold b2SegmentAndPolygonManifold(B2Shape shapeA, in B2Transform xfA, B2Shape shapeB, in B2Transform xfB, ref B2SimplexCache cache) { B2_UNUSED(cache); - return b2CollideSegmentAndPolygon(shapeA.us.segment, xfA, ref shapeB.us.polygon, xfB); + return b2CollideSegmentAndPolygon(shapeA.us.segment, xfA, shapeB.us.polygon, xfB); } internal static B2Manifold b2ChainSegmentAndCircleManifold(B2Shape shapeA, in B2Transform xfA, B2Shape shapeB, in B2Transform xfB, ref B2SimplexCache cache) @@ -108,7 +108,7 @@ internal static B2Manifold b2ChainSegmentAndCapsuleManifold(B2Shape shapeA, in B internal static B2Manifold b2ChainSegmentAndPolygonManifold(B2Shape shapeA, in B2Transform xfA, B2Shape shapeB, in B2Transform xfB, ref B2SimplexCache cache) { - return b2CollideChainSegmentAndPolygon(shapeA.us.chainSegment, xfA, ref shapeB.us.polygon, xfB, ref cache); + return b2CollideChainSegmentAndPolygon(shapeA.us.chainSegment, xfA, shapeB.us.polygon, xfB, ref cache); } internal static void b2AddType(b2ManifoldFcn fcn, B2ShapeType type1, B2ShapeType type2) diff --git a/src/Box2D.NET/B2Manifolds.cs b/src/Box2D.NET/B2Manifolds.cs index 010244f3..39e6e76e 100644 --- a/src/Box2D.NET/B2Manifolds.cs +++ b/src/Box2D.NET/B2Manifolds.cs @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 Erin Catto +// SPDX-FileCopyrightText: 2023 Erin Catto // SPDX-FileCopyrightText: 2025 Ikpil Choi(ikpil@naver.com) // SPDX-License-Identifier: MIT @@ -140,7 +140,7 @@ public static B2Manifold b2CollideCapsuleAndCircle(in B2Capsule capsuleA, in B2T } /// Compute the contact manifold between a polygon and a circle - public static B2Manifold b2CollidePolygonAndCircle(ref B2Polygon polygonA, in B2Transform xfA, in B2Circle circleB, in B2Transform xfB) + public static B2Manifold b2CollidePolygonAndCircle(in B2Polygon polygonA, in B2Transform xfA, in B2Circle circleB, in B2Transform xfB) { B2Manifold manifold = new B2Manifold(); float speculativeDistance = B2_SPECULATIVE_DISTANCE; @@ -157,8 +157,8 @@ public static B2Manifold b2CollidePolygonAndCircle(ref B2Polygon polygonA, in B2 int normalIndex = 0; float separation = -float.MaxValue; int vertexCount = polygonA.count; - ReadOnlySpan vertices = polygonA.vertices.AsSpan(); - ReadOnlySpan normals = polygonA.normals.AsSpan(); + ReadOnlySpan vertices = polygonA.vertices.AsReadOnlySpan(); + ReadOnlySpan normals = polygonA.normals.AsReadOnlySpan(); for (int i = 0; i < vertexCount; ++i) { @@ -537,10 +537,10 @@ public static B2Manifold b2CollideSegmentAndCapsule(in B2Segment segmentA, in B2 } /// Compute the contact manifold between a polygon and capsule - public static B2Manifold b2CollidePolygonAndCapsule(ref B2Polygon polygonA, in B2Transform xfA, in B2Capsule capsuleB, in B2Transform xfB) + public static B2Manifold b2CollidePolygonAndCapsule(in B2Polygon polygonA, in B2Transform xfA, in B2Capsule capsuleB, in B2Transform xfB) { B2Polygon polyB = b2MakeCapsule(capsuleB.center1, capsuleB.center2, capsuleB.radius); - return b2CollidePolygons(ref polygonA, xfA, ref polyB, xfB); + return b2CollidePolygons(polygonA, xfA, polyB, xfB); } // Polygon clipper used to compute contact points when there are potentially two contact points. @@ -718,7 +718,24 @@ internal static float b2FindMaxSeparation(ref int edgeIndex, ref B2Polygon poly1 } /// Compute the contact manifold between two polygons - public static B2Manifold b2CollidePolygons(ref B2Polygon polygonA, in B2Transform xfA, ref B2Polygon polygonB, in B2Transform xfB) + // Due to speculation, every polygon is rounded + // Algorithm: + // + // compute edge separation using the separating axis test (SAT) + // if (separation > speculation_distance) + // return + // find reference and incident edge + // if separation >= 0.1f * B2_LINEAR_SLOP + // compute closest points between reference and incident edge + // if vertices are closest + // single vertex-vertex contact + // else + // clip edges + // end + // else + // clip edges + // end + public static B2Manifold b2CollidePolygons(in B2Polygon polygonA, in B2Transform xfA, in B2Polygon polygonB, in B2Transform xfB) { B2Vec2 origin = polygonA.vertices[0]; float linearSlop = B2_LINEAR_SLOP; @@ -1071,10 +1088,10 @@ public static B2Manifold b2CollideSegmentAndCircle(in B2Segment segmentA, in B2T } /// Compute the contact manifold between an segment and a polygon - public static B2Manifold b2CollideSegmentAndPolygon(in B2Segment segmentA, in B2Transform xfA, ref B2Polygon polygonB, in B2Transform xfB) + public static B2Manifold b2CollideSegmentAndPolygon(in B2Segment segmentA, in B2Transform xfA, in B2Polygon polygonB, in B2Transform xfB) { B2Polygon polygonA = b2MakeCapsule(segmentA.point1, segmentA.point2, 0.0f); - return b2CollidePolygons(ref polygonA, xfA, ref polygonB, xfB); + return b2CollidePolygons(polygonA, xfA, polygonB, xfB); } /// Compute the contact manifold between a chain segment and a circle @@ -1169,7 +1186,7 @@ public static B2Manifold b2CollideChainSegmentAndCircle(in B2ChainSegment segmen public static B2Manifold b2CollideChainSegmentAndCapsule(in B2ChainSegment segmentA, in B2Transform xfA, in B2Capsule capsuleB, in B2Transform xfB, ref B2SimplexCache cache) { B2Polygon polyB = b2MakeCapsule(capsuleB.center1, capsuleB.center2, capsuleB.radius); - return b2CollideChainSegmentAndPolygon(segmentA, xfA, ref polyB, xfB, ref cache); + return b2CollideChainSegmentAndPolygon(segmentA, xfA, polyB, xfB, ref cache); } internal static B2Manifold b2ClipSegments(B2Vec2 a1, B2Vec2 a2, B2Vec2 b1, B2Vec2 b2, B2Vec2 normal, float ra, float rb, ushort id1, ushort id2) @@ -1287,7 +1304,7 @@ internal static B2NormalType b2ClassifyNormal(B2ChainSegmentParams param, B2Vec2 } /// Compute the contact manifold between a chain segment and a rounded polygon - public static B2Manifold b2CollideChainSegmentAndPolygon(in B2ChainSegment segmentA, in B2Transform xfA, ref B2Polygon polygonB, + public static B2Manifold b2CollideChainSegmentAndPolygon(in B2ChainSegment segmentA, in B2Transform xfA, in B2Polygon polygonB, B2Transform xfB, ref B2SimplexCache cache) { B2Manifold manifold = new B2Manifold();