// Last edited on 2023-12-23 01:59:13 by stolfi
background{ color rgb < 0.75, 0.80, 0.95 > }

#declare tx_plastico = 
  texture{
    pigment{ color rgb < 0.40, 0.70, 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, 0.60 > }
    finish{ diffuse 0.9 ambient 0.1 }
  }

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

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

#declare r_cilindro = 0.5;
#declare r_bola = 0.6;

#declare toco_hor = 
  cylinder{
    <0, 0, 0>, 
    <0.5, 0, 0>,
    0.1
    texture{ tx_plastico }
  }

#declare toco_ver = 
  cylinder{
    <0, 0, 0>, 
    <0, 0, 0.5>,
    0.1
    texture{ tx_plastico }
  }

#declare vertice1 =
  union{
    sphere {
      <0, 0, 0.6>, r_bola // <x, y, z>, radius
      texture{ tx_plastico }
    }
    object{toco_ver translate<0,0,1.2> rotate <0, 0, 0> }
  }

#declare vertice3 =
  union {
    cylinder {
      <0, 0, 0>, 
      <0, 0, 2>,
      r_cilindro 
      texture{ tx_plastico }
    }
    sphere {
      <0, 0, 2.3>, r_bola // <x, y, z>, radius
      texture{ tx_plastico }
    }
    object{toco_hor translate<0.5,0,0> rotate <0, 0, 0> }
    object{toco_hor translate<0.5,0,0> rotate <0, 0, 120> }
    object{toco_hor translate<0.5,0,0> rotate <0, 0, 240> }
  }

#declare vertice2 =
  union {
    cylinder {
      <0, 0, 0>, 
      <0, 0, 2>,
      r_cilindro 
      texture{ tx_plastico }
    }
    cone {
      <0, 0, 3.0>, 0.0 // <x, y, z>, center & radius of one end
      <0, 0, 2.0>, 0.5 // <x, y, z>, center & radius of the other end
      texture{ tx_plastico }
    }
    object{toco_hor translate<0.5,0,0> rotate <0, 0, 0> }
    object{toco_hor translate<0.5,0,0> rotate <0, 0, 180> }
  }

#declare vertice4 = 
  union {
    cylinder {
      <0, 0, 0>, 
      <0, 0, 2>,
      r_cilindro 
      texture{ tx_plastico }
    }
    box {
      <-1, -1, 2>, <1, 1, 3> // <x, y, z> near lower left corner, <x, y, z> far upper right corner
      texture{ tx_plastico }
    }
    object{toco_hor translate<1, 0, 2> rotate <0, 0, 180> }
    object{toco_hor translate<1, 0, 2> rotate <0, 0, 0> }
    object{toco_hor translate<1, 0, 2> rotate <0, 0, 90> }
    object{toco_hor translate<1, 0, 2> rotate <0, 0, 270> }
  }

#declare roleta = seed(1);

#declare N_MAX = 300;

#declare topo_cano_1 = array[N_MAX];
#declare comeco_cano_1 = array[N_MAX];
#declare topo_cano_2 = array[N_MAX];
#declare comeco_cano_2 = array[N_MAX];
#declare topo_cano_3 = array[N_MAX];
#declare comeco_cano_3 = array[N_MAX];
#declare topo_cano_4 = array[N_MAX];
#declare comeco_cano_4 = array[N_MAX];
#declare vertices1 = array[N_MAX];
#declare vertices2 = array[N_MAX];
#declare vertices3 = array[N_MAX];
#declare vertices4 = array[N_MAX];

#macro gera_vertice1(xx, yy, zz, i_1, topo_cano_1, comeco_cano_1) //coloca vertice na posiçao xx, yy
  #local q_t = <xx, yy, zz+1.7>;
  #local q_c = <xx, yy, zz+1.2>;
  #local vt = object{vertice1 translate<xx, yy, zz>}
  #declare topo_cano_1[i_1] = q_t;
  #declare comeco_cano_1[i_1] = q_c;
vt
#end

