// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
// %                                                                   %
// %   IsoCSG Include File - experimental version 0.2                  %
// %                                                                   %
// %   iso_csg.inc - CSG-like operations with isosurface functions     %   
// %                                                                   %
// %   written June 2001 - February 2002                               %  
// %   by Christoph Hormann <chris_hormann@gmx.de>                     %
// %                                                                   %
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// %                                                                   %
// %   Experimental version                                            %
// %   please do not redistribute                                      %
// %                                                                   %
// %   I encourage you to contact me if you have ideas for             %
// %   improvements                                                    %
// %                                                                   %
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       

#ifdef(iso_CSG_Inc_Temp)
// do nothing
#else
#declare iso_CSG_Inc_Temp = version;

#ifdef(View_POV_Include_Stack)
#   debug "including iso_csg.inc\n"
#end 

#include "math.inc" 
#include "transforms.inc"     
#include "functions.inc"

//------------------------------------------------------------- 
// ----   CSG macros   ----------------------------------------  
//------------------------------------------------------------- 
    
#macro IC_Merge2(fn_A, fn_B)                    // merge 2 objects
  function(x, y, z){ 
    min(fn_A(x, y, z), 
        fn_B(x, y, z))   
  }
#end 

#macro IC_Merge3(fn_A, fn_B, fn_C)              // merge 3 objects
  function(x, y, z){ 
    min(fn_A(x, y, z), 
        fn_B(x, y, z), 
        fn_C(x, y, z)) 
  }
#end 

#macro IC_Merge4(fn_A, fn_B, fn_C, fn_D)        // merge 4 objects
  function(x, y, z){ 
    min(fn_A(x, y, z), 
        fn_B(x, y, z), 
        fn_C(x, y, z), 
        fn_D(x, y, z)) 
  }
#end     

    

#macro IC_Intersection2(fn_A, fn_B)             // intersection between 2 objects
  function(x, y, z){ 
    max(fn_A(x, y, z), 
        fn_B(x, y, z)) 
  }
#end

#macro IC_Intersection3(fn_A, fn_B, fn_C)       // intersection between 3 objects
  function(x, y, z){ 
    max(fn_A(x, y, z), 
        fn_B(x, y, z), 
        fn_C(x, y, z)) 
  }
#end  

#macro IC_Intersection3(fn_A, fn_B, fn_C, fn_D) // intersection between 4 objects
  function(x, y, z){ 
    max(fn_A(x, y, z), 
        fn_B(x, y, z), 
        fn_C(x, y, z), 
        fn_D(x, y, z)) 
  }
#end 
   
    
    
#macro IC_Difference2(fn_A, fn_B)               // difference between 2 objects
  function(x, y, z){ 
    max(fn_A(x, y, z), 
      (-fn_B(x, y, z))) 
  }
#end

#macro IC_Difference3(fn_A, fn_B, fn_C)         // difference between 3 objects
  function(x, y, z){ 
    max(fn_A(x, y, z), 
      (-fn_B(x, y, z)), 
      (-fn_C(x, y, z))) 
  }
#end 

#macro IC_Difference3(fn_A, fn_B, fn_C, fn_D)   // difference between 4 objects
  function(x, y, z){ 
    max(fn_A(x, y, z), 
      (-fn_B(x, y, z)), 
      (-fn_C(x, y, z)), 
      (-fn_D(x, y, z)))       
  }
#end    
           

//------------------------------------------------------------- 
// ----   Shape macros   --------------------------------------  
//------------------------------------------------------------- 

#macro IC_Plane (Direction, Distance)  
  #local Cx=Direction.x;  
  #local Cy=Direction.y;    
  #local Cz=Direction.z; 
                
  function(x, y, z){ 
    ((x*Cx)+(y*Cy)+(z*Cz)-Distance) 
  }
#end 
 
#macro IC_Sphere (Center, Radius)  
  #local Cx=Center.x;  
  #local Cy=Center.y;    
  #local Cz=Center.z;   
  
  function(x, y, z){ 
    f_sphere(x-Cx, y-Cy, z-Cz, Radius)      
    //(sqrt((x-Cx)^2 + (y-Cy)^2 + (z-Cz)^2) - Radius)
  }  
#end 

#macro IC_Box (Start, End)  
  #local Cx=max(Start.x, End.x);  
  #local Cy=max(Start.y, End.y); 
  #local Cz=max(Start.z, End.z);   
  #local Dx=min(Start.x, End.x);  
  #local Dy=min(Start.y, End.y); 
  #local Dz=min(Start.z, End.z); 
                
  function(x, y, z){ 
    max(x-Cx, y-Cy, z-Cz, Dx-x, Dy-y, Dz-z) 
  }
#end 

#macro IC_Torus (MaR, MiR)                  
  function(x, y, z){ 
    f_torus(x, y, z, MaR, MiR)   
  }
#end 

#macro IC_Cylinder (Start, End, Radius)  
  #local Cx=Start.x;  
  #local Cy=Start.y;    
  #local Cz=Start.z;  
     
  #local Len=vlength(End-Start);      
     
  #if (Len=0)
    #error "iso_csg.inc: Error: zero height cylinder"   
  #end 
  
  #local fn_T=function { Reorient_Trans(End-Start, x)  }                      
    
  #local fn_X=
  function(x, y, z){ 
    max(sqrt(y^2 + z^2) - Radius, -x, x-Len) 
  }    
  #local fn_Y=
  function(x, y, z){ 
    fn_X(fn_T(x, y, z).x, 
         fn_T(x, y, z).y, 
         fn_T(x, y, z).z) 
  }         
  
  function(x, y, z){ 
    (fn_Y((x-Cx),(y-Cy),(z-Cz)))     
  }                                
