// Exemplo de arquivo de descricao de cena para POV-ray
// Last edited on 2023-12-23 09:05:26 by stolfi

// ======================================================================
// CORES E TEXTURAS

background{ color rgb < 0.75, 0.80, 0.85 > }

#declare tx_plastico = 
  texture{
    pigment{ color rgb < 0.10, 0.80, 1.00 > }
    finish{ diffuse 0.8 ambient 0.1 specular 0.5 roughness 0.005 }
  }

#declare tx_fosca = 
  texture{
    pigment{ color rgb < 1.00, 0.80, 1.00 > }
    finish{ diffuse 0.8 ambient 0.1 specular 0.5 roughness 0.005 }
  }

#declare tx_espelho = 
  texture{
    pigment{ color rgb < 1.00, 0.85, 0.30 > }
    finish{ diffuse 0.2 reflection 0.7*< 1.00, 0.85, 0.30 > ambient 0.1 }
  }

#declare tx_vidro = 
  texture{
    pigment{ color rgb < 0.85, 0.95, 1.00 > filter 0.70 }
    finish{ diffuse 0.03 reflection 0.25 ambient 0.02 specular 0.25 roughness 0.005 }
  }


#declare tx_xadrez =
  texture{
    pigment{ checker color rgb < 1, 0, 0 >, color rgb < 0, 0, 0 > }
    finish{ diffuse 0.9 ambient 0.1 }
    scale 2.0
  }


#declare tx_aresta = texture {
    pigment { color rgb < 1.000, 0.200, 0.400> }
    finish { diffuse 0.8 ambient 0.2 }
  }

#declare tx_cano = texture {
    pigment { color rgb < 1.000, 0.700, 0.000> }
    finish { diffuse 0.8 ambient 0.2 }
  }

#declare tx_node = texture {
    pigment { rgb <0, 0.5, 1> }
    finish { ambient 0.2 diffuse 0.8 }
}

#macro ponta(inicio, fim)
  union{
    object {
      cylinder {
        inicio, fim, 0.1 // center of one end, center of other end, radius
      } texture { tx_cano }
    }
  }
#end

#macro grau1(position)
  union{
    object {
      sphere {
        <0,0,0>, 1
      } translate position texture { tx_node }
    }

    object{ ponta(<0,1,0>, <0,1.5,0>) translate position }
  }
#end

#macro basesGrau1(p)
  #local T = array [ 1 ];
  #local T[0] = p + <0,1,0>;
  T
#end

#macro terminaisGrau1(p)
  #local T = array [ 1 ];
  #local T[0] = p + <0,1.5,0>;
  T
#end


#macro grau2(position)
  union {
    object{ 
      cylinder {
        <0, 0, 0>, <0, 0, 0.75>, 0.5 // center of one end, center of other end, radius
      }
      translate position texture { tx_node } 
    }
    object{ 
      sphere {
        <0, 0, 1>, 0.75 // <x, y, z>, radius
      }
      translate position texture { tx_node } 
    }

    object{ 
      cone {
        <0, 0, 1.6>, 0.5 // <x, y, z>, center & radius of one end
        <0, 0, 2.4>, 0 // <x, y, z>, center & radius of the other end 
      }
      translate position texture { tx_node } 
    }

    object{ ponta(<0, 0,1.9>, <0,0.7,1.9>) translate position }
    object{ ponta(<0,-0.5,0.25>, <0,-0.75,0.25>) translate position }
  }
#end

#macro basesGrau2(p)
  #local T = array [ 2 ];
  #local T[0] = p + <0, 0,1.9>;
  #local T[1] = p + <0,-0.5,0.25>;
  T
#end

#macro terminaisGrau2(p)
  #local T = array [ 2 ];
  #local T[0] = p + <0,0.7,1.9>;
  #local T[1] = p + <0,-0.75,0.25>;
  T
#end

#macro grau3(position)
  union {
    object{ 
      cylinder {
        <0, 0, 0.5>, <0, 0, 1.5>, 1 // center of one end, center of other end, radius
      }
      translate position texture { tx_node } 
    }
    object{ 
      box {
        <-0.3, -0.3, 2.5>, <0.3, 0.3, 1.5> // <x, y, z> near lower left corner, <x, y, z> far upper right corner
      }
      translate position texture { tx_node } 
    }

    difference {
      object {
        sphere {
          <0, 0, 0>, 0.75 // <x, y, z>, radius
        } translate position texture { tx_node }  
      }
      object {
        cylinder {
          <0, 0, -1>, <0, 0, 0>, 1 // center of one end, center of other end, radius
        }
      }
    }

    object{ ponta(<0,1,1>, <0,1.5,1>) translate position }
    object{ ponta(<0,-0.3,0.2>, <0,-1,0.2>) translate position }
    object{ ponta(<0,0,2.5>, <0,0,3>) translate position }
  }
#end

#macro basesGrau3(p)
  #local T = array [ 3 ];
  #local T[0] = p + <0,1,1>;
  #local T[1] = p + <0,-0.3,0.2>;
  #local T[2] = p + <0,0,2.5>;
  T
