/* RoundedLPrism_padding.pov 2010 Samuel Benge A WIP. To see an animation, render with: +a0.3 +am2 +r3 +w512 +h512 +kff20 The animation shows how, as the arc radii of each point are increased, the arcs will auto- matically fit themselves if the values are either too large or too small. It currently has problems if the corner angles are much too acute. Change f_pigment's trans- late value to 40 to see. */ // this will correlate to the amount of beveling // change it in .05 increments to see what happens #declare inset = 0.1; // default arc radius #declare eRad_default = 0.0001+clock/2; #include "shapes.inc" #default{finish{ambient 1}} // a pigment function to disturb the points #declare f_pigment = function{ pigment{ granite scale .01 frequency 2 translate 44 } }; // the points #declare np = 7; #declare pts = array[np]; #declare V=0; #while(V*(f_pigment(V,0,0).x); #declare V=V+1; #end // line thickness for display (in pixels) #declare lthk = 1/image_width; // enable arc auto fitting #declare autofit = true; // number of points in array #declare npts = dimension_size(pts,1); // el modulo #macro WrapV(V, Repeat) mod(V+Repeat, Repeat) #end // line intersection for a pair of 2D lines , C,D> #macro Line_Intersect_2D(A,B,C,D) #local m1 = (A.y-B.y)/(A.x-B.x); #local m2 = (C.y-D.y)/(C.x-D.x); #local b1 = A.y - m1*A.x; #local b2 = C.y - m2*C.x; #local slope_intercept_x = (b2-b1)/(m1-m2); #local slope_intercept_y = m1*slope_intercept_x + b1; #end // IArc_2D(A,B,C) // fits an arc into the equal sides of an an Isosceles triangle based on three 2D points // line A, B: assumed symmetric bisecting line, A = apex, B = bisecting line point // line A, C: assumed equal side, A = apex, C = end point #macro IArc_2D(A,B,C) #local perpC = C+VPerp_To_Vector(-); #local intersect = Line_Intersect_2D(A,B,C,perpC); #local bisector = vnormalize(B-A); #declare IArc_radius = vlength( intersect - C ); #declare IArc_offset = A+bisector*vlength(A-intersect); #declare IArc_angle = VAngleD( A-intersect, C-intersect )*2; #end // out: IArc_radius, IArc_offset, IArc_angle union{ #macro get_metrics() // if a point-specific arc radius is available, use it, otherwise use default #if(pts[V].z!=0) #declare eRad = pts[V].z; #else #declare eRad = eRad_default; #end // point CCW, middle, CW #local ptL = < pts[WrapV(V-1,npts)].x, pts[WrapV(V-1,npts)].y, 0 >; #local ptM = < pts[V].x, pts[V].y, 0>; // middle point #local ptR = < pts[WrapV(V+1,npts)].x, pts[WrapV(V+1,npts)].y, 0 >; // the actual corner normal, point B for arc #declare cNA = ptM + vnormalize( vnormalize(ptR-ptM) + vnormalize(ptL-ptM) ); // autofit #if(1) // test edge radius (for display only) #declare TER = eRad; // find center of CW, CCW line segments #declare cePtL = (ptL+ptM)/2; #declare cePtR = (ptR+ptM)/2; // intersection of inset lines #local li = Line_Intersect_2D( ptM, cNA, cePtL+VPerp_To_Vector(ptM-ptL)*inset, ptM+VPerp_To_Vector(ptM-ptL)*inset ); // length of line from middle point to the point perpendicular to li #local ilength = vlength( (li +VPerp_To_Vector(ptM-ptR)*inset ) -ptM )+0.00001; // test for inside angle and enforce minimum distance #if( VEq( ptM + VPerp_To_Vector( (ptM + vnormalize(ptR-ptM)*eRad) - (ptM + vnormalize(ptL-ptM)*eRad ) ), cNA) ) #declare eRad = max(eRad,ilength); #end // the length from middle point to the segment's center #local distL = vlength(cePtL-ptM); #local distR = vlength(cePtR-ptM); // the minimum distance #local distMin = min(distL,distR); // enforce maximum distance #declare eRad = min(eRad,distMin); #end // ~autofit // extend from corners CW, CCW by eRad #declare eCW = ptM + vnormalize(ptR-ptM)*eRad; #declare eCCW = ptM + vnormalize(ptL-ptM)*eRad; // perpendicular extension from eCW, point C for arc #declare epCW = eCW + VPerp_To_Vector( eCW - ptM )*inset; // perpendicular extension from eCCW #declare epCCW = eCCW + VPerp_To_Vector( ptM - eCCW)*inset; // perpendicular extensions from segment center points #declare epCPL = cePtL + VPerp_To_Vector( ptM - cePtL)*inset; #declare epCPR = cePtR - VPerp_To_Vector( ptM - cePtR)*inset; // inward corner normal #local cN = VPerp_To_Vector( eCW - eCCW ); // perpendicular extension from epCW #local backtrack = epCW+VPerp_To_Vector( epCW-eCW )*eRad*2; // might need to be changed for highly-acute angles // finds point A for arc #local pA = ptM; #local pB = ptM+cN*.5; #local pC = epCW; #local pD = backtrack; #declare cNIsect = Line_Intersect_2D(pA,pB,pC,pD); #end // get_metrics out: eRad, cN, cNA, eCW, eCCW, epCW, epCCW, cNIsect, cePtL, cePtR, epCPL, epCPR // Object Assembly Main Loop #declare V = 0; #while(V < npts) // generate some variables get_metrics() // edge radius test points union{ sphere{ pts[V] + vnormalize(pts[WrapV(V-1,npts)]-pts[V])*min(TER,eRad), lthk*2 } sphere{ pts[V] + vnormalize(pts[WrapV(V+1,npts)]-pts[V])*min(TER,eRad), lthk*2 } pigment{rgb x+y} } IArc_2D( cNIsect, cNA, epCW ) // arc (yellow) torus{ IArc_radius, lthk*3 clipped_by{ object{ Wedge(IArc_angle) rotate -y*IArc_angle/2 } } rotate x*90 Point_At_Trans( cNA-cNIsect ) translate IArc_offset pigment{rgb x+y} } // connecting lines (yellow) #if(VEq(epCW,epCPR)=0) cylinder{epCW,epCPR, lthk*3 pigment{rgb x+y}} #end #if(VEq(epCCW,epCPL)=0) cylinder{epCCW,epCPL, lthk*3 pigment{rgb x+y}} #end // representation of corner, extension and inset points union{ sphere{pts[V], lthk*4} sphere{epCW, lthk*2} sphere{epCCW, lthk*2} sphere{cNIsect, lthk*2} // CW & CWW extensions from corners sphere{eCW, lthk*2 pigment{rgb x+y}} sphere{eCCW, lthk*2 pigment{rgb x+y}} pigment{rgb x+y} } // representation of inset lines union{ cylinder{pts[V],cNIsect,lthk} cylinder{epCCW,cNIsect,lthk} cylinder{cNIsect,epCW,lthk} // CW & CWW perpendicular extensions cylinder{eCW, epCW, lthk} cylinder{eCCW, epCCW, lthk} pigment{rgb z+x} } // basic liner_spline from points cylinder{pts[V],pts[WrapV(V+1,npts)],lthk} #declare V=V+1; #end pigment{rgb x} } camera{ orthographic right x*2 up y*2 location -z*10 }