function SottoCubo(matFacce)
{
   /*Private:*/

   /*Matrice RAW contenente [[Vertici Faccia+Normale],[V+N],...]*/
   /*Formato deve essere [B,F,N,S,E,O]*/
   /*B-->Back F-->Front N-->Nord S-->Sud E-->Est O-->Ovest*/
   this.matrix3D = matFacce;

   /*Facce che compongono il SottoCubo Ruotato*/
   this.faccia_ruotata = new Array(6);

   /*Index Faccia Esterna del SottoCubo (Indice relativo a "faccia_ruotata[]")*/
   /*Vale "null" se SottoCubo non e' Esterno al Cubo*/
   this.index_faccia_esterna = null;

   /*Normale Originale del Sottocubo nella forma [1,0,0] o [1,0,0] o [0,0,1]*/
   this.normale_originale = null;

   /*Normale Ruotata del Sottocubo*/
   this.normale_ruotata = null;

   /*Vettore d'Orientamento del Sottocubo nella forma [1,0,0] o [1,0,0] o [0,0,1]*/
   this.vettore_originale = null;

   /*Vettore d'Orientamento Ruotato del Sottocubo*/
   this.vettore_ruotato = null;

   /*Metodo utilizzato da IsPuntoInternoFaccia*/
   /*Devono essere passati 2 vertici e un punto*/
   this.segno = Calc_Segno;

   /*Metodo per verificare se un punto e' Interno ad una Faccia*/
   /*Deve essere passato l'indice della faccia e il punto nel formato [x,y]*/
   this.IsPuntoInternoFaccia = Verfica_Punto_Interno_Faccia;

   /*Public:*/

   /*Metodo di Inizializzazione SottoCubo*/
   this.init = InitSottoCubo;

   /*Metodo per Settare la Faccia Esterna del SottoCubo*/
   this.SetFacciaEsterna = SettaFacciaEsternaSottoCubo;

   /*Metodo per Settare la Normale Originale al SottoCubo*/
   this.SetNormaleOriginale = Setta_Normale_Originale_SottoCubo;

   /*Metodo per Settare il Vettore d'Orientamento Originale del SottoCubo*/
   this.SetVettoreOriginale = Setta_Vettore_Originale_SottoCubo;

   /*Metodo per Settare le Texture delle Facce del SottoCubo*/
   this.SetTexture = Setta_Texture_SottoCubo;

   /*Metodo per la rotazione del SottoCubo*/
   this.ruotaX = ruotaXSottoCubo; //attorno all'asse x
   this.ruotaY = ruotaYSottoCubo; //attorno all'asse y
   this.ruotaZ = ruotaZSottoCubo; //attorno all'asse z

   /*Metodo per la rotazione del SottoCubo relativa al Cubo*/
   this.ruota_rel = ruotaSottoCubo_rel; //attorno al proprio asse

   /*Metodo per la Renderizzazione*/
   this.draw = drawSottoCubo;
}

function InitSottoCubo()
{
   /*SottoCubo Ruotato*/
   for(var i=0;i<6;i++)
   {
      this.faccia_ruotata[i] = new Faccia([this.matrix3D[i*5],this.matrix3D[i*5+1],this.matrix3D[i*5+2],this.matrix3D[i*5+3]]);
      this.faccia_ruotata[i].init();
      this.faccia_ruotata[i].SetNormale(this.matrix3D[i*5+4]);
   }

   /*Index Faccia Esterna del SottoCubo (Indice relativo a "faccia_ruotata[]")*/
   /*Vale "null" se SottoCubo non e' Esterno al Cubo*/
   this.index_faccia_esterna = null;

   /*Normale Originale del Sottocubo nella forma [1,0,0] o [1,0,0] o [0,0,1]*/
   this.normale_originale = null;

   /*Normale Ruotata del Sottocubo*/
   this.normale_ruotata = null;

   /*Vettore d'Orientamento del Sottocubo nella forma [1,0,0] o [1,0,0] o [0,0,1]*/
   this.vettore_originale = null;

   /*Vettore d'Orientamento Ruotato del Sottocubo*/
   this.vettore_ruotato = null;
}

function SettaFacciaEsternaSottoCubo(indice)
{
   this.index_faccia_esterna = indice;
}