#macro gera_vertice2(xx, yy, zz, i_2, topo_cano_2, comeco_cano_2) //coloca vertice na posiçao xx, yy
  #local qt1 = <xx-1.5, yy, zz>;
  #local qt2 = <xx+1.5, yy, zz>;
  #local qc1 = <xx-1, yy, zz>;
  #local qc2 = <xx+1, yy, zz>;
  #local vt = object{vertice2 translate<xx, yy, zz>}
  #declare topo_cano_2[i_2] = qt1;
  #declare topo_cano_2[i_2+1] = qt2;
  #declare comeco_cano_3[i_2] = qc1;
  #declare comeco_cano_3[i_2+1] = qc2;
vt
#end

#macro gera_vertice3(xx, yy, zz, i_3, topo_cano_3, comeco_cano_3) //coloca vertice na posiçao xx, yy
  #local qt1 = <xx+1.5, yy, zz>;
  #local qt2 = <xx+1.5*(cos(radians(120))), yy+1.5*(sin(radians(120))),zz>;
  #local qt3 = <xx+1.5*(cos(radians(240))), yy+1.5*(sin(radians(240))),zz>;
  #local qc1 = <xx+1, yy, zz>;
  #local qc2 = <xx+1*(cos(radians(120))), yy+1.5*(sin(radians(120))),zz>;
  #local qc3 = <xx+1*(cos(radians(240))), yy+1.5*(sin(radians(240))),zz>;
  #local vt = object{vertice3 translate<xx, yy, zz>}
  #declare topo_cano_3[i_3] = qt1;
  #declare topo_cano_3[i_3+1] = qt2;
  #declare topo_cano_3[i_3+2] = qt3;
  #declare comeco_cano_3[i_3] = qc1;
  #declare comeco_cano_3[i_3+1] = qc2;
  #declare comeco_cano_3[i_3+2] = qc3;
vt
#end

#macro gera_vertice4(xx, yy, zz, i_4, topo_cano_4, comeco_cano_4) //coloca vertice na posiçao xx, yy
  #local qt1 = <xx+1.5, yy, zz+2>;
  #local qt2 = <xx-1.5, yy, zz+2>;
  #local qt3 = <xx, yy+1.5, zz+2>;
  #local qt4 = <xx, yy-1.5, zz+2>;
  #local qc1 = <xx+1, yy, zz+2>;
  #local qc2 = <xx-1, yy, zz+2>;
  #local qc3 = <xx, yy+1, zz+2>;
  #local qc4 = <xx, yy-1, zz+2>;
  #local vt = object{vertice4 translate<xx, yy, zz>} // prof
  #declare topo_cano_4[i_4] = qt1;
  #declare topo_cano_4[i_4+1] = qt2;
  #declare topo_cano_4[i_4+2] = qt3;
  #declare topo_cano_4[i_4+3] = qt4;
  #declare comeco_cano_4[i_4] = qc1;
  #declare comeco_cano_4[i_4+1] = qc2;
  #declare comeco_cano_4[i_4+2] = qc3;
  #declare comeco_cano_4[i_4+3] = qc4;
vt
#end

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

#macro interpola3(t_, t0, v0, t1, v1, v2, v3)
  #local v01 = interpola1(t_, t0, v0, t1, v1);
  #local v12 = interpola1(t_, t0, v1, t1, v2);
  #local v23 = interpola1(t_, t0, v2, t1, v3);

  #local v012 = interpola1(t_, t0, v01, t1, v12);
  #local v123 = interpola1(t_, t0, v12, t1, v23);

  #local v0123 = interpola1(t_, t0, v012, t1, v123);
  v0123
#end

#macro testa_interpola3(p0, p1, p2, p3, n, raio)
  union{
    #local i = 0;
    #while(i < n)
      #local j=0;
      #local centro = interpola3(i,j,p0,n,p1,p2, p3);
      object{ sphere {
        centro, raio // <x, y, z>, radius
        texture{tx_plastico}
      }}
      #local i = i + 1;
    #end
  }
#end

