
//              3___9___2
//             / `\    /´\ 
//            /    `\/´   \
//           /     / `\    \
//          /    5´    `\   7
//         6   /´        `8  \
//        /  /´            `\ \
//       / /´                `\\
//    0 /´________4____________`\1

// code / indice / nombre
static int Mesh::code[64][3] =
{    
    {0, 0, 0},
    {1, 22, 2},
    {2, 24, 2},
    {3, 34, 3},    
    {4, 26, 2},
    {5, 39, 3},
    {6, 52, 3},
    {7, 0, 0},
    {8, 28, 2},
    {9, 42, 3},
    {10, 55, 3},
    {11, 20, 4},
    {12, 65, 4},
    {13, 0, 0},
    {14, 0, 0},
    {15, 0, 0},
    {16, 30, 2},
    {17, 45, 3},
    {18, 58, 4},
    {19, 0, 0},
    {20, 69, 3},
    {21, 16, 4},
    {22, 0, 0},
    {23, 0, 0},
    {24, 0, 0},
    {25, 0, 0},
    {26, 0, 0},
    {27, 0, 0},
    {28, 0, 0},
    {29, 0, 0},
    {30, 0, 0},
    {31, 0, 0},
    {32, 32, 2},
    {33, 48, 4},
    {34, 62, 3},
    {35, 0, 0},
    {36, 0, 0},
    {37, 0, 0},
    {38, 12, 4},
    {39, 0, 0},
    {40, 0, 0},
    {41, 0, 0},
    {42, 0, 0},
    {43, 0, 0},
    {44, 0, 0},
    {45, 0, 0},
    {46, 0, 0},
    {47, 0, 0},
    {48, 0, 0},
    {49, 0, 0},
    {50, 0, 0},
    {51, 0, 0},
    {52, 0, 0},
    {53, 0, 0},
    {54, 0, 0},
    {55, 0, 0},
    {56, 8, 4},
    {63, 0, 8},
};

static const int idnt[][4] =
{
    // refine 1 --> 8 // code 63
    {0, 4, 5, 6},
    {1, 7, 4, 8},
    {2, 5, 7, 9},
    {3, 6, 9, 8},
    {5, 6, 4, 8},
    {5, 4, 7, 8},
    {5, 7, 9, 8},
    {5, 9, 6, 8},
    // refine 1 --> 4
    // face 0 // code 56
    {1, 8, 7, 0},
    {2, 7, 9, 0},
    {3, 9, 8, 0},
    {7, 8, 9, 0},
    // face 1 // code 38
    {0, 5, 6, 1},
    {2, 9, 5, 1},
    {3, 6, 9, 1},
    {5, 9, 6, 1},
    // face 2 // code 21
    {0, 6, 4, 2},
    {1, 4, 8, 2},
    {3, 8, 6, 2},
    {6, 8, 4, 2},
    // face 3 // code 11
    {0, 4, 6, 3},
    {1, 5, 4, 3},
    {2, 6, 5, 3},
    {4, 5, 6, 3},
    // refine 1 --> 2
    // arete 0 // code 1
    {0, 4, 2, 3},
    {4, 1, 2, 3},
    // arete 1 // code 2
    {2, 5, 1, 3},
    {5, 0, 1, 3},
    // arete 2 // code 4
    {3, 6, 2, 1},
    {6, 0, 2, 1},
    // arete 3 // code 8
    {1, 7, 0, 3},
    {7, 2, 0, 3},
    // arete 4 // code 16
    {1, 8, 2, 0},
    {8, 3, 2, 0},
    // arete 5  // code 32
    {2, 9, 0, 1}, // 34
    {9, 3, 0, 1},
    // non implemente pour l'instant
    // refine 1 --> 3
    // arete 0 1 // code 3
    {0, 4, 5, 3},
    {4, 2, 5, 3},
    {4, 1, 2, 3},
    // arete 0 2 // code 5
    {0, 6, 4, 2},
    {6, 1, 4, 2},
    {6, 3, 1, 2},
    // arete 0 3 // code 9
    {1, 7, 4, 3}, // 42
    {7, 0, 4, 3},
    {7, 2, 1, 3},
    // arete 0 4 // code 17
    {1, 4, 8, 2},
    {4, 3, 8, 2},
    {4, 0, 3, 2},
    // arete 0 5 // code 33
    {0, 4, 2, 9},
    {0, 4, 9, 3},
    {4, 1, 2, 9},
    {4, 1, 9, 3},
    // arete 1 2 // code 6
    {0, 5, 6, 1}, // 52
    {5, 3, 6, 1},
    {5, 2, 3, 1},
    // arete 1 3 // code 10
    {2, 5, 7, 3},
    {5, 1, 7, 3},
    {5, 0, 1, 3},
    // arete 1 4 // code 18
    {2, 5, 1, 8},
    {2, 5, 8, 3},
    {5, 0, 1, 8},
    {5, 0, 8, 3},
    // arete 1 5 // code 34
    {2, 9, 5, 1}, // 62
    {9, 0, 5, 1},
    {9, 3, 0, 1},
    // arete 2 3 // code 12
    {1, 7, 0, 6},
    {1, 7, 6, 3},
    {7, 2, 0, 6},
    {7, 2, 6, 3},
    // arete 2 4 // code 20
    {3, 8, 6, 2},
    {8, 0, 6, 2},
    {8, 1, 0, 2},
    // arete 2 5 // code 36
    {3, 6, 9, 1}, // 72
    {6, 2, 9, 1},
    {6, 0, 2, 1},
    // refine 1 --> 5
    // face 0 / arete 0
    {1, 8, 7, 0},
    {2, 7, 9, 0},
    {3, 9, 8, 0},
    {7, 8, 9, 0},
    // face 1
    {0, 5, 6, 1},
    {2, 9, 5, 1},
    {3, 6, 9, 1},
    {5, 9, 6, 1},
    // face 2
    {0, 6, 4, 2},
    {1, 4, 8, 2},
    {3, 8, 6, 2},
    {6, 8, 4, 2},
    // face 3
    {0, 4, 6, 3},
    {1, 5, 4, 3},
    {2, 6, 5, 3},
    {4, 5, 6, 3},
    
    

};

