1 | /************************************************************************* |
2 | * Copyright (c) 2011 AT&T Intellectual Property |
3 | * All rights reserved. This program and the accompanying materials |
4 | * are made available under the terms of the Eclipse Public License v1.0 |
5 | * which accompanies this distribution, and is available at |
6 | * http://www.eclipse.org/legal/epl-v10.html |
7 | * |
8 | * Contributors: See CVS logs. Details at http://www.graphviz.org/ |
9 | *************************************************************************/ |
10 | |
11 | #include "config.h" |
12 | |
13 | #ifdef HAVE_ANN |
14 | //---------------------------------------------------------------------- |
15 | // File: get_nearest_neighb_graph.cpp |
16 | //---------------------------------------------------------------------- |
17 | |
18 | #include <cstdlib> // C standard library |
19 | #include <cstdio> // C I/O (for sscanf) |
20 | #include <cstring> // string manipulation |
21 | #include <fstream> // file I/O |
22 | #include <ANN/ANN.h> // ANN declarations |
23 | |
24 | using namespace std; // make std:: accessible |
25 | int dim = 4; // dimension |
26 | |
27 | |
28 | static void printPt(ostream &out, ANNpoint p) // print point |
29 | { |
30 | out << "" << p[0]; |
31 | for (int i = 1; i < dim; i++) { |
32 | out << "," << p[i]; |
33 | } |
34 | out << "" ; |
35 | } |
36 | |
37 | static void sortPtsX(int n, ANNpointArray pts){ |
38 | /* sort so that edges always go from left to right in x-doordinate */ |
39 | ANNpoint p; |
40 | ANNcoord x, y; |
41 | int i, j; |
42 | for (i = 0; i < n; i++){ |
43 | for (j = 0; j < dim; j++){ |
44 | p = pts[i]; |
45 | if (p[0] < p[2] || (p[0] == p[2] && p[1] < p[3])) continue; |
46 | x = p[0]; y = p[1]; |
47 | p[0] = p[2]; |
48 | p[1] = p[3]; |
49 | p[2] = x; |
50 | p[3] = y; |
51 | } |
52 | } |
53 | } |
54 | |
55 | static void sortPtsY(int n, ANNpointArray pts){ |
56 | /* sort so that edges always go from left to right in x-doordinate */ |
57 | ANNpoint p; |
58 | ANNcoord x, y; |
59 | int i, j; |
60 | for (i = 0; i < n; i++){ |
61 | for (j = 0; j < dim; j++){ |
62 | p = pts[i]; |
63 | if (p[1] < p[3] || (p[1] == p[3] && p[0] < p[2])) continue; |
64 | x = p[0]; y = p[1]; |
65 | p[0] = p[2]; |
66 | p[1] = p[3]; |
67 | p[2] = x; |
68 | p[3] = y; |
69 | } |
70 | } |
71 | } |
72 | |
73 | |
74 | extern "C" void nearest_neighbor_graph_ann(int nPts, int dim, int k, double eps, double *x, int *nz0, int **irn0, int **jcn0, double **val0); |
75 | |
76 | void nearest_neighbor_graph_ann(int nPts, int dim, int k, double eps, double *x, int *nz0, int **irn0, int **jcn0, double **val0){ |
77 | |
78 | /* Gives a nearest neighbor graph is a list of dim-dimendional points. The connectivity is in irn/jcn, and the distance in val. |
79 | |
80 | nPts: number of points |
81 | dim: dimension |
82 | k: number of neighbors needed |
83 | eps: error tolerance |
84 | x: nPts*dim vector. The i-th point is x[i*dim : i*dim + dim - 1] |
85 | nz: number of entries in the connectivity matrix irn/jcn/val |
86 | irn, jcn: the connectivity |
87 | val: the distance |
88 | |
89 | note that there could be repeates |
90 | */ |
91 | |
92 | ANNpointArray dataPts; // data points |
93 | ANNidxArray nnIdx; // near neighbor indices |
94 | ANNdistArray dists; // near neighbor distances |
95 | ANNkd_tree* kdTree; // search structure |
96 | |
97 | double *xx; |
98 | int *irn, *jcn; |
99 | double *val; |
100 | int nz; |
101 | |
102 | irn = *irn0; |
103 | jcn = *jcn0; |
104 | val = *val0; |
105 | |
106 | |
107 | dataPts = annAllocPts(nPts, dim); // allocate data points |
108 | nnIdx = new ANNidx[k]; // allocate near neigh indices |
109 | dists = new ANNdist[k]; // allocate near neighbor dists |
110 | |
111 | for (int i = 0; i < nPts; i++){ |
112 | xx = dataPts[i]; |
113 | for (int j = 0; j < dim; j++) xx[j] = x[i*dim + j]; |
114 | } |
115 | |
116 | //========= graph when sort based on x ======== |
117 | nz = 0; |
118 | sortPtsX(nPts, dataPts); |
119 | kdTree = new ANNkd_tree( // build search structure |
120 | dataPts, // the data points |
121 | nPts, // number of points |
122 | dim); // dimension of space |
123 | for (int ip = 0; ip < nPts; ip++){ |
124 | kdTree->annkSearch( // search |
125 | dataPts[ip], // query point |
126 | k, // number of near neighbors |
127 | nnIdx, // nearest neighbors (returned) |
128 | dists, // distance (returned) |
129 | eps); // error bound |
130 | |
131 | for (int i = 0; i < k; i++) { // print summary |
132 | if (nnIdx[i] == ip) continue; |
133 | val[nz] = dists[i]; |
134 | irn[nz] = ip; |
135 | jcn[nz++] = nnIdx[i]; |
136 | //cout << ip << "--" << nnIdx[i] << " [len = " << dists[i]<< ", weight = \"" << 1./(dists[i]) << "\", wt = \"" << 1./(dists[i]) << "\"]\n"; |
137 | //printPt(cout, dataPts[ip]); |
138 | //cout << "--"; |
139 | //printPt(cout, dataPts[nnIdx[i]]); |
140 | //cout << "\n"; |
141 | } |
142 | } |
143 | |
144 | |
145 | //========= graph when sort based on y ======== |
146 | sortPtsY(nPts, dataPts); |
147 | kdTree = new ANNkd_tree( // build search structure |
148 | dataPts, // the data points |
149 | nPts, // number of points |
150 | dim); // dimension of space |
151 | for (int ip = 0; ip < nPts; ip++){ |
152 | kdTree->annkSearch( // search |
153 | dataPts[ip], // query point |
154 | k, // number of near neighbors |
155 | nnIdx, // nearest neighbors (returned) |
156 | dists, // distance (returned) |
157 | eps); // error bound |
158 | |
159 | for (int i = 0; i < k; i++) { // print summary |
160 | if (nnIdx[i] == ip) continue; |
161 | val[nz] = dists[i]; |
162 | irn[nz] = ip; |
163 | jcn[nz++] = nnIdx[i]; |
164 | // cout << ip << "--" << nnIdx[i] << " [len = " << dists[i]<< ", weight = \"" << 1./(dists[i]) << "\", wt = \"" << 1./(dists[i]) << "\"]\n"; |
165 | } |
166 | } |
167 | |
168 | delete [] nnIdx; // clean things up |
169 | delete [] dists; |
170 | delete kdTree; |
171 | |
172 | *nz0 = nz; |
173 | |
174 | annClose(); // done with ANN |
175 | |
176 | |
177 | |
178 | } |
179 | |
180 | #endif /* HAVE_ANN */ |
181 | |