#macro interpola3_multi(t_, p_ini, m, n, P1, P2, p_fim)//n eh qntas bolas vai ter e m eh qntas curvas sao as esperadas
  union{
    #local k = int(t_);
    #local pk_ant = p_ini;
    #local raio = 0.1;
    #local pk = 0;
    #while(k < m)
      #if(k > 0)
        #local pk_ant = pk;
      #end
      #if(k < m-1)
        #local pk = (P2[k]+P1[k+1])/2;
        object{testa_interpola3(pk_ant, P1[k], P2[k], pk, n, raio)}
      #elseif(k=m-1)
        #local pk = p_fim;
        object{testa_interpola3(pk_ant, P1[k], P2[k], pk, n, raio)}
      #end
      #local k = k+1;
    #end
  }
#end

#macro liga_vertices(p0, p1, canos_vertices)
  union{
    object{vertice4 translate(p0)}
    object{vertice2 translate(p1)}
    #local p_0 = p0 + <1.5, 0, 2>;
    #local p_3 = p1 + <-1, 0, 0>;
    #local p_1 = p_0 + <5, 0, 0>;
    #local p_2 = p_1 + <-8, -6, 3>;
    #local n = 100;
    #local raio = 0;
    object{testa_interpola3(p_0, p_1, p_2, p_3, n, raio)}
  }
#end

#macro gera_grafo(nv, ne, org, dst, D, na, nb)
  #local deg = array[nv];
  #local i = 0;
  #while(i < nv)
    #local deg[i] = 0;
    #local i = i + 1;
  #end
  #local i = 0;
  #while(i < ne)
    #local vert1 = org[i];
    #local vert2 = dst[i];
    #local deg[vert1] = deg[vert1]+1;
    #local deg[vert2] = deg[vert2]+1;
    #local i = i+1;
  #end
  #local i_1 = 0;
  #local i_2 = 0;
  #local i_3 = 0;
  #local i_4 = 0;
  #local g_1 = 0;
  #local g_2 = 0;
  #local g_3 = 0;
  #local g_4 = 0;
  #local i = 0;
  #local nv1 = 0;
  #local nv2 = 0;
  #local nv3 = 0;
  #local nv4 = 0;
  union{
    #while(i < nv)
      #local grau = deg[i];
      #local xx = int(D*rand(roleta)+1);
      #local yy = int(D*rand(roleta)+1);
      #local zz = int(D*rand(roleta)+1);
      #if(grau = 1)
        #local vt = object{gera_vertice1(xx, yy, zz, i_1, topo_cano_1, comeco_cano_1)}
        object{vt}
        #local i_1 = i_1 + 1;
        #declare vertices1[g_1] = i;
        #local g_1 = g_1 + 1;
        #local nv1 = nv1+1;
      #elseif(grau = 2)
        #local vt = object{gera_vertice2(xx, yy, zz, i_2, topo_cano_2, comeco_cano_2)}
        object{vt}
        #local i_2 = i_2 + 2;
        #declare vertices2[g_2] = i;
        #local g_2 = g_2 + 1;
        #local nv2 = nv2+1;
      #elseif(grau = 3)
        #local vt = object{gera_vertice3(xx, yy, zz, i_3, topo_cano_3, comeco_cano_3)}
        object{vt}
        #local i_3 = i_3 + 3;
        #declare vertices3[g_3] = i;
        #local g_3 = g_3 + 1;
        #local nv3 = nv3+1;
      #elseif(grau = 4)
        #local vt = object{gera_vertice4(xx, yy, zz, i_4, topo_cano_4, comeco_cano_4)}
        object{vt}
        #local i_4 = i_4 + 4;
        #declare vertices4[g_4] = i;
        #local g_4 = g_4 + 1;
        #local nv4 = nv4+1;
      #else
      #end
      #local i = i + 1;
    #end
    #local i = 0;
    #local nt = array[nv];
    #local j = 0;
    #while(j<nv)
      #local nt[j] = 0;
      #local j = j+1;
    #end
    // object{ gera_arestas(nv, ne, org, dst, deg, nt, na, nb) } // prof
  }