// // split un tetra en 8 nouveaux
// void Mesh::refine_1_8 (Tetra *t)
// {
//     Vertex *nv[10];
//     nv[0] = t->getVertex(0);
//     nv[1] = t->getVertex(1);
//     nv[2] = t->getVertex(2);
//     nv[3] = t->getVertex(3);
//     nv[4] = NULL;
//     nv[5] = NULL;
//     nv[6] = NULL;
//     nv[7] = NULL;
//     nv[8] = NULL;
//     nv[9] = NULL;
// 
//     for ( int i = 0; i < 6; i++ ) //calcul des nouveaux vertex si besoin
//     {
//         hashEdgeKey *k1 = new hashEdgeKey(t, i, NULL);
//         hashEdgeKey *k2 = _hes->query(k1);
//         assert(k2 != NULL);
//         delete k1;
// 
//         Vertex *m = k2->middle();
//         assert(m != NULL);
//         nv[4+i] = m;
//     }
// 
//     static const int idnt[8][4] =
//     {
//         {0, 4, 6, 7},
//         {1, 5, 4, 8},
//         {2, 6, 5, 9},
//         {3, 7, 9, 8},
//         {6, 7, 4, 8},
//         {6, 4, 5, 8},
//         {6, 5, 9, 8},
//         {6, 9, 7, 8}
//     };
// 
//     for (int i = 0; i < 8; i++)
//     {
//         Tetra *c = t->getChild(i);
//         if (c != NULL)
//             delete_tetra(c);
//     }
// 
//     for ( int i = 0; i < 8; i++ )
//     {
//         Tetra * nt = new_tetra(nv[idnt[i][0]], nv[idnt[i][1]], nv[idnt[i][2]], nv[idnt[i][3]]);
//         _new_tetra_stack.push(nt);
//     }
// 
//     // le tetra est maintenant raffine
//     t->setCurrentState(REFINED_1_T0_8);
//     t->setNextState(UNDEFINED);
// 
//     // on peut updater le parametre "_max_generation"
//     if (t->getGen() == _max_generation)
//         _max_generation++;
// 
// }
// 
// // split un tetra en 4 nouveaux, connaissant la face d'appui
// void Mesh::conform_1_4 ( Tetra *t, int face )
// {
//     // tableau des nouveaux tetraedres
//     static const int idnt[4][4] =
//     {
//         {0, 4, 6, 3},
//         {1, 5, 4, 3},
//         {2, 6, 5, 3},
//         {4, 5, 6, 3}
//     };
// 
//     Vertex *nv[7];
//     nv[0] = t->getFaceVertex(face, 0);
//     nv[1] = t->getFaceVertex(face, 1);
//     nv[2] = t->getFaceVertex(face, 2);
//     nv[3] = t->getVertex(face);
//     nv[4] = NULL;
//     nv[5] = NULL;
//     nv[6] = NULL;
// 
//     for ( int i = 0; i < 3; i++ ) //calcul des nouveaux vertex si besoin
//     {
//         hashEdgeKey *k1 = new hashEdgeKey(t, t->getFaceEdgeIndex(face, i), NULL);
//         hashEdgeKey *k2 = _hes->query(k1);
//         assert(k2 != NULL);
//         delete k1;
// 
//         Vertex *m = k2->middle();
//         assert(m != NULL);
//         nv[4+i] = m;
//     }
// 
//     // cree les nouveaux tetras
//     for ( int i = 0; i < 4; i++ )
//     {
//         Tetra * nt = new_tetra(nv[idnt[i][0]], nv[idnt[i][1]], nv[idnt[i][2]], nv[idnt[i][3]]);
//         _new_tetra_stack.push(nt);
//     }
// 
//     // le tetra est maintenant raffine
//     t->setCurrentState(REFINED_1_T0_4);
//     t->setNextState(UNDEFINED);
// 
// }
// 
// // split un tetra en 2 nouveaux, connaissant l'arete splittee
// void Mesh::conform_1_2 ( Tetra *t, int edge)
// {
//     // tableau des nouveaux tetraedres
//     static const int idnt[2][4] = { {0, 4, 2, 3}, {1, 2, 4, 3} };
// 
//     Vertex *nv[5];
//     nv[0] = t->getOppEdgeVertex(edge, 0);
//     nv[1] = t->getOppEdgeVertex(edge, 1);
//     nv[2] = t->getEdgeVertex(edge, 0);
//     nv[3] = t->getEdgeVertex(edge, 1);
//     nv[4] = NULL;
// 
//     hashEdgeKey *k1 = new hashEdgeKey(t, edge, NULL);
//     hashEdgeKey *k2 = _hes->query(k1);
//     assert(k2 != NULL);
//     delete k1;
// 
//     Vertex *m = k2->middle();
//     assert(m != NULL);
//     nv[4] = m;
// 
//     // cree les nouveaux tetras
//     for ( int i = 0; i < 2; i++ )
//     {
//         Tetra * nt = new_tetra(nv[idnt[i][0]], nv[idnt[i][1]], nv[idnt[i][2]], nv[idnt[i][3]]);
//         _new_tetra_stack.push(nt);
//     }
// 
//     // le tetra est maintenant raffine
//     t->setCurrentState(REFINED_1_T0_2);
//     t->setNextState(UNDEFINED);
// }

