// Exemplo de arquivo de descricao de cena para POV-ray
// Last edited on 2020-09-30 19:57:13 by jstolfi

// ======================================================================
// 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 }
  }

// ======================================================================
// BASIC
#declare roleta = seed(27);
#declare M = 4;
#declare N = 3;


// ======================================================================
// TANQUES
#declare TANK_SIZE = 2;
#declare TANK_OFFSET = 1;
#declare BASE_SIZE = 0.5;

#declare cylinder_tank =
  union {
    box{ <-TANK_SIZE / 2, -TANK_SIZE / 2, 0>, <TANK_SIZE / 2, TANK_SIZE / 2, BASE_SIZE> }
    cylinder {
      <0, 0, 0>, <0, 0, TANK_SIZE>, TANK_SIZE / 4
    }

    texture { tx_plastico }
  }

#declare cone_tank =
  union {
    cylinder{ <0, 0, 0>, <0, 0, 2 * TANK_SIZE / 3>, TANK_SIZE / 2 }
    cone {
      <0, 0, 2 * TANK_SIZE / 3>, TANK_SIZE / 2
      <0, 0, TANK_SIZE>, 0
    }
    texture { tx_plastico }
  }

#declare sphere_tank =
  union {
    sphere { <0, 0, TANK_SIZE / 3>, TANK_SIZE / 3 }
    sphere { <0, 0, 2 * TANK_SIZE / 3>, TANK_SIZE / 3 }
    texture { tx_plastico }
  }

// ======================================================================
// PINS
#declare NUMBER_OF_PINS = 3 * M * N;
#declare PINS = array[NUMBER_OF_PINS];
#declare PINS_DIRECTIONS = array[NUMBER_OF_PINS];
#declare CURRENT_PIN = 0;

#declare PIN_SIZE = 0.2;
#declare PIN_LENGTH = 0.5;

#macro tube_IO(from, to)
  object {
    cylinder {
      from, to, PIN_SIZE
    }
    texture { tx_plastico }
  }

  #declare PINS[CURRENT_PIN] = to;
  #declare PINS_DIRECTIONS[CURRENT_PIN] = to - from;
  #declare CURRENT_PIN = CURRENT_PIN + 1;
#end

#macro full_4th_degree_vertex(position)
  union {
    object { cylinder_tank translate position } 
    #local tube_center = position + <0, 0, BASE_SIZE / 2>;
    tube_IO(tube_center, tube_center + <PIN_LENGTH + TANK_SIZE / 2, 0, 0>)
    tube_IO(tube_center, tube_center - <PIN_LENGTH + TANK_SIZE / 2, 0, 0>)
    tube_IO(tube_center, tube_center + <0, PIN_LENGTH + TANK_SIZE / 2, 0>)
    tube_IO(tube_center, tube_center - <0, PIN_LENGTH + TANK_SIZE / 2, 0>)
  }
#end

#macro full_3th_degree_vertex(position)
  union {
    object { cone_tank translate position } 
    #local tube_center = position + <0, 0, 2 * TANK_SIZE / 3>;
    tube_IO(tube_center, tube_center - <PIN_LENGTH + TANK_SIZE / 2, 0, 0>)
    tube_IO(tube_center, tube_center + <PIN_LENGTH + TANK_SIZE / 2, PIN_LENGTH + TANK_SIZE / 2, 0>)
    tube_IO(tube_center, tube_center + <0, -(PIN_LENGTH + TANK_SIZE / 2), 0>)
  }
#end

#macro full_2th_degree_vertex(position)
  union {
    object { sphere_tank translate position } 
    #local tube_center = position + <0, 0, TANK_SIZE / 2>;
    tube_IO(tube_center, tube_center + <0, 0, PIN_LENGTH + TANK_SIZE / 2>)
    tube_IO(tube_center, tube_center - <0, 0, PIN_LENGTH + TANK_SIZE / 2>)
  }
#end

#macro full_1th_degree_vertex(position)
  union {
    object { sphere { <0, 0, TANK_SIZE / 2>, TANK_SIZE / 2 } translate position texture { tx_plastico } } 
    #local tube_center = position + <0, 0, TANK_SIZE / 2>;
    tube_IO(tube_center, tube_center + <0, PIN_LENGTH + TANK_SIZE / 2, 0>)
  }
#end

// ======================================================================
// GRID
#macro calculate_xy(M_VALUE, N_VALUE) 
  #local resultadoX = (M_VALUE - 1) * (TANK_OFFSET + TANK_SIZE) + TANK_SIZE / 2;
  #local resultadoY = (N_VALUE - 1) * (TANK_OFFSET + TANK_SIZE) + TANK_SIZE / 2;
  <resultadoX, resultadoY, 0>
#end


