%let name=spinward; /* This is my slight modification of Richard's DeVenezia's animation from here: http://www.devenezia.com/downloads/sas/samples/spinward-triangles-anim1.sas Robert Allison (January 2012) */ /* Richard says: * This code is courtesy of R. Forrest McCluer, 11/4/2005. * "I thought that you might like this DSGI code - it is a variation of your * descent program, albeit without the fill color gradient." * * I cleaned up the macros, some of the calling sequences and added * the anim1 macro destined for GIFANIM output. * - Richard A. DeVenezia 01may2006 * * Note: This sample code is sized for customization of Motorola Razr v3 phones. * The utility "P2k Commander" (http://s5vi.vxxxstuff.com/) can be used to copy the output file * graphics.gif over the phones /a/custwakeup.gif, thus replacing the hohum * Cingular branded poweron animation. */ %macro ComputeNestedTriangles ( data=Triangles /* name of table to contain coordinates */ , levels = 0 /* numbers of levels of nesting of triangles */ , radius = 50 , x0 = 50 , y0 = 50 , tilt = 0 /* clockwise degrees baseline tilted */ ); /* * X,Y coordinate units are LL(0,0) UR(100,100) and * correspond to percent of active viewport */ * Step 0 - construct an outer triangle; data &DATA. (keep=level--y3); length level radius theta x0 y0 x1 y1 x2 y2 x3 y3 8; d2r = atan( 1 ) / 45; /* degrees to radians */ radius = &RADIUS.; x0 = &X0.; label x0 = 'x0: Center of Triangle'; y0 = &Y0.; label y0 = 'y0: Center of Triangle'; theta = -30 - &TILT.; x1=x0+(radius)*cos(d2r*(theta+0*120)); y1=y0+(radius)*sin(d2r*(theta+0*120)); x2=x0+(radius)*cos(d2r*(theta+1*120)); y2=y0+(radius)*sin(d2r*(theta+1*120)); x3=x0+(radius)*cos(d2r*(theta+2*120)); y3=y0+(radius)*sin(d2r*(theta+2*120)); level=0; run; * poor mans recursion, one data step per level descended; %local level; %do level=1 %to &levels; data &DATA. (keep=level--y3); set &DATA.; output; if level = &level-1 then do; * recurse; * nest four triangles within current triangle; level = level + 1; radius = radius / 2; x00 = x0; y00 = y0; x10 = x1; y10 = y1; x20 = x2; y20 = y2; x30 = x3; y30 = y3; x1= x10; y1= y10; x2=(x10+x20)/2; y2=(y10+y20)/2; x3=(x10+x30)/2; y3=(y10+y30)/2; x0=(x1+x2+x3)/3; y0=(y1+y2+y3)/3; output; x1=(x20+x10)/2; y1=(y20+y10)/2; x2= x20; y2= y20; x3=(x20+x30)/2; y3=(y20+y30)/2; x0=(x1+x2+x3)/3; y0=(y1+y2+y3)/3; output; x1=(x30+x10)/2; y1=(y30+y10)/2; x2=(x30+x20)/2; y2=(y30+y20)/2; x3= x30; y3= y30; x0=(x1+x2+x3)/3; y0=(y1+y2+y3)/3; output; * the central nested triangle is * flipped with respect to parent triangle; x1=(x10+x20)/2; y1=(y10+y20)/2; x2=(x20+x30)/2; y2=(y20+y30)/2; x3=(x30+x10)/2; y3=(y30+y10)/2; x0=(x1+x2+x3)/3; y0=(y1+y2+y3)/3; theta = mod (theta + 180, 360); output; end; keep x0-x3 y0-y3 level radius theta; run; %end; %mend; %macro PlotSpinwardTriangles ( data = Triangles , level = 0 , step = 5 , steps = 36 , glib = work , gmem = triangles ); data _null_; rc=gset('catalog',"&GLIB.","&GMEM."); rc=ginit(); rc=graph('clear','spinward'); rc=gset('colrep',1,'blue'); rc=gset('colrep',2,'red'); rc=gset('lincolor',1); rc=gset('linwidth',1); d2r = atan( 1 ) / 45; do until (last); set &DATA. end=last; if level ne &LEVEL. then continue; * rc=gdraw('ellarc',x0,y0,radius*2,radius*2,0,360,0); x10=x1; y10=y1; x20=x2; y20=y2; x30=x3; y30=y3; theta0 = theta; * step = 180 / &STEPS.; step = &STEP.; angle_c = 180 - 30 - step; nradius = radius; do itheta = theta to theta + &STEP. * &STEPS. /*180*/ by step; rc=gdraw('line',2,x10,x20,y10,y20); rc=gdraw('line',2,x20,x30,y20,y30); rc=gdraw('line',2,x30,x10,y30,y10); x10=x0+(nradius)*cos(d2r*(itheta+0*120)); x20=x0+(nradius)*cos(d2r*(itheta+1*120)); x30=x0+(nradius)*cos(d2r*(itheta+2*120)); y10=y0+(nradius)*sin(d2r*(itheta+0*120)); y20=y0+(nradius)*sin(d2r*(itheta+1*120)); y30=y0+(nradius)*sin(d2r*(itheta+2*120)); nradius = nradius / sin(angle_c*d2r) * sin(30*d2r); end; end; rc=graph('update'); rc=gterm(); stop; run; %mend; %macro NestedSpinwardTriangles ( levels = 0 , x0 = 50 , y0 = 50 , radius = 50 , tilt = 0 , step = 5 , steps = 36 ); %ComputeNestedTriangles (data=Triangles, levels=&levels, x0=&x0, y0=&y0, radius=&radius, tilt=&tilt); %PlotSpinwardTriangles (data=Triangles, level =&levels, step=&step, steps=&steps); %mend; options mprint; %macro anim1; %put %sysfunc(FDELETE(GOUT)); %if %sysfunc(cexist(WORK.TRIANGLES)) %then %do; proc datasets nolist lib=WORK; delete TRIANGLES / mt=catalog; quit; %end; /* goptions gsfmode=replace; */ options nomprint; %let radius = 20; %let levels = 0; %let tilt = 0; %let lo = -26; %let hi = +60; %do i =&lo %to &hi; %let y0 = &i; %if &i > %eval(&hi-45) %then %let radius = %eval(&radius-2); %NestedSpinwardTriangles ( levels = &levels , y0 = &y0 , radius = &radius , tilt = &tilt , steps = 0 ); goptions gsfmode=append; /* after the first image, then append the next images */ %let i = %eval(&i+4); %end; %let radius = 0; %let levels = %eval(&levels+2); %do i = 1 %to 20; %let radius = %sysevalf((1+&radius)**1.05); %NestedSpinwardTriangles ( levels = &levels , y0 = &y0 , radius = &radius , tilt = &tilt , steps = 0 ); %end; %let n = 15; %do i = 1 %to &n; %let tilt = %sysevalf(&tilt + 120 / &n ); %NestedSpinwardTriangles ( levels = &levels , y0 = &y0 , radius = &radius , tilt = &tilt , steps = 0 ); %end; %let n = 20; %do i = 1 %to &n; %let steps = &i; %let tilt = %sysevalf(&tilt + 120 / &n ); %NestedSpinwardTriangles ( levels = &levels , y0 = &y0 , radius = &radius , tilt = &tilt , step = %sysevalf ( 120 / &n ) , steps = &steps ); %end; %mend; /* -----------------------------------------------------------*/ /* ODS hasn't automated doing a simple gifanimation yet, so we have to do some manual scripting of the html file ... */ /** Create the HTML file that will display the **/ /** GIF animation. **/ data _null_; file "&name..htm"; put ''; put '(SAS/Graph gifanim) '; put ''; put '
'; put '

'; put ''; put ''; filename gifname "&name..gif"; /* Set the GOPTIONs necessary for the animation */ goption reset device=gifanim gsfname=gifname gsfmode=replace /* For the first graph, gsfmode=replace */ disposal=background /* none, background, previous, or unspecified */ userinput /* allow user input during animation, if supported by browser */ delay=10 /* .10 seconds between images */ iteration=1 /* loop through animation 3 time (0=infinite) */ /* xpixels=170 ypixels=220 */ xpixels=340 ypixels=440 hsize= vsize= ; goptions cback=white gunit=pct border; %anim1; /* Now, write out the end of the animated gif trailer - otherwise it won't play in some gif players. Internet Explorer will sometimes display animated GIFs that do not have it, but the W3C spec says it is required. Office 2002 and 2003 apparently do not recognize the files unless they include this trailer. */ data _null_; file gifname recfm=n mod; put '3B'x; run; quit; /* options xmin noxwait noxsync; x start "Preview" "%sysfunc(pathname(GOUT))"; */