// Persistence of Vision Ray Tracer Scene Description File // File: spline_tools.inc // Vers: 3.6 // Desc: tools for extruding a spline // Date: August 20, 2006 // Updated: March 8, 2007 // now supports uv_mapping and smooth_triangles // except in morphed extrusions // Auth: Tim Attwood #ifndef(SPLINE_TOOLS_TEMP) #declare SPLINE_TOOLS_TEMP = version; #version 3.6; #ifndef(STRINGS_INC_TEMP) #include "strings.inc" #end #ifndef(TRANSFORMS_INC_TEMP) #include "transforms.inc" #end #ifndef(ARRAYS_INC_TEMP) #include "arrays.inc" #end #ifndef(POLYFUNCTIONS_INC) #include "polyfunctions.inc" #end // returns a spline that is a section of another spline #macro Split_Spline(SplA SplB begin_at stop_at rez stype) #local Split = concat("#declare ",SplB," = spline {\n",stype,"\n"); #local c = -rez; #while (c <= 1+rez) #local Split = concat(Split,str(c,1,3),",<", vstr(3, SplA(c * (stop_at - begin_at) + begin_at), ",", 0,3),">\n"); #local c = c + rez; #end #local Split = concat(Split,"};\n"); Parse_String(Split) #end // calculate the length of a spline #macro Len_Spline(Espl begin_at stop_at num) #local c = 1/num; #local V1 = Espl(begin_at); #local result = 0; #while (c <= 1) #local V2 = Espl( c*(stop_at - begin_at) + begin_at); #local result = result + vlength(V2-V1); #local V1 = V2; #local c = c + 1/num; #end (result) #end // saves a spline to a file // Usage: (spline_identifier, string, string, float, float, float, string) #macro Save_Spline(SplA, SplB, Filename, begin_at, stop_at, rez, stype) #fopen FOut2 Filename write #write (FOut2, concat("#declare ",SplB," = spline {\n",stype,"\n") ) #local cin = begin_at; #while (cin <= stop_at) //Parse_String(concat("#declare A = ", SplB, "(",str(cin,0,-1),");\n") // SplA(cin) #write(FOut2,concat(str(cin,0,3),",<",vstr(3, SplA(cin), ",", 0,3),">\n") ) #local cin = cin + rez; #end #write (FOut2, "};\n" ) #fclose FOut2 #end // remap spline #macro Remap_Spline(SplA SplB begin_at stop_at rez stype begin_out stop_out) #local outrez = (stop_out - begin_out)/((stop_at - begin_at)/rez); #fopen FOut "spline_tools.tmp" write #write (FOut, concat("#declare ",SplB," = spline {\n",stype,"\n") ) #local cin = begin_at; #local cout = begin_out; #while (cin <= stop_at) #write(FOut,concat(str(cout,0,3),",<",vstr(3, SplA(cin),",", 0,3),">\n") ) #local cout = cout + outrez; #local cin = cin + rez; #end #write (FOut, "};\n" ) #fclose FOut #include "spline_tools.tmp" #end // transforms a vector by a matrix #macro VMatrix_Trans(vec, A, B, C, D) #local fn = function { transform { matrix < A.x, A.y, A.z, B.x, B.y, B.z, C.x, C.y, C.z, D.x, D.y, D.z> } } #local result = (fn(vec.x, vec.y, vec.z)); (result) #end // transforms a vector along Path_Spline #macro VSpline_Trans_Path (Vect, Time, Sky, Foresight, Banking) #ifndef (Path_Spline) #error "VSpline_Trans_Path requires Path_Spline to be #declared!\n" #end #local Location = <0,0,0>+Path_Spline(Time); #local LocationNext = <0,0,0>+Path_Spline(Time+Foresight); #local LocationPrev = <0,0,0>+Path_Spline(Time-Foresight); #local Forward = vnormalize(LocationNext-Location); #local Right = VPerp_To_Plane(Sky,Forward); #local Up = VPerp_To_Plane(Forward,Right); #local BankingRotation = degrees(atan2( VRotation( VProject_Plane((LocationNext-Location),Sky), VProject_Plane((Location-LocationPrev),Sky), Up )*Banking ,1 )); #local result = vrotate(Vect, BankingRotation*z); #local result = VMatrix_Trans(result,Right,Up,Forward,Location); (result) #end // creates a mesh by extruding Shape_Spline along Path_spline #macro Extrude_Spline(W, L, Sky, Foresight, Banking) #ifndef (Path_Spline) #error "Extrude_Spline requires Path_Spline to be #declared!\n" #end #ifndef (Shape_Spline) #error "Extrude_Spline requires Shape_Spline to be #declared!\n" #end #local rez = 1/L; #local shaperez = 1/W; mesh { #local loop1 = 0; #while (loop1<=(1-rez)) #local loop2 = 0; #while (loop2<=(1-shaperez)) #local A = VSpline_Trans_Path(Shape_Spline(loop2), loop1, Sky, Foresight, Banking); #local B = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1, Sky, Foresight, Banking); #local C = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez, Sky, Foresight, Banking); #local D = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez, Sky, Foresight, Banking); // calculate normals (equidistant surrounding points) #local PA1 = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez*0.5, Sky, Foresight, Banking);; #local PA2 = VSpline_Trans_Path(Shape_Spline(loop2 + shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PA3 = VSpline_Trans_Path(Shape_Spline(loop2 - shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PB1 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez*0.5, Sky, Foresight, Banking); #local PB2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez +shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PB3 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez -shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PC1 = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez+rez*0.5, Sky, Foresight, Banking); #local PC2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PC3 = VSpline_Trans_Path(Shape_Spline(loop2-shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PD1 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez+rez*0.5, Sky, Foresight, Banking); #local PD2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez+shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PD3 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez-shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); // the normals #local NA = vnormalize(vcross(PA1-PA3,PA2-PA3)); #local NB = vnormalize(vcross(PB1-PB3,PB2-PB3)); #local NC = vnormalize(vcross(PC1-PC3,PC2-PC3)); #local ND = vnormalize(vcross(PD1-PD3,PD2-PD3)); // this quad of 2 smooth triangles smooth_triangle { A, NA, C, NC, B, NB uv_vectors ,, } smooth_triangle { B, NB, C, NC, D, ND uv_vectors ,, } /* // without smooth triangles triangle {A, C, B uv_vectors ,, } triangle {B, C, D uv_vectors ,, } */ #local loop2=loop2+shaperez; #end #local loop1=loop1+rez; #end } #end // creates a mesh by extruding Shape_Spline along Path_spline #macro Extrude_Spline_Closed(W, L, Sky, Foresight, Banking) #ifndef (Path_Spline) #error "Extrude_Spline requires Path_Spline to be #declared!\n" #end #ifndef (Shape_Spline) #error "Extrude_Spline requires Shape_Spline to be #declared!\n" #end #if (VEq(Shape_Spline(0),Shape_Spline(1))=false) // error check #error "Extrude_Spline_Closed requires Shape_Spline to be a closed spline.\n" #end #local rez = 1/L; #local shaperez = 1/W; mesh { #local loop1 = 0; #while (loop1<=(1-rez)) #local loop2 = 0; #while (loop2<=(1-shaperez)) #local A = VSpline_Trans_Path(Shape_Spline(loop2), loop1, Sky, Foresight, Banking); #local B = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1, Sky, Foresight, Banking); #local C = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez, Sky, Foresight, Banking); #local D = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez, Sky, Foresight, Banking); // calculate normals (equidistant surrounding points) #local PA1 = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez*0.5, Sky, Foresight, Banking);; #local PA2 = VSpline_Trans_Path(Shape_Spline(loop2 + shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PA3 = VSpline_Trans_Path(Shape_Spline(loop2 - shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PB1 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez*0.5, Sky, Foresight, Banking); #local PB2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez +shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PB3 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez -shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PC1 = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez+rez*0.5, Sky, Foresight, Banking); #local PC2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PC3 = VSpline_Trans_Path(Shape_Spline(loop2-shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PD1 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez+rez*0.5, Sky, Foresight, Banking); #local PD2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez+shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PD3 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez-shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); // the normals #local NA = vnormalize(vcross(PA1-PA3,PA2-PA3)); #local NB = vnormalize(vcross(PB1-PB3,PB2-PB3)); #local NC = vnormalize(vcross(PC1-PC3,PC2-PC3)); #local ND = vnormalize(vcross(PD1-PD3,PD2-PD3)); // this quad of 2 smooth triangles smooth_triangle { A, NA, C, NC, B, NB uv_vectors ,, } smooth_triangle { B, NB, C, NC, D, ND uv_vectors ,, } // without uv or smooth_triangles //triangle {A, C, B} //triangle {B, C, D} #local loop2=loop2+shaperez; #end #local loop1=loop1+rez; #end #local Num = W; // create an array of the shape #local point = array[Num+1]; #local loop = 0; #while (loop < Num) #local point[loop] = Shape_Spline(loop/Num); #local loop = loop + 1; #end #local point[Num] = Shape_Spline(0); // extra closed // if path is counter-clockwise reverse array #if ( Clockwise_Test(point) = false) Reverse_Array(point) #end #local Triangles = Triangulate_Polygon(point) #local d = dimension_size(Triangles,1); // near end cap #local a = 0; #while (a,<0,0>,<0,0> } #local a = a + 1; #end // far end cap #local a = 0; #while (a,<1,1>,<1,1> } #local a = a + 1; #end // calculate inside vector #local a = int(d/2); #local p0 = Triangles[a][0]; #local p1 = Triangles[a][1]; #local p2 = Triangles[a][2]; #local PAvg = (p0 + p1 + p2)/3; #local Pinside = VSpline_Trans_Path(PAvg, 0.5, Sky, Foresight, Banking); inside_vector Pinside } // end mesh #end // creates a mesh by extruding Shape_Spline along Path_spline // and saves it to a file #macro Extrude_Spline_To_File(MeshName, Filename, W, L, Sky, Foresight, Banking) #ifndef (Path_Spline) #error "Extrude_Spline requires Path_Spline to be #declared!\n" #end #ifndef (Shape_Spline) #error "Extrude_Spline requires Shape_Spline to be #declared!\n" #end #fopen File Filename write #local rez = 1/L; #local shaperez = 1/W; #write (File, concat("#declare ",MeshName," = mesh {\n") ) #local loop1 = 0; #while (loop1<=(1-rez)) #local loop2 = 0; #while (loop2<=(1-shaperez)) #local A = VSpline_Trans_Path(Shape_Spline(loop2), loop1, Sky, Foresight, Banking); #local B = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1, Sky, Foresight, Banking); #local C = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez, Sky, Foresight, Banking); #local D = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez, Sky, Foresight, Banking); // calculate normals (equidistant surrounding points) #local PA1 = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez*0.5, Sky, Foresight, Banking);; #local PA2 = VSpline_Trans_Path(Shape_Spline(loop2 + shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PA3 = VSpline_Trans_Path(Shape_Spline(loop2 - shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PB1 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez*0.5, Sky, Foresight, Banking); #local PB2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez +shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PB3 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez -shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PC1 = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez+rez*0.5, Sky, Foresight, Banking); #local PC2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PC3 = VSpline_Trans_Path(Shape_Spline(loop2-shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PD1 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez+rez*0.5, Sky, Foresight, Banking); #local PD2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez+shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PD3 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez-shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); // the normals #local NA = vnormalize(vcross(PA1-PA3,PA2-PA3)); #local NB = vnormalize(vcross(PB1-PB3,PB2-PB3)); #local NC = vnormalize(vcross(PC1-PC3,PC2-PC3)); #local ND = vnormalize(vcross(PD1-PD3,PD2-PD3)); // with smooth triangles and uv mapping #write (File, concat(" smooth_triangle {\n <", vstr(3, A, ",", 0,3),">,<", vstr(3, NA, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, NC, ",", 0,3),">,<", vstr(3, B, ",", 0,3),">,<", vstr(3, NB, ",", 0,3),">\n", " uv_vectors\n <",str(loop1,0,3),",",str(loop2,0,3),">,<", str(loop1+rez,0,3),",",str(loop2,0,3),">,<", str(loop1,0,3),",",str(loop2+shaperez,0,3),">}\n" )) //uv_vectors // ,,} #write (File, concat(" smooth_triangle {<", vstr(3, B, ",", 0,3),">,<", vstr(3, NB, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, NC, ",", 0,3),">,<", vstr(3, D, ",", 0,3),">,<", vstr(3, ND, ",", 0,3),">\n", " uv_vectors\n <",str(loop1,0,3),",",str(loop2+shaperez,0,3),">,<", str(loop1+rez,0,3),",",str(loop2,0,3),">,<", str(loop1+rez,0,3),",",str(loop2+shaperez,0,3),">}\n" )) //uv_vectors // ,, /* // without smooth triangles or uv mapping #write (File, concat(" triangle {<", vstr(3, A, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, B, ",", 0,3),">}\n" ) ) #write (File, concat(" triangle {<", vstr(3, B, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, D, ",", 0,3),">}\n" ) ) */ #local loop2=loop2+shaperez; #end #local loop1=loop1+rez; #end #write (File, "};\n") #fclose File #end // creates a mesh by extruding Shape_Spline along Path_spline // and saves it to a file #macro Extrude_Spline_Closed_To_File(MeshName, Filename, W, L, Sky, Foresight, Banking) #ifndef (Path_Spline) #error "Extrude_Spline requires Path_Spline to be #declared!\n" #end #ifndef (Shape_Spline) #error "Extrude_Spline requires Shape_Spline to be #declared!\n" #end #if (VEq(Shape_Spline(0),Shape_Spline(1))=false) // error check #error "Extrude_Spline_Closed requires Shape_Spline to be a closed spline.\n" #end #fopen File Filename write #local rez = 1/L; #local shaperez = 1/W; #write (File, concat("#declare ",MeshName," = mesh {\n") ) #local loop1 = 0; #while (loop1<=(1-rez)) #local loop2 = 0; #while (loop2<=(1-shaperez)) #local A = VSpline_Trans_Path(Shape_Spline(loop2), loop1, Sky, Foresight, Banking); #local B = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1, Sky, Foresight, Banking); #local C = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez, Sky, Foresight, Banking); #local D = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez, Sky, Foresight, Banking); // calculate normals (equidistant surrounding points) #local PA1 = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez*0.5, Sky, Foresight, Banking);; #local PA2 = VSpline_Trans_Path(Shape_Spline(loop2 + shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PA3 = VSpline_Trans_Path(Shape_Spline(loop2 - shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PB1 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez*0.5, Sky, Foresight, Banking); #local PB2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez +shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PB3 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez -shaperez*0.433), loop1-rez*0.25, Sky, Foresight, Banking); #local PC1 = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez+rez*0.5, Sky, Foresight, Banking); #local PC2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PC3 = VSpline_Trans_Path(Shape_Spline(loop2-shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PD1 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez+rez*0.5, Sky, Foresight, Banking); #local PD2 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez+shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); #local PD3 = VSpline_Trans_Path(Shape_Spline(loop2+shaperez-shaperez*0.433), loop1+rez-rez*0.25, Sky, Foresight, Banking); // the normals #local NA = vnormalize(vcross(PA1-PA3,PA2-PA3)); #local NB = vnormalize(vcross(PB1-PB3,PB2-PB3)); #local NC = vnormalize(vcross(PC1-PC3,PC2-PC3)); #local ND = vnormalize(vcross(PD1-PD3,PD2-PD3)); // with smooth triangles and uv mapping #write (File, concat(" smooth_triangle {\n <", vstr(3, A, ",", 0,3),">,<", vstr(3, NA, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, NC, ",", 0,3),">,<", vstr(3, B, ",", 0,3),">,<", vstr(3, NB, ",", 0,3),">\n", " uv_vectors\n <",str(loop1,0,3),",",str(loop2,0,3),">,<", str(loop1+rez,0,3),",",str(loop2,0,3),">,<", str(loop1,0,3),",",str(loop2+shaperez,0,3),">}\n" )) //uv_vectors // ,,} #write (File, concat(" smooth_triangle {<", vstr(3, B, ",", 0,3),">,<", vstr(3, NB, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, NC, ",", 0,3),">,<", vstr(3, D, ",", 0,3),">,<", vstr(3, ND, ",", 0,3),">\n", " uv_vectors\n <",str(loop1,0,3),",",str(loop2+shaperez,0,3),">,<", str(loop1+rez,0,3),",",str(loop2,0,3),">,<", str(loop1+rez,0,3),",",str(loop2+shaperez,0,3),">}\n" )) /* // without smooth triangles or uv #write (File, concat(" triangle {<", vstr(3, A, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, B, ",", 0,3),">}\n" ) ) #write (File, concat(" triangle {<", vstr(3, B, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, D, ",", 0,3),">}\n" ) ) */ #local loop2=loop2+shaperez; #end #local loop1=loop1+rez; #end #local Num = W; // create an array of the shape #local point = array[Num+1]; #local loop = 0; #while (loop < Num) #local point[loop] = Shape_Spline(loop/Num); #local loop = loop + 1; #end #local point[Num] = Shape_Spline(0); // extra closed // if path is counter-clockwise reverse array #if ( Clockwise_Test(point) = false) Reverse_Array(point) #end #local Triangles = Triangulate_Polygon(point) #local d = dimension_size(Triangles,1); #write (File, "// near end cap\n") // near end cap #local a = 0; #while (a,<", vstr(3, p1, ",", 0,3),">,<", vstr(3, p2, ",", 0,3),">\n", " uv_vectors\n <0.001,0>,<0,0>,<0,0>}\n" ) ) //triangle { p0, p1, p2 // uv_vectors // <0.001,0>,<0,0>,<0,0>} #local a = a + 1; #end #write (File, "// far end cap\n") // far end cap #local a = 0; #while (a,<", vstr(3, p1, ",", 0,3),">,<", vstr(3, p2, ",", 0,3),">\n" " uv_vectors\n <0.999,1>,<1,1>,<1,1>}\n" )) //triangle { p0, p1, p2 } #local a = a + 1; #end // calculate inside vector #local a = int(d/2); #local p0 = Triangles[a][0]; #local p1 = Triangles[a][1]; #local p2 = Triangles[a][2]; #local PAvg = (p0 + p1 + p2)/3; #local Pinside = VSpline_Trans_Path(PAvg, 0.5, Sky, Foresight, Banking); #write (File, concat(" inside_vector <",vstr(3, Pinside, ",", 0,3),">\n") ) //inside_vector Pinside #write (File, "};\n") #fclose File #end // creates a mesh by extruding Shape_Spline along Path_spline // and saves it to a file #macro Extrude_Spline_Morphed(MeshName, Filename, W, L, Sky, Foresight, Banking ) #ifndef (Path_Spline) #error "Extrude_Spline_Morphed requires Path_Spline to be #declared!\n" #end #ifndef (Shape_Array) #error "Extrude_Spline_Morphed requires Shape_Array to be #declared!\n" #end // #if (VEq(Shape_Spline(0),Shape_Spline(1))=false) // error check // #error // "Extrude_Spline_Closed requires Shape_Spline to be a closed spline.\n" // #end #ifndef (Twist_Spline) #local Twist_Spline = spline { linear_spline 0.00,<0,0,0> 1.00,<0,0,0> }; #end #local Num_Shapes = dimension_size(Shape_Array,1); // number of shape spline in array #fopen File Filename write #local rez = 1/L; #local shaperez = 1/W; #write (File, concat("#declare ",MeshName," = mesh {\n") ) #local loop1 = 0; #while (loop1<=(1-rez)) #local loop2 = 0; #while (loop2<=(1-shaperez)) // morph A and B #local Shape1Index = int(loop1*(Num_Shapes-1)); #local Shape2Index = Shape1Index+1; #if (Shape2Index >= Num_Shapes) #local Shape2Index = Num_Shapes -1; #local Shape1Index = Num_Shapes -2; #end #local Shape1Weight = 1-mod(loop1*(Num_Shapes-1),1); // nearness to shape1 #local Shape2Weight = 1-Shape1Weight; // nearness to shape2 #local A0 = Shape_Array[Shape1Index](loop2) * Shape1Weight + Shape_Array[Shape2Index](loop2) * Shape2Weight ; #local B0 = Shape_Array[Shape1Index](loop2+shaperez) * Shape1Weight + Shape_Array[Shape2Index](loop2+shaperez) * Shape2Weight ; // morph C and D #local Shape1Index = int((loop1+rez)*(Num_Shapes-1)); #local Shape2Index = Shape1Index+1; #if (Shape2Index >= Num_Shapes) #local Shape2Index = Num_Shapes -1; #local Shape1Index = Num_Shapes -2; #end #local Shape1Weight = 1-mod((loop1+rez)*(Num_Shapes-1),1); // nearness to shape1 #local Shape2Weight = 1-Shape1Weight; // nearness to shape2 #local C0 = Shape_Array[Shape1Index](loop2) * Shape1Weight + Shape_Array[Shape2Index](loop2) * Shape2Weight ; #local D0 = Shape_Array[Shape1Index](loop2+shaperez) * Shape1Weight + Shape_Array[Shape2Index](loop2+shaperez) * Shape2Weight ; // twist A, B, C, and D #local A0 = vrotate(A0, <0,0,Twist_Spline(loop1).x>); #local B0 = vrotate(B0, <0,0,Twist_Spline(loop1).x>); #local C0 = vrotate(C0, <0,0,Twist_Spline(loop1+rez).x>); #local D0 = vrotate(D0, <0,0,Twist_Spline(loop1+rez).x>); // translate A, B, C, and D along path #local A = VSpline_Trans_Path(A0, loop1, Sky, Foresight, Banking); #local B = VSpline_Trans_Path(B0, loop1, Sky, Foresight, Banking); #local C = VSpline_Trans_Path(C0, loop1+rez, Sky, Foresight, Banking); #local D = VSpline_Trans_Path(D0, loop1+rez, Sky, Foresight, Banking); /* #local A = VSpline_Trans_Path(Shape_Spline(loop2), loop1, Sky_Spline(loop2), Foresight, Banking); #local B = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1, Sky_Spline(loop2+shaperez), Foresight, Banking); #local C = VSpline_Trans_Path(Shape_Spline(loop2), loop1+rez, Sky_Spline(loop2), Foresight, Banking); #local D = VSpline_Trans_Path(Shape_Spline(loop2+shaperez), loop1+rez, Sky_Spline(loop2+shaperez), Foresight, Banking); */ #write (File, concat(" triangle {<", vstr(3, A, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, B, ",", 0,3),">}\n" ) ) #write (File, concat(" triangle {<", vstr(3, B, ",", 0,3),">,<", vstr(3, C, ",", 0,3),">,<", vstr(3, D, ",", 0,3),">}\n" ) ) #local loop2=loop2+shaperez; #end #local loop1=loop1+rez; #end #local Num = W; // create an array of the first shape #local point = array[Num+1]; #local loop = 0; #while (loop < Num) #local point[loop] = Shape_Array[0](loop/Num); #local loop = loop + 1; #end #local point[Num] = Shape_Array[0](0); // extra closed // if path is counter-clockwise reverse array #if ( Clockwise_Test(point) = false) Reverse_Array(point) #end #local Triangles = Triangulate_Polygon(point) #local d = dimension_size(Triangles,1); #write (File, "// near end cap\n") // near end cap #local a = 0; #while (a); #local p1 = vrotate(p1, <0,0,Twist_Spline(0).x>); #local p2 = vrotate(p2, <0,0,Twist_Spline(0).x>); #local p0 = VSpline_Trans_Path(p0, 0, Sky, Foresight, Banking); #local p1 = VSpline_Trans_Path(p1, 0, Sky, Foresight, Banking); #local p2 = VSpline_Trans_Path(p2, 0, Sky, Foresight, Banking); #write (File, concat(" triangle {<", vstr(3, p0, ",", 0,3),">,<", vstr(3, p1, ",", 0,3),">,<", vstr(3, p2, ",", 0,3),">}\n" ) ) //triangle { p0, p1, p2 } #local a = a + 1; #end // fill array with the last shape #local loop = 0; #while (loop < Num) #local point[loop] = Shape_Array[Num_Shapes-1](loop/Num); #local loop = loop + 1; #end #local point[Num] = Shape_Array[Num_Shapes-1](0); // extra closed // if path is counter-clockwise reverse array #if ( Clockwise_Test(point) = false) Reverse_Array(point) #end #local Triangles = Triangulate_Polygon(point) #local d = dimension_size(Triangles,1); #write (File, "// far end cap\n") // far end cap #local a = 0; #while (a); #local p1 = vrotate(p1, <0,0,Twist_Spline(1).x>); #local p2 = vrotate(p2, <0,0,Twist_Spline(1).x>); #local p0 = VSpline_Trans_Path(p0, 1, Sky, Foresight, Banking); #local p1 = VSpline_Trans_Path(p1, 1, Sky, Foresight, Banking); #local p2 = VSpline_Trans_Path(p2, 1, Sky, Foresight, Banking); #write (File, concat(" triangle {<", vstr(3, p0, ",", 0,3),">,<", vstr(3, p1, ",", 0,3),">,<", vstr(3, p2, ",", 0,3),">}\n" ) ) //triangle { p0, p1, p2 } #local a = a + 1; #end #write (File, "};\n") #fclose File #end // translates the points in a spline // Usage: (spline_identifier, string, float, float, float, string, vector) #macro Spline_Translate(SplA SplB begin_at stop_at rez stype vec) #fopen FOut "spline_tools.tmp" write #write (FOut, concat("#declare ",SplB," = spline {\n",stype,"\n") ) #local cin = begin_at; #while (cin <= stop_at) #local Temp = SplA(cin) + vec; #write(FOut,concat(str(cin,0,3),",<",vstr(3, Temp,",", 0,3),">\n") ) #local cin = cin + rez; #end #write (FOut, "};\n" ) #fclose FOut #include "spline_tools.tmp" #end // rotates the points in a spline // Usage: (spline_identifier, string, float, float, float, string, vector) #macro Spline_Rotate(SplA SplB begin_at stop_at rez stype vec) #fopen FOut "spline_tools.tmp" write #write (FOut, concat("#declare ",SplB," = spline {\n",stype,"\n") ) #local cin = begin_at; #while (cin <= stop_at) #local Temp = vrotate(SplA(cin),vec); #write(FOut,concat(str(cin,0,3),",<",vstr(3, Temp,",", 0,3),">\n") ) #local cin = cin + rez; #end #write (FOut, "};\n" ) #fclose FOut #include "spline_tools.tmp" #end // scales the points in a spline // Usage: (spline_identifier, string, float, float, float, string, vector) #macro Spline_Scale(SplA SplB begin_at stop_at rez stype vec) #fopen FOut "spline_tools.tmp" write #write (FOut, concat("#declare ",SplB," = spline {\n",stype,"\n") ) #local cin = begin_at; #while (cin <= stop_at) #local Temp = ; #write(FOut,concat(str(cin,0,3),",<",vstr(3, Temp,",", 0,3),">\n") ) #local cin = cin + rez; #end #write (FOut, "};\n" ) #fclose FOut #include "spline_tools.tmp" #end /* // repeated calls will use excessive memory for copies of splines #macro VSpline_Trans (Vect, Spline, Time, Sky, Foresight, Banking) #local Location = <0,0,0>+Spline(Time); #local LocationNext = <0,0,0>+Spline(Time+Foresight); #local LocationPrev = <0,0,0>+Spline(Time-Foresight); #local Forward = vnormalize(LocationNext-Location); #local Right = VPerp_To_Plane(Sky,Forward); #local Up = VPerp_To_Plane(Forward,Right); #local BankingRotation = degrees(atan2( VRotation( VProject_Plane((LocationNext-Location),Sky), VProject_Plane((Location-LocationPrev),Sky), Up )*Banking ,1 )); #local result = vrotate(Vect, BankingRotation*z); #local result = VMatrix_Trans(result,Right,Up,Forward,Location); (result) #end */ // --- close polygon macros ------------------------------------------------- // counter-clockwise angle of a vector from the x-axis (0-359.999) #macro Line_Angle(vec) #if ((vec.y=0)&(vec.x=0)) #error "<0,0> has an undefined angle in Line_Angle!" #end #if (vec.y>=0) #local result = VAngleD(vec,<1,0,0>); #else #local result = 360-VAngleD(vec,<1,0,0>); #end (result) #end // find inside angle at B in ABC #macro Inside_Angle(A, B, C) #if ( VEq(A,B)|VEq(A,C)|VEq(B,C)) #error "Points A, B,and C must be distinct in Inside_Angle!\n" #end #local AB_angle = Line_Angle(B-A); #local BC_angle = Line_Angle(C-B); #local IA = mod(540 + BC_angle - AB_angle,360); (IA) #end #macro Point_In_Triangle2D(vec, A, B, C) // test bounds #local VX = vec.x; #local VY = vec.y; #if( (VX <= max(A.x, B.x, C.x)) & (VX >= min(A.x, B.x, C.x)) & (VY <= max(A.y, B.y, C.y)) & (VY >= min(A.y, B.y, C.y)) ) #local BAC_angle = VAngleD(B-A,C-A); #local ABC_angle = VAngleD(A-B,C-B); #local BAT_angle = VAngleD(vec-A,B-A); #local TAC_angle = VAngleD(vec-A,C-A); #local ABT_angle = VAngleD(vec-B,A-B); #local TBC_angle = VAngleD(vec-B,C-B); #if (((BAT_angle+TAC_angle) > (BAC_angle + 0.00000001))| ((ABT_angle+TBC_angle) > (ABC_angle + 0.00000001))) #local result = false; #else #local result = true; #end #else #local result = false; #end (result) #end // index of next point #macro Next_Point(Num, Used) #local Size = dimension_size(Used, 1); #local Checked = 0; #local result = mod(Num + 1, Size); #while (Used[result]=true) #local result = mod(result + 1, Size); #local Checked = Checked + 1; #if (Checked >= Size + 10) #error "No unused points in Next_Point!" #end #end (result) #end // index of last point #macro Last_Point(Num, Used) #local Size = dimension_size(Used, 1); #local Checked = 0; #local result = Num; #local flag = true; #while (flag) #local result = result - 1; #if (result < 0) #local result = Size-1; #end #if ( Used[result] = false ) #local flag = false; #end #local Checked = Checked + 1; #if (Checked >= Size+10) #error "No unused points in Next_Point!" #end #end (result) #end // test if point_array is defined clockwise // Usage: (array_identifier, array_identifier) #macro Clockwise_Test(point_array) #local Size = dimension_size(point_array, 1); // find left-most point #local point_min_x = 0; #local loop = 1; #while (loop < Size) #if ( point_array[loop].x < point_array[point_min_x].x ) #local point_min_x = loop; #end #local loop = loop + 1; #end #local last = mod(point_min_x-1+Size,Size);//Last_Point(point_min_x, used_array); #local next = mod(point_min_x+1,Size);//Next_Point(point_min_x, used_array); #if ( (point_array[point_min_x].x = point_array[last].x) & (point_array[point_min_x].x = point_array[next].x) ) #if (point_array[last].y < point_array[next].y) #local result = true; #else #local result = false; #end #else #local LA = VAngleD(point_array[last] - point_array[point_min_x], <0,-1,0>); #local NA = VAngleD(point_array[next] - point_array[point_min_x], <0,-1,0>); #if ( LA < NA ) #local result = true; #else #local result = false; #end #end (result) #end #macro Triangle_Area(Ain, Bin, Cin) #local ABdist = abs(VDist(Ain, Bin)); #local BCdist = abs(VDist(Bin, Cin)); #local CAdist = abs(VDist(Cin, Ain)); // Heron's formula for the area #local semi = (ABdist+BCdist+CAdist)/2; //semiperimiter #local K_inner = semi*(semi-CAdist)*(semi-BCdist)*(semi-ABdist); #if (K_inner<=0) #local K = 0; // no area #else #local K = sqrt(K_inner); #end (K) #end // comb sort 11 #macro comb_compare(AR, A, B) (AR[A][0] > AR[B][0]) #end // comb sort 11 #macro comb_swap(AR, A, B) #local Tmp = AR[A][0]; #declare AR[A][0] = AR[B][0]; #declare AR[B][0] = Tmp; #local Tmp = AR[A][1]; #declare AR[A][1] = AR[B][1]; #declare AR[B][1] = Tmp; #end // comb sort 11 #macro update_gap(gap) #local result = int((gap * 10) / 13); #if ((result = 9) | (result = 10)) #local result = 11; #else #local result = max(1, result); #end (result) #end // comb sort 11 #macro combsort(AR) #local DS = dimension_size(AR,1); #local gap = DS; #local swapped = true; #if (gap > 1) #while ((gap > 1) | (swapped)) #local gap = update_gap(gap); #local swapped = false; #local C = 0; #while (C < (DS - gap)) #if ( comb_compare(AR,C,C+gap) ) comb_swap(AR, C, C+gap) #local swapped = true; #end #local C = C + 1; #end #end #end #end //====================================== // Triangulate_Polygon_Indices by Tim Attwood // uses Triangulate_Polygon by Florian Brucker //====================================== /* Splits the given polygon into triangles. Returns an array of indicies to poly points: Index[n][3] */ #macro Triangulate_Polygon_Indices(Poly) #local point_array = Poly; #local number_of_points = dimension_size(Poly,1); #local point_triangles = Triangulate_Polygon(point_array); #local number_of_triangles = dimension_size(point_triangles,1); #local Index = array[number_of_triangles][3]; //re-find point indices #local point_count = 0; #while (point_count < number_of_points) #local current_point = point_array[point_count]; #local triangle_count = 0; #while (triangle_count < number_of_triangles) #if (VEq(current_point,point_triangles[triangle_count][0]) ) Index[triangle_count][0] = point_count; #end #if (VEq(current_point,point_triangles[triangle_count][1]) ) Index[triangle_count][1] = point_count; #end #if (VEq(current_point,point_triangles[triangle_count][2]) ) Index[triangle_count][2] = point_count; #end #local triangle_count = triangle_count + 1; #end #local point_count = point_count + 1; #end (Index) #end // close shape with polyfunctions Triangulate_Polygon by Florian Brucker #macro Close_Shape(Num) #ifndef (Shape_Spline) #error "Close_Shape requires Shape_Spline to be defined!\n" #end #if (Num < 3) #error "Close_Shape requires Num >= 3 as a parameter!" #end #if (VEq(Shape_Spline(0),Shape_Spline(1))=false) // error check #error "Close_Shape requires Shape_Spline to be a closed spline.\n" #end // create an array of flags // this isn't really used in this context, but // allows use of Clockwise_Test //#local used = array[Num]; //#local loop = 0; //#while (loop < Num) // #local used[loop] = false; // #local loop = loop + 1; //#end // create an array of the shape #local point = array[Num+1]; #local loop = 0; #while (loop < Num) #local point[loop] = Shape_Spline(loop/Num); #local loop = loop + 1; #end #local point[Num] = Shape_Spline(0); // extra closed // if path is counter-clockwise reverse array #if ( Clockwise_Test(point) = false) Reverse_Array(point) #end #local Triangles = Triangulate_Polygon(point) #local d = dimension_size(Triangles,1); #local a = 0; #while (a, , } #local a = a + 1; #end #end // close shape with polyfunctions Triangulate_Polygon by Florian Brucker #macro Close_Shape_End_Caps(Num) #ifndef (Shape_Spline) #error "Close_Shape requires Shape_Spline to be defined!\n" #end #if (Num < 3) #error "Close_Shape requires Num >= 3 as a parameter!" #end #if (VEq(Shape_Spline(0),Shape_Spline(1))=false) // error check #error "Close_Shape requires Shape_Spline to be a closed spline.\n" #end // create an array of flags // this isn't really used in this context, but // allows use of Clockwise_Test #local used = array[Num]; #local loop = 0; #while (loop < Num) #local used[loop] = false; #local loop = loop + 1; #end // create an array of the shape #local point = array[Num+1]; #local loop = 0; #while (loop < Num) #local point[loop] = Shape_Spline(loop/Num); #local loop = loop + 1; #end #local point[Num] = Shape_Spline(0); // extra closed // if path is counter-clockwise reverse array #if ( Clockwise_Test(point) = false) Reverse_Array(point) #end #local ITriangles = Triangulate_Polygon_Indices(point) #local d = dimension_size(Triangles,1); // grrrr requires points anyways // make the caps #local a = 0; #while (a, , } #local a = a + 1; #end #end #version SPLINE_TOOLS_TEMP; #end // spline tools