OpenGL and Direct3D are for sissies...
...real men do their 3-d graphics in PostScript! :-)
What the Cantor dust is in one dimension and the Sierpinski carpet in two, the Menger sponge (also known as the Sierpinski cube) is in three dimensions. Start with a cube and divide it into 3*3*3 smaller cubes; then remove those that do not touch any of the edges of the original cube. This leaves 20 out of the 27 smaller cubes. Now the same step can be performed on them, resulting in an object composed of 400 even smaller cubes, and so on. The volume of the object tends towards zero, but its surface increases beyond all bounds. The picture shown here is the object obtained after we perform this step four times.
Anyway, I thought it would be fun to draw this in PostScript. It doesn't have any particular support for 3-d graphics, so we have to project things by ourselves. The surface of the sponge consists of a number of small squares; we just have to be careful to draw them in the correct order, so that the ones which appear closer to the viewer will be drawn last (and thus won't be obscured by other things). The correct order depends on the angle from which we are looking at the object; the one used by the showCube
procedure below is suitable for the particular angles (lat
and lon
) used, but if these were changed considerably, the procedure might need to be rearranged a bit.
%!PS-Adobe-2.0 EPSF-2.0 %%BoundingBox: 109 199 495 600 /n 4 def % approximation level of the fractal /xyColor { 1 0.5 0.5 setrgbcolor } def /xzColor { 0.5 1 0.5 setrgbcolor } def /yzColor { 0.5 0.5 1 setrgbcolor } def /distanceFromCamera 2.5 def /lon 50 def /lat 36 def % to rotate the object /scale 600 def % larger values = larger object /pow { % a b pow -> a^b 2 dict begin /b exch def /a exch def 1 { b 0 le { exit } if a mul /b b 1 sub def } loop end } def /isPresent { % x y z isPresent --> true/false 20 dict begin /z exch def /y exch def /x exch def x 0 lt y 0 lt or z 0 lt or x n3 ge or y n3 ge or z n3 ge or { false } { { n 0 le { true exit } if x 3 mod 1 eq { 1 } { 0 } ifelse y 3 mod 1 eq { 1 } { 0 } ifelse z 3 mod 1 eq { 1 } { 0 } ifelse add add 2 ge { false exit } if /x x 3 idiv def /y y 3 idiv def /z z 3 idiv def /n n 1 sub def } loop } ifelse end } def /map3dTo2d { % x y z map3dTo2d --> xMapped yMapped 30 dict begin /zi exch n3 2 div sub n3 div def /yi exch n3 2 div sub n3 div def /xi exch n3 2 div sub n3 div def % Rotate by 'lon' degrees around the z-axis. xi lon cos mul yi lon sin mul sub % new xi xi lon sin mul yi lon cos mul add % new yi /yi exch def /xi exch def % Rotate by 'lat' degrees around the y-axis. xi lat cos mul zi lat sin mul sub % new xi xi lat sin mul zi lat cos mul add % new zi /zi exch def /xi exch def % Project. /xi xi distanceFromCamera add def yi xi div scale mul zi xi div scale mul end } def /xyfacet { 30 dict begin /zi exch def /yi exch def /xi exch def newpath xi yi zi map3dTo2d moveto xi yi 1 add zi map3dTo2d lineto xi 1 add yi 1 add zi map3dTo2d lineto xi 1 add yi zi map3dTo2d lineto xyColor fill end } def /xzfacet { 30 dict begin /zi exch def /yi exch def /xi exch def newpath xi yi zi map3dTo2d moveto xi yi zi 1 add map3dTo2d lineto xi 1 add yi zi 1 add map3dTo2d lineto xi 1 add yi zi map3dTo2d lineto xzColor fill end } def /yzfacet { 30 dict begin /zi exch def /yi exch def /xi exch def newpath xi yi zi map3dTo2d moveto xi yi zi 1 add map3dTo2d lineto xi yi 1 add zi 1 add map3dTo2d lineto xi yi 1 add zi map3dTo2d lineto yzColor fill end } def /showCube { 30 dict begin 0 1 n3 1 sub { % We will now show level r % (z-coordinate from r to r+1). /r exch def % First show the bottom facets. 0 1 n3 1 sub { /yi exch def 0 1 n3 1 sub { /xi exch def xi yi r 1 sub isPresent xi yi r isPresent not and { xi yi r xyfacet} if } for } for % Then show the facets which are not % perpendicular to the z-axis. 0 1 n3 { /yi exch def n3 -1 0 { /xi exch def xi yi 1 sub r isPresent xi yi r isPresent not and { xi yi r xzfacet } if } for n3 -1 0 { /xi exch def xi yi r isPresent xi 1 sub yi r isPresent not and { xi yi r yzfacet } if } for } for % For the last (topmost) layer, % also show the top facets. r n3 1 sub eq { 0 1 n3 1 sub { /yi exch def 0 1 n3 1 sub { /xi exch def xi yi r isPresent { xi yi r 1 add xyfacet } if } for } for } if } for end } def gsave 0.2 setlinewidth /n3 3 n pow def % Center it on the A4 sheet of paper. 0.5 595 mul 0.5 842 mul translate showCube grestore showpage
You can copy the above code into a file and send it to your favourite PostScript printer, or open it in a viewer such as Ghostview.
For a level-4 sponge, such as we see in the picture above, this draws 168192 facets. When I tried converting this PostScript file to PDF, the resulting PDF file was several megabytes long, because PDF is not really a programming language with loops and so forth, and the PDF file simply contained all the objects drawn by the above program. However, of these 168192 facets, most aren't really visible in the end because they are obscured by other facets. I wrote a C++ program to determine which ones are completely obscured by others and may be removed; only approx. 22000 facets were left, and the image when rendered at 1200 DPI was completely unchanged; the resulting PDF file was only about 400 KB long.
P.S. Since the title mentions sissies, this comic should not be missed.
3 Comments:
This is a complete surprise, a fan of history books who can program in PostScript. None of my classmates at the faculty for physics knew this language.
In fact I think that if the same experiment were repeated at the CS dept., the results wouldn't be much different :) Which is not suprising, as it's a completely useless language, unless you need to talk to printers or something like that (which most people don't). I learnt it mostly because it can be quite handy for preparing illustrations for use with TeX. And it's also interesting as a kind of curiosity due to its stack-based paradigm.
Incidentally, I would guess that many physicists are probably fond of Hewlett-Packard calculators, which (if I understand correctly) lean heavily on postfix notation and stack-based processing. If so, they might find PostScript quite congenial to their tastes. :)
Yes. :) HP calculators are neat also because of this special notation called RPN. Not all of them implements it, and I don't think HP makes such calculators any more. I have a bit older model 32SII that has RPN and I am fond of it.
So you are a TeXmaster too, another surprise. What is your formal education anyway; and what do you do for a living? You don't have to answer these questions of course, I am just growing very curious.
Well, good luck.
Post a Comment
<< Home