/** * Transforms the specified array of times and marks. Known samples are those for which times are * zero, and times and marks for these known samples are used to compute times and marks for * unknown samples. * * @param times input/output array of times. * @param marks input/output array of marks. */ public void apply(float[][][] times, int[][][] marks) { // Measure elapsed time in seconds. Stopwatch sw = new Stopwatch(); sw.start(); log.fine("TimeMarker3.apply: begin time=" + (int) sw.time()); // Initialize all unknown times to infinity. for (int i3 = 0; i3 < _n3; ++i3) { for (int i2 = 0; i2 < _n2; ++i2) { for (int i1 = 0; i1 < _n1; ++i1) { if (times[i3][i2][i1] != 0.0f) times[i3][i2][i1] = INFINITY; } } } // Indices of known samples in random order. short[][] kk = indexKnownSamples(times); short[] k1 = kk[0]; short[] k2 = kk[1]; short[] k3 = kk[2]; shuffle(k1, k2, k3); int nk = k1.length; // Array for the eikonal solution times. float[][][] t = new float[_n3][_n2][_n1]; // Active list of samples used to compute times. ActiveList al = new ActiveList(); // For all known samples, ... for (int ik = 0; ik < nk; ++ik) { if (ik % (1 + (nk - 1) / 100) == 0) log.fine(" apply: ik/nk=" + ik + "/" + nk + " time=" + (int) sw.time()); int i1 = k1[ik]; int i2 = k2[ik]; int i3 = k3[ik]; // Clear activated flags so we can tell which samples become activated. clearActivated(); // Put the known sample with time zero into the active list. t[i3][i2][i1] = 0.0f; al.append(_s[i3][i2][i1]); // The mark for the known sample. int m = marks[i3][i2][i1]; // Process the active list until empty. solve(al, t, m, times, marks); } // Log elapsed time. sw.stop(); log.fine("TimeMarker3.apply: end time=" + (int) sw.time()); }
/* * Processes one sample from the A list. * Appends samples not yet converged to the B list. */ private void solveOne( float[][][] t, int m, float[][][] times, int[][][] marks, Sample s, ActiveList bl, float[] d) { // Sample indices. int i1 = s.i1; int i2 = s.i2; int i3 = s.i3; // Current time and new time computed from all four neighbors. float ti = currentTime(t, i1, i2, i3); float ci = computeTime(t, i1, i2, i3, K1S[6], K2S[6], K3S[6], d); t[i3][i2][i1] = ci; // If new and current times are close enough (converged), then ... if (ci >= ti * ONE_MINUS_EPSILON) { // Neighbors may need to be activated if computed time is small // relative to the minimum time computed so far. The factor 1.5 // improves accuracy for large anisotropy. Cost increases as the // square of this factor, so we do not want it to be too large. boolean checkNabors = ci <= 1.5f * times[i3][i2][i1]; // If computed time less than minimum time, mark this sample. if (ci < times[i3][i2][i1]) { times[i3][i2][i1] = ci; marks[i3][i2][i1] = m; } // If necessary, check the neighbors. if (checkNabors) { // For all six neighbors, ... for (int k = 0; k < 6; ++k) { // Neighbor sample indices; skip if out of bounds. int j1 = i1 + K1[k]; if (j1 < 0 || j1 >= _n1) continue; int j2 = i2 + K2[k]; if (j2 < 0 || j2 >= _n2) continue; int j3 = i3 + K3[k]; if (j3 < 0 || j3 >= _n3) continue; // Skip neighbor sample if computed time would be too big. // if (!doComputeTime(t,times,j1,j2)) continue; // Current and computed times for the neighbor. float tj = currentTime(t, j1, j2, j3); float cj = computeTime(t, j1, j2, j3, K1S[k], K2S[k], K3S[k], d); // If computed time is significantly less than current time, ... if (cj < tj * ONE_MINUS_EPSILON) { // Replace the current time. t[j3][j2][j1] = cj; // Append neighbor to the B list, thereby activating it. bl.append(_s[j3][j2][j1]); } } } } // Else, if not converged, append this sample to the B list. else { bl.append(s); } }