|
![](/i/fill.gif) |
Janet's image in
http://news.povray.org/povray.binaries.images/thread/%3Cweb.4494513cc659528fa30dd5a00%40news.povray.org%3E/
motivated me to clean up my Penrose macros and she wanted to see them, so
they are coming in this thread, along with several demo images...
(Provided I can get all the software to work the way I want it to.)
The macros are pretty short, but the demonstration scene file is much longer
than it needs to be for any one image, because it has #if's all over it so
it can do them all at the same time. (I should have made it generate each
image based on the clock, but I haven't done it in a long time and my first
guess at it was wrong.)
Note that the macros only generate tile type, placement, and orientation
information. The scene file has all the information about actual shapes,
colors, etc. In particular, notice that the Ammon Bars for the Dart tile
go outside the boundaries of the dart itself.
As for cloning Janet's image with my macros, I haven't done it, but it looks
like it is a Kite&Dart pattern with each tile broken in half and colored
seperately. The colors look like they are a random function based on the
distance from the center point of the image. Doing either of those things,
or both of them should not be difficult with these macros.
Let me know if you like (or don't like) them, and any changes you would like
(or have made). Finally, please don't judge them based on the colors and
textures in the images, they can be described in no other way than "utterly
simplistic in the extreme".
Jon
----- Begin Penrose.inc -----
// Penrose tiling macros
// ---------- Penrose Constants ----------
#declare phi = (sqrt (5) + 1) / 2; // ~= 1.61803
#declare c36 = phi / 2; // = cos ( pi / 5) ~= 0.80902
#declare c72 = (phi - 1) / 2; // = cos (2 * pi / 5) ~= 0.30902
#declare s36 = sqrt ((5 - sqrt (5)) / 8); // = sin ( pi / 5) ~= 0.58779
#declare s72 = sqrt ((5 + sqrt (5)) / 8); // = sin (2 * pi / 5) ~= 0.95106
// ---------- Macros to cache results of inflation ----------
// This isn't strictly necessary, but due to the way tiles overlap when
// the inflation routines operate on tiles, many duplicate tiles will be
// generated without doing this. The procedure is simple, take the location
// of a new tile, and check the array entry for that location. If false,
// the tile has not been done yet. If true, it's already been done, so skip
it.
// This should be done at every level of the recursion to really be worth
while.
#declare inflate_cache_scale = phi + 1;
// Use this to initialize everything, the values define the rectangle where
// Penrose tiles will be allowed, level is the maximum level of recursion
// the inflation routines will be using.
#macro inflate_init (min_r, min_c, max_r, max_c, level)
#declare inflate_minr = min_r;
#declare inflate_minc = min_c;
#declare inflate_maxr = max_r - min_r;
#declare inflate_maxc = max_c - min_c;
#local inflate_rs = ceil (inflate_cache_scale * inflate_maxr);
#local inflate_cs = ceil (inflate_cache_scale * inflate_maxc);
#declare inflate_done = array[inflate_rs][inflate_cs][level+1];
#local row = 0;
#while (row < inflate_rs)
#local col = 0;
#while (col < inflate_cs)
#local lev = 0;
#while (lev < level + 1)
#declare inflate_done[row][col][lev] = false;
#local lev = lev + 1;
#end
#local col = col + 1;
#end
#local row = row + 1;
#end
#end
// This macro will determine if the tile has already been generated. If it
hasn't
// been generated yet, call PENROSE_object to generate it.
#macro PENROSE_cache (pos, ang, level)
#local row = floor (inflate_cache_scale * pos.x) - inflate_minr;
#local col = floor (inflate_cache_scale * pos.z) - inflate_minc;
#if (row > 0 & row < inflate_maxr & col > 0 & col < inflate_maxc)
#if (inflate_done[row][col][level] = false)
#declare inflate_done[row][col][level] = true;
PENROSE_object (pos, ang, level)
#end
#end
#end
// ---------- Thick & Thin Rhomb macros ----------
// The Rhomb's sides are all of length 1. The thick
// rhomb has angles of 72 and 108 degrees, the thin
// rhomb uses angles of 36 and 144 degrees instead.
// Given the center and orientation of a thick tile,
// generate the corners of the tile and pass them to the
// "thick_corners" macro.
#macro PENROSE_thick_corners (pos, ang)
#local major = c36 * vrotate (x, ang * y);
#local minor = s36 * vrotate (x, (ang + 90) * y);
PENROSE_object (pos + major, pos + minor, pos - major, pos - minor)
#end
// Inflate a thick rhomb. The original rhomb should be centered
// at "pos", and be oriented in the direction "ang".
#macro thick (pos, ang, level)
#macro PENROSE_object (pos, ang, level)
#if (level < 1)
PENROSE_thick (pos, ang)
#else
#local new = 2 * c36 * (pos + vrotate((c36 - 1 / (2 * c36)) * x, ang *
y));
thick (new + vrotate (s36 * x, (ang + 54) * y), ang + 144, level - 1)
thin (new + vrotate (s72 * x, (ang + 126) * y), ang + 36, level - 1)
thick (new + vrotate (c36 * x, (ang + 180) * y), ang + 180, level - 1)
thin (new + vrotate (s72 * x, (ang - 126) * y), ang - 36, level - 1)
thick (new + vrotate (s36 * x, (ang - 54) * y), ang - 144, level - 1)
#end
#end
PENROSE_cache (pos, ang, level)
#end
// Now do the same things for the "thin" rhomb. Note the similarities.
// Differences should be in the locations of the corners, and the portion
// of the inflation routine that turns a single tile into multiple tiles.
#macro PENROSE_thin_corners (pos, ang)
#local major = s72 * vrotate (x, (ang + 90) * y);
#local minor = c72 * vrotate (x, ang * y);
PENROSE_object (pos + minor, pos + major, pos - minor, pos - major)
#end
#macro thin (pos, ang, level)
#macro PENROSE_object (pos, ang, level)
#if (level < 1)
PENROSE_thin (pos, ang)
#else
#local new = 2 * c36 * (pos + vrotate(c72 * x, ang * y));
thick (new + vrotate (c36 * x, (ang + 108) * y), ang + 108, level - 1)
thin (new + vrotate (s72 * x, (ang + 162) * y), ang - 108, level - 1)
thin (new + vrotate (s72 * x, (ang - 162) * y), ang + 108, level - 1)
thick (new + vrotate (c36 * x, (ang - 108) * y), ang - 108, level - 1)
#end
#end
PENROSE_cache (pos, ang, level)
#end
// ---------- Kite & Dart macros ----------
// These two macros convert from Kites and Darts to Thick and Thin Rhombs.
#macro PENROSE_kite_rhombs (pos, ang, level)
thick (pos + vrotate (s36 * x, (ang + 126) * y), ang - 144, level)
thin (pos + vrotate (c72 * x, ang * y), ang, level)
thick (pos + vrotate (s36 * x, (ang - 126) * y), ang + 144, level)
#end
#macro PENROSE_dart_rhombs (pos, ang, level)
thick (pos + vrotate (s36 * x, (ang + 54) * y), ang + 144, level)
thick (pos + vrotate (s36 * x, (ang - 54) * y), ang - 144, level)
#end
// These macros are for Kites and Darts. They should look a whole lot
// like the Thick and Thin Rhomb macros, except the corners are a bit
different
// and the inflation itself is a bit different. On the other hand, by
abstracting
// out some mundane thing like PENROSE_cache, we don't have to duplicate all
that
// stuff and can concentrate on stuff that actually matters.
#macro PENROSE_kite_corners (pos, ang)
PENROSE_object (pos + vrotate (2 * c72 * x, ang * y),
pos + vrotate (<c72,0,-s72>, ang * y),
pos + vrotate (-x, ang * y),
pos + vrotate (<c72,0,s72>, ang * y))
#end
#macro kite (pos, ang, level)
#macro PENROSE_object (pos, ang, level)
#if (level < 2)
PENROSE_kite (pos, ang)
#else
#local new = 2 * c36 * pos;
kite (new + vrotate (2 * c72 * x, (ang + 72) * y), ang - 108, level -
1)
dart (new + vrotate ( x, (ang + 144) * y), ang - 144, level -
1)
dart (new + vrotate ( x, (ang - 144) * y), ang + 144, level -
1)
kite (new + vrotate (2 * c72 * x, (ang - 72) * y), ang + 108, level -
1)
#end
#end
PENROSE_cache (pos, ang, level)
#end
#macro PENROSE_dart_corners (pos, ang)
PENROSE_object (pos,
pos + vrotate (<-c72,0,s72>, ang * y),
pos + vrotate (x, ang * y),
pos + vrotate (<-c72,0,-s72>, ang * y))
#end
#macro dart (pos, ang, level)
#macro PENROSE_object (pos, ang, level)
#if (level < 2)
PENROSE_dart (pos, ang)
#else
#local new = 2 * c36 * pos;
dart (new + vrotate ( x, (ang + 72) * y), ang + 144, level -
1)
kite (new + vrotate (2 * c72 * x, ang * y), ang + 180, level -
1)
dart (new + vrotate ( x, (ang - 72) * y), ang - 144, level -
1)
#end
#end
PENROSE_cache (pos, ang, level)
#end
----- End Penrose.inc
Post a reply to this message
Attachments:
Download 'penrose0.png' (565 KB)
Preview of image 'penrose0.png'
![penrose0.png](/povray.binaries.images/attachment/%3Cweb.449aeaa42c4ebcd048362b170%40news.povray.org%3E/penrose0.png?ttop=443866&toff=4400&preview=1)
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
"PM 2Ring" <nomail@nomail> wrote:
> "Jon Buller" <jon### [at] bullers net> wrote:
>
> > The disadvantage is that I am not sure if it is
> > easy/possible to tell which triangles belong to which Kite, Dart, or Rhomb
> > without looking at the triangle's neighbors. I'll play with it some more
> > and see if I can figure it out.
>
> Good luck! I think you will need to examine neighbours.
OK, I now see that doing Rhomb tiling is simple without any duplicate
detection. (That is, the inflation doesn't overlap it's neighbors, and it
works without using that init_inflate macro and friends.)
Consider this:
#macro tri (pos, ang, typ, level)
#if (level < 1)
PENROSE_triangle (pos, ang, typ)
#else
#if (abs(typ) = 18)
tri (phi * (pos + vrotate (x, (ang - typ) * y)),
ang + typ * 6, typ, level - 1)
tri (phi * pos + vrotate (x, (ang + typ) * y),
ang - typ * 6, typ * 3, level - 1)
#else
#local new = phi * pos + (phi - 1) * vrotate (x, (ang + typ) * y);
tri (new, ang, -typ, level - 1)
#local new = new + vrotate (x, (ang - typ) * y);
tri (new, ang - typ * 8/3, typ, level - 1)
tri (new, ang + typ * 8/3, -typ / 3, level - 1)
#end
#end
#end
Call this as the others, pos and ang are the location and orientation of the
triangle, level is how many inflate operations to do. That typ parameter is
the size and orientation of the triangle. It takes values of -54, -18, 18,
and 54. To draw a triangle, draw unit length edges from pos in the
direction of ang + typ and ang - typ (and connect those two points for the
final edge).
It is simple to draw the triangles themselves. But notice that if you draw
each edge (I'll call them +, -, and o) in a different color, all the
triangles have the same edge type for a shared edge. Since a Rhomb is just
two 54 triangles that share an "o" edge, and any triangle with an "o" edge
has the neighbor of that edge that is also an "o" edge. The other
interesting thing is that the other triangle is the negative type of its
neighbor. So to draw rhombs instead of triangles, just ignore the negative
type triangles(-54 & -18), and treat the +54 triangles as rhombs that have
points of pos, pos+, pos-, and pos+- (add the + and - direction vectors
together for pos+-)
Starting with a +54 triangle and a -54 triangle sharing "o" edges, and using
the rhomb generation macros from before with all the decorations on, you get
the attached image. Note that the tri macro does not need that huge array
of true/false values to tell if it has already generated a tile at a
specific location or not, but can still generate a rhomb tiling without any
duplicate objects.
I still haven't figured out how to do Kites & Darts yet, but I think it
might be possible. In fact, I think it's more possible now than I did when
I wrote that last message.
Post a reply to this message
Attachments:
Download 'penrose.png' (183 KB)
Preview of image 'penrose.png'
![penrose.png](/povray.binaries.images/attachment/%3Cweb.44a0d3916376349e2ff3aa640%40news.povray.org%3E/penrose.png?ttop=443866&toff=4400&preview=1)
|
![](/i/fill.gif) |