GJK C Program Example-1
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <stdbool.h>
#include "vector3.h"
typedef struct TSimplex {
TVec3 points[4];
int size;
} TSimplex;
typedef enum EShapeType {
CS_SPHERE,
CS_CONVEX,
} EShapeType;
typedef struct TConvexShape {
TVec3 * points;
int count;
int type;
float radius; // for sphere
} TConvexShape;
// ===========================
// HELPERS
// ===========================
bool Helper_SameDirection( TVec3 a, TVec3 b ) {
return Vec3_Dot( a, b ) > 0;
}
// ===========================
// SIMPLEX ROUTINE
// ===========================
void Simplex_RemovePoint( TSimplex * s, int num ) {
if( s->size > 0 ) {
if( num == 0 ) {
s->points[0] = s->points[1];
s->points[1] = s->points[2];
s->points[2] = s->points[3];
}
if( num == 1 ) {
s->points[1] = s->points[2];
s->points[2] = s->points[3];
}
if( num == 2 ) {
s->points[2] = s->points[3];
}
s->size--;
}
}
void Simplex_AddPoint( TSimplex * s, TVec3 p ) {
if( s->size < 3 ) {
s->points[ s->size ] = p;
s->size++;
}
}
// ===========================
// CONVEX SHAPE ROUTINE
// ===========================
void ConvexShape_CreateTriangle( TConvexShape * shape, TVec3 a, TVec3 b, TVec3 c ) {
shape->count = 3;
shape->points = malloc( shape->count * sizeof( TVec3 ));
shape->points[0] = a;
shape->points[1] = b;
shape->points[2] = c;
shape->type = CS_CONVEX;
shape->radius = 0;
}
void ConvexShape_CreateTetrahedron( TConvexShape * shape, TVec3 a, TVec3 b, TVec3 c, TVec3 d ) {
shape->count = 4;
shape->points = malloc( shape->count * sizeof( TVec3 ));
shape->points[0] = a;
shape->points[1] = b;
shape->points[2] = c;
shape->points[3] = d;
shape->type = CS_CONVEX;
shape->radius = 0;
}
void ConvexShape_CreateSphere( TConvexShape * shape, TVec3 position, float radius ) {
shape->count = 1;
shape->points = malloc( shape->count * sizeof( TVec3 ));
shape->points[ 0 ] = position;
shape->type = CS_SPHERE;
shape->radius = radius;
}
TVec3 ConvexShape_GetFarthestPointInDirection( TConvexShape * shape, TVec3 dir ) {
if( shape->type == CS_CONVEX ) {
TVec3 farthest;
float lastDot = -FLT_MAX;
for( int i = 0; i < shape->count; i++ ) {
float dot = Vec3_Dot( dir, shape->points[i] );
if( dot > lastDot ) {
farthest = shape->points[i];
lastDot = dot;
}
}
return farthest;
} else {
if( fabs( dir.x ) < 0.000001 &&
fabs( dir.y ) < 0.000001 &&
fabs( dir.z ) < 0.000001 ) {
printf( "Warn! Zero dir passed!\n" );
}
TVec3 dn = Vec3_Normalize( dir );
return Vec3_Add( shape->points[0], Vec3_Scale( dn, shape->radius ));
}
}
// ===========================
// GJK ALGORITHM ROUTINE
// ===========================
TVec3 GJK_GetSupport( TConvexShape * shape1, TConvexShape * shape2, TVec3 dir ) {
return Vec3_Sub( ConvexShape_GetFarthestPointInDirection( shape1, dir ), ConvexShape_GetFarthestPointInDirection( shape2, Vec3_Negate( dir )));
}
bool GJK_ProcessLine( TSimplex * simplex, TVec3 * outDirection ) {
TVec3 a = simplex->points[1];
TVec3 b = simplex->points[0];
TVec3 ab = Vec3_Sub( b, a );
TVec3 aO = Vec3_Negate( a );
if( Helper_SameDirection( ab, aO )) {
*outDirection = Vec3_Cross( Vec3_Cross( ab, aO ), ab );
} else {
Simplex_RemovePoint( simplex, 0 );
*outDirection = aO;
}
return false;
}
bool GJK_ProcessTriangle( TSimplex * simplex, TVec3 * outDirection ) {
TVec3 a = simplex->points[2];
TVec3 b = simplex->points[1];
TVec3 c = simplex->points[0];
TVec3 aO = Vec3_Negate( a );
TVec3 ab = Vec3_Sub( b, a );
TVec3 ac = Vec3_Sub( c, a );
TVec3 abPerp = Vec3_Cross( Vec3_Cross( ac, ab ), ab );
TVec3 acPerp = Vec3_Cross( Vec3_Cross( ab, ac ), ac );
if( Helper_SameDirection( abPerp, aO )) {
Simplex_RemovePoint( simplex, 0 );
*outDirection = abPerp;
} else {
if( Helper_SameDirection( acPerp, aO )) {
Simplex_RemovePoint( simplex, 1 );
*outDirection = acPerp;
} else {
return true;
}
}
return false;
}
bool GJK_ProcessTetrahedron( TSimplex * simplex, TVec3 * outDirection ) {
TVec3 a = simplex->points[3];
TVec3 b = simplex->points[2];
TVec3 c = simplex->points[1];
TVec3 d = simplex->points[0];
TVec3 ac = Vec3_Sub( c, a );
TVec3 ab = Vec3_Sub( b, a );
TVec3 ad = Vec3_Sub( d, a );
TVec3 acd = Vec3_Cross( ad, ac );
TVec3 abd = Vec3_Cross( ab, ad );
TVec3 abc = Vec3_Cross( ac, ab );
TVec3 aO = Vec3_Negate( a );
if( Helper_SameDirection( abc, aO )) {
if( Helper_SameDirection( Vec3_Cross( abc, ac ), aO )) {
Simplex_RemovePoint( simplex, 2 );
Simplex_RemovePoint( simplex, 0 );
*outDirection = Vec3_Cross( Vec3_Cross( ac, aO ), ac );
} else if( Helper_SameDirection( Vec3_Cross( ab, abc ), aO )) {
Simplex_RemovePoint( simplex, 1 );
Simplex_RemovePoint( simplex, 0 );
*outDirection = Vec3_Cross( Vec3_Cross( ab, aO ), ab );
} else {
Simplex_RemovePoint( simplex, 0 );
*outDirection = abc;
}
} else if( Helper_SameDirection( acd, aO )) {
if( Helper_SameDirection( Vec3_Cross( acd, ad ), aO )) {
Simplex_RemovePoint( simplex, 2 );
Simplex_RemovePoint( simplex, 1 );
*outDirection = Vec3_Cross( Vec3_Cross( ad, aO ), ad );
} else if ( Helper_SameDirection( Vec3_Cross( ac, acd ), aO )) {
Simplex_RemovePoint( simplex, 2 );
Simplex_RemovePoint( simplex, 0 );
*outDirection = Vec3_Cross( Vec3_Cross( ac, aO ), ac );
} else {
Simplex_RemovePoint( simplex, 2 );
*outDirection = acd;
}
} else if( Helper_SameDirection( abd, aO )) {
if( Helper_SameDirection( Vec3_Cross( abd, ab ), aO )) {
Simplex_RemovePoint( simplex, 1 );
Simplex_RemovePoint( simplex, 0 );
*outDirection = Vec3_Cross( Vec3_Cross( ab, aO ), ab );
} else if( Helper_SameDirection( Vec3_Cross( ad, abd ), aO )) {
Simplex_RemovePoint( simplex, 2 );
Simplex_RemovePoint( simplex, 1 );
*outDirection = Vec3_Cross( Vec3_Cross( ad, aO ), ad );
} else {
Simplex_RemovePoint( simplex, 1 );
*outDirection = abd;
}
} else {
return true;
}
return false;
}
bool GJK_ProcessSimplex( TSimplex * simplex, TVec3 * outDirection ) {
if( simplex->size == 2 ) {
return GJK_ProcessLine( simplex, outDirection );
} else if ( simplex->size == 3 ) {
return GJK_ProcessTriangle( simplex, outDirection );
} else {
return GJK_ProcessTetrahedron( simplex, outDirection );
}
}
bool GJK_IsIntersects( TConvexShape * shape1, TConvexShape * shape2 ) {
TVec3 dir = Vec3_Set( 0, 1, 0 );
TSimplex simplex = { 0 };
Simplex_AddPoint( &simplex, GJK_GetSupport( shape1, shape2, dir ));
dir = Vec3_Negate( dir );
int convergenceLimit = 45;
for( int i = 0; i < convergenceLimit; i++ ) {
TVec3 lastSupport = GJK_GetSupport( shape1, shape2, dir );
if( Helper_SameDirection( dir, lastSupport )) {
Simplex_AddPoint( &simplex, lastSupport );
if( GJK_ProcessSimplex( &simplex, &dir )) {
printf( "Intersection! %d iteration(s)!\n", i );
return true;
}
} else {
printf( "No intersection! %d iteration(s)!\n", i );
return false;
}
}
printf( "No intersection! Convergence limit has reached!\n" );
return false;
}
int main(int argc, char **argv) {
{
printf( "Triangle-Triangle Intersection Test - " );
TConvexShape shape1, shape2;
ConvexShape_CreateTriangle( &shape1, Vec3_Set( 0, 0, 0 ), Vec3_Set( 0, 1, 0 ), Vec3_Set( 1, 0, 0 ));
ConvexShape_CreateTriangle( &shape2, Vec3_Set( 0, 0.5, 0 ), Vec3_Set( 0, 1.5, 1 ), Vec3_Set( 1, 0.5, 1 ));
GJK_IsIntersects( &shape1, &shape2 );
}
{
printf( "Triangle-Tetrahedron Intersection Test - " );
TConvexShape shape1, shape2;
ConvexShape_CreateTriangle( &shape1, Vec3_Set( 0, 0, 0.5 ), Vec3_Set( 0, 1, 0.5 ), Vec3_Set( 1, 0, 0.5 ));
ConvexShape_CreateTetrahedron( &shape2, Vec3_Set( 0, 0, 0 ), Vec3_Set( 0, 1, 0 ), Vec3_Set( 1, 0, 0 ), Vec3_Set( 0, 0, 1 ));
GJK_IsIntersects( &shape1, &shape2 );
}
{
{
printf( "Sphere-Tetrahedron Intersection Test Without Small Offset - " );
TConvexShape shape1, shape2;
ConvexShape_CreateSphere( &shape1, Vec3_Set( 0,0,0 ), 1 );
ConvexShape_CreateTetrahedron( &shape2, Vec3_Set( 0, 0, 0 ), Vec3_Set( 0, 1, 0 ), Vec3_Set( 1, 0, 0 ), Vec3_Set( 0, 0, 1 ));
GJK_IsIntersects( &shape1, &shape2 );
}
{
printf( "Sphere-Tetrahedron Intersection Test With Small Offset - " );
TConvexShape shape1, shape2;
ConvexShape_CreateSphere( &shape1, Vec3_Set( 0.0001, 0, 0 ), 1 );
ConvexShape_CreateTetrahedron( &shape2, Vec3_Set( 0, 0, 0 ), Vec3_Set( 0, 1, 0 ), Vec3_Set( 1, 0, 0 ), Vec3_Set( 0, 0, 1 ));
GJK_IsIntersects( &shape1, &shape2 );
}
}
{
printf( "Tetrahedron-Tetrahedron Intersection Test - " );
TConvexShape shape1, shape2;
ConvexShape_CreateTetrahedron( &shape1, Vec3_Set( 0, 0, 0.5 ), Vec3_Set( 0, 1, 0.5 ), Vec3_Set( 1, 0, 0.5 ), Vec3_Set( 0, 0, 1.5 ));
ConvexShape_CreateTetrahedron( &shape2, Vec3_Set( 0, 0, 0 ), Vec3_Set( 0, 1, 0 ), Vec3_Set( 1, 0, 0 ), Vec3_Set( 0, 0, 1 ));
GJK_IsIntersects( &shape1, &shape2 );
}
{
printf( "Sphere-Sphere Intersection Test - " );
TConvexShape shape1, shape2;
ConvexShape_CreateSphere( &shape1, Vec3_Set( 1,0,0 ), 1 );
ConvexShape_CreateSphere( &shape2, Vec3_Set( 0,0,0 ), 1 );
GJK_IsIntersects( &shape1, &shape2 );
}
return 0;
}
Learn More :
Data Structure
- C program to remove last of singly linked list and insert it at beginning of list
- C Program To Read A Parenthesised Infix Expression From The User And Check Whether It Is Well Parenthesised Or Not
- C Program To Remove Last Of Singly Linked List And Insert It At Beginning of List
- C Program To Remove First Node Of Singly Linked List And Insert It At End Of The List
- C Program To Read The Adjecancy Matrix of Directed Graph And Convert It Into Adjecancy List
- C Program To Create Two Singly Linked List and Perform Following Operation
- C Program - Hash Table to store information about a student
- Create Two Singly Linked List Perform Differences Display It C Program
- Adding two polynomial functions C Program Using Structure
- Program to Add Two Polynomials Using Linked List C Program
- Adding Two Polynomial Functions in C Program
Structure
- C Program Structure Example-2
- C Program Structure Example
- C Program To Make Employee Payment Record Using Structure
- C Program To Store Students Record Using Structure
- Generic stack in C Program
- C Program To Multiply Two Polynomials
- C Program LEXICAL ANALYSER
- C Program Implement Binary Search Tree And Its Traversals
- Adding two polynomial functions C Program Using Structure