#macro gera_tanques(M_VALUE, N_VALUE)
  union {
    #declare CURRENT_M = 1;
    #while (CURRENT_M <= M_VALUE)
      #declare CURRENT_N = 1;
      #while (CURRENT_N <= N_VALUE)
        #local random = rand(roleta);
        #if (random < 0.33)
          full_cone_tank(calculate_xy(CURRENT_M, CURRENT_N))
        #else
          #if (random < 0.66)
            full_cylinder_tank(calculate_xy(CURRENT_M, CURRENT_N))
          #else
            full_sphere_tank(calculate_xy(CURRENT_M, CURRENT_N)) 
          #end
        #end
        #declare CURRENT_N = CURRENT_N + 1;
      #end
      #declare CURRENT_M = CURRENT_M + 1;
    #end
  }
#end

// ======================================================================
// INTERPOLACAO

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

#macro interpola3(currentT, t0, t1, v0, v1, v2, v3)
  #local v01 = interpola1(currentT, t0, v0, t1, v1);
  #local v12 = interpola1(currentT, t0, v1, t1, v2);
  #local v23 = interpola1(currentT, t0, v2, t1, v3);
  #local v012 = interpola1(currentT, t0, v01, t1, v12);
  #local v123 = interpola1(currentT, t0, v12, t1, v23);
  #local v0123 = interpola1(currentT, t0, v012, t1, v123);
  v0123
#end

#macro testa_interpola1(p0, p1, n, raio)
  union {
    #local CURRENT_K = 0;
    #while (CURRENT_K <= n)
      #local centro = interpola1(CURRENT_K, 0, p0, n, p1);
      sphere {
        centro, raio
      }
      #local CURRENT_K = CURRENT_K + 1;
    #end
    texture { tx_plastico }
  }
#end

#macro testa_interpola3(p0, p1, v0, v1, n, raio)
  union {
    #local CURRENT_K = 0;
    #while (CURRENT_K <= n)
      #local centro = interpola3(CURRENT_K, 0, n, p0, v0, v1, p1);
      sphere {
        centro, raio
      }
      #local CURRENT_K = CURRENT_K + 1;
    #end
    texture { tx_plastico }
  }
#end

// ======================================================================
// TUBES
#declare MIN_TUBE_HEIGHT = 2.5;
#declare DELTA_TUBE_HEIGHT = 1.5;

#macro build_tube(fromIndex, toIndex)
  #local from = PINS[fromIndex];
  #local fromDir = PINS_DIRECTIONS[fromIndex];
  #local to = PINS[toIndex];
  #local toDir = PINS_DIRECTIONS[toIndex];
  #local numberOfSpheres = 500;

  union {
    #local CURRENT_K = 0;
    #while (CURRENT_K <= numberOfSpheres)
      #local centro = interpola3(CURRENT_K, 0, numberOfSpheres, from, from + fromDir, to + toDir, to);
      sphere {
        centro, PIN_SIZE
      }
      #local CURRENT_K = CURRENT_K + 1;
    #end
    texture { tx_plastico }
  }
#end

#macro tubulation()
  union {
    #local AVAILABLE_PINS = NUMBER_OF_PINS;
    #while (AVAILABLE_PINS >= 2)
      #local LHS_PIN_INDEX = int(AVAILABLE_PINS * rand(roleta));
      #local RHS_PIN_INDEX = int((AVAILABLE_PINS - 1) * rand(roleta));
      #if (RHS_PIN_INDEX = LHS_PIN_INDEX)
        #local RHS_PIN_INDEX = RHS_PIN_INDEX + 1;
      #end

      build_tube(LHS_PIN_INDEX, RHS_PIN_INDEX)

      #if (RHS_PIN_INDEX > LHS_PIN_INDEX)
        #declare PINS[RHS_PIN_INDEX] = PINS[AVAILABLE_PINS - 1];
        #local AVAILABLE_PINS = AVAILABLE_PINS - 1; 
        #declare PINS[LHS_PIN_INDEX] = PINS[AVAILABLE_PINS - 1];
        #local AVAILABLE_PINS = AVAILABLE_PINS - 1; 
      #else
        #declare PINS[LHS_PIN_INDEX] = PINS[AVAILABLE_PINS - 1];
        #local AVAILABLE_PINS = AVAILABLE_PINS - 1; 
        #declare PINS[RHS_PIN_INDEX] = PINS[AVAILABLE_PINS - 1];
        #local AVAILABLE_PINS = AVAILABLE_PINS - 1; 
      #end
    #end
  }
#end

// ======================================================================
// DESCRI��O DA CENA 

#declare raio = 2.000;

#include "eixos.inc"

union{
  object{ eixos(3.00) }
  full_2th_degree_vertex(<0, 0, 0>)
  full_4th_degree_vertex(<-5, 5, 0>)
  build_tube(1, 5)
  // full_1th_degree_vertex(<0, 0, 0>)
  // full_3th_degree_vertex(<0, 0, 0>)
  // testa_interpola1(<0, 0, 0>, <0, 3, 3>, 5, 0.2)
  // testa_interpola3(<0, 0, 0>, <0, 3, 3>, <0, 0, 2>, <0, 3, 1>, 300, 0.2)
}

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