// Last edited on 2011-05-12 21:46:51 by stolfilocal // Fukushima Daiichi - generic macros (for any unit) #declare eps = 0.0001; // Fudge factor to avoid coincident surfaces. #declare epsv = < eps, eps, eps >; // Fudge vector for box corners. #macro generic_flanged_capped_cylinder(H,R,D,T,FR,FT,bc,tc) // A vertical cylindrical vessel terminated by hemiellipsoidal caps or flanges. // The cylindical part has length {H} and outer radius {R}. // Each dome has height {D}. // The flanges have vertical thickness {FT} and extend by {FR} outwards. // The walls have thickness {T}. // The bottom is dome if {bc=1}, flange if {bc=0}. // The top is dome if {tc=1}, flange if {tc=0}. // The origin is on the axis at the height of the bottom seam. #local bot_ctr = < 0, 0, 0 >; #local top_ctr = < 0, 0, H >; union{ #if (bc > 0) object{ generic_vessel_dome(R,D,T) scale <1,1,-1> } #else object{ generic_vessel_flange(R,T,FR,FT) } #end difference{ cylinder{ #if (bc > 0) bot_ctr + eps*z #else bot_ctr - eps*z #end, #if (tc > 0) top_ctr + eps*z #else top_ctr - eps*z #end, R - eps } cylinder{ bot_ctr - 3*eps*z, top_ctr + 3*eps*z, R - T + eps } } #if (tc > 0) object{ generic_vessel_dome(R,D,T) translate top_ctr } #else object{ generic_vessel_flange(R,T,FR,FT) scale <1,1,-1> translate top_ctr } #end bounded_by{ cylinder{ #if (bc > 0) bot_ctr - D*z #else bot_ctr #end, #if (tc > 0) top_ctr + D*z #else top_ctr #end, #if ((bc > 0) | (tc > 0)) R + FR #else R #end } } } #end #macro generic_vessel_dome(R,D,T) // Hemiellipsoidal dome with height {D} for closing a cylindrical vessel of // of outer radius {R} and thickness {T}. // Sitting on {Z=0} plane, dome up, centered on {Z} axis. #local ot_scZ = (D-eps)/(R-eps); // Z flattening factor for outer surf of dome. #local in_scZ = (D-T+eps)/(R-T+eps); // Z flattening factor for inner surf of dome. #local ctr = <0,0,0>; intersection{ cylinder{ ctr - eps*z, ctr + D*z, R } difference{ sphere{ ctr, R-eps scale <1,1,ot_scZ> } sphere{ ctr, R-T+eps scale <1,1,in_scZ> } } bounded_by{ cylinder{ ctr - eps*z, ctr + D*z, R } } } #end #macro generic_vessel_flange(R,T,FR,FT) // Flange for a round tube of outer radius {R} and thickness {T}. // The flange has thckness {FT} and extends out by {FR}. // Sits on {Z=0} plane centered on {Z} axis. #local bot_ctr = <0,0,0>; #local top_ctr = bot_ctr + FT*z; difference{ cylinder{ bot_ctr + eps*z, top_ctr - eps*z, R + FR - eps } cylinder{ bot_ctr - eps*z, top_ctr + eps*z, R - T + 2*eps } bounded_by{ cylinder { bot_ctr, top_ctr, R+FR } } } #end // POOLS #macro generic_pool_cavity( lo_X,sz_X,lo_Y,sz_Y,lo_Z,hi_Z, ch_wid,ch_len,ch_pos,ch_dir,ch_lo_Z) // A negative object to excavate a pool on some floor, and its connecting channel. // The channel extends from the the pool's center in direction {ch_dir}. // {lo_Y} = Min X of pool cavity, rel west wall. // {sz_X} = X size of pool cavity. // {lo_Y} = Min Y of pool cavity, rel south wall. // {sz_Y} = Y size of pool cavity. // {lo_Z} = Z of bottom of pool cavity, rel OP. // {hi_Z} = Z of top of pool cavity (= room floor), rel OP. // {ch_wid} = Width of channel. // {ch_len} = Length of channel from pool's edge. // {ch_pos} = Coordinate of midline of channel. // {ch_lo_Z} = Z of bottom of channel, rel OP. // Coordinates of the pool cavity proper: #local hi_X = lo_X + sz_X; // Max X, rel east wall.. #local hi_Y = lo_Y + sz_Y; // Max Y, rel south wall. #local lo_corner = < lo_X, lo_Y, lo_Z >; #local hi_corner = < hi_X, hi_Y, hi_Z + 0.500 >; union{ box{ lo_corner - epsv, hi_corner + epsv } object{ generic_pool_channel_cavity( lo_X,sz_X,lo_Y,sz_Y, ch_wid,ch_len,ch_pos,ch_dir,ch_lo_Z) } } #end #macro generic_pool_channel_cavity( lo_X,sz_X,lo_Y,sz_Y, ch_wid,ch_len,ch_pos,ch_dir,ch_lo_Z) // A negative object to excavate the connecting channel of a pool. // The channel cavity extends from the the pool's center in direction {ch_dir} with the // midline in position {ch_pos} center, reaching {ch_len} beyond the pool's edge. // {lo_Y} = Min X of pool cavity, rel west wall. // {sz_X} = X size of pool cavity. // {lo_Y} = Min Y of pool cavity, rel south wall. // {sz_Y} = Y size of pool cavity. // {ch_wid} = Width of channel. // {ch_len} = Length of channel. // {ch_lo_Z} = Z of bottom of channel, rel OP. // Coordinates of the pool cavity proper: #local hi_X = lo_X + sz_X; // Max X, rel east wall.. #local hi_Y = lo_Y + sz_Y; // Max Y, rel south wall. #local lo_corner = < lo_X, lo_Y, lo_Z >; #local hi_corner = < hi_X, hi_Y, hi_Z + 0.500 >; // Coordinates of the channel between pool and parent cavity: #if (ch_dir.y = 0) // Channel parallel to X axis: #local ch_md_Y = ch_pos; // Midline Y. #local ch_lo_Y = ch_md_Y - ch_wid/2; // Min Y, rel south wall. #local ch_hi_Y = ch_lo_Y + ch_wid; // Max Y, rel south wall. #if (ch_dir.x > 0) #local ch_lo_X = (lo_X + hi_X)/2; // Min X, rel east wall. #local ch_hi_X = hi_X + ch_len; // Max X, rel east wall. #else #local ch_hi_X = (lo_X + hi_X)/2; // Max X, rel east wall. #local ch_lo_X = lo_X - ch_len; // Min X, rel east wall. #end #end #if (ch_dir.x = 0) // Channel parallel to Y axis: #local ch_md_X = ch_pos; // Midline X. #local ch_lo_X = ch_md_X - ch_wid/2; // Min X, rel east wall.. #local ch_hi_X = ch_lo_X + ch_wid; // Max X, rel east wall.. #if (ch_dir.y > 0) #local ch_lo_Y = (lo_Y + hi_Y)/2; // Min Y, rel east wall. #local ch_hi_Y = hi_Y + ch_len; // Max Y, rel east wall. #else #local ch_hi_Y = (lo_Y + hi_Y)/2; // Max Y, rel east wall. #local ch_lo_Y = lo_Y - ch_len; // Min Y, rel east wall. #end #end #local ch_hi_Z = hi_Z; // Max Z, rel OP. #local ch_lo_corner = < ch_lo_X, ch_lo_Y, ch_lo_Z >; #local ch_hi_corner = < ch_hi_X, ch_hi_Y, ch_hi_Z + 0.500 >; box{ ch_lo_corner - 2*epsv, ch_hi_corner + 2*epsv } #end #macro generic_pool_cavity_walls( lo_X,sz_X,lo_Y,sz_Y,lo_Z,hi_Z,thk, ch_wid,ch_len,ch_pos,ch_dir,ch_lo_Z,ch_thk) // A positive object to create a block from which one may excavate a {generic_pool_cavity} // to obtain the walls of the pool and of its connecting channel. // The channel walls extend from the pool's edge in direction {ch_dir}. // {lo_Y} = Min X of pool cavity, rel west wall. // {sz_X} = X size of pool cavity. // {lo_Y} = Min Y of pool cavity, rel south wall. // {sz_Y} = Y size of pool cavity. // {lo_Z} = Z of bottom of pool cavity, rel OP. // {hi_Z} = Z of top of pool cavity (= room floor), rel OP. // {thk} = pool wall thickness. // {ch_wid} = Width of channel. // {ch_len} = Length of channel from pool's edge. // {ch_pos} = Coordinate of midline of channel. // {ch_lo_Z} = Z of bottom of channel, rel OP. // {ch_thk} = channel wall thickness. #local T = thk; #local S = ch_thk; // Coordinates of the pool cavity proper: #local hi_X = lo_X + sz_X; // Max X, rel east wall.. #local hi_Y = lo_Y + sz_Y; // Max Y, rel south wall. #local lo_corner = < lo_X, lo_Y, lo_Z >; #local hi_corner = < hi_X, hi_Y, hi_Z >; union{ #if (T > 0) box{ lo_corner - + epsv, hi_corner + - epsv } #end #if (S > 0) generic_pool_channel_cavity_walls( lo_X,sz_X,lo_Y,sz_Y, ch_wid,ch_len,ch_pos,ch_dir,ch_lo_Z,ch_thk) #end } #end #macro generic_pool_channel_cavity_walls( lo_X,sz_X,lo_Y,sz_Y, ch_wid,ch_len,ch_pos,ch_dir,ch_lo_Z,ch_thk) // A positive object to create a block from which one may excavate a {generic_pool_channel_cavity} // to obtain the walls of the channel connecting a pool to some other pool. // The channel extends from the pool in direction {ch_dir}. // {lo_Y} = Min X of pool cavity, rel west wall. // {sz_X} = X size of pool cavity. // {lo_Y} = Min Y of pool cavity, rel south wall. // {sz_Y} = Y size of pool cavity. // {ch_wid} = Width of channel. // {ch_len} = Length of channel from pool's edge. // {ch_pos} = Coordinate of midline of channel. // {ch_lo_Z} = Z of bottom of channel, rel OP. // {ch_thk} = channel wall thickness. #local S = ch_thk; // Coordinates of the pool cavity proper: #local hi_X = lo_X + sz_X; // Max X, rel east wall.. #local hi_Y = lo_Y + sz_Y; // Max Y, rel south wall. #local lo_corner = < lo_X, lo_Y, lo_Z >; #local hi_corner = < hi_X, hi_Y, hi_Z >; // Coordinates of the channel between pool and parent cavity: #if (ch_dir.y = 0) // Channel parallel to X axis: #local ch_md_Y = ch_pos; // Midline Y. #local ch_lo_Y = ch_md_Y - ch_wid/2; // Min Y, rel south wall. #local ch_hi_Y = ch_lo_Y + ch_wid; // Max Y, rel south wall. #if (ch_dir.x > 0) #local ch_lo_X = (lo_X + hi_X)/2; // Min X, rel east wall. #local ch_hi_X = hi_X + ch_len; // Max X, rel east wall. #else #local ch_hi_X = (lo_X + hi_X)/2; // Max X, rel east wall. #local ch_lo_X = lo_X - ch_len; // Min X, rel east wall. #end #end #if (ch_dir.x = 0) // Channel parallel to Y axis: #local ch_md_X = ch_pos; // Midline X. #local ch_lo_X = ch_md_X - ch_wid/2; // Min X, rel east wall.. #local ch_hi_X = ch_lo_X + ch_wid; // Max X, rel east wall.. #if (ch_dir.y > 0) #local ch_lo_Y = (lo_Y + hi_Y)/2; // Min Y, rel east wall. #local ch_hi_Y = hi_Y + ch_len; // Max Y, rel east wall. #else #local ch_hi_Y = (lo_Y + hi_Y)/2; // Max Y, rel east wall. #local ch_lo_Y = lo_Y - ch_len; // Min Y, rel east wall. #end #end #local ch_hi_Z = hi_Z; // Max Z, rel OP. #local ch_lo_corner = < ch_lo_X, ch_lo_Y, ch_lo_Z >; #local ch_hi_corner = < ch_hi_X, ch_hi_Y, ch_hi_Z >; box{ ch_lo_corner - + epsv, ch_hi_corner + - epsv } #end // ---------------------------------------------------------------------- // GENERIC RECTANGULAR GRIDS #macro generic_ref_grid(org, U,lo_U,hi_U, V,lo_V,hi_V, step, diag, mids, line_R) // A rectangular frame with sides parallel to the vectors {U} and {V}, // assumed ortogonal. The frame passes through the point {org} // and extends from from coordinate {lo_U} to {hi_U} in the // {U} direction and {lo_V} to {hi_V} in the {V} direction. // // If {step} is positive, the frame is // filled with a regular grid, with gridline spacing {step*U} and // {ste*V}, with origin at {org}. // If {mids} is positive, draws lines parallel to {U} and {V} // that bisect the rectangle. If {diag} is positive, draws the // diagonals of the frame. // // The grid, middle, and diagonal lines (if any) have radius {line_R}, // and the frame sides are twice as thick. #local org_dot_R = 2.0*line_R; #local big_rod_R = 1.5*line_R; // Thick line. #local sma_rod_R = 1.0*line_R; // Thin line. #local crn_dot = sphere{ <0,0,0>, big_rod_R } // Corner-filling dot. #local big_rod_U = cylinder{ lo_U*U, hi_U*U, big_rod_R } #local big_rod_V = cylinder{ lo_V*V, hi_V*V, big_rod_R } #local sma_rod_U = cylinder{ lo_U*U, hi_U*U, sma_rod_R } #local sma_rod_V = cylinder{ lo_V*V, hi_V*V, sma_rod_R } union{ object{ crn_dot translate org + lo_U*U + lo_V*V } object{ crn_dot translate org + lo_U*U + hi_V*V } object{ crn_dot translate org + hi_U*U + lo_V*V } object{ crn_dot translate org + hi_U*U + hi_V*V } object{ big_rod_U translate org + lo_V*V } object{ big_rod_U translate org + hi_V*V } object{ big_rod_V translate org + lo_U*U } object{ big_rod_V translate org + hi_U*U } #if (mids > 0) #local md_U = (lo_U + hi_U)/2; #local md_V = (lo_V + hi_V)/2; object{ sma_rod_U translate org + md_V*V } object{ sma_rod_V translate org + md_U*U } #end #if (diag > 0) #local sma_rod_pp_mm = cylinder{ lo_U*U + lo_V*V, hi_U*U + hi_V*V, sma_rod_R } #local sma_rod_pm_mp = cylinder{ lo_U*U + hi_V*V, hi_U*U + lo_V*V, sma_rod_R } object{ sma_rod_pp_mm translate org } object{ sma_rod_pm_mp translate org } #end #if (step > sma_rod_R) #local org_U = vdot(org,U)/vdot(U,U); #local nU = int((lo_U - org_U)/step) - 1; #local bU = nU*step; #while (bU < hi_U) #if (bU > lo_U) object{ sma_rod_V translate org + bU*U } #end #local bU = bU + step; #end #local org_V = vdot(org,V)/vdot(V,V); #local nV = int((lo_V - org_V)/step) - 1; #local bV = nV*step; #while (bV < hi_V) #if (bV > lo_V) object{ sma_rod_U translate org + bV*V } #end #local bV = bV + step; #end #if ((lo_U < org_U) & (hi_U > org_U) & (lo_V < org_V) & (hi_V > org_V)) #local org_dot = sphere{ <0,0,0>, org_dot_R } // Origin dot. object{ org_dot translate org } #end #end } #end #macro generic_horizontal_ref_circle(ctr, rad, mids, line_R) // An horizontal axis-aligned circular frame with the // symmetry axes, centered at {ctr} with radius {rad}. // If {mids} is positive, draws diameters // aligned with the X and Y axes. The diameters have radius {line_R}, // the frame itself is somewhat thicker. #local big_rod_R = 1.5*line_R; // Thick line. #local sma_rod_R = 1.0*line_R; // Thin line. #local rod_WE = cylinder{ <-rad,0,0>, <+rad,0,0>, sma_rod_R } #local rod_NS = cylinder{ <0,-rad,0>, <0,+rad,0>, sma_rod_R } union{ torus{ rad, big_rod_R rotate 90*x } object{ rod_NS } object{ rod_WE } translate ctr } #end // UTILITIES #macro pink_ball(rad) sphere{ <0,0,0>,rad texture{ tx_pink } } #end #macro empty() // A shpere of radius zero centerd at the origin. sphere{ <0,0,0>, 1.0e-6 } #end #macro debug_coord(lab,vv) #debug "\n" #debug "!! " #debug lab #debug " = " #debug str(vv,8,5) #debug "\n" #end #macro debug_int(lab,vv) #debug "\n" #debug "!! " #debug lab #debug " = " #debug str(vv,1,0) #debug "\n" #end #macro debug_point(lab,pt) #debug "\n" #debug "!! " #debug lab #debug " = < " #debug str(pt.x,6,3) #debug " " #debug str(pt.y,6,3) #debug " " #debug str(pt.z,6,3) #debug " >\n" #end