//Takes in an array of 4D vectors where x, y, & z are world coordinates
//as you'd expect and t represents the value-along-spline for the given
//control point.  Returns a transformed array still suitable for turning
//into a spline.  Order of rotation matches that of spine-macros.  
//
#macro Transform_Array(TheArray,TheArrayLength,TheScale,TheRotation,TheTranslation)       
       #local Ctr = 0;
       #local tempArray = TheArray;
       #while(Ctr < TheArrayLength)
          #local tempVector = <tempArray[Ctr].x,tempArray[Ctr].y,tempArray[Ctr].z> * TheScale;
          #local tempVector = vrotate(tempVector, <TheRotation.x,0,0>);
          #local tempVector = vrotate(tempVector, <0,0,TheRotation.z>);
          #local tempVector = vrotate(tempVector, <0,TheRotation.y,0>);
          #local tempVector = tempVector + TheTranslation;
          #local tempArray[Ctr] = <tempVector.x,tempVector.y,tempVector.z,tempArray[Ctr].t>;
          #local Ctr = Ctr + 1;
       #end  //end while
       tempArray //returned value
#end  //end macro Transform_Array()
/*
//Like Transform_Array() but order is !IN REVERSE!
//
#macro Transform_Array_In_Reverse(TheArray,TheArrayLength,TheScale,TheRotation,TheTranslation)       
       #local Ctr = 0;
       #local tempArray = TheArray;
       #while(Ctr < TheArrayLength)
          #local tempVector = <tempArray[Ctr].x,tempArray[Ctr].y,tempArray[Ctr].z>;
          #local tempVector = tempVector + TheTranslation;
          #local tempVector = vrotate(tempVector, <0,TheRotation.y,0>);
          #local tempVector = vrotate(tempVector, <0,0,TheRotation.z>);
          #local tempVector = vrotate(tempVector, <TheRotation.x,0,0>);
          #local tempVector = tempVector * TheScale;
          #local tempArray[Ctr] = <tempVector.x,tempVector.y,tempVector.z,tempArray[Ctr].t>;
          #local Ctr = Ctr + 1;
       #end  //end while
       tempArray //returned value
#end  //end macro Transform_Array_In_Reverse()
*/

//Takes in an array of 4D vectors where x, y, & z are world coordinates
//as you'd expect and t represents the value-along-spline for the given
//control point.  Returns a spline.  
//
#macro Spline_From_Array (The_Array, Array_Length )
  #declare TempSpline = spline{
   cubic_spline
   #local ctr = 0;
   #while (ctr < Array_Length)
      #local tempfloat = The_Array[ctr].t; 
      //tempfloat avoids a type-error iirc
      tempfloat,  <The_Array[ctr].x, The_Array[ctr].y, The_Array[ctr].z>,
      #local ctr = ctr+1;
   #end //end while
   //Note that the last value has an extra comma at the end.  
   //That could be fixed with an #if statement but is it a problem?
  } //end spline
  TempSpline      
#end //end #macro Spline_From_Array() 

 
//It's an analogy.  a_posi is to the range a_low to a_high
//what RESULT is to the range b_low to b_high.
//E.g. Range_Convert(25,0,100,32,212) returns: 77 (degrees F)
//E.g. Range_Convert(77,32,212,0,100) returns: 25 (degrees C) 
//
#macro Range_Convert(a_posi, a_low, a_high, b_low, b_high)
      (   ( (a_posi-a_low)*(b_high-b_low)/(a_high-a_low) ) + b_low    )    
#end // end macro Range_Convert()


//It's pretty straight foward:
//
#macro Plot_Spline2(TheSpline,Plot_Min_Val,Plot_Max_Val,Thickness,Frequency,Color1,Color2)
   union{
    #local ctr = Plot_Min_Val;
    #while (ctr < Plot_Max_Val)
      sphere {
        TheSpline(ctr),Thickness
        pigment {rgb  Color1*(Range_Convert(ctr,Plot_Min_Val,Plot_Max_Val,1,0)) 
                     +Color2*(Range_Convert(ctr,Plot_Min_Val,Plot_Max_Val,0,1))
                }
                //{ rgb <1-ctr,ctr,0> }
        finish {ambient 1 }
        }
      #local ctr = ctr + Frequency;
    #end //end while
   } //end union
