Single point contacts plus zero sized gaps between adjacent meshes are the modelers nightmare. If you're lucky, the contype/conaffinity mechanism may get you out of this convex hell. But it is difficult to find a combination manually. Here is a little program that performs an automated brute force search. It assumes that all contacts are allowed by default and only the exceptions are listed in the array no_contacts[]. Code: #include <conio.h> #include <iostream> using namespace std; const int BITS = 3; // increase this if it doesn't find a solution const int MASK = (1 << BITS) - 1; struct OBJECT { int id; char* name; } objects[] = { 0, "everything else", // default at id 0 1, "washer segment", 2, "washer cylinder", 3, "contact ball", }; struct NO_COLLISION { int o1, o2; } no_collisions[] = { 2, 0, 3, 1, }; const int NO = _countof(objects); const int NNC = _countof(no_collisions); bool forbidden[NO][NO]; unsigned int combi; void verify_data() { for (int i = 0; i < NO; i++) { if (objects[i].id != i) throw "?ID SEQUENCE ERROR in objects[]"; } for (int i = 0; i < NNC; i++) { if ((unsigned)no_collisions[i].o1 >= NO || (unsigned)no_collisions[i].o2 >= NO) throw "?OUT OF RANGE ERROR in no_collisions[]"; } if (sizeof(combi) * 8 < NO * 2 * BITS) throw "sizeof(combi) too small, use __int64"; } void init_forbidden() { cout << "No collisions between:" << endl; for (int i = 0; i < NNC; i++) { NO_COLLISION& nc = no_collisions[i]; forbidden[nc.o1][nc.o2] = forbidden[nc.o2][nc.o1] = true; cout << "- " << objects[nc.o1].name << " and " << objects[nc.o2].name << endl; } } bool search_for_solution() { for (combi = 1 | (1 << BITS); combi < 1i64 << NO * 2 * BITS; combi += 1 << 2 * BITS) { for (int o1 = 0; o1 < NO; o1++) { int contype1 = int(combi >> o1 * 2 * BITS) & MASK; int conaffinity1 = int(combi >> o1 * 2 * BITS >> BITS) & MASK; for (int o2 = o1; o2 < NO; o2++) { int contype2 = int(combi >> o2 * 2 * BITS) & MASK; int conaffinity2 = int(combi >> o2 * 2 * BITS >> BITS) & MASK; bool collision = (contype1 & conaffinity2 || contype2 & conaffinity1); if (collision == forbidden[o1][o2]) goto next_combination; } } return true; next_combination: ; } return false; } void output_solution() { cout << "solution found" << endl; cout << "contype,conaffinity:" << endl; for (int o1 = 0; o1 < NO; o1++) { int contype = int(combi >> o1 * 2 * BITS) & MASK; int conaffinity = int(combi >> o1 * 2 * BITS >> BITS) & MASK; cout << " " << contype << "," << conaffinity << " for " << objects[o1].name << endl; } } int _cdecl main(int argc, char* argv[]) { try { verify_data(); init_forbidden(); if (search_for_solution()) output_solution(); else cout << "No solution found, increase BITS" << endl; } catch (const char* msg) { cerr << endl << msg; } cout << endl << "READY." << endl; do _getch(); while (_kbhit()); return 0; }