updateGeoNormalsUniformityColors()

in src/engine/actvolume/actvol.js [1116:1320]


  updateGeoNormalsUniformityColors(geo, normalSpeed) {
    const numVertices = geo.getNumVertices();
    // float array
    const vertices = geo.getVertices();
    // THREE.Vector3 array
    const normals = geo.getNormals();
    const numTriangles = geo.getNumTriangles();
    const indices = geo.getIndices();

    // perform laplasian smoother
    // ...
    if (this.m_lapSmoother === null) {
      this.m_lapSmoother = new LaplasianSmoother();
    }

    this.m_lapSmoother.performSmoothStep(numVertices, vertices, numTriangles, indices, this.m_verticesNew);

    const DEEP_DEBUG = false;

    // use smoothed vertices to update geo
    const NUM_COMPS_VERTEX = 4;
    const OFF_0 = 0;
    const OFF_1 = 1;
    const OFF_2 = 2;
    let i, i4;

    // when sphere touch edges, this definately means iterations end
    let sphereTouchEdge = false;
    // if too much matched, than stop iterations
    // let numMatchedToColor = 0;

    for (i = 0, i4 = 0; i < numVertices; i++, i4 += NUM_COMPS_VERTEX) {
      let vx = vertices[i4 + OFF_0];
      let vy = vertices[i4 + OFF_1];
      let vz = vertices[i4 + OFF_2];
      const vn = normals[i];

      // pixel coordinate in the volume
      let x = Math.floor(vx);
      let y = Math.floor(vy);
      let z = Math.floor(vz);

      if (DEEP_DEBUG && i === 0) {
        console.log(`v = ${vx}, ${vy}, ${vz}. int xyz = ${x},${y},${z}`);
        console.log(`vn = ${vn.x}, ${vn.y}, ${vn.z}`);
      }

      if (x >= this.m_xDim) {
        sphereTouchEdge = true;
        x = this.m_xDim - 1;
      }
      if (y >= this.m_yDim) {
        sphereTouchEdge = true;
        y = this.m_yDim - 1;
      }
      if (z >= this.m_zDim) {
        sphereTouchEdge = true;
        z = this.m_zDim - 1;
      }
      if (x < 0) {
        sphereTouchEdge = true;
        x = 0;
      }
      if (y < 0) {
        sphereTouchEdge = true;
        y = 0;
      }
      if (z < 0) {
        sphereTouchEdge = true;
        z = 0;
      }

      const xyDim = this.m_xDim * this.m_yDim;
      const off = x + y * this.m_xDim + z * xyDim;
      const uni = this.m_imageUniformity[off];
      const valGaussCur = this.m_imageGauss[off];

      if (DEEP_DEBUG && i === 0) {
        console.log(`uni = ${uni}, valGaussCur = ${valGaussCur}`);
      }

      let compSum = uni;
      // predict next position
      const NEXT_STEP = 2.5;
      let nx = Math.floor(vx + vn.x * NEXT_STEP);
      let ny = Math.floor(vy + vn.y * NEXT_STEP);
      let nz = Math.floor(vz + vn.z * NEXT_STEP);

      if (DEEP_DEBUG && i === 0) {
        console.log(`nx = ${nx}, ny = ${ny}, nz = ${nz}`);
      }
      if (nx < 0 || ny < 0 || nz < 0 || nx >= this.m_xDim || ny >= this.m_yDim || nz >= this.m_zDim) {
        sphereTouchEdge = true;
      }
      nx = nx >= 0 ? nx : 0;
      ny = ny >= 0 ? ny : 0;
      nz = nz >= 0 ? nz : 0;
      nx = nx < this.m_xDim ? nx : this.m_xDim - 1;
      ny = ny < this.m_yDim ? ny : this.m_yDim - 1;
      nz = nz < this.m_zDim ? nz : this.m_zDim - 1;

      const nextOff = nx + ny * this.m_xDim + nz * xyDim;
      const valGaussNext = this.m_imageGauss[nextOff];
      const KOEF_GAUSS_DEC_MULT = 0.3;
      if (valGaussNext > valGaussCur) {
        compSum *= KOEF_GAUSS_DEC_MULT;
      }

      if (DEEP_DEBUG && i === 0) {
        console.log(`valGaussNext = ${valGaussNext}`);
      }

      // use colors
      const koef = this.m_colorProbability[Math.floor(valGaussCur)];
      compSum *= koef;
      const COLOR_MATCH = 0.9;
      const isColorMatch = koef <= COLOR_MATCH;
      // numMatchedToColor += (isColorMatch) ? 1 : 0;

      if (DEEP_DEBUG && i === 0) {
        console.log(`koef = ${koef}, isColorMatch = ${isColorMatch}`);
      }

      const vAddSmooth = new THREE.Vector3();
      vAddSmooth.x = this.m_verticesNew[i4 + OFF_0] - vx;
      vAddSmooth.y = this.m_verticesNew[i4 + OFF_1] - vy;
      vAddSmooth.z = this.m_verticesNew[i4 + OFF_2] - vz;
      vAddSmooth.normalize();
      vAddSmooth.multiplyScalar(normalSpeed);

      const vAddGeo = new THREE.Vector3();
      vAddGeo.x = vn.x * compSum * normalSpeed;
      vAddGeo.y = vn.y * compSum * normalSpeed;
      vAddGeo.z = vn.z * compSum * normalSpeed;

      if (DEEP_DEBUG && i === 0) {
        console.log(`vAddSmooth = ${vAddSmooth.x}, ${vAddSmooth.y}, ${vAddSmooth.z}`);
        console.log(`vAddGeo = ${vAddGeo.x}, ${vAddGeo.y}, ${vAddGeo.z}`);
      }

      const KOEF_ADD_SMOOTH = 0.3;
      const KOEF_ADD_GEO = 1.0 - KOEF_ADD_SMOOTH;

      if (isColorMatch) {
        // do nothing
      } else {
        const vNew = new THREE.Vector3();
        vNew.x = vx + vAddGeo.x * KOEF_ADD_GEO + vAddSmooth.x * KOEF_ADD_SMOOTH;
        vNew.y = vy + vAddGeo.y * KOEF_ADD_GEO + vAddSmooth.y * KOEF_ADD_SMOOTH;
        vNew.z = vz + vAddGeo.z * KOEF_ADD_GEO + vAddSmooth.z * KOEF_ADD_SMOOTH;

        vx = vNew.x;
        vy = vNew.y;
        vz = vNew.z;
      }

      this.m_verticesNew[i4 + OFF_0] = vx;
      this.m_verticesNew[i4 + OFF_1] = vy;
      this.m_verticesNew[i4 + OFF_2] = vz;
    } // for i

    // debug
    // if (numMatchedToColor > 0) {
    //   console.log(`numMatchedToColor = ${numMatchedToColor}. geoStage = ${this.m_geoStage}`);
    // }

    // copy back
    let errAve = 0.0;
    for (i = 0, i4 = 0; i < numVertices; i++, i4 += NUM_COMPS_VERTEX) {
      // estimate error of modification
      const dx = this.m_verticesNew[i4 + OFF_0] - vertices[i4 + OFF_0];
      const dy = this.m_verticesNew[i4 + OFF_1] - vertices[i4 + OFF_1];
      const dz = this.m_verticesNew[i4 + OFF_2] - vertices[i4 + OFF_2];
      const err = dx * dx + dy * dy + dz * dz;
      errAve += err;

      vertices[i4 + OFF_0] = this.m_verticesNew[i4 + OFF_0];
      vertices[i4 + OFF_1] = this.m_verticesNew[i4 + OFF_1];
      vertices[i4 + OFF_2] = this.m_verticesNew[i4 + OFF_2];
    }
    errAve /= numVertices;
    errAve = Math.sqrt(errAve);
    const DIF_VERTICES_LIMIT = 0.12;
    if (errAve < DIF_VERTICES_LIMIT) {
      this.finalizeUpdatesGeo(geo, DEEP_DEBUG);
      return true;
    }
    const aveUni = this.getAveUniformityForGeoVertices(geo);
    const MIN_POSSIBLE_UNIFORMITY = 0.6;
    if (aveUni < MIN_POSSIBLE_UNIFORMITY) {
      this.finalizeUpdatesGeo(geo, DEEP_DEBUG);
      return true;
    }
    if (sphereTouchEdge) {
      this.finalizeUpdatesGeo(geo, DEEP_DEBUG);
      return true;
    }

    const DEEP_ERR_DEBUG = false;
    if (DEEP_ERR_DEBUG) {
      const VERTICES_UNIFORMITY = 1024;
      console.log(`Iters errAve = ${errAve} < ${DIF_VERTICES_LIMIT}. aveUni = ${aveUni} < ${VERTICES_UNIFORMITY}`);
    }
    return false;
  } // updateGeoNormalsUniformityColors