#end

#macro gera_arestas(nv, ne, org, dst, deg, nt, na, nb)
  union{
    #local i = 0;
    #while(i < ne)
      #local origem = org[i];
      #local destino = dst[i];
      #local grau_o = deg[origem];
      #local nto = nt[origem];
      #if(grau_o > nto)
        #local nt1 = mod(nt[origem],grau_o);
        #if(grau_o = 1)
          #local t1 = topo_cano_1[0];
          #local c1 = comeco_cano_1[0];
        #elseif(grau_o = 2)
          #local t1 = topo_cano_2[nt1];
          #local c1 = comeco_cano_2[nt1];
        #elseif(grau_o = 3)
          #local t1 = topo_cano_3[nt1];
          #local c1 = comeco_cano_3[nt1];
        #elseif(grau_o = 4)
          #local t1 = topo_cano_4[nt1];
          #local c1 = comeco_cano_4[nt1];
        #else
        #end
        #local grau_d = deg[destino];
        #local ntd = mod(nt[destino],grau_d);
        #if(grau_d > ntd)
          #local nt2 = nt[destino];
          #if(grau_d = 1)
            #local t2 = topo_cano_1[0];
            #local c2 = comeco_cano_1[0];
          #elseif(grau_d = 2)
            #local t2 = topo_cano_2[nt2];
            #local c2 = comeco_cano_2[nt2];
          #elseif(grau_d = 3)
            #local t2 = topo_cano_3[nt2];
            #local c2 = comeco_cano_3[nt2];
          #elseif(grau_d = 4)
            #local t2 = topo_cano_4[nt2];
            #local c2 = comeco_cano_4[nt2];
          #else
          #end
          object{conetor(na, c1, t1, c2, t2, D, nb)}
          #local nt[destino]= nt[destino] + 1;
        #end
        #local nt[origem]= nt[origem] + 1;
      #end
      #local i = i + 1;
    #end
  }
#end

#macro conetor(na, pini, tini, pfim, tfim, D, nb)
  #local P1 = array[na];
  #local P2 = array[na];
  #local k = 0;
  #while(k < na)
    #if(k > 0)
      #local xx1 = int(D*rand(roleta)+1);
      #local yy1 = int(D*rand(roleta)+1);
      #local zz1 = int(D*rand(roleta)+1);
      #local P1[k] = <xx1, yy1, zz1>;
    #else
      #local P1[0] = tini;
    #end
    #if(k != na-1)
      #local xx2 = int(D*rand(roleta)+1);
      #local yy2 = int(D*rand(roleta)+1);
      #local zz2 = int(D*rand(roleta)+1);
      #local P2[k] = <xx2, yy2, zz2>;
    #else
      #local P2[k] = tfim;
    #end
    #local k = k + 1;
  #end
  #local tt = 0;
  object{interpola3_multi(tt, pini, na, nb, P1, P2, pfim)}
#end

#include "eixos.inc"

//cena

#local D = 10;//limite de coord

union{
  // object{ eixos(D+3) }
  #local nv = 4;
  #local ne = 5;
  #local org = array[ne];
  #local dst = array[ne];
  #local org[0] = 0;
  #local org[1] = 1;
  #local org[2] = 1;
  #local org[3] = 2;
  #local org[4] = 2;

  #local dst[0] = 3;
  #local dst[1] = 2;
  #local dst[2] = 3;
  #local dst[3] = 3;
  #local dst[4] = 3;

  #local na = 3;//numero aros da curva
  #local nb = 100;//numero bolas cruva

  object{gera_grafo(nv, nv, org, dst, D, na, nb)}
}

#declare cmin = < 0, 0, 0 >;
#declare cmax = < D, D, D > + <1, 1, 1>;

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

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

#include "camlight.inc"
#declare dir_camera = < 9, 7, 5 >;
#declare intens_luz = 1.20;
camlight(centro_cena, raio_cena, dir_camera, dist_camera , z, intens_luz)