private void findNeighbors() {
    // find the nearest-neighbor for each point in the cloud
    nn.setPoints(usedNnData, listPointVector.toList());

    for (int i = 0; i < listPointVector.size; i++) {
      // find the nearest-neighbors
      resultsNN.reset();

      double[] targetPt = usedNnData.get(i);
      // numNeighbors+1 since the target node will also be returned and is removed
      nn.findNearest(targetPt, maxDistanceNeighbor, numNeighbors + 1, resultsNN);

      PointVectorNN p = listPointVector.get(i);

      // save the results
      p.neighbors.reset();
      for (int j = 0; j < resultsNN.size; j++) {
        NnData<PointVectorNN> n = resultsNN.get(j);

        // don't add the point to its own list of neighbors list
        if (n.point != targetPt) {
          p.neighbors.add(n.data);
        }
      }
    }
  }
  /** Converts points into a format understood by the NN algorithm and initializes it */
  public void process(List<Point3D_F64> cloud) {
    nn.init(3);

    // swap the two lists to recycle old data and avoid creating new memory
    Stack<double[]> tmp = unusedNnData;
    unusedNnData = usedNnData;
    usedNnData = tmp;
    // add the smaller list to the larger one
    unusedNnData.addAll(usedNnData);
    usedNnData.clear();

    // convert the point cloud into the NN format
    for (int i = 0; i < cloud.size(); i++) {
      Point3D_F64 p = cloud.get(i);

      double[] d;
      if (unusedNnData.isEmpty()) {
        d = new double[3];
      } else {
        d = unusedNnData.pop();
      }

      d[0] = p.x;
      d[1] = p.y;
      d[2] = p.z;

      usedNnData.add(d);
    }

    // declare the output data for creating the NN graph
    listPointVector.reset();
    for (int i = 0; i < cloud.size(); i++) {
      PointVectorNN p = listPointVector.grow();
      p.reset();
      p.p = cloud.get(i);
      p.index = i;
    }

    findNeighbors();
  }