I'm relatively inexperienced in C++, and am trying to compile a library to DLL for use in Unity. As far as generating the DLL and interfacing with it, I've had success in getting my below function to call and return a dummy value in Unity, no worries.
Where I'm struggling is working out how to interface with this Approximate Nearest Neighbour library, and could use some pointers. (This may be a hard problem to define without downloading the above-linked source and having a look yourself, but I will attempt to make it simple)
In Unity, I have a three-dimensional array (points[] = float[x,y,z]), and a query point in space (float[x,y,z]). I wish to feed this data into something like the below function (which I have modified from the ann_sample.cpp - original linked at the bottom), and return the nearest neighbour to this point.
My function
int myInit(float x, float y, float z, int numPoints, int maxPoints, int nn)
{
int nPts;
ANNpointArray dataPts;
ANNpoint queryPt;
ANNidxArray nnIdx;
ANNdistArray dists;
ANNkd_tree* kdTree;
int dimension = 3;
queryPt = annAllocPt(dimension , x); //This only expects the dimension, and a coord - I assume this is pre-allocation?
dataPts = annAllocPts(maxPoints, dimension); //Again, this does not expect the coordinate (xyz) data, is pre-allocating the array?
nnIdx = new ANNidx[nn]; // more pre-allocating?
dists = new ANNdist[nn]; // more pre-allocating?
nPts = numPoints;
//Should we be populating the actual queryPt and dataPts here?
//at the moment, these are still empty?
kdTree = new ANNkd_tree( // build search structure
dataPts, // the data points
nPts, // number of points
dimension); // dimension of space
kdTree->annkSearch( // search
queryPt, // query point
nn, // number of near neighbors
nnIdx, // nearest neighbors (returned)
dists, // distance (returned)
eps); // error bound
annClose(); // done with ANN
return nnIdx[0]; //this is the nearest neighbor
}
Original Function (This is expecting a command-line input - i.e. ann_sample [-d dim] [-max mpts] [-nn k] [-e eps] [-df data] [-qf query])
int main(int argc, char **argv)
{
int nPts; // actual number of data points
ANNpointArray dataPts; // data points
ANNpoint queryPt; // query point
ANNidxArray nnIdx; // near neighbor indices
ANNdistArray dists; // near neighbor distances
ANNkd_tree* kdTree; // search structure
getArgs(argc, argv); // read command-line arguments
queryPt = annAllocPt(dim); // allocate query point
dataPts = annAllocPts(maxPts, dim); // allocate data points
nnIdx = new ANNidx[k]; // allocate near neigh indices
dists = new ANNdist[k]; // allocate near neighbor dists
nPts = 0; // read data points
cout << "Data Points:\n";
while (nPts < maxPts && readPt(*dataIn, dataPts[nPts])) {
printPt(cout, dataPts[nPts]);
nPts++;
}
kdTree = new ANNkd_tree( // build search structure
dataPts, // the data points
nPts, // number of points
dim); // dimension of space
while (readPt(*queryIn, queryPt)) { // read query points
cout << "Query point: "; // echo query point
printPt(cout, queryPt);
kdTree->annkSearch( // search
queryPt, // query point
k, // number of near neighbors
nnIdx, // nearest neighbors (returned)
dists, // distance (returned)
eps); // error bound
cout << "\tNN:\tIndex\tDistance\n";
for (int i = 0; i < k; i++) { // print summary
dists[i] = sqrt(dists[i]); // unsquare distance
cout << "\t" << i << "\t" << nnIdx[i] << "\t" << dists[i] << "\n";
}
}
delete [] nnIdx; // clean things up
delete [] dists;
delete kdTree;
annClose(); // done with ANN
return EXIT_SUCCESS;
}
As you can see in my comments, I am having trouble determining where and how I might actually feed the input data in, that is - my point array mentioned above.
It appears the data is being populated (in the reference function) with the below code, by utilizing an "istream" class, but I do not understand how this is working, or how I would emulate it.
while (nPts < maxPts && readPt(*dataIn, dataPts[nPts])) {
printPt(cout, dataPts[nPts]);
nPts++;
}
...
bool readPt(istream &in, ANNpoint p) // read point (false on EOF)
{
for (int i = 0; i < dim; i++) {
if(!(in >> p[i])) return false;
}
return true;
}
Update:
Writing this all out was evidently the push I needed in the right direction! In case it's relevant for anyone in the future, the manner through which I interfaced with it was fairly straightforward.
I passed a few 2D arrays into the C++ plugin, which I then converted into ANNpointArrays. Given it's C++, I needed to first instantiate the arrays of the appropriate size, then populate as the below:
Once I had this, it was relatively simple to run an annKSearch on each of my query points, returning an array of integers for Nearest Neighbour, and floats for distances. I needed to learn a few things about how to pass and instantiate arrays in C++, but it was a lot easier than I thought!
Not that anyone's reading it - but this has been a useful exercise for me, and I'm leaving the question up just in case someone else is trying to implement this library in C#!