#end

#macro terminaisGrau3(p)
  #local T = array [ 3 ];
  #local T[0] = p + <0,1.5,1>;
  #local T[1] = p + <0,-1,0.2>;
  #local T[2] = p + <0,0,3>;
  T
#end

#macro grau4(position)
  union {
    object{ 
      cylinder {
        <0, 0, 2>, <0, 0, 3>, 0.3 // center of one end, center of other end, radius
      }
      translate position texture { tx_node } 
    }
    object{ 
      box {
        <-1, -1, 0.75>, <1, 1, 2> // <x, y, z> near lower left corner, <x, y, z> far upper right corner
      } 
      translate position texture { tx_node } 
    }

    object{ 
      cone {
        <0, 0, 0>, 0// <x, y, z>, center & radius of one end
        <0, 0, 0.75>, 0.5 // <x, y, z>, center & radius of the other end 
      }
      translate position texture { tx_node } 
    }

    object{ ponta(<0,1,1.25>, <0,1.5,1.25>) translate position }
    object{ ponta(<0,-1,1.25>, <0,-1.5,1.25>) translate position }
    object{ ponta(<1,0,1.25>, <1.25,0,1.25>) translate position }
    object{ ponta(<0,0.2,2.5>, <0,0.75,2.5>) translate position }
  }
#end

#macro basesGrau4(p)
  #local T = array [ 4 ];
  #local T[0] = p + <0,1,1.25>;
  #local T[1] = p + <0,-1,1.25>;
  #local T[2] = p + <1.25,0,1.25>;
  #local T[3] = p + <1,0,1.25>;
  T
#end

#macro terminaisGrau4(p)
  #local T = array [ 4 ];
  #local T[0] = p + <0,1.5,1.25>;
  #local T[1] = p + <0,-1.5,1.25>;
  #local T[2] = p + <1.25,0,1.25>;
  #local T[3] = p + <0,0.75,2.5>;
  T
#end


#macro interpolacao(tw, t0, v0, t1, v1)
  #local ss = (tw - t0) / (t1 - t0);
  #local vv = (1 - ss) * v0 + ss * v1;
  vv
#end

#macro interpolacaoBezier(g, ta, tb, v0, v1, v2, v3)
  #local v01 = interpolacao(g, ta, v0, tb, v1);
  #local v12 = interpolacao(g, ta, v1, tb, v2);
  #local v23 = interpolacao(g, ta, v2, tb, v3);

  #local v012 = interpolacao(g, ta, v01, tb, v12);
  #local v123 = interpolacao(g, ta, v12, tb, v23);

  #local v0123 = interpolacao(g, ta, v012, tb, v123);
  v0123
#end



#macro interpola3_multi(tt, n, Pini, P1, P2, Pfim)
  
  #local k = int(tt);
    
  #local Q0 = Pini;
  #local Q2 = Pfim;

  #if (k > 0)
    #local Q0 = (P1[k] + P2[k - 1]) / 2;
  #end 
  #if (k < n - 1)
    #local Q2 = (P1[k + 1] + P2[k]) / 2; 
  #end

  #local c = interpolacaoBezier(tt, k, k + 1, Q0, P1[k], P2[k], Q2);
  c
#end


#macro conector(na, passo, pini, tini, pfin, tfin, D)
  union {
    #local P1 = array [ na ];
    #local P2 = array [ na ];
    #local i = 0;

    #local roletaPx1 = seed( pini.x );
    #local roletaPy1 = seed( pini.y );
    #local roletaPz1 = seed( pini.z );

    #local roletaPx2 = seed( pfin.x );
    #local roletaPy2 = seed( pfin.y );
    #local roletaPz2 = seed( pfin.z );

    #while (i < na)
      #local x0 = int(rand(roletaPx1) * 2 * D - D);
      #local y0 = int(rand(roletaPy1) * 2 * D - D);
      #local z0 = int(rand(roletaPz1) * 2 * D - D);

      #local P1[i] = <x0, y0, z0>;

      #local x0 = int(rand(roletaPx2) * 2 * D - D);
      #local y0 = int(rand(roletaPy2) * 2 * D - D);
      #local z0 = int(rand(roletaPz2) * 2 * D - D);

      #local P2[i] = <x0, y0, z0>;

      #local i = i + 1;
    #end

    #local P1[0] = tini;
    #local P2[na - 1] = tfin;

    #local tt = 0;

    #while (tt < na)
      #local c = interpola3_multi(tt, na, pini, P1, P2, pfin);
      object { sphere { c, 0.1 } }
      #local tt = tt + passo;
    #end
    texture{ tx_aresta }
  }
#end


