// SPDX-FileCopyrightText: 2023 Erin Catto // SPDX-License-Identifier: MIT #include "test_macros.h" #include "box2d/collision.h" #include "box2d/math_functions.h" #include static b2Capsule capsule = { { -1.0f, 0.0f }, { 1.0f, 0.0f }, 1.0f }; static b2Circle circle = { { 1.0f, 0.0f }, 1.0f }; static b2Polygon box; static b2Segment segment = { { 0.0f, 1.0f }, { 0.0f, -1.0f } }; #define N 4 static int ShapeMassTest( void ) { { b2MassData md = b2ComputeCircleMass( &circle, 1.0f ); ENSURE_SMALL( md.mass - b2_pi, FLT_EPSILON ); ENSURE( md.center.x == 1.0f && md.center.y == 0.0f ); ENSURE_SMALL( md.rotationalInertia - 1.5f * b2_pi, FLT_EPSILON ); } { float radius = capsule.radius; float length = b2Distance( capsule.center1, capsule.center2 ); b2MassData md = b2ComputeCapsuleMass( &capsule, 1.0f ); // Box that full contains capsule b2Polygon r = b2MakeBox( radius, radius + 0.5f * length ); b2MassData mdr = b2ComputePolygonMass( &r, 1.0f ); // Approximate capsule using convex hull b2Vec2 points[2 * N]; float d = b2_pi / ( N - 1.0f ); float angle = -0.5f * b2_pi; for ( int i = 0; i < N; ++i ) { points[i].x = 1.0f + radius * cosf( angle ); points[i].y = radius * sinf( angle ); angle += d; } angle = 0.5f * b2_pi; for ( int i = N; i < 2 * N; ++i ) { points[i].x = -1.0f + radius * cosf( angle ); points[i].y = radius * sinf( angle ); angle += d; } b2Hull hull = b2ComputeHull( points, 2 * N ); b2Polygon ac = b2MakePolygon( &hull, 0.0f ); b2MassData ma = b2ComputePolygonMass( &ac, 1.0f ); ENSURE( ma.mass < md.mass && md.mass < mdr.mass ); ENSURE( ma.rotationalInertia < md.rotationalInertia && md.rotationalInertia < mdr.rotationalInertia ); } { b2MassData md = b2ComputePolygonMass( &box, 1.0f ); ENSURE_SMALL( md.mass - 4.0f, FLT_EPSILON ); ENSURE_SMALL( md.center.x, FLT_EPSILON ); ENSURE_SMALL( md.center.y, FLT_EPSILON ); ENSURE_SMALL( md.rotationalInertia - 8.0f / 3.0f, 2.0f * FLT_EPSILON ); } return 0; } static int ShapeAABBTest( void ) { { b2AABB b = b2ComputeCircleAABB( &circle, b2Transform_identity ); ENSURE_SMALL( b.lowerBound.x, FLT_EPSILON ); ENSURE_SMALL( b.lowerBound.y + 1.0f, FLT_EPSILON ); ENSURE_SMALL( b.upperBound.x - 2.0f, FLT_EPSILON ); ENSURE_SMALL( b.upperBound.y - 1.0f, FLT_EPSILON ); } { b2AABB b = b2ComputePolygonAABB( &box, b2Transform_identity ); ENSURE_SMALL( b.lowerBound.x + 1.0f, FLT_EPSILON ); ENSURE_SMALL( b.lowerBound.y + 1.0f, FLT_EPSILON ); ENSURE_SMALL( b.upperBound.x - 1.0f, FLT_EPSILON ); ENSURE_SMALL( b.upperBound.y - 1.0f, FLT_EPSILON ); } { b2AABB b = b2ComputeSegmentAABB( &segment, b2Transform_identity ); ENSURE_SMALL( b.lowerBound.x, FLT_EPSILON ); ENSURE_SMALL( b.lowerBound.y + 1.0f, FLT_EPSILON ); ENSURE_SMALL( b.upperBound.x, FLT_EPSILON ); ENSURE_SMALL( b.upperBound.y - 1.0f, FLT_EPSILON ); } return 0; } static int PointInShapeTest( void ) { b2Vec2 p1 = { 0.5f, 0.5f }; b2Vec2 p2 = { 4.0f, -4.0f }; { bool hit; hit = b2PointInCircle( p1, &circle ); ENSURE( hit == true ); hit = b2PointInCircle( p2, &circle ); ENSURE( hit == false ); } { bool hit; hit = b2PointInPolygon( p1, &box ); ENSURE( hit == true ); hit = b2PointInPolygon( p2, &box ); ENSURE( hit == false ); } return 0; } static int RayCastShapeTest( void ) { b2RayCastInput input = { { -4.0f, 0.0f }, { 8.0f, 0.0f }, 1.0f }; { b2CastOutput output = b2RayCastCircle( &input, &circle ); ENSURE( output.hit ); ENSURE_SMALL( output.normal.x + 1.0f, FLT_EPSILON ); ENSURE_SMALL( output.normal.y, FLT_EPSILON ); ENSURE_SMALL( output.fraction - 0.5f, FLT_EPSILON ); } { b2CastOutput output = b2RayCastPolygon( &input, &box ); ENSURE( output.hit ); ENSURE_SMALL( output.normal.x + 1.0f, FLT_EPSILON ); ENSURE_SMALL( output.normal.y, FLT_EPSILON ); ENSURE_SMALL( output.fraction - 3.0f / 8.0f, FLT_EPSILON ); } { b2CastOutput output = b2RayCastSegment( &input, &segment, true ); ENSURE( output.hit ); ENSURE_SMALL( output.normal.x + 1.0f, FLT_EPSILON ); ENSURE_SMALL( output.normal.y, FLT_EPSILON ); ENSURE_SMALL( output.fraction - 0.5f, FLT_EPSILON ); } return 0; } int ShapeTest( void ) { box = b2MakeBox( 1.0f, 1.0f ); RUN_SUBTEST( ShapeMassTest ); RUN_SUBTEST( ShapeAABBTest ); RUN_SUBTEST( PointInShapeTest ); RUN_SUBTEST( RayCastShapeTest ); return 0; }