Automated contype/conaffinity search

Discussion in 'Modeling' started by wlorenz65, Aug 5, 2016.

  1. 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;
    }
    
     
    Last edited: Aug 5, 2016