#end 

#macro IC_Cone (Start, Radius1, End, Radius2)  
  #local Cx=Start.x;  
  #local Cy=Start.y;    
  #local Cz=Start.z; 
   
  #local Len=vlength(End-Start);        
     
  #if (Len=0)
    #error "iso_csg.inc: Error: zero height cone"   
  #end   
      
  #local fn_T=function { Reorient_Trans(End-Start, x)  }                      
        
  #local fn_X=function(x, y, z){ 
    max(sqrt(y^2 + z^2) - Radius1+x*((Radius1-Radius2)/Len), -x, x-Len) 
  } 
  #local fn_Y=
  function(x, y, z){ 
    fn_X(fn_T(x, y, z).x, 
         fn_T(x, y, z).y, 
         fn_T(x, y, z).z) 
  }           
  
  function(x, y, z){ 
    (fn_Y((x-Cx),(y-Cy),(z-Cz))) 
  }              
#end 

//------------------------------------------------------------- 
// ----   Transform macros   ----------------------------------  
//------------------------------------------------------------- 

#macro IC_Transform (Fn, Trans)   
  
  #local fn_T=function { transform { Trans inverse } }                      
                                    
  function(x, y, z){ 
    Fn(fn_T(x, y, z).x, 
       fn_T(x, y, z).y, 
       fn_T(x, y, z).z) 
  }             
#end 

#macro IC_Translate (Fn, Vect)     
  #local Cx=Vect.x;  
  #local Cy=Vect.y;    
  #local Cz=Vect.z;  
  
  function(x, y, z){ 
    (Fn(x-Cx, y-Cy, z-Cz)) 
  }     
#end  

#macro IC_Scale (Fn, Vect)     
  #local Cx=Vect.x;  
  #local Cy=Vect.y;     
  #local Cz=Vect.z; 
  #if (Cx=0)
    #warning "iso_csg.inc: Scale 0 changed to Scale 1"   
    Cx=1.0;
  #end 
  #if (Cy=0)
    #warning "iso_csg.inc: Scale 0 changed to Scale 1"   
    Cy=1.0;
  #end 
  #if (Cz=0)
    #warning "iso_csg.inc: Scale 0 changed to Scale 1"   
    Cz=1.0;
  #end 
      
  function(x, y, z){ 
    (Fn(x/Cx, y/Cy, z/Cz)) 
  }     
#end   

#macro IC_Matrix (Fn, Mtrx)       // not equivalent to the matrix transform!
  
  function(x, y, z){ 
    Fn(x*Mtrx[0][0] + y*Mtrx[0][1] + z*Mtrx[0][2], 
       x*Mtrx[1][0] + y*Mtrx[1][1] + z*Mtrx[1][2], 
       x*Mtrx[2][0] + y*Mtrx[2][1] + z*Mtrx[2][2])
  }         
#end   

#macro IC_RotateR (Fn, Vect)      // Rotate Radians
  #local Cx=-Vect.x;  
  #local Cy=-Vect.y;    
  #local Cz=-Vect.z;
       
  #local MtrxA=array[3][3]    
  #local MtrxB=array[3][3]    
  #local MtrxC=array[3][3] 
  
  #local MtrxA[0][0] = 1.0; 
  #local MtrxA[0][1] = 0;  
  #local MtrxA[0][2] = 0;  
  #local MtrxA[1][0] = 0;  
  #local MtrxA[1][1] = cos(Cx);  
  #local MtrxA[1][2] = sin(Cx);  
  #local MtrxA[2][0] = 0;  
  #local MtrxA[2][1] = -sin(Cx);   
  #local MtrxA[2][2] = cos(Cx); 
     
  #local MtrxB[0][0] = cos(Cy);  
  #local MtrxB[0][1] = 0;  
  #local MtrxB[0][2] = -sin(Cy);   
  #local MtrxB[1][0] = 0;  
  #local MtrxB[1][1] = 1; 
  #local MtrxB[1][2] = 0;  
  #local MtrxB[2][0] = sin(Cy);  
  #local MtrxB[2][1] = 0;  
  #local MtrxB[2][2] = cos(Cy); 
  
  #local MtrxC[0][0] = cos(Cz);  
  #local MtrxC[0][1] = sin(Cz);   
  #local MtrxC[0][2] = 0;   
  #local MtrxC[1][0] = -sin(Cz);  
  #local MtrxC[1][1] = cos(Cz); 
  #local MtrxC[1][2] = 0;  
  #local MtrxC[2][0] = 0; 
  #local MtrxC[2][1] = 0;  
  #local MtrxC[2][2] = 1;     
   
  #local fn_X=IC_Matrix (function(x, y, z){ Fn(x, y, z) }, MtrxA)      
  #local fn_Y=IC_Matrix (function(x, y, z){ fn_X(x, y, z) }, MtrxB)  
    
  IC_Matrix (function { fn_Y(x, y, z) }, MtrxC)    
       
#end

#macro IC_Rotate (Fn, Vect)       // Rotate Degrees
  #local Cx=(Vect.x/180)*pi;  
  #local Cy=(Vect.y/180)*pi;    
  #local Cz=(Vect.z/180)*pi;   
  IC_RotateR (function(x, y, z){ Fn(x, y, z) }, <Cx, Cy, Cz>)  
#end 


//-------------------------------------------------------------    


#version iso_CSG_Inc_Temp;
#end