Lozenge

Based on a drawing from a year an a half ago:

I showed it to Brent Yorgey in the #diagrams IRC channel and he made this:
strip :: (Double -> Double) -> Double -> Double -> Int -> Double -> Diagram SVG R2
strip f lo hi n offset
= [lo, lo + (hi - lo) / (fromIntegral n - 1) .. hi]
# map (square . f)
# hcat' with {sep = offset, catMethod = Distrib}
# fc black
example = vcat' with { sep = 3, catMethod = Distrib } (replicate 7 str)
# centerXY # pad 1.5
where str = strip (\x -> cos x + 1) (-pi) pi 23 3
--Lozenge (Brent Yorgey)
Then I showed him how they interleave and he made this:
strip :: (Double -> Double) -> Double -> Double -> Int -> Double -> Diagram SVG R2
strip f lo hi n offset
= [lo, lo + (hi - lo) / (fromIntegral n - 1) .. hi]
# map (square . f)
# hcat' with {sep = offset, catMethod = Distrib}
lozenge = vcat' with { sep = 3, catMethod = Distrib } (replicate 7 str)
# centerXY
where str = strip (\x -> cos x + 1) (-pi) pi 23 3
example = mconcat
[ lozenge # fc black
, lozenge # fc red
# translateY (-1.5)
# translateX (width lozenge / 2 - 4.5)
]
--Lozenges (Brent Yorgey)
These are so much simpler than my original code which was horrible C numerical stuff to converge a waveform to the right shape, printing numbers which I fed into GNUplot and then editing the image with GIMP to correct the aspect ratio. I don't have that original code any more, but here's a similar version:
#include <math.h> #include <stdio.h> #include <stdlib.h> const double pi = 3.141592653589793; int cmp(const void *x, const void *y) { const double *a = x; const double *b = y; if (*a < *b) return -1; if (*a > *b) return 1; return 0; } double y(double x) { return (cos(pi * x) + 1) / 2; } int main(int argc, char **argv) { if (argc < 2) { return 1; } int n = atoi(argv[1]); double a[2]; double x[2][n+1]; int w = 0; a[0] = 0.001; for (int i = 0; i <= n; ++i) { x[0][i] = (2.0 * i) / (2.0 * n + 1.0); } x[1][0] = 0; while (1) { printf("a\t= %g\n", a[w]); for (int i = 0; i <= n; ++i) { printf("x[%d]\t= %g\t%g\n", i, x[w][i], y(x[w][i])); } double s = y(x[w][0]); for (int i = 1; i <= n; ++i) { s += 2 * y(x[w][i]); } a[1 - w] = 1 / s; for (int i = 1; i <= n; ++i) { x[1 - w][i] = x[w][i-1] + a[w] * ((y(x[w][i-1]) + y(x[w][i]))/2 + y(x[w][n+1-i])); } w = 1 - w; qsort(&x[w][0], n+1, sizeof(x[w][0]), cmp); } return 0; }gcc -std=c99 -lm lozenge.c ./a.out 19 | head -n 2100 | tail -n 20 > lozenge.dat ; gnuplotunset key unset xtics unset ytics unset border set style fill solid set terminal png size 8192,8192 set output "lozenge-raw.png" plot [-0.2:1.2] [-0.7:0.7] "lozenge.dat" using 3:(0):\ ($3 - $4 * 0.0512405/3):($3 + $4 * 0.0512405/3):\ ((-1+$4) * 0.0512405/3):((1-$4) * 0.0512405/3) with boxxyerrorbars,\ "lozenge.dat" using (1-$3):(0):\ (1-$3 - $4 * 0.0512405/3):(1-$3 + $4 * 0.0512405/3):\ ((-1+$4) * 0.0512405/3):((1-$4) * 0.0512405/3) with boxxyerrorbarsgimp (crop image)

A further experiment led to this gradient with 5 colours out of phase:

Do check out the links above to the Haskell diagrams pastebin, it's quite awesome.