#include "simplex.h"


Tetra::Tetra(Vertex *v0, Vertex *v1, Vertex *v2, Vertex *v3)
{
    assert(v0 != NULL);
    assert(v1 != NULL);
    assert(v2 != NULL);
    assert(v3 != NULL);
    _v[0] = v0;
    _v[1] = v1;
    _v[2] = v2;
    _v[3] = v3;
    v0->setTetra(this);
    v1->setTetra(this);
    v2->setTetra(this);
    v3->setTetra(this);
    _a[0] = _a[1] = _a[2] = _a[3] = NULL;
    _o[0] = _o[1] = _o[2] = _o[3] = -1;
    id = -1;
    index = -1;
    flag = -1;
    _state = NOT_REFINED;
    _father = NULL;
    _child[0] = _child[1] = _child[2] = _child[3] = _child[4] = _child[5] = _child[6] = _child[7] = NULL;
    _generation = 0;
    _refdepth = 0;
    bit_edge = 0;
    
    _rl = 0.0;
    for (int i = 0; i < 6; i++)
    {
        Vertex ab;
        ab.setVector(getEdgeVertex(i, 0), getEdgeVertex(i, 1));
        double el = ab.norm();
        if (el > _rl)
            _rl = el;
    }
}

Tetra::Tetra(int i, Vertex *v0, Vertex *v1, Vertex *v2, Vertex *v3)
{
    assert(v0 != NULL);
    assert(v1 != NULL);
    assert(v2 != NULL);
    assert(v3 != NULL);
    _v[0] = v0;
    v0->setTetra(this);
    _v[1] = v1;
    v1->setTetra(this);
    _v[2] = v2;
    v2->setTetra(this);
    _v[3] = v3;
    v3->setTetra(this);
    _a[0] = _a[1] = _a[2] = _a[3] = NULL;
    _o[0] = _o[1] = _o[2] = _o[3] = -1;
    id = i;
    index = -1;
    flag = -1;
    _state = NOT_REFINED;
    _father = NULL;
    _child[0] = _child[1] = _child[2] = _child[3] = _child[4] = _child[5] = _child[6] = _child[7] = NULL;
    _generation = 0;
    _refdepth = 0;
    bit_edge = 0;

    _rl = 0.0;
    for (int i = 0; i < 6; i++)
    {
        Vertex ab;
        ab.setVector(getEdgeVertex(i, 0), getEdgeVertex(i, 1));
        double el = ab.norm();
        if (el > _rl)
            _rl = el;
    }
}

int Tetra::getEdgeIndex(Vertex *v0, Vertex *v1)
{
    assert(v0 != NULL);
    assert(v1 != NULL);
    int edge = 0;
    for (int i = 0; i < 4; i++)
        if (v0 == getVertex(i))
            for (int j = i+1; j < 4; j++)
                if (v1 == getVertex(j))
                    return edge;
                else
                    edge++;
        else if (v1 == getVertex(i))
            for (int j = i+1; j < 4; j++)
                if (v0 == getVertex(j))
                    return edge;
                else
                    edge++;
        else
            edge += (3-i);
}

int Tetra::getFaceEdgeIndex(int face, int edge)
{
    assert(face>=0 && face<4);
    assert(edge>=0 && edge<3);

    static int fe[4][3] = {{4,5,3,},{1,5,2},{2,4,0},{0,3,1}}; // indice arete face
    return fe[face][edge];
}

int Tetra::getEdgeVertexIndex(int edge, int vertex)
{
    assert(edge>=0 && edge<6);
    assert(vertex>=0 && vertex<2);

    static int ev[6][2] = {{0, 1},{0, 2},{0, 3},{1, 2},{1, 3},{2, 3}}; // indice sommet arete
    return ev[edge][vertex];
}

int Tetra::getEdgeCode(int edge)
{
    assert(edge>=0 && edge<6);
    static int ec[6] = {1, 2, 4, 8, 16, 32}; // indice arete
    return ec[edge];
}

Vertex *Tetra::getEdgeVertex(int edge, int vertex)
{
    assert(edge>=0 && edge<6);
    assert(vertex>=0 && vertex<2);

    return getVertex(getEdgeVertexIndex(edge, vertex));
}

