Skip to content

Instantly share code, notes, and snippets.

@hivehand
Last active November 17, 2022 20:15
Show Gist options
  • Save hivehand/e6ecad689c321a896e3cc6e8efd82628 to your computer and use it in GitHub Desktop.
Save hivehand/e6ecad689c321a896e3cc6e8efd82628 to your computer and use it in GitHub Desktop.
Teeny tiny hexagon tiling
% Draw, in white on black, the set of Pointer Pattern Pad hexagons described
% here:
%
% http://bitsavers.trailing-edge.com/pdf/xerox/mouse/lyon_optical/018P87005_D_Pointer_Pattern_Pad_Oct84.pdf
/inch { 72 mul } def
% Alter the following for different page sizes.
/pagewidth 8.5 inch def
/pageheight 11 inch def
<< /PageSize [pagewidth pageheight] >> setpagedevice
% Alter the following to change the hexagon width (that is, the distance
% between two opposing edges of the same hexagon) and the distance between
% lines of hex edges.
/hexwidth 0.008 inch def
/edgesep 0.007 inch def
% Set this to true if you want a peek at what's actually going on. When
% enabled, the actual page is outlined in red, and zoomed out by a factor of
% two, allowing you to see the linesets used to generate the pattern.
/demo false def
/offset hexwidth edgesep add def
% Given two values, return the one with the greater absolute value.
/abs_max {
2 dict begin
/num1 exch abs def
/num2 exch abs def
num1 num2 gt
{ num1 }
{ num2 }
ifelse
end
} def
% Given an angle, return the width and height of the bounding box encompassing
% the page twisted at that angle.
/get_bounds {
4 dict begin
/twist_angle exch def
/hypotenuse
pagewidth 2 exp
pageheight 2 exp
add sqrt
def
pagewidth pageheight atan dup
/a1 exch twist_angle add def
/a2 exch twist_angle sub def
a1 sin hypotenuse mul
a2 sin hypotenuse mul
abs_max
a1 cos hypotenuse mul
a2 cos hypotenuse mul
abs_max
end
} def
% Given an angle, first compute the bounding box for the page at that angle,
% then rotate to said angle and cover the bounding box with a set of stripes whose
% width is the distance between hexagons, separated by the width of the
% hexagons themselves.
/weave {
6 dict begin
/twist_angle exch def
twist_angle get_bounds
/spanheight exch def
/spanwidth exch def
/stripecount spanwidth offset div round def
/leftedge stripecount -2 div ceiling offset mul
offset 2 div sub def
/bottom spanheight -2 div def
gsave
twist_angle rotate
0 1 stripecount {
offset mul
leftedge add bottom moveto
0 spanheight rlineto
stroke
} for
grestore
end
} def
% Showtime.
% Set the linewidth to match the separation distance between hexagon edges.
edgesep setlinewidth
% Center the page around a hexagon, so that it will be symmetric.
pagewidth 2 div
pageheight 2 div
translate
% Scale the page down if we're in demo mode.
demo { 0.5 0.5 scale } if
% Move to what is now page center.
0 0 moveto
% Draw three sets of lines, twisted 60 degrees relative to one another, to
% create a set of hexagons.
0 60 120 {
weave
} for
% If we're in demo mode, draw the border of the page itself, to verify that
% the bounding boxes are exactly as large as they need to be, and no larger.
demo {
1 0 0 setrgbcolor
0 setlinewidth
pagewidth -2 div pageheight -2 div moveto
0 pageheight rlineto
pagewidth 0 rlineto
0 pageheight neg rlineto
closepath
stroke
} if
showpage
% DON'T USE THIS. Use ppmesh.ps instead.
%
% This was a first attempt, and while it technically works, it turns out to
% be a stupefyingly greedy resource hog that chokes printers and generates a
% 50-megabyte PDF. It's drawing several thousand tiny hexagons. This could
% no doubt be optimized down to reasonable resource consumption, but in this
% particular instance, the spacing of the hexagons means that you can generate
% them via negative space: just draw three sets of parallel lines at 120° to
% one another.
% Draw, in white on black, the set of Pointer Pattern Pad hexagons described
% here:
%
% http://bitsavers.trailing-edge.com/pdf/xerox/mouse/lyon_optical/018P87005_D_Pointer_Pattern_Pad_Oct84.pdf
/inch { 72 mul } def
% Alter the following for different page sizes.
/pagewidth 8.5 inch def
/pageheight 11 inch def
<< /PageSize [pagewidth pageheight] >> setpagedevice
% Alter the following to change the hexagon width (that is, the distance
% between two opposing edges of the same hexagon) and the distance between
% lines of hex edges.
/hexwidth 0.008 inch def
/edgesep 0.007 inch def
% Fill a white hexagon. We cheat and use global variables here because when
% you're drawing a million or so of these, every little performance optimization
% helps.
/hex {
gsave
0 edgelength 2 div rmoveto
120 neg rotate
1 1 5 {
pop
0 edgelength rlineto
60 rotate
} for
closepath
fill
grestore
} def
% Blacken the page.
0 0 0 setrgbcolor
0 0 moveto
0 pageheight lineto
pagewidth pageheight lineto
pagewidth 0 lineto
closepath
fill
% Now set up the hex show.
1 1 1 setrgbcolor
/edgelength
hexwidth 2 div
30 cos div
def
% The distance between any point on a given hex and the corresponding point on
% a neighbor.
/distance edgesep 30 cos div edgelength 2 mul add def
% The number of vertical hex tiles per page.
/tilecount pageheight distance div ceiling def
% The distance between a vertical strip of hexes and its neighbor.
/stripsep hexwidth edgesep add def
% The number of vertical strips spanning the width of the page.
/stripcount pagewidth stripsep div ceiling def
0 0 moveto
% Draw a succession of strips, each consisting of a succession of tiles.
0 1 stripcount 1 sub {
/i exch def
/offset i 2 mod def
i stripsep mul 0 moveto
% To stagger alternating strips, add a downward offset and an extra tile,
% but only if we're on an odd-numbered strip.
0 distance -2 div
offset mul
rmoveto
1 1 tilecount offset add {
pop
hex
0 distance rmoveto
} for
} for
showpage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment