/* rounded_lsweep.inc 2010 Samuel Benge */ #include"shapes.inc" #macro rounded_lsweep_torus_wedge( Angle, R1, R2 ) torus{ R1, R2 clipped_by{ Wedge( Angle ) } rotate -y*Angle/2 } #end /* Rune's macro for aligning an object based on the z and y axes. The z-axis will be given precedence over the y-axis. */ #macro rounded_lsweep_z_align( Normal_vector, Z_vector ) #local ObjectZ = vnormalize( Z_vector ); #local ObjectY = VPerp_Adjust( Normal_vector, Z_vector ); #local ObjectX = vcross( ObjectY, ObjectZ ); transform{ Shear_Trans( ObjectX, ObjectY, ObjectZ ) } #end // wrap a value; useful for safely accessing an array #macro rounded_lsweep_wrap_value( value, array_size ) mod( value+array_size*array_size, array_size ) #end #macro rounded_lsweep_get_metrics( pt_array, pt, adir, rad ) #local n_pts = dimension_size( pt_array, 1 ); // accessing the array in a wrap-friendly way #local pt_plus = rounded_lsweep_wrap_value( pt+1, n_pts ); #local pt_minus = rounded_lsweep_wrap_value( pt-1, n_pts ); // end point corrections #if( rounded_lsweep_closed = true & pt = 0 ) #local pt_plus = rounded_lsweep_wrap_value( pt+1, n_pts ); #local pt_minus = rounded_lsweep_wrap_value( pt-2, n_pts ); #end #if( rounded_lsweep_closed = true & pt = n_pts-1 ) #local pt_plus = rounded_lsweep_wrap_value( pt+2, n_pts ); #local pt_minus = rounded_lsweep_wrap_value( pt-1, n_pts ); #end // custom arc radius #if( pt_array[pt].t > 0 ) #local rad2 = pt_array[pt].t; #else #local rad2 = rad; #end // converting vectors from 4D to 3D #local point_mid = < pt_array[pt].x, pt_array[pt].y, pt_array[pt].z >; #local point_minus = < pt_array[pt_minus].x, pt_array[pt_minus].y, pt_array[pt_minus].z >; #local point_plus = < pt_array[pt_plus].x, pt_array[pt_plus].y, pt_array[pt_plus].z >; // getting the middle normal for this point #declare rounded_lsweep_this_normal = vnormalize( vnormalize( point_plus - point_mid ) + vnormalize( point_minus - point_mid ) ); // the angle between three points #local corner_angle = VAngleD( point_plus - point_mid , point_minus - point_mid ); // the actual angle for the arc #declare rounded_lsweep_round_angle = 180 - corner_angle; // a safe distance for line intersection #local large_distance = max( vlength( point_plus - point_mid ) , vlength( point_minus - point_mid ) ); // angle and line metrics for either direction #local rad_ang = < sin( radians( (rounded_lsweep_round_angle/2)*adir ) ) , cos( radians( (rounded_lsweep_round_angle/2)*adir ) ) >*rad2; #local rad_extend = rad_ang + < sin( radians( (corner_angle/2)*-adir ) ) , cos( radians( (corner_angle/2)*-adir ) ) >*large_distance; #local p1 = rad_ang; #local p2 = rad_extend; // a ratio for properly extending arc and line points #if(adir=1) #local Ratio = abs( p2.x ) / ( p2.x - p1.x ); #else #local Ratio = abs( p2.x ) / ( p1.x - p2.x ); #end // a value for extending arc and line points #declare rounded_lsweep_this_offset = ( p2.y - p1.y )*Ratio + p2.y; // getting the point for this direction's line segment #if(adir=1) #local ldir = vnormalize( point_plus - point_mid ); #else #local ldir = vnormalize( point_minus - point_mid ); #end #local ldist = vlength( y*rounded_lsweep_this_offset - p1 ); // actual point for this line #declare rounded_lsweep_line_point = point_mid+ldir*ldist; #end #macro rounded_lsweep( pts, arc_radius, line_thickness ) union{ #local n_pts = dimension_size(pts,1); // is the spline closed? #if( pts[0].x = pts[n_pts-1].x & pts[0].y = pts[n_pts-1].y & pts[0].z = pts[n_pts-1].z) #declare rounded_lsweep_closed = true; #else #declare rounded_lsweep_closed = false; #end // converting vectors from 4D to 3D #local new_pts = array[n_pts]; #local V = 0; #while( V < n_pts ) #local new_pts[V] = < pts[V].x, pts[V].y, pts[V].z >; #local V = V + 1; #end #local V = 0; #while( V < n_pts ) // points #if( V < n_pts -1 ) // line segments // get first point for segment rounded_lsweep_get_metrics( pts, rounded_lsweep_wrap_value(V+1,n_pts), -1, arc_radius ) #if( V+1 = n_pts-1 & rounded_lsweep_closed = 0 ) #local lp1 = new_pts[V+1]; disc{ new_pts[V+1], vnormalize( new_pts[V+1]-new_pts[V] ), line_thickness } #else #local lp1 = rounded_lsweep_line_point; #end // get second point for segment rounded_lsweep_get_metrics( pts, rounded_lsweep_wrap_value(V,n_pts), 1, arc_radius ) #if( V = 0 & rounded_lsweep_closed = 0 ) #local lp2 = new_pts[V]; disc{ new_pts[V], vnormalize( new_pts[V]-new_pts[V+1] ), line_thickness } #else #local lp2 = rounded_lsweep_line_point; #end // place segment #if( vlength( lp2-lp1 ) != 0 ) cylinder{ lp1, lp2, line_thickness open } #end #if( V > 0 | rounded_lsweep_closed = true ) // arcs // get metrics for arc offset from point rounded_lsweep_get_metrics( pts, V, 1, arc_radius ) // stuff for a custom arc radius #if( pts[V].t > 0 ) #local arc_radius2 = pts[V].t; #else #local arc_radius2 = arc_radius; #end // arc placement #if( rounded_lsweep_round_angle > 0 ) object{ rounded_lsweep_torus_wedge( rounded_lsweep_round_angle, arc_radius2, line_thickness ) rotate z*90 rounded_lsweep_z_align( new_pts[V]-new_pts[V+1], -rounded_lsweep_this_normal ) translate new_pts[V]+rounded_lsweep_this_normal*rounded_lsweep_this_offset } #end #end // ~arcs #end // ~line segments #local V = V + 1; #end // ~points loop } #end #macro rounded_lsweep_actual( pts, sphere_radius ) union{ #local n_pts = dimension_size(pts,1); #local V = 0; #while( V < n_pts ) // points // display points sphere{ < pts[V].x, pts[V].y, pts[V].z >, sphere_radius pigment{ rgb x+y } } #if( V < n_pts -1 ) // line segments // display linear spline cylinder{ < pts[V].x, pts[V].y, pts[V].z >, < pts[V+1].x, pts[V+1].y, pts[V+1].z >, sphere_radius/2 pigment{ rgb x } } #end #local V=V+1; #end } #end