int Tetra::getFaceVertexIndex(int face, int vertex)
{
    assert(face>=0 && face<4);
    assert(vertex>=0 && vertex<3);

    static int fv[4][3] = {{1,3,2},{0,2,3},{0,3,1},{0,1,2}}; // indice sommet  face
    return fv[face][vertex];
}

int Tetra::getFaceCode(int face)
{
     assert(face>=0 && face<4);
    return getEdgeCode(getFaceEdgeIndex(face, 0)) + getEdgeCode(getFaceEdgeIndex(face, 1)) + getEdgeCode(getFaceEdgeIndex(face, 2));
}

Vertex *Tetra::getFaceVertex(int face, int vertex)
{
    assert(face>=0 && face<4);
    assert(vertex>=0 && vertex<3);

    return getVertex(getFaceVertexIndex(face, vertex));
}

int Tetra::getOppEdgeVertexIndex(int edge, int vertex)
{
    assert(edge>=0 && edge<6);
    assert(vertex>=0 && vertex<2);

    static int ev[6][2] = {{0, 1},{0, 2},{0, 3},{1, 2},{1, 3},{2, 3}}; // indice sommet arete
    static int eo[6] = {5, 4, 3, 2, 1, 0}; // indice arete opposee
    return ev[eo[edge]][vertex];
}

Vertex *Tetra::getOppEdgeVertex(int edge, int vertex)
{
    assert(edge>=0 && edge<6);
    assert(vertex>=0 && vertex<2);

    return getVertex(getOppEdgeVertexIndex(edge, vertex));
}

int Tetra::getOppEdgeOppVertexIndex(int edge, int vertex)
{
    assert(edge>=0 && edge<6);
    assert(vertex>=0 && vertex<4);

    static int ev[6][4] = {{-1, -1, 3, 2},{-1, 3, -1, 1},{-1, 2, 1, -1},{3, -1, -1, 0},{2, -1, 0, -1},{1, 0, -1, -1}}; // indice sommet arete
    assert(ev[edge][vertex] != -1);
    return ev[edge][vertex];
}

Vertex *Tetra::getOppEdgeOppVertex(int edge, int vertex)
{
    assert(edge>=0 && edge<6);
    assert(vertex>=0 && vertex<4);

    return getVertex(getOppEdgeOppVertexIndex(edge, vertex));
}

void Tetra::setMutualAdj(int opp1, Tetra *t2, int opp2)
{
    assert(opp1>=0 && opp1<4);
    assert(opp2>=0 && opp2<4);
    assert(t2 != NULL);
    setAdj(opp1, t2, opp2);
    t2->setAdj(opp2, this, opp1);
}

void Tetra::reset()
{
    _v[0] = _v[1] = _v[2] = _v[3] = NULL;
    _a[0] = _a[1] = _a[2] = _a[3] = NULL;
    _o[0] = _o[1] = _o[2] = _o[3] = -1;
    id = -1;
    index = -1;
    flag = -1;
    _state = NOT_REFINED;
    _father = NULL;
    _child[0] = _child[1] = _child[2] = _child[3] = _child[4] = _child[5] = _child[6] = _child[7] = NULL;
    _generation = 0;
    _refdepth = 0;
    bit_edge = 0;
    
    _rl = 0.0;
    for (int i = 0; i < 6; i++)
    {
        Vertex ab;
        ab.setVector(getEdgeVertex(i, 0), getEdgeVertex(i, 1));
        double el = ab.norm();
        if (el > _rl)
            _rl = el;
    }
}

void Tetra::split_edge(int edge)
{
//   printf("before --> %d\n", edge_state(edge));
  assert(edge>= 0 && edge <6);
  bit_edge |= (1U << edge);
//   printf("after --> %d\n", edge_state(edge));
}

int Tetra::edge_state(int edge)
{
  assert(edge>= 0 && edge <6);
//   printf("bit_edge = %d\n", (int)bit_edge);
  return (bit_edge & (1U << edge)) != 0;
}

int Tetra::edge_split_count()
{
  int count = 0;
  for (int i = 0; i < 6; i++)    
    count += edge_state(i);
  return count;
}