#macro gera_grafo(nv, ne, org, dst, D, na, passo)
  union {
    #local G = array [ nv ];
    #local deg = array [ nv ];
    #local nt = array [ nv ];

    #local roletaDeg = seed( 293293 );
    #local roletaXG = seed( 92302 );
    #local roletaYG = seed( 13213 );
    #local roletaZG = seed( 193912 );

    #local i = 0;
    #while (i < nv)
      #local d = int(rand(roletaDeg) * 4 + 1);
      #local deg[i] = d;
      #local nt[i] = d;

      #local x0 = int(rand(roletaXG) * 2 * D - D);
      #local y0 = int(rand(roletaYG) * 2 * D - D);
      #local z0 = int(rand(roletaZG) * 2 * D - D);
      
      #local p = <x0, y0, z0>;
      #local G[i] = p;

      #if (d = 1)
        object { grau1(p) }
      #end
      #if (d = 2)
        object { grau2(p) }
      #end
      #if (d = 3)
        object { grau3(p) }
      #end
      #if (d = 4)
        object { grau4(p) }
      #end

      #local i = i + 1;
    #end

    #local j = 0;
    #while (j < ne)
      #local ixOrg = org[j];
      #local ixDst = dst[j];

      #local pOrg = G[ixOrg];
      #local pDst = G[ixDst];

      #local dOrg = deg[ixOrg];
      #local dDst = deg[ixDst];

      #local ntOrg = nt[ixOrg];
      #local ntDst = nt[ixDst];

      #local pTini = 0;
      #local pTfin = 0;

      #if (ntOrg > 0 & ntDst > 0)
        #local ttOrg = ntOrg - 1;
        #local ttDst = ntDst - 1;

        #local basOrg = -1;
        #local basDst = -1;
        #local tmsOrg = -1;
        #local tmsDst = -1;

        #if (dOrg = 1)
          #local basOrg = basesGrau1(pOrg);
          #local tmsOrg = terminaisGrau1(pOrg);
        #end
        #if (dOrg = 2)
          #local basOrg = basesGrau2(pOrg);
          #local tmsOrg = terminaisGrau2(pOrg);
        #end
        #if (dOrg = 3)
          #local basOrg = basesGrau3(pOrg);
          #local tmsOrg = terminaisGrau3(pOrg);
        #end
        #if (dOrg = 4)
          #local basOrg = basesGrau4(pOrg);
          #local tmsOrg = terminaisGrau4(pOrg);
        #end

        #if (dDst = 1)
          #local basDst = basesGrau1(pDst);
          #local tmsDst = terminaisGrau1(pDst);
        #end
        #if (dDst = 2)
          #local basDst = basesGrau2(pDst);
          #local tmsDst = terminaisGrau2(pDst);
        #end
        #if (dDst = 3)
          #local basDst = basesGrau3(pDst);
          #local tmsDst = terminaisGrau3(pDst);
        #end
        #if (dDst = 4)
          #local basDst = basesGrau4(pDst);
          #local tmsDst = terminaisGrau4(pDst);
        #end

        #local pini = basOrg[ttOrg];
        #local pfin = basDst[ttDst];
        #local tini = tmsOrg[ttOrg];
        #local tfin = tmsDst[ttDst];
        
        #if ((ixOrg = ixOrg) | (ixDst = 3)) 
          object { conector(na, passo, pini, tini, pfin, tfin, D) }
        #end

        #local nt[ixOrg] = nt[ixOrg] - 1;
        #local nt[ixDst] = nt[ixDst] - 1;
      #end
      #local j = j + 1;
    #end
  }
#end

#include "eixos.inc"

// Aqui est� a cena, finalmente:

#declare D = 15;
#declare nv = 8;
#declare ne = 10;
#declare na = 4;
#declare passo = 0.002;

union{
  #local org = array [ ne ];
  #local dst = array [ ne ];

  #local org[0] = 0; #local dst[0] = 3;
  #local org[1] = 0; #local dst[1] = 4;
  #local org[2] = 5; #local dst[2] = 2;
  #local org[3] = 3; #local dst[3] = 0;
  #local org[4] = 6; #local dst[4] = 7;
  #local org[5] = 3; #local dst[5] = 7;
  #local org[6] = 3; #local dst[6] = 0;
  #local org[7] = 1; #local dst[7] = 7;
  #local org[8] = 6; #local dst[8] = 5;
  #local org[9] = 2; #local dst[9] = 7;

  object { gera_grafo(nv, ne, org, dst, D, na, passo) }
} 
#declare cmin = -D*<1,1,1>;
#declare cmax = +D*<1,1,1>;

#include "gaiola.inc"
// object{ gaiola(cmin,cmax) }

#declare centro_cena = (cmin + cmax)/2;
#declare raio_cena = 0.55*vlength(cmax-cmin);

// #declare centro_cena = D * < 0.7, 0.2, 0.2 >;
// #declare raio_cena = 0.25*vlength(cmax-cmin);

#declare dist_camera = 7*raio_cena;

#include "camlight.inc"
#declare dir_camera = < 14.00, 7.00, 4.00 >;
#declare intens_luz = 1.20;
camlight(centro_cena, raio_cena, dir_camera, dist_camera , z, intens_luz)