// Title: Frustum.inc // Version: 1.0.0 // Written by: Matthew Goulet // Created on: March 6, 2008 // Last updated: March 6, 2008 // // A set of macros to create frustums (truncated pyramids) and bifrustums (two frustrums joined // at the bases) with regular polygonal bases, and with or without rounded edges. // #ifndef(Frustum_Inc) #declare Frustum_Inc = version; #version 3.61; #ifdef(View_POV_Include_Stack) #debug "including frustum.inc\n" #end #macro Frustum(Base_Sides, Base_Radius, Top_Radius, Height) #if(Top_Radius > Base_Radius) #warning "Frustum: Base radius is smaller than top radius, exchanging values.\n" #end #if(Base_Sides < 3) #error "Frustum: Base sides must be 3 or greater." #end #local Base_R = max(Base_Radius, Top_Radius); #local Top_R = min(Base_Radius, Top_Radius); #if(Base_R <= 0) #error "Frustum: Base radius must be greater than zero.\n" #end #if(Top_R < 0) #error "Frustum: Top radius must be greater or equal to zero.\n" #end #local Angle = 360/Base_Sides; #if(Base_R = Top_R) #local Ht_1 = 0; #local Ht_2 = Height; #else #local Ht_1 = Top_R / Base_R; #local Ht_2 = 1; #end #local Ct = 0; prism { #if(Base_R = Top_R) linear_sweep #else conic_sweep #end linear_spline Ht_1, Ht_2, Base_Sides + 1, #while(Ct <= Base_Sides) #local V = vrotate(<0, 0, Base_R>, Ct * y * Angle); #if(Ct < Base_Sides) , #end #local Ct = Ct + 1; #end #if(Base_R != Top_R) translate -y rotate x * 180 rotate y * 180 scale <1, 1/(1-Ht_1), 1> scale <1, Height, 1> #end } #end #macro Bifrustum(Base_Sides, Base_Radius, Top_Radius, Height, Use_Merge) #local Sm = 1e-15; #local Ht = Height/2 + Sm; #local Half = object { Frustum(Base_Sides, Base_Radius, Top_Radius, Ht) translate y * -Sm } #if(Use_Merge) merge { #else union { #end object { Half } object { Half scale <1, -1, 1> } } #end #macro Round_Frustum(Base_Sides, Bot_Radius, Top_Radius, Height, Round, Use_Merge) #if(Top_Radius > Bot_Radius) #warning "Round_Frustum: Top radius is larger than bottom radius, exchanging values.\n" #end #local BR = max(Bot_Radius, Top_Radius) - Round; #local TR = max(0, min(Bot_Radius, Top_Radius) - Round); #local Rot_Angle = 360/Base_Sides; #local Sm = 1e-10; #if(Use_Merge) merge { #else union { #end #local Ct = 0; #while(Ct < Base_Sides) #local Pt_B1 = vrotate(<0, Round, BR>, y * Rot_Angle * Ct); #local Pt_B2 = vrotate(Pt_B1, y * Rot_Angle); #local Pt_T1 = vrotate(<0, Height-Round, TR>, y * Rot_Angle * Ct); #local Pt_T2 = vrotate(Pt_T1, y * Rot_Angle); sphere { Pt_B1, Round } cylinder { Pt_B1, Pt_B2, Round } cylinder { Pt_B1, Pt_T1, Round } #if(TR > 0| Ct = 0) sphere { Pt_T1, Round } #end #if(TR > 0) cylinder { Pt_T1, Pt_T2, Round } #end #local Ct = Ct + 1; #end mesh { #local Ct = 0; #while(Ct < Base_Sides) #local Pt_B1 = vrotate(<0, Round, BR>, y * Rot_Angle * Ct); #local Pt_B2 = vrotate(Pt_B1, y * Rot_Angle); #local Pt_B3 = vrotate(Pt_B2, y * Rot_Angle); #local Pt_T1 = vrotate(<0, Height-Round, TR>, y * Rot_Angle * Ct); #local Pt_T2 = vrotate(Pt_T1, y * Rot_Angle); #local Pt_T3 = vrotate(Pt_T2, y * Rot_Angle); #local Delta = vnormalize(vcross(Pt_T2 - Pt_T1, Pt_B1 - Pt_T1)) * -Round; #local Delta2 = vnormalize(vcross(Pt_T3 - Pt_T2, Pt_B3 - Pt_T2)) * -Round; #local Pt_TD1 = Pt_T1 + Delta; #local Pt_TD2 = Pt_T2 + Delta; #local Pt_TD3 = Pt_T2 + Delta2; #local Pt_BD1 = Pt_B1 + Delta; #local Pt_BD2 = Pt_B2 + Delta; #local Pt_BD3 = Pt_B2 + Delta2; #local Pt_Top_1 = vrotate(<0, Height, TR>, y * Rot_Angle * Ct); #local Pt_Top_2 = vrotate(Pt_Top_1, y * Rot_Angle); #local Pt_Bot_1 = vrotate(z * BR, y * Rot_Angle * Ct); #local Pt_Bot_2 = vrotate(Pt_Bot_1, y * Rot_Angle); #if(TR > 0) triangle { y * Height, Pt_Top_1, Pt_Top_2 } triangle { Pt_Top_1, Pt_Top_2, Pt_TD2 } triangle { Pt_Top_1, Pt_TD1, Pt_TD2 } triangle { Pt_TD1, Pt_TD2, Pt_BD2 } triangle { Pt_Top_2, Pt_TD2, Pt_TD3 } #end triangle { Pt_BD2, Pt_BD1, Pt_TD1 } triangle { Pt_BD1, Pt_BD2, Pt_Bot_2 } triangle { Pt_BD1, Pt_Bot_1, Pt_Bot_2 } triangle { Pt_Bot_1, Pt_Bot_2, 0 } triangle { Pt_TD2, Pt_TD3, Pt_BD3 } triangle { Pt_TD2, Pt_BD2, Pt_BD3 } triangle { Pt_BD2, Pt_BD3, Pt_Bot_2 } #local Ct = Ct + 1; #end inside_vector z } } #end #macro Round_Bifrustum(Base_Sides, Mid_Radius, End_Radius, Height, Round, Use_Merge) #if(Mid_Radius < End_Radius) #warning "Round_Bifrustum: Mid radius is smaller than end radius, exchanging values.\n" #end #local Half_Ht = Height/2 + Round; #local Sm = 1e-15; #if(Use_Merge) merge { #else union { #end object { Round_Frustum(Base_Sides, Mid_Radius, End_Radius, Half_Ht, Round, Use_Merge) translate y * -Round } object { Round_Frustum(Base_Sides, Mid_Radius - 0.0001, End_Radius, Half_Ht, Round, Use_Merge) translate y * -Round scale <1, -1, 1> } } #end #version Frustum_Inc; #end