// Adelson Checker-shadow illusion
w = 700; h = 600;
n = 5;
grey1 = 50; grey3 = 200;
grey2 = (grey1 + grey3) / 2; grey4 = (grey3 + 255) / 2;
x1 = w / 3; x2 = 2 * w / 3;
y1 = h / 5; y2 = 2 * h / 5; y4 = 9 * h / 10; y3 = y4 - y2 + y1;
dxx = (x2 - 0) / n; dxy = (y4 - y3) / n;
dyx = (x1 - 0) / n; dyy = (y1 - y3) / n;
dy = h - y4;

function getX(i, j) {
	return dxx * i + dyx * j;
}

function getY(i, j) {
	return y3 + dxy * i + dyy * j;
}

function square(i, j) {
	makePolygon(getX(i, j), getY(i, j),
		getX(i + 1, j), getY(i + 1, j),
		getX(i + 1, j + 1), getY(i + 1, j + 1),
		getX(i, j + 1), getY(i, j + 1));
}

function edge(i, j) {
	makePolygon(getX(i, j), getY(i, j),
		getX(i, j), getY(i, j) + dy,
		getX(i + 1, j), getY(i + 1, j) + dy,
		getX(i + 1, j), getY(i + 1, j));
}
function edge2(i, j) {
	makePolygon(getX(i, j), getY(i, j),
		getX(i, j), getY(i, j) + dy,
		getX(i, j + 1), getY(i, j + 1) + dy,
		getX(i, j + 1), getY(i, j + 1));
}

function diamond(i, j) {
	x = getX(i, j) + (dxx + dyx) / 2;
	y = getY(i, j) + (dxy + dyy) / 2;
	r1 = 1 / 6; r2 = 1 / 4;
	ow = dxx * r1; oh = dyy * r2;
	makePolygon(x - dxx * r1, y - dxy * r1,
		x - dyx * r2, y - dyy * r2,
		x + dxx * r1, y + dxy * r1,
		x + dyx * r2, y + dyy * r2);
}

newImage("Grey square optical illusion", "RGB White", w, h, 1);
image = getImageID();

setBatchMode(true);
setForegroundColor(grey2, grey2, grey2);
for (i = 0; i < n; i++)
	for (j = ((i + 1) % 2); j < n; j += 2) {
		square(i, j);
		run("Fill");
	}
for (i = 1; i < n - 1; i++) {
	square(i, i);
	run("Fill");
}
setForegroundColor(grey3, grey3, grey3);
for (i = 0; i < n; i += 2) {
	square(0, i);
	run("Fill");
	square(i, 0);
	run("Fill");
	square(n - 1, i);
	run("Fill");
	square(i, n - 1);
	run("Fill");
}

setForegroundColor(grey3+48, grey3+48, grey3+48);
for (i = 0; i < n; i += 2) {
	edge2(n, i);
	run("Fill");
}

setForegroundColor(grey2, grey2, grey2);
for (i = 0; i < n; i += 2) {
	edge(i, 0);
	run("Fill");
}

setForegroundColor(grey3, grey3, grey3);
for (i = 1; i < n - 1; i += 2) {
	edge2(n, i);
	run("Fill");
}

setForegroundColor(grey1, grey1, grey1);
for (i = 1; i < n; i += 2) {
	edge(i, 0);
	run("Fill");
}
setForegroundColor(grey4, grey4, grey4);
square(n - 1, n - 1);
run("Fill");
newImage("scratch pad", "RGB White", w, h, 1);
scratch = getImageID();
setBackgroundColor(grey3, grey3, grey3);
setForegroundColor(grey1, grey1, grey1);
makeLine(getX(0, 4), getY(0, 4), getX(2, 2), getY(2, 2));
run("Linear Gradient");
square(0, 3);
run("Copy");
selectImage(image);
for (i = 2; i < n - 1; i++) {
	square(i - 2, i);
	run("Paste");
}
selectImage(scratch);
square(1, 2);
run("Copy");
selectImage(image);
for (i = 1; i < n - 1; i++) {
	square(i - 1, i);
	run("Paste");
}

selectImage(scratch);
makeLine(getX(4, 0), getY(4, 0), getX(2, 2), getY(2, 2));
run("Linear Gradient");
square(3, 0);
run("Copy");
selectImage(image);
for (i = 0; i < n - 3; i++) {
	square(i + 2, i);
	run("Paste");
}
selectImage(scratch);
square(2, 1);
run("Copy");
selectImage(image);
for (i = 0; i < n - 2; i++) {
	square(i + 1, i);
	run("Paste");
}

x1 = getX(3.25, 3); y1 = getY(4, 4.5);
x2 = getX(4.25, 5); y2 = getY(4, 3);
h1 = h / 3; dy = (y2 - y1) / 2;
selectImage(scratch);
makeLine(x2, y1, x1, y1);
setBackgroundColor(255, 255, 255);
run("Linear Gradient");
makeRectangle(x1, y1 - h1, x2 - x1, h1);
run("Copy");
selectImage(image);
makeRectangle(x1, y1 - h1 + dy, x2 - x1, h1);
run("Paste");
selectImage(scratch);
makeOval(x1, y1, x2 - x1, y2 - y1);
run("Copy");
selectImage(image);
makeOval(x1, y1, x2 - x1, y2 - y1);
run("Paste");

setForegroundColor(grey2, grey2, grey2);
makeOval(x1, y1 - h1, x2 - x1, y2 - y1);
run("Fill");

setForegroundColor(grey1, grey1, grey1);
selectImage(image);
diamond(1, 4);
run("Fill");
diamond(2, 2);
run("Fill");

run("Select None");
selectImage(scratch);
close();
setBatchMode(false);