// void Mesh::print_tetra_info(int tetra, int depth)
// {
// #define MAX_DEPTH 1
// 
//     static const int edge[6][2] = { {0, 1}, {1, 2}, {0, 2}, {0, 3}, {1, 3}, {2, 3} };
//     for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//     std::cout<<"############  Tetra "<<tetra<<"  #########"<<std::endl;
//     for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//     std::cout<<"Generation      : "<<get_tetra(tetra)->generation<<std::endl;
//     for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//     std::cout<<"Current state   : "<<get_tetra(tetra)->current_state<<std::endl;
//     for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//     std::cout<<"Next state      : "<<get_tetra(tetra)->next_state<<std::endl;
//     if ( get_tetra(tetra)->father != -1 )
//     {
//         for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//         std::cout<<"Father          : "<<get_tetra(tetra)->father<<std::endl;
// //       print_tetra_info(get_tetra(tetra)->father, MAX_DEPTH + 1);
//     }
// 
//     for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//     for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//     for ( int t = 0; t < depth; t++ )std::cout<<"\t";
// 
//     for ( int i = 0; i < 4; i++ )  // boucle sur tout les tetraedres
//     {
//         for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//         std::cout<<"Vertex "<<i<<" : "<<get_tetra(tetra)->vertex[i]<<std::endl;
//     }
// 
//     // on inspecte les aretes
//     for (int i = 0; i < 6; i++)
//     {
//         int tested_edge = query_edge ( &m_hcode_edge, get_tetra(tetra)->vertex[edge[i][0]], get_tetra(tetra)->vertex[edge[i][1]] );
// 
//         for ( int t = 0; t < depth; t++ )std::cout<<"\t";
// 
//         if ( tested_edge != -1 )
//             std::cout<<"Edge "<<i<<" ( "<<get_tetra(tetra)->vertex[edge[i][0]]<<", "<<get_tetra(tetra)->vertex[edge[i][1]]<<" ) is splitted !!"<<std::endl;
//         else
//             std::cout<<"Edge "<<i<<" ( "<<get_tetra(tetra)->vertex[edge[i][0]]<<", "<<get_tetra(tetra)->vertex[edge[i][1]]<<" ) is not splitted !!"<<std::endl;
// 
//     }
// 
//     for ( int i = 0; i < 4; i++ )  // boucle sur tout les tetraedres
//     {
//         for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//         std::cout<<"Adjacency "<<i<<" : "<<get_tetra(tetra)->adjacency[i]<<std::endl;
//         if ( get_tetra(tetra)->adjacency[i] != -1 && depth <= MAX_DEPTH)
//             print_tetra_info(get_tetra(tetra)->adjacency[i], depth+1 );
//     }
//     for ( int t = 0; t < depth; t++ )std::cout<<"\t";
//     std::cout<<"##########################################"<<std::endl;
// }