#end   




// ****************************************** 
#local XZ_Circle_Radius = 1;
//Maybe next time I'll just use fractions of pi.
#declare XZ_Circle_Array =   
array[19]{ 
<sin(radians(-112.5))*XZ_Circle_Radius,0,cos(radians(-112.5))*XZ_Circle_Radius, -.125/2> //tangent
<sin(radians(   -90))*XZ_Circle_Radius,0,cos(radians(   -90))*XZ_Circle_Radius,  .0  /2> //start
<sin(radians( -67.5))*XZ_Circle_Radius,0,cos(radians( -67.5))*XZ_Circle_Radius,  .125/2>
<sin(radians(   -45))*XZ_Circle_Radius,0,cos(radians(   -45))*XZ_Circle_Radius,  .25 /2>
<sin(radians( -22.5))*XZ_Circle_Radius,0,cos(radians( -22.5))*XZ_Circle_Radius,  .375/2>  
<sin(radians(     0))*XZ_Circle_Radius,0,cos(radians(     0))*XZ_Circle_Radius,  .5  /2>
<sin(radians(  22.5))*XZ_Circle_Radius,0,cos(radians(  22.5))*XZ_Circle_Radius,  .625/2>  
<sin(radians(    45))*XZ_Circle_Radius,0,cos(radians(    45))*XZ_Circle_Radius,  .75 /2>
<sin(radians(  67.5))*XZ_Circle_Radius,0,cos(radians(  67.5))*XZ_Circle_Radius,  .875/2>  
<sin(radians(    90))*XZ_Circle_Radius,0,cos(radians(    90))*XZ_Circle_Radius, 1.0  /2>  //middle
<sin(radians( 112.5))*XZ_Circle_Radius,0,cos(radians( 112.5))*XZ_Circle_Radius, 1.125/2>
<sin(radians(   135))*XZ_Circle_Radius,0,cos(radians(   135))*XZ_Circle_Radius, 1.25 /2>
<sin(radians( 157.5))*XZ_Circle_Radius,0,cos(radians( 157.5))*XZ_Circle_Radius, 1.375/2>  
<sin(radians(   180))*XZ_Circle_Radius,0,cos(radians(   180))*XZ_Circle_Radius, 1.5  /2>
<sin(radians( 202.5))*XZ_Circle_Radius,0,cos(radians( 202.5))*XZ_Circle_Radius, 1.625/2>  
<sin(radians(   225))*XZ_Circle_Radius,0,cos(radians(   225))*XZ_Circle_Radius, 1.75 /2>
<sin(radians( 247.5))*XZ_Circle_Radius,0,cos(radians( 247.5))*XZ_Circle_Radius, 1.875/2>  
<sin(radians(   270))*XZ_Circle_Radius,0,cos(radians(   270))*XZ_Circle_Radius, 2.0  /2>  //end
<sin(radians( 292.5))*XZ_Circle_Radius,0,cos(radians( 292.5))*XZ_Circle_Radius, 2.125/2>  //tangent
} // end array XZ_Circle_Array




//I think the problem is dependent related to the value of token_count.
//For the following list of 21 #declare statements, the use of extra "+"
//and/or "-" symbols affects where whether the error occurs on line ...
//or on line ....  If the total number of extra symbols is divisible by
//3 in the case of this block, the error occurs on line ..., otherwise
//it occurs on line ...  Try it. Try moving them.  It doesn't matter where
//they go.
//
//3 or 7 extra + or - symbols will cause it to fail even if infinate loop
//below is changed to finite.
//
#declare dummy_var = +1;//bug avoidance 1
#declare dummy_var = +1;//bug avoidance 2
#declare dummy_var = +1;//bug avoidance 3
#declare dummy_var = -1;//bug avoidance 4
#declare dummy_var = 1;//bug avoidance 5
#declare dummy_var = -1;//bug avoidance 6
#declare dummy_var = -1;//bug avoidance 7
#declare dummy_var = 1;//bug avoidance 8
#declare dummy_var = 1;//bug avoidance 9
#declare dummy_var = 1;//bug avoidance 10
#declare dummy_var = 1;//bug avoidance 11
#declare dummy_var = 1;//bug avoidance 12
#declare dummy_var = 1;//bug avoidance 13
#declare dummy_var = 1;//bug avoidance 14
#declare dummy_var = 1;//bug avoidance 15
#declare dummy_var = 1;//bug avoidance 16
#declare dummy_var = 1;//bug avoidance 17
#declare dummy_var = 1;//bug avoidance 18
#declare dummy_var = 1;//bug avoidance 19
#declare dummy_var = 1;//bug avoidance 20
#declare dummy_var = 1;//bug avoidance 21

