function projectPoints()

in packages/miew/src/gfx/geometries/ContactSurface.js [335:440]


  function projectPoints() {
    // For each atom:
    //     Iterate over a subsection of the grid, for each point:
    //         If current value < 0.0, unvisited, set positive
    //
    //         In any case: Project this point onto surface of the atomic sphere
    //         If this projected point is not obscured by any other atom
    //             Calcualte delta distance and set grid value to minimum of
    //             itself and delta

    // Should we alias frequently accessed closure constiables??
    // Assume JS engine capable of optimizing this
    // anyway...
    const maxRad = 4.0;
    const sigma = (maxRad) / 3;
    const sigma2Inv = 1 / (2 * sigma * sigma);

    for (let innI = 0; innI < nAtoms; innI++) {
      const innCI = itemSize * innI;
      const ax = posRad[innCI];
      const ay = posRad[innCI + 1];
      const az = posRad[innCI + 2];
      const ar = posRad[innCI + 3];
      const ar2 = r2[innI];

      hash.withinRadii(ax, ay, az, ar, neighbours);

      // Number of grid points, round this up...
      const ng = Math.ceil(ar * scaleFactor);

      // Center of the atom, mapped to grid points (take floor)
      const iax = Math.floor(scaleFactor * (ax - min[0]));
      const iay = Math.floor(scaleFactor * (ay - min[1]));
      const iaz = Math.floor(scaleFactor * (az - min[2]));

      // Extents of grid to consider for this atom
      const minx = Math.max(0, iax - ng);
      const miny = Math.max(0, iay - ng);
      const minz = Math.max(0, iaz - ng);

      // Add two to these points:
      // - iax are floor'd values so this ensures coverage
      // - these are loop limits (exclusive)
      const maxx = Math.min(dim[0], iax + ng + 2);
      const maxy = Math.min(dim[1], iay + ng + 2);
      const maxz = Math.min(dim[2], iaz + ng + 2);

      const colIdx = innI * 3;
      const cr = colors[colIdx];
      const cg = colors[colIdx + 1];
      const cb = colors[colIdx + 2];

      for (let iz = minz; iz < maxz; iz++) {
        const dz = gridz[iz] - az;
        const zOffset = dim[1] * dim[0] * iz;

        for (let iy = miny; iy < maxy; iy++) {
          const dy = gridy[iy] - ay;
          const dzy2 = dz * dz + dy * dy;
          const zyOffset = zOffset + dim[0] * iy;

          for (let ix = minx; ix < maxx; ix++) {
            const idx = ix + zyOffset;
            const dx = gridx[ix] - ax;
            const d2 = dzy2 + dx * dx;

            if (d2 < ar2) {
              const w = Math.exp(-d2 * sigma2Inv);
              const cIdx = idx * 3;
              volTex[cIdx] += cr * w;
              volTex[cIdx + 1] += cg * w;
              volTex[cIdx + 2] += cb * w;
              weights[idx] += w;
              if (visibilitySelector !== null && w > weightsMap[idx]) {
                weightsMap[idx] = w;
                atomMap[idx] = atoms[innI];
              }

              if (grid[idx] < 0.0) {
                // Unvisited, make positive
                grid[idx] = -grid[idx];
              }
              // Project on to the surface of the sphere
              // sp is the projected point ( dx, dy, dz ) * ( ra / d )
              const d = Math.sqrt(d2);
              const ap = ar / d;
              let spx = dx * ap;
              let spy = dy * ap;
              let spz = dz * ap;

              spx += ax;
              spy += ay;
              spz += az;

              if (obscured(spx, spy, spz, innI, -1) === -1) {
                const dd = ar - d;
                if (dd < grid[idx]) {
                  grid[idx] = dd;
                }
              }
            }
          }
        }
      }
    }
  }