// void Mesh::check_triangulation_conformity( int generation)
// {
//     static const int edge[6][2] = { {0, 1}, {1, 2}, {0, 2}, {0, 3}, {1, 3}, {2, 3} };
//     static const int conformity[6][6] =
//     {
//         {0,2,1,4,3,-1},
//         {2,1,0,-1,5,4},
//         {1,0,2,5,-1,3},
//         {4,-1,5,3,0,2},
//         {3,5,-1,0,4,1},
//         {-1,4,3,2,1,5}
//     };
// 
//     for ( int i = 0; i < tetra_size(); i++ )
//     {
//         if ( t->getGen() <= generation )
//         {
//             if ( m_tetra[i].current_state == NOT_REFINED )
//             {
//                 int count = 0;
//                 int list[6];
// 
//                 for (int j = 0; j < 6; j++)
//                 {
//                     int tested_edge = query_edge ( &m_hcode_edge, m_tetra[i].vertex[edge[j][0]], m_tetra[i].vertex[edge[j][1]] );
// 
//                     if ( tested_edge != -1)
//                     {
//                         list[count] = j;
//                         count++;
//                     }
//                 }
// 
//                 // check if we are not going to refine an already 1_4 or 1_2 refined tetra
//                 int father = m_tetra[i].father;
// 
//                 if (father != -1 && count > 0)
//                 {
//                     ASSERT1(p->getCurrentState() != REFINED_1_T0_2, "Refining %d (1_2 refined tetra) !!", i);
//                     ASSERT1(p->getCurrentState() != REFINED_1_T0_4, "Refining %d (1_4 refined tetra) !!", i);
//                 }
// 
//                 CHECK1(count != 2, "Tetra %d has 2 splitted edges !!", i);
// 
//                 if (count > 3)
//                 {
//                     ASSERT2(count == 6, "Tetra %d has only %d splitted edges", i, count);
//                     ASSERT3(t->getNextState() == TO_REFINE_1_T0_8, "Tetra %d with 6 splitted edges is not flag to be refine 1 to 8 (current flag = %d, next flag = %d)", i, m_tetra[i].current_state, t->getNextState());
//                 }
// 
//                 if (count == 1)
//                 {
//                     ASSERT3(t->getNextState() == TO_REFINE_1_T0_2, "Tetra %d with 1 splitted edge is not flag to be refine 1 to 2 (current flag = %d, next flag = %d)", i, m_tetra[i].current_state, t->getNextState());
//                 }
// 
//                 if (count == 3)
//                 {
//                     int edge_to_split = conformity[list[0]][list[1]];
// 
//                     ASSERT1(edge_to_split == list[2], "Tetra %d has 3 edges splitted but not on the same face", i);
//                     ASSERT3(t->getNextState() == TO_REFINE_1_T0_4, "Tetra %d with 3 splitted edges is not flag to be refine 1 to 4 (current flag = %d, next flag = %d)", i, m_tetra[i].current_state, t->getNextState());
//                 }
//             }
//         }
//     }
// }

