// Exemplo de arquivo de descricao de cena para POV-ray
// Last edited on 2023-10-23 17:42:28 by stolfilocal

// ======================================================================
// 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 interpola3_multi(tt, n, initial, p1, p2, final)
  #local k = int(tt);
  #local patchStart = initial;
  #local patchFinish = final;
  #if (k > 0)
    #local patchStart = (p2[k - 1] + p1[k]) / 2;
  #end
  #if (k < n - 1)
    #local patchFinish = (p2[k] + p1[k + 1]) / 2;
  #end
  #local result = interpola3(tt, k, k + 1, patchStart, p1[k], p2[k], patchFinish);
  result
#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
  
#include "bezpoly.inc"

#macro testa_interpola3_multi(numberOfSegments, initial, p1, p2, final, numberOfCylinders, raio)
  union {
   object{ bezpoly_multi(numberOfSegments, initial, p1, p2, final, 0.9*raio) }
   #local CURRENT_K = 0;
    #while (CURRENT_K < numberOfSegments)
      #local centro = interpola3_multi(CURRENT_K, numberOfSegments, initial, p1, p2, final);
      sphere {
        centro, raio
      }
      #local CURRENT_K = CURRENT_K + numberOfSegments / numberOfCylinders;
    #end
    texture{
      pigment{ color rgb < 1, 0.11, 0.32 > }
    }
  }
#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

// ======================================================================
// Test bezier

#macro half_heart(sign)
  #local testP1 = array[2];
  #local testP2 = array[2];
  #local testP1[0] = <0, 0, 3>;
  #local testP2[0] = <0, sign * 5, 3>;
  #local testP1[1] = <0, sign * 5, -3>;
  #local testP2[1] = <0, 0, -3.5>;
  testa_interpola3_multi(2, <0, 0, 0>, testP1, testP2, <0, 0, -6>, 300, 0.2)
#end

#macro heart()
  half_heart(1)
  half_heart(-1)
#end

#declare raio = 2.000;

union{
  // 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)

  #local testP1 = array[3];
  #local testP2 = array[3];
  #local testP1[0] = <7, -5, 7>;
  #local testP2[0] = <2, -4, 6>;
  #local testP1[1] = <7, -2, 3>;
  #local testP2[1] = <2, -1, 7>;
  #local testP1[2] = <7, 1, 5>;
  #local testP2[2] = <2, 4, 9>;
  testa_interpola3_multi(3, <2, -6, 5>, testP1, testP2, <7, 8, 5>, 300, 0.2)

  heart()
}

#include "eixos.inc"
// object{ eixos(15) }

#declare cmin = < -2,-8,-7 >;
#declare cmax = < +9,+10,+10 >;

box{ cmin-0.1*z, <cmax.x,cmax.y,cmin.z>  texture{ pigment{ color rgb <0.80,0.70,0.60> } finish {diffuse 0.7 ambient 0.3 } } }

#include "camlight.inc"
#declare centro_cena = (cmin + cmax)/2;
#declare raio_cena = 0.5*vlength(cmin - cmax);
#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)