public void getNeighborsHamiltonianDistance(
      final int x,
      final int y,
      final int z,
      final int dist,
      final boolean toroidal,
      IntBag xPos,
      IntBag yPos,
      IntBag zPos) {
    // won't work for negative distances
    if (dist < 0) {
      throw new RuntimeException(
          "Runtime exception in method getNeighborsHamiltonianDistance: Distance must be positive");
    }

    if (xPos == null || yPos == null || zPos == null) {
      throw new RuntimeException(
          "Runtime exception in method getNeighborsHamiltonianDistance: xPos and yPos should not be null");
    }

    xPos.clear();
    yPos.clear();
    zPos.clear();

    // local variables are faster
    final int height = this.height;
    final int width = this.width;
    final int length = this.length;

    // for toroidal environments the code will be different because of wrapping arround
    if (toroidal) {
      // compute xmin and xmax for the neighborhood
      final int xmax = x + dist;
      final int xmin = x - dist;
      for (int x0 = xmin; x0 <= xmax; x0++) {
        final int x_0 = stx(x0, width);
        // compute ymin and ymax for the neighborhood; they depend on the curreny x0 value
        final int ymax = y + (dist - ((x0 - x >= 0) ? x0 - x : x - x0));
        final int ymin = y - (dist - ((x0 - x >= 0) ? x0 - x : x - x0));
        for (int y0 = ymin; y0 <= ymax; y0++) {
          final int y_0 = sty(y0, height);
          final int zmax =
              z + (dist - ((x0 - x >= 0) ? x0 - x : x - x0) - ((y0 - y >= 0) ? y0 - y : y - y0));
          final int zmin =
              z - (dist - ((x0 - x >= 0) ? x0 - x : x - x0) - ((y0 - y >= 0) ? y0 - y : y - y0));
          for (int z0 = zmin; z0 <= zmax; z0++) {
            final int z_0 = stz(z0, length);
            if (x_0 != x || y_0 != y || z_0 != z) {
              xPos.add(x_0);
              yPos.add(y_0);
              zPos.add(z_0);
            }
          }
        }
      }
    } else // not toroidal
    {
      // compute xmin and xmax for the neighborhood such that they are within boundaries
      final int xmax = ((x + dist <= width - 1) ? x + dist : width - 1);
      final int xmin = ((x - dist >= 0) ? x - dist : 0);
      for (int x0 = xmin; x0 <= xmax; x0++) {
        final int x_0 = x0;
        // compute ymin and ymax for the neighborhood such that they are within boundaries
        // they depend on the curreny x0 value
        final int ymax =
            ((y + (dist - ((x0 - x >= 0) ? x0 - x : x - x0)) <= height - 1)
                ? y + (dist - ((x0 - x >= 0) ? x0 - x : x - x0))
                : height - 1);
        final int ymin =
            ((y - (dist - ((x0 - x >= 0) ? x0 - x : x - x0)) >= 0)
                ? y - (dist - ((x0 - x >= 0) ? x0 - x : x - x0))
                : 0);
        for (int y0 = ymin; y0 <= ymax; y0++) {
          final int y_0 = y0;
          final int zmin =
              ((z - (dist - ((x0 - x >= 0) ? x0 - x : x - x0) - ((y0 - y >= 0) ? y0 - y : y - y0))
                      >= 0)
                  ? z
                      - (dist
                          - ((x0 - x >= 0) ? x0 - x : x - x0)
                          - ((y0 - y >= 0) ? y0 - y : y - y0))
                  : 0);
          final int zmax =
              ((z + (dist - ((x0 - x >= 0) ? x0 - x : x - x0) - ((y0 - y >= 0) ? y0 - y : y - y0))
                      <= length - 1)
                  ? z
                      + (dist
                          - ((x0 - x >= 0) ? x0 - x : x - x0)
                          - ((y0 - y >= 0) ? y0 - y : y - y0))
                  : length - 1);
          for (int z0 = zmin; z0 <= zmax; z0++) {
            final int z_0 = z0;
            if (x_0 != x || y_0 != y || z_0 != z) {
              xPos.add(x_0);
              yPos.add(y_0);
              zPos.add(z_0);
            }
          }
        }
      }
    }
  }