function Setta_Normale_Originale_SottoCubo(vettNormale)
{
   this.normale_originale = vettNormale;

   this.normale_ruotata = new Coord(vettNormale);
   this.normale_ruotata.init();
}

function Setta_Vettore_Originale_SottoCubo(vettOrientamento)
{
   this.vettore_originale = vettOrientamento;

   this.vettore_ruotato = new Coord(vettOrientamento);
   this.vettore_ruotato.init();
}

function Setta_Texture_SottoCubo(matTexture)
{
   for(var i=0;i<6;i++) this.faccia_ruotata[i].SetTexture(matTexture[i][0],matTexture[i][1]);
}

function ruotaXSottoCubo(omega)
{
   for(var i=0;i<6;i++) this.faccia_ruotata[i].ruotaX(omega,1);

   this.normale_ruotata.ruotaX(omega,1);
   this.vettore_ruotato.ruotaX(omega,1);
}

function ruotaYSottoCubo(omega)
{
   for(var i=0;i<6;i++) this.faccia_ruotata[i].ruotaY(omega,1);

   this.normale_ruotata.ruotaY(omega,1);
   this.vettore_ruotato.ruotaY(omega,1);
}

function ruotaZSottoCubo(omega)
{
   for(var i=0;i<6;i++) this.faccia_ruotata[i].ruotaZ(omega,1);

   this.normale_ruotata.ruotaZ(omega,1);
   this.vettore_ruotato.ruotaZ(omega,1);
}

function ruotaSottoCubo_rel(omega)
{
   if(this.normale_originale[0] != 0)
   {
      for(var i=0;i<6;i++) this.faccia_ruotata[i].ruotaX(omega,0);
   }
   if(this.normale_originale[1] != 0)
   {
      for(var i=0;i<6;i++) this.faccia_ruotata[i].ruotaY(omega,0);
   }
   if(this.normale_originale[2] != 0)
   {
      for(var i=0;i<6;i++) this.faccia_ruotata[i].ruotaZ(omega,0);
   }
}

function Calc_Segno(a,b,p)
{
   var c = p[0]*(a[1]-b[1])-p[1]*(a[0]-b[0])+a[0]*b[1]-a[1]*b[0];

   if(Math.abs(c) < 0.000001) return 0;
   else if(c > 0) return 1;
        else return -1;
}

function Verfica_Punto_Interno_Faccia(f,punto)
{
   var segno_poligono = this.segno(this.faccia_ruotata[f].vertice_ruotato[0].vett2D,this.faccia_ruotata[f].vertice_ruotato[1].vett2D,this.faccia_ruotata[f].vertice_ruotato[2].vett2D);
   var segno_punto;

   for(var i=0;i<4;i++)
   {
      segno_punto = segno_poligono*this.segno(this.faccia_ruotata[f].vertice_ruotato[i].vett2D,this.faccia_ruotata[f].vertice_ruotato[(i+1)%4].vett2D,punto);

      if(segno_punto <= 0) return false;
   }
   return true;
}

function drawSottoCubo(lavagna)
{
   var trovato;

   for(var i=0;i<6;i++)
   {
      /*Metodo per Verificare Visibilita' Faccia*/
      this.faccia_ruotata[i].IsVisible();

      /*Forzatura leggo un membro privato*/
      /*Se Visibile Converte Faccia da 3D -> 2D*/
      if(this.faccia_ruotata[i].visibility) this.faccia_ruotata[i].convFaccia3D2D();
   }

   for(var f=0;f<6;f++)
   {
      if(this.faccia_ruotata[f].visibility)
      {
         /*Verifica che la Faccia non sia ulteriormente nascosta da un'altra Faccia*/
         trovato = false;
         for(var ff=0;ff<6 && !trovato;ff++)
         {
            if(ff != f && this.faccia_ruotata[ff].visibility)
            {
               for(var v=0;v<4;v++)
               {
                  if(this.IsPuntoInternoFaccia(ff,this.faccia_ruotata[f].vertice_ruotato[v].vett2D)) trovato = true;
               }
            }
         }

         if(!trovato) this.faccia_ruotata[f].draw(lavagna);
      }
   }
}