/*This macro is based on the turtle graphics code by Norbert Vischer. It creates Merz grid with semi-circular lines and points as non-destructive overlay. Merz grid is a linear test system with built-in 2D isotropy, so you do not need to rotate the grid to get isotropic line orientation. Do not forget to "Set Scale" to get correct printout of the grid parameters, which are reflected in the "Merz grid parameters" window. "Central Points" makes two points in every tile. "Line Points" makes 4 additional points per tile. "Segmented lines" makes circular arcs with total length 2 times shorter than solid lines. Grid constant a/l (area per line unit) is used to estimate total length of a flat structure. Total length equals to number of intersections (between linear feature and test lines) multiplied by PI/2 times the grid constant a/l. Area per point can be used to estimate an area in 2D samples or volume density in isotropic uniform random sections. Test line per point (l/p) constant is used to estimate surface density (surface area per unit volume) in isotropic uniform random sections. Version: 1.0 Date: 04/09/2014 Author: Aleksandr Mironov amj-box@mail.ru */ requires("1.46b"); var k57 = 180/PI, turtleX = newArray(2000), turtleY = newArray(2000), turtlePhi, tPtr, newX, newY, aa1, aa2, aa3, aa4, bb1, bb2, bb3, bb4; macro "Merz_Grid" { //help html = "" +"

Merz Grid

" +"is a linear test system with built-in 2D isotropy

" +"Options:
" +"Tile density - determines density of the grid
" +"Central Points - two points per grid tile
" +"Line Points - 4 additional points per grid tile

" +"New Overlay - removes previous overlays
" +"Random Offset - randomizes grid location
" +"Random Phase - randomizes initial arc phase

" +"Segmented lines - arcs with half of total length of solid lines

" +"Set Scale to get correct printout of the grid parameters,
" +"which are reflected in the 'Merz grid parameters' window

" +"Useful parameters:

" +"Area per point can be used to estimate an area in 2D samples
" +"or volume density isotropic uniform random sections

" +"Test line per point constant is used to estimate surface density
" +"(surface area per unit volume) in isotropic uniform random sections

" +"Grid constant a/l (area per line unit) is used to estimate total length
" +"of a flat structure. Total length equals to number of intersections
" +"multiplied by PI/2 times the grid constant a/l
" //Creating dialog box Dialog.create("Merz Grid, ver. 1.0"); Dialog.addNumber("Tile density =", 6,0,2,"within height"); Dialog.addCheckbox("Central Points", true); Dialog.addCheckbox("Line Points (x2 of central)", true); Dialog.addMessage("\n "); Dialog.addCheckbox("New Overlay", true); Dialog.addCheckbox("Random Offset", true); Dialog.addCheckbox("Random Phase", true); Dialog.addChoice("Line type", newArray("solid", "segmented")); Dialog.addNumber("Line thickness =", 1,0,2,"pixels"); Dialog.addChoice("Color:", newArray("cyan", "red", "green", "magenta", "blue", "yellow", "orange", "black", "white")); Dialog.addHelp(html); Dialog.show(); //grid parameters name = getTitle(); ntiles = Dialog.getNumber(); point = Dialog.getCheckbox(); points = Dialog.getCheckbox(); new = Dialog.getCheckbox(); if (new == true) Overlay.remove; getDimensions(w, h, channels, slices, frames); tile = h/ntiles; //creating random offset off1 = random; off2 = random; offset = Dialog.getCheckbox(); if (offset == false) off1 = off2 = 0; xoff = -round(tile/2*off1); yoff = -round(tile/2*off2); //creating random phase phase = random; offphase = Dialog.getCheckbox(); if (offphase == false) phase = 0.1; typeL = Dialog.getChoice(); t = Dialog.getNumber(); color = Dialog.getChoice(); setColor(color); setLineWidth(t); //tile parameters step = tile*PI/40; //length of a step in pixels nSteps = 10;// dPhi = 9; //degrees between 2 steps cycles = w/tile/2; cycless = cycles+1; xx1 = xoff; yy1 = yoff; //phase change if (phase<0.25){ dPhi1=dPhi4=dPhi; dPhi2=dPhi3=-dPhi; phi=0; } else if (phase>=0.25 && phase<0.5){ dPhi1=dPhi4=-dPhi; dPhi2=dPhi3=dPhi; phi=0; } else if (phase>=0.5 && phase<0.75){ dPhi1=dPhi2=-dPhi; dPhi3=dPhi4=dPhi; phi=-90; } else { dPhi1=dPhi2=dPhi; dPhi3=dPhi4=-dPhi; phi=90; } //main loop for (waves = 0; waves <= (ntiles+1); waves++){ turtleInit(xx1, yy1, phi);//starting point and angle for (kk =0; kk=0.25 && phase<0.5) { bb1=tile/32; bb2=tile/32; bb3=0; bb4=tile/16; } else if (phase>=0.5 && phase<0.75) { bb1=-tile/2; bb2=-tile/2; bb3=-tile/2-tile/32; bb4=-tile/2+tile/32; } else { bb1=tile/2; bb2=tile/2; bb3=tile/2-tile/32; bb4=tile/2+tile/32; } } //y for segment 3 function y_phaseDep3(){ if (phase<0.25){ bb1=tile/32; bb2=tile/32; bb3=0; bb4=tile/16; } else if(phase>=0.25 && phase<0.5) { bb1=-tile/32; bb2=-tile/32; bb3=-tile/16; bb4=0; } else if (phase>=0.5 && phase<0.75){ bb1=tile/2; bb2=tile/2; bb3=tile/2-tile/32; bb4=tile/2+tile/32; } else { bb1=-tile/2; bb2=-tile/2; bb3=-tile/2-tile/32; bb4=-tile/2+tile/32; } } /* Turtle routines =============== at any moment, the turtle has position turtleX[tPtr], turtleY[tPtr], and orientation turtlePhi. Turtle array is 1-based. Negative indices count from the back, so -1 addresses last vertex. turtleX[0] and turtleY[0] are not used. */ //initialize function turtleInit(xx, yy, phi){ tPtr =1; turtleX[1]= xx; turtleY[1]= yy; turtlePhi= phi; } //create a selection function turtleMakeSelection(type){ xx = newArray(tPtr); yy = newArray(tPtr); for (jj = 1; jj<=tPtr; jj++){ xx[jj-1] = turtleX[jj]; yy[jj-1] = turtleY[jj]; } makeSelection(type, xx, yy); } //create line coordinates function turtleLine(dPhi, rad){ turtlePhi -= dPhi; while(turtlePhi < 0) turtlePhi += 360; while(turtlePhi >= 360) turtlePhi -= 360; dx = rad * cos(turtlePhi/k57); dy = -rad * sin(turtlePhi/k57); newX = turtleX[tPtr] + dx; newY = turtleY[tPtr] + dy; tPtr++; turtleX[tPtr] = newX; turtleY[tPtr] = newY; }