// iso2d // // Demo of finding isocontours via Newton-Raphson method. // Initializes positions on a grid, and each update applies one // step of Newton-Raphson. // // Process output with: // unu jhisto -i mip.txt -b 512 512 -min 0 0 -max 1 1 | unu 2op neq - 0 | unu quantize -b 8 -o iso2d.png int gridSize = 300; field#1(2)[] F = load("../data/ddro-80.nrrd") ⊛ ctmr; int stepsMax = 10; real epsilon = 0.0001; strand sample (int ui, int vi) { output vec2 pos = [lerp(0.0, 1.0, -0.5, real(ui), real(gridSize)-0.5), lerp(0.0, 1.0, -0.5, real(vi), real(gridSize)-0.5)]; // set the isvalue to 50, 30, or 10, depending on whichever we're closest to real isoval = 50.0 if F(pos) >= 40.0 else 30.0 if F(pos) >= 20.0 else 10.0; int steps = 0; update { // We bail if we're no longer inside or taken too many steps. // We tag this strand result as garbage by setting it to a // non-finite position; these will be filtered later. // This is really what "die" is for, though (see below). if (!inside(pos, F) || steps > stepsMax) { pos = [nan,nan]; // HEY (BUG) we shouldn't even have to use non-finite values; // we should be able to just say "die;". Currently, using // "die" leads to the program never finishing... stabilize; } vec2 grad = ∇F(pos); real gmsq = grad • grad; // If |∇F|=0 we can't compute update; we have to bail if (gmsq == 0.0) { pos = [nan,nan]; stabilize; } // delta = Newton-Raphson step vec2 delta = -(F(pos) - isoval)*grad/gmsq; // We've converged if the update is small enough if (|delta| < epsilon) { stabilize; } pos = pos + delta; steps = steps + 1; } } initially { sample(ui, vi) | vi in 0..(gridSize-1), ui in 0..(gridSize-1) };
Click to toggle
does not end with </html> tag
does not end with </body> tag
The output has ended thus: s = steps + 1; } } initially { sample(ui, vi) | vi in 0..(gridSize-1), ui in 0..(gridSize-1) };