// Again, the failure point depends on how many added tokens there
// are in the above block...
//
//  # (of "-" anywhere in the list.)
//  1 fails at Plot_Spline2(...)
//  2 fails at Plot_Spline2(...)
//  3 fails at #local Spline_A = Spline_From_Array(Array_A,19);
//  4 fails at Plot_Spline2(...)
//  5 fails at Plot_Spline2(...)
//  6 fails at #local Spline_A = Spline_From_Array(Array_A,19);
//  7 fails at Plot_Spline2(...)
//  8 fails at Plot_Spline2(...)
//  9 fails at #local Spline_A = Spline_From_Array(Array_A,19);
// 10 fails at Plot_Spline2(...)
// 11 fails at Plot_Spline2(...)
// 12 fails at #local Spline_A = Spline_From_Array(Array_A,19);
// 13 fails at Plot_Spline2(...)
// 14 fails at Plot_Spline2(...)
// 15 fails at #local Spline_A = Spline_From_Array(Array_A,19);
// 16 fails at Plot_Spline2(...)
// 17 fails at Plot_Spline2(...)
// 18 fails at #local Spline_A = Spline_From_Array(Array_A,19);
// 19 fails at Plot_Spline2(...)
// 20 fails at Plot_Spline2(...)
// 21 fails at #local Spline_A = Spline_From_Array(Array_A,19);


#local M_Rand = seed(0);

#local Itr_Ctr = 0;
#while(Itr_Ctr < 40)  
  #local Some_Scale = <rand(M_Rand),rand(M_Rand)rand(M_Rand)>/10;
  #local Some_Rot   = <rand(M_Rand),rand(M_Rand)rand(M_Rand)>*360;
  #local Some_Tran  = <rand(M_Rand),rand(M_Rand)rand(M_Rand)>*1;
  #local Some_Thk   = rand(M_Rand)/9;
  #local Some_Clr_1 = <rand(M_Rand),rand(M_Rand)rand(M_Rand)>;
  #local Some_Clr_2 = <rand(M_Rand),rand(M_Rand)rand(M_Rand)>;
  #local Some_Freq  = .05;//rand(M_Rand)/10;
  //#if(Some_Freq < .01) #local Some_Freq = .01; #end 
  //Too many spheres don't help show the problem.
  
  //usage: Transform_Array(TheArray,TheArrayLength,TheScale,TheRotation,TheTranslation)       
  #local Array_A = Transform_Array(XZ_Circle_Array,19,Some_Scale,Some_Rot,Some_Tran);

  //usage: Spline_From_Array (The_Array, Array_Length)                                   
  #local Spline_A = Spline_From_Array(Array_A,19); 
    
  //usage: Plot_Spline2(TheSpline,Plot_Min_Val,Plot_Max_Val,Thickness,Frequency,Color1,Color2)
  Plot_Spline2(Spline_A,0,1,Some_Thk,Some_Freq,Some_Clr_1,Some_Clr_2)

    //Infinite loop is by default.  Un-comment it to have a chance at rendering.
    //If un-commented it will render if the "bug avoidance" block above contains 
    //anything other than exactly 3 or 7 "-" or "+" symbols aka extra tokens. 
    //
  //#local Itr_Ctr = Itr_Ctr+1;   

#end //end #while