Commit c72184d1c24eb8d1d7408105780ced09f5739184

Authored by Jiaming Guo
1 parent 57914be5

add many function in order to work with netmets

stim/biomodels/centerline.h
... ... @@ -3,7 +3,6 @@
3 3  
4 4 #include <vector>
5 5 #include <stim/math/vec3.h>
6   -//#include <ANN/ANN.h>
7 6  
8 7 namespace stim{
9 8  
... ... @@ -12,195 +11,123 @@ namespace stim{
12 11 * class to describe an interconnected (often biological) network.
13 12 */
14 13 template<typename T>
15   -class centerline{
  14 +class centerline : public std::vector< stim::vec3<T> >{
16 15  
17 16 protected:
18   - unsigned int N; //number of points in the fiber
19   - double **c; //centerline (array of double pointers)
20   -// ANNkd_tree* kdt; //kd-tree stores all points in the fiber for fast searching
21 17  
22   - /// Initialize an empty fiber
23   - void init()
24   - {
25   - N=0;
26   - c=NULL;
27   -// kdt = NULL;
28   - }
29   -
30   - /// Initialize a fiber with N centerline points (all located at [0, 0, 0] with radius 0)
31   - void init(unsigned int n)
32   - {
  18 + std::vector<T> L; //stores the integrated length along the fiber (used for parameterization)
33 19  
34   - N = n; //set the number of points
35   -// kdt = NULL;
36   - c = (double**) malloc(sizeof(double*) * N); //allocate the array pointer
  20 + ///Return the normalized direction vector at point i (average of the incoming and outgoing directions)
  21 + vec3<T> d(size_t i) {
  22 + if (size() <= 1) return vec3<T>(0, 0, 0); //if there is insufficient information to calculate the direction, return a null vector
  23 + if (size() == 2) return (at(1) - at(0)).norm(); //if there are only two points, the direction vector at both is the direction of the line segment
  24 + if (i == 0) return (at(1) - at(0)).norm(); //the first direction vector is oriented towards the first line segment
  25 + if (i == size() - 1) return at(size() - 1) - at(size() - 2); //the last direction vector is oriented towards the last line segment
37 26  
38   - for(unsigned int i = 0; i < N; i++) //allocate space for each point
39   - c[i] = (double*) malloc(sizeof(double) * 3);
  27 + //all other direction vectors are the average direction of the two joined line segments
  28 + return ((at(i) - at(i - 1)).norm() + (at(i + 1) - at(i)).norm()).norm();
40 29 }
41   -
42   - /// Copies an existing fiber to the current fiber
43   -
44   - /// @param cpy stores the new copy of the fiber
45   - void copy( const stim::centerline<T>& cpy, bool kd = 0){
46   -
47   - ///allocate space for the new fiber
48   - init(cpy.N);
49   -
50   - ///copy the points
51   - for(unsigned int i = 0; i < N; i++){
52   - for(unsigned int d = 0; d < 3; d++) //for each dimension
53   - c[i][d] = cpy.c[i][d]; //copy the coordinate
  30 + //initializes the integrated length vector to make parameterization easier, starting with index idx (all previous indices are assumed to be correct)
  31 + void update_L(size_t start = 0) {
  32 + L.resize(size()); //allocate space for the L array
  33 + if (start == 0) {
  34 + L[0] = 0; //initialize the length value for the first point to zero (0)
  35 + start++;
54 36 }
55   -// if(kd)
56   -// gen_kdtree(); //generate the kd tree for the new fiber
57   - }
58 37  
59   - /// generate a KD tree for points on fiber
60   -// void gen_kdtree()
61   -// {
62   -// int n_data = N; //create an array of data points
63   -// ANNpointArray pts = (ANNpointArray)c; //cast the centerline list to an ANNpointArray
64   -// kdt = new ANNkd_tree(pts, n_data, 3); //build a KD tree
65   -// }
66   -
67   - /// find distance between two points
68   - double dist(double* p0, double* p1){
69   -
70   - double sum = 0; // initialize variables
71   - float v;
72   - for(unsigned int d = 0; d < 3; d++)
73   - {
74   - v = p1[d] - p0[d];
75   - sum +=v * v;
  38 + stim::vec3<T> d;
  39 + for (size_t i = start; i < size(); i++) { //for each line segment in the centerline
  40 + d = at(i) - at(i - 1);
  41 + L[i] = L[i - 1] + d.len(); //calculate the running length total
76 42 }
77   - return sqrt(sum);
78 43 }
79 44  
80   - /// This function retreives the index for the fiber point closest to q
81   -
82   - /// @param q is a reference point used to find the closest point on the fiber center line
83   -// unsigned int ann( stim::vec<double> q ){
84   -// ANNidxArray idx = new ANNidx[1]; //variable used to hold the nearest point
85   -// ANNdistArray sq_dist = new ANNdist[1]; //variable used to hold the squared distance to the nearest point
86   -// kdt->annkSearch(q.data(), 1, idx, sq_dist); //search the KD tree for the nearest neighbor
87   -// return *idx;
88   -// }
  45 + void init() {
  46 + if (size() == 0) return; //return if there aren't any points
  47 + update_L();
  48 + }
89 49  
90 50 /// Returns a stim::vec representing the point at index i
91 51  
92 52 /// @param i is an index of the desired centerline point
93 53 stim::vec<T> get_vec(unsigned i){
94   - stim::vec3<T> r;
95   - r.resize(3);
96   - r[0] = c[i][0];
97   - r[1] = c[i][1];
98   - r[2] = c[i][2];
  54 + return std::vector< stim::vec3<T> >::at(i);
  55 + }
  56 +
  57 + ///finds the index of the point closest to the length l on the lower bound.
  58 + ///binary search.
  59 + size_t findIdx(T l) {
  60 + size_t i = L.size() / 2;
  61 + size_t max = L.size() - 1;
  62 + size_t min = 0;
  63 + while (i > 0 && i < L.size() - 1){
  64 + if (l < L[i]) {
  65 + max = i;
  66 + i = min + (max - min) / 2;
  67 + }
  68 + else if (L[i] <= l && L[i + 1] >= l) {
  69 + break;
  70 + }
  71 + else {
  72 + min = i;
  73 + i = min + (max - min) / 2;
  74 + }
  75 + }
  76 + return i;
  77 + }
99 78  
100   - return r;
  79 + ///Returns a position vector at the given length into the fiber (based on the pvalue).
  80 + ///Interpolates the radius along the line.
  81 + ///@param l: the location of the in the cylinder.
  82 + ///@param idx: integer location of the point closest to l but prior to it.
  83 + stim::vec3<T> p(T l, int idx) {
  84 + T rat = (l - L[idx]) / (L[idx + 1] - L[idx]);
  85 + stim::vec3<T> v1 = at(idx);
  86 + stim::vec3<T> v2 = at(idx + 1);
  87 + return(v1 + (v2 - v1)*rat);
101 88 }
102 89  
103 90  
104 91 public:
105 92  
106   - centerline(){
107   - init();
108   - }
  93 + using std::vector< stim::vec3<T> >::at;
  94 + using std::vector< stim::vec3<T> >::size;
109 95  
110   - /// Copy constructor
111   - centerline(const stim::centerline<T> &obj){
112   - copy(obj);
  96 + centerline() : std::vector< stim::vec3<T> >() {
  97 + init();
113 98 }
114   -
115   - //temp constructor for graph visualization
116   - centerline(int n)
117   - {
118   - init(n);
  99 + centerline(size_t n) : std::vector< stim::vec3<T> >(n){
  100 + init();
119 101 }
120 102  
121   - /// Constructor takes a list of stim::vec points, the radius at each point is set to zero
122   - centerline(std::vector< stim::vec<T> > p, bool kd = 0){
123   - init(p.size()); //initialize the fiber
124   -
125   - //for each point, set the centerline position and radius
126   - for(unsigned int i = 0; i < N; i++){
127   -
128   - //set the centerline position
129   - for(unsigned int d = 0; d < 3; d++)
130   - c[i][d] = (double) p[i][d];
131   -
132   - //set the radius
133   - }
134   - //generate a kd tree
135   -// if(kd)
136   -// gen_kdtree();
  103 + //overload the push_back function to update the length vector
  104 + void push_back(stim::vec3<T> p) {
  105 + std::vector< stim::vec3<T> >::push_back(p);
  106 + update_L(size() - 1);
137 107 }
138 108  
139   - /// constructor takes a list of points
140   - centerline(std::vector< stim::vec3< T > > pos, bool kd = 0){
141   - init(pos.size()); //initialize the fiber
  109 + ///Returns a position vector at the given p-value (p value ranges from 0 to 1).
  110 + ///interpolates the position along the line.
  111 + ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
  112 + stim::vec3<T> p(T pvalue) {
  113 + if (pvalue <= 0.0) return at(0); //return the first element
  114 + if (pvalue >= 1.0) return back(); //return the last element
142 115  
143   - //for each point, set the centerline position and radius
144   - for(unsigned int i = 0; i < N; i++){
145   - //set the centerline position
146   - for(unsigned int d = 0; d < 3; d++)
147   - c[i][d] = (double) pos[i][d];
148   - //set the radius
149   - }
150   -
151   - //generate a kd tree
152   - //if(kd)
153   - // gen_kdtree();
  116 + T l = pvalue*L[L.size() - 1];
  117 + int idx = findIdx(l);
  118 + return p(l, idx);
154 119 }
155 120  
156   - /// Assignment operation
157   - centerline& operator=(const centerline &rhs){
158   - if(this == &rhs) return *this; //test for and handle self-assignment
159   - copy(rhs);
160   - return *this;
161   - }
162   -
163   -
164   - /// Return the point on the fiber closest to q
165   - /// @param q is the query point used to locate the nearest point on the fiber centerline
166   -// stim::vec<T> nearest(stim::vec<T> q){
167   -//
168   -// stim::vec<double> temp( (double) q[0], (double) q[1], (double) q[2]);
169   -//
170   -// unsigned int idx = ann(temp); //determine the index of the nearest neighbor
171   -//
172   -// return stim::vec<T>((T) c[idx][0], (T) c[idx][1], (T) c[idx][2]); //return the nearest centerline point
173   -// }
174   -
175   - /// Return the point index on the fiber closest to q
176   - /// @param q is the query point used to locate the nearest point on the fiber centerline
177   -// unsigned int nearest_idx(stim::vec<T> q){
178   -//
179   -// stim::vec<double> temp((double) q[0], (double) q[1], (double) q[2]);
180   -//
181   -// unsigned int idx = ann(temp); //determine the index of the nearest neighbor
182   -//
183   -// return idx; //return the nearest centerline point index
184   -// }
185   -
186   - /// Returns the fiber centerline as an array of stim::vec points
187   - std::vector< stim::vec<T> > get_centerline(){
188   -
189   - //create an array of stim vectors
190   - std::vector< stim::vec3<T> > pts(N);
191   -
192   - //cast each point to a stim::vec, keeping only the position information
193   - for(unsigned int i = 0; i < N; i++)
194   - pts[i] = stim::vec3<T>((T) c[i][0], (T) c[i][1], (T) c[i][2]);
195   -
196   - //return the centerline array
197   - return pts;
  121 + ///Return the length of the entire centerline
  122 + T length() {
  123 + return L.back();
198 124 }
199 125  
200 126 /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned
201 127 std::vector< stim::centerline<T> > split(unsigned int idx){
202 128  
203   - std::vector< stim::centerline<T> > fl; //create an array to store up to two fibers
  129 + std::vector< stim::centerline<T> > fl; //create an array to store up to two fibers
  130 + size_t N = size();
204 131  
205 132 //if the index is an end point, only the existing fiber is returned
206 133 if(idx == 0 || idx == N-1){
... ... @@ -211,128 +138,89 @@ public:
211 138 //if the index is not an end point
212 139 else{
213 140  
214   - unsigned int N1 = idx + 1; //calculate the size of both fibers
  141 + unsigned int N1 = idx; //calculate the size of both fibers
215 142 unsigned int N2 = N - idx;
216 143  
217 144 fl.resize(2); //set the array size to 2
218 145  
219   - fl[0].init(N1); //set the size of each fiber
220   - fl[1].init(N2);
  146 + fl[0] = stim::centerline<T>(N1); //set the size of each fiber
  147 + fl[1] = stim::centerline<T>(N2);
221 148  
222 149 //copy both halves of the fiber
223   - unsigned int i, d;
  150 + unsigned int i;
224 151  
225 152 //first half
226   - for(i = 0; i < N1; i++){ //for each centerline point
227   - for(d = 0; d < 3; d++)
228   - fl[0].c[i][d] = c[i][d]; //copy each coordinate
229   - }
  153 + for(i = 0; i < N1; i++) //for each centerline point
  154 + fl[0][i] = std::vector< stim::vec3<T> >::at(i);
  155 + fl[0].init(); //initialize the length vector
230 156  
231 157 //second half
232   - for(i = 0; i < N2; i++){
233   - for(d = 0; d < 3; d++)
234   - fl[1].c[i][d] = c[idx + i][d];
235   -
236   - }
  158 + for(i = 0; i < N2; i++)
  159 + fl[1][i] = std::vector< stim::vec3<T> >::at(idx+i);
  160 + fl[1].init(); //initialize the length vector
237 161 }
238 162  
239 163 return fl; //return the array
240 164  
241 165 }
242 166  
243   - /// Calculates the set of fibers resulting from a connection between the current fiber and a fiber f
244   -
245   - /// @param f is the fiber that will be connected to the current fiber
246   -/* std::vector< stim::centerline<T> > connect( stim::centerline<T> &f, double dist){
247   -
248   - double min_dist;
249   - unsigned int idx0, idx1;
250   -
251   - //go through each point in the query fiber, looking for the indices for the closest points
252   - for(unsigned int i = 0; i < f.n_pts(); i++){
253   - //Run through all points and find the index with the closest point, then partition the fiber and return two fibers.
254   -
255   - }
256   -
257   -
258   -
259   - }
260   -*/
261 167 /// Outputs the fiber as a string
262 168 std::string str(){
263 169 std::stringstream ss;
264   -
265   - //create an iterator for the point list
266   - //typename std::list< point<T> >::iterator i;
267   - for(unsigned int i = 0; i < N; i++){
268   - ss<<" [ ";
269   - for(unsigned int d = 0; d < 3; d++){
270   - ss<<c[i][d]<<" ";
271   - }
272   - }
  170 + size_t N = std::vector< stim::vec3<T> >::size();
  171 + ss << "---------[" << N << "]---------" << std::endl;
  172 + for (size_t i = 0; i < N; i++)
  173 + ss << std::vector< stim::vec3<T> >::at(i) << std::endl;
  174 + ss << "--------------------" << std::endl;
273 175  
274 176 return ss.str();
275 177 }
276   - /// Returns the number of centerline points in the fiber
277   - unsigned int size(){
278   - return N;
279   - }
280   -
281   -
282   - /// Bracket operator returns the element at index i
283   -
284   - /// @param i is the index of the element to be returned as a stim::vec
285   - stim::vec<T> operator[](unsigned i){
286   - return get_vec(i);
287   - }
288 178  
289 179 /// Back method returns the last point in the fiber
290   - stim::vec<T> back(){
291   - return get_vec(N-1);
  180 + stim::vec3<T> back(){
  181 + return std::vector< stim::vec3<T> >::back();
292 182 }
  183 +
293 184 ////resample a fiber in the network
294 185 stim::centerline<T> resample(T spacing)
295 186 {
296 187 std::cout<<"fiber::resample()"<<std::endl;
297 188  
298   - std::vector<T> v(3); //v-direction vector of the segment
299   - stim::vec<T> p(3); //- intermediate point to be added
300   - stim::vec<T> p1(3); // p1 - starting point of an segment on the fiber,
301   - stim::vec<T> p2(3); // p2 - ending point,
302   - double sum=0; //distance summation
303   - std::vector<stim::vec<T> > fiberPositions = centerline();
304   - std::vector<stim::vec<T> > newPointList; // initialize list of new resampled points on the fiber
  189 + stim::vec3<T> v; //v-direction vector of the segment
  190 + stim::vec3<T> p; //- intermediate point to be added
  191 + stim::vec3<T> p1; // p1 - starting point of an segment on the fiber,
  192 + stim::vec3<T> p2; // p2 - ending point,
  193 + //double sum=0; //distance summation
  194 +
  195 + size_t N = size();
  196 +
  197 + centerline<T> new_c; // initialize list of new resampled points on the fiber
305 198 // for each point on the centerline (skip if it is the last point on centerline)
306   - //unsigned int N = fiberPositions.size(); // number of points on the fiber
307 199 for(unsigned int f=0; f< N-1; f++)
308   - {
  200 + {
  201 + p1 = at(f);
  202 + p2 = at(f+1);
  203 + v = p2 - p1;
309 204  
310   - p1 = fiberPositions[f]; p2 = fiberPositions[f + 1]; v = p2 - p1;
311   - for(unsigned int d = 0; d < 3; d++){
312   - sum +=v[d] * v[d];} //length of segment-distance between starting and ending point
313   -
314   - T lengthSegment = sqrt(sum); //find Length of the segment as distance between the starting and ending points of the segment
315   -
316   - if(lengthSegment >= spacing) // if length of the segment is greater than standard deviation resample
317   - {
318   - // repeat resampling until accumulated stepsize is equsl to length of the segment
319   - for(T step=0.0; step<lengthSegment; step+=spacing)
320   - {
321   - // calculate the resampled point by travelling step size in the direction of normalized gradient vector
322   - for(unsigned int i=0; i<3;i++)
323   - {
324   - p[i] = p1[i] + v[i]*(step/lengthSegment);
325   - } //for each dimension
326   - // add this resampled points to the new fiber list
327   - newPointList.push_back(p);
328   - }
  205 + T lengthSegment = v.len(); //find Length of the segment as distance between the starting and ending points of the segment
  206 +
  207 + if(lengthSegment >= spacing){ // if length of the segment is greater than standard deviation resample
  208 +
  209 + // repeat resampling until accumulated stepsize is equsl to length of the segment
  210 + for(T step=0.0; step<lengthSegment; step+=spacing){
  211 + // calculate the resampled point by travelling step size in the direction of normalized gradient vector
  212 + p = p1 + v * (step / lengthSegment);
  213 +
  214 + // add this resampled points to the new fiber list
  215 + new_c.push_back(p);
329 216 }
330   - else // length of the segment is now less than standard deviation, push the ending point of the segment and proceed to the next point in the fiber
331   - newPointList.push_back(fiberPositions[f+1]);
332 217 }
333   - newPointList.push_back(fiberPositions[N-1]); //add the last point on the fiber to the new fiber list
334   - centerline newFiber(newPointList);
335   - return newFiber;
  218 + else // length of the segment is now less than standard deviation, push the ending point of the segment and proceed to the next point in the fiber
  219 + new_c.push_back(at(f+1));
  220 + }
  221 + new_c.push_back(at(N-1)); //add the last point on the fiber to the new fiber list
  222 + //centerline newFiber(newPointList);
  223 + return new_c;
336 224 }
337 225  
338 226 };
... ...
stim/biomodels/centerline_dep.h 0 → 100644
  1 +#ifndef STIM_CENTERLINE_H
  2 +#define STIM_CENTERLINE_H
  3 +
  4 +#include <vector>
  5 +#include <stim/math/vec3.h>
  6 +
  7 +namespace stim{
  8 +
  9 +/** This class stores information about a single fiber represented as a set of geometric points
  10 + * between two branch or end points. This class is used as a fundamental component of the stim::network
  11 + * class to describe an interconnected (often biological) network.
  12 + */
  13 +template<typename T>
  14 +class centerline{
  15 +
  16 +protected:
  17 + unsigned int N; //number of points in the fiber
  18 + double **c; //centerline (array of double pointers)
  19 +
  20 + /// Initialize an empty fiber
  21 + void init(){
  22 + N=0;
  23 + c=NULL;
  24 + }
  25 +
  26 + /// Initialize a fiber with N centerline points (all located at [0, 0, 0] with radius 0)
  27 + void init(unsigned int n){
  28 +
  29 + N = n; //set the number of points
  30 + c = (double**) malloc(sizeof(double*) * N); //allocate the array pointer
  31 +
  32 + for(unsigned int i = 0; i < N; i++) //allocate space for each point
  33 + c[i] = (double*) malloc(sizeof(double) * 3);
  34 + }
  35 +
  36 + /// Copies an existing fiber to the current fiber
  37 +
  38 + /// @param cpy stores the new copy of the fiber
  39 + void copy( const stim::centerline<T>& cpy, bool kd = 0){
  40 +
  41 + ///allocate space for the new fiber
  42 + init(cpy.N);
  43 +
  44 + ///copy the points
  45 + for(unsigned int i = 0; i < N; i++){
  46 + for(unsigned int d = 0; d < 3; d++) //for each dimension
  47 + c[i][d] = cpy.c[i][d]; //copy the coordinate
  48 + }
  49 + }
  50 +
  51 + /// find distance between two points
  52 + double dist(double* p0, double* p1){
  53 +
  54 + double sum = 0; // initialize variables
  55 + float v;
  56 + for(unsigned int d = 0; d < 3; d++)
  57 + {
  58 + v = p1[d] - p0[d];
  59 + sum +=v * v;
  60 + }
  61 + return sqrt(sum);
  62 + }
  63 +
  64 + /// Returns a stim::vec representing the point at index i
  65 +
  66 + /// @param i is an index of the desired centerline point
  67 + stim::vec<T> get_vec(unsigned i){
  68 + stim::vec3<T> r;
  69 + r.resize(3);
  70 + r[0] = c[i][0];
  71 + r[1] = c[i][1];
  72 + r[2] = c[i][2];
  73 +
  74 + return r;
  75 + }
  76 +
  77 +
  78 +public:
  79 +
  80 + centerline(){
  81 + init();
  82 + }
  83 +
  84 + /// Copy constructor
  85 + centerline(const stim::centerline<T> &obj){
  86 + copy(obj);
  87 + }
  88 +
  89 + //initialize a centerline with n points
  90 + centerline(int n){
  91 + init(n);
  92 + }
  93 +
  94 + /// Constructor takes a list of stim::vec points, the radius at each point is set to zero
  95 + centerline(std::vector< stim::vec<T> > p, bool kd = 0){
  96 + init(p.size()); //initialize the fiber
  97 +
  98 + //for each point, set the centerline position and radius
  99 + for(unsigned int i = 0; i < N; i++){
  100 +
  101 + //set the centerline position
  102 + for(unsigned int d = 0; d < 3; d++)
  103 + c[i][d] = (double) p[i][d];
  104 + }
  105 + }
  106 +
  107 + /// constructor takes a list of points
  108 + centerline(std::vector< stim::vec3< T > > pos, bool kd = 0){
  109 + init(pos.size()); //initialize the fiber
  110 +
  111 + //for each point, set the centerline position and radius
  112 + for(unsigned int i = 0; i < N; i++){
  113 + //set the centerline position
  114 + for(unsigned int d = 0; d < 3; d++)
  115 + c[i][d] = (double) pos[i][d];
  116 + }
  117 + }
  118 +
  119 + /// Assignment operation
  120 + centerline& operator=(const centerline &rhs){
  121 + if(this == &rhs) return *this; //test for and handle self-assignment
  122 + copy(rhs);
  123 + return *this;
  124 + }
  125 +
  126 +
  127 + /// Returns the fiber centerline as an array of stim::vec points
  128 + std::vector< stim::vec<T> > get_centerline(){
  129 +
  130 + //create an array of stim vectors
  131 + std::vector< stim::vec3<T> > pts(N);
  132 +
  133 + //cast each point to a stim::vec, keeping only the position information
  134 + for(unsigned int i = 0; i < N; i++)
  135 + pts[i] = stim::vec3<T>((T) c[i][0], (T) c[i][1], (T) c[i][2]);
  136 +
  137 + //return the centerline array
  138 + return pts;
  139 + }
  140 +
  141 + /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned
  142 + std::vector< stim::centerline<T> > split(unsigned int idx){
  143 +
  144 + std::vector< stim::centerline<T> > fl; //create an array to store up to two fibers
  145 +
  146 + //if the index is an end point, only the existing fiber is returned
  147 + if(idx == 0 || idx == N-1){
  148 + fl.resize(1); //set the size of the fiber to 1
  149 + fl[0] = *this; //copy the current fiber
  150 + }
  151 +
  152 + //if the index is not an end point
  153 + else{
  154 +
  155 + unsigned int N1 = idx + 1; //calculate the size of both fibers
  156 + unsigned int N2 = N - idx;
  157 +
  158 + fl.resize(2); //set the array size to 2
  159 +
  160 + fl[0].init(N1); //set the size of each fiber
  161 + fl[1].init(N2);
  162 +
  163 + //copy both halves of the fiber
  164 + unsigned int i, d;
  165 +
  166 + //first half
  167 + for(i = 0; i < N1; i++){ //for each centerline point
  168 + for(d = 0; d < 3; d++)
  169 + fl[0].c[i][d] = c[i][d]; //copy each coordinate
  170 + }
  171 +
  172 + //second half
  173 + for(i = 0; i < N2; i++){
  174 + for(d = 0; d < 3; d++)
  175 + fl[1].c[i][d] = c[idx + i][d];
  176 +
  177 + }
  178 + }
  179 +
  180 + return fl; //return the array
  181 +
  182 + }
  183 +
  184 + /// Outputs the fiber as a string
  185 + std::string str(){
  186 + std::stringstream ss;
  187 +
  188 + //create an iterator for the point list
  189 + //typename std::list< point<T> >::iterator i;
  190 + for(unsigned int i = 0; i < N; i++){
  191 + ss<<" [ ";
  192 + for(unsigned int d = 0; d < 3; d++){
  193 + ss<<c[i][d]<<" ";
  194 + }
  195 + }
  196 +
  197 + return ss.str();
  198 + }
  199 + /// Returns the number of centerline points in the fiber
  200 + unsigned int size(){
  201 + return N;
  202 + }
  203 +
  204 +
  205 + /// Bracket operator returns the element at index i
  206 +
  207 + /// @param i is the index of the element to be returned as a stim::vec
  208 + stim::vec<T> operator[](unsigned i){
  209 + return get_vec(i);
  210 + }
  211 +
  212 + /// Back method returns the last point in the fiber
  213 + stim::vec<T> back(){
  214 + return get_vec(N-1);
  215 + }
  216 + ////resample a fiber in the network
  217 + stim::centerline<T> resample(T spacing)
  218 + {
  219 + std::cout<<"fiber::resample()"<<std::endl;
  220 +
  221 + std::vector<T> v(3); //v-direction vector of the segment
  222 + stim::vec<T> p(3); //- intermediate point to be added
  223 + stim::vec<T> p1(3); // p1 - starting point of an segment on the fiber,
  224 + stim::vec<T> p2(3); // p2 - ending point,
  225 + double sum=0; //distance summation
  226 + std::vector<stim::vec<T> > fiberPositions = centerline();
  227 + std::vector<stim::vec<T> > newPointList; // initialize list of new resampled points on the fiber
  228 + // for each point on the centerline (skip if it is the last point on centerline)
  229 + for(unsigned int f=0; f< N-1; f++)
  230 + {
  231 +
  232 + p1 = fiberPositions[f]; p2 = fiberPositions[f + 1]; v = p2 - p1;
  233 + for(unsigned int d = 0; d < 3; d++){
  234 + sum +=v[d] * v[d];} //length of segment-distance between starting and ending point
  235 +
  236 + T lengthSegment = sqrt(sum); //find Length of the segment as distance between the starting and ending points of the segment
  237 +
  238 + if(lengthSegment >= spacing) // if length of the segment is greater than standard deviation resample
  239 + {
  240 + // repeat resampling until accumulated stepsize is equsl to length of the segment
  241 + for(T step=0.0; step<lengthSegment; step+=spacing)
  242 + {
  243 + // calculate the resampled point by travelling step size in the direction of normalized gradient vector
  244 + for(unsigned int i=0; i<3;i++)
  245 + {
  246 + p[i] = p1[i] + v[i]*(step/lengthSegment);
  247 + } //for each dimension
  248 + // add this resampled points to the new fiber list
  249 + newPointList.push_back(p);
  250 + }
  251 + }
  252 + else // length of the segment is now less than standard deviation, push the ending point of the segment and proceed to the next point in the fiber
  253 + newPointList.push_back(fiberPositions[f+1]);
  254 + }
  255 + newPointList.push_back(fiberPositions[N-1]); //add the last point on the fiber to the new fiber list
  256 + centerline newFiber(newPointList);
  257 + return newFiber;
  258 + }
  259 +
  260 +};
  261 +
  262 +
  263 +
  264 +} //end namespace stim
  265 +
  266 +
  267 +
  268 +#endif
... ...
stim/biomodels/network.h
... ... @@ -15,6 +15,39 @@
15 15 #include <stim/cuda/cudatools/timer.h>
16 16  
17 17  
  18 +#ifdef __CUDACC__
  19 +//device gaussian function
  20 +__device__ float gaussianFunction(float x, float std){ return expf(-x/(2*std*std));}
  21 +
  22 +//compute metric in parallel
  23 +template <typename T>
  24 +__global__ void d_metric(T* M, size_t n, T* D, float sigma){
  25 + size_t x = blockDim.x * blockIdx.x + threadIdx.x;
  26 + if(x >= n) return;
  27 + M[x] = 1.0f - gaussianFunction(D[x], sigma);
  28 +}
  29 +
  30 +//find the corresponding edge index from array index
  31 +__global__ void d_findedge(size_t* I, size_t n, unsigned* R, size_t* E, size_t ne){
  32 + size_t x = blockDim.x * blockIdx.x + threadIdx.x;
  33 + if(x >= n) return;
  34 + unsigned i = 0;
  35 + size_t N = 0;
  36 + for(unsigned e = 0; e < ne; e++){
  37 + N += E[e];
  38 + if(I[x] < N){
  39 + R[x] = i;
  40 + break;
  41 + }
  42 + i++;
  43 + }
  44 +}
  45 +#endif
  46 +
  47 +//hard-coded factor
  48 +int threshold_fac = 10;
  49 +float metric_fac = 0.6f; // might be related to the distance field
  50 +
18 51 namespace stim{
19 52 /** This is the a class that interfaces with gl_spider in order to store the currently
20 53 * segmented network. The following data is stored and can be extracted:
... ... @@ -22,7 +55,6 @@ namespace stim{
22 55 * 2)Network connectivity (a graph of nodes and edges), reconstructed using ANN library.
23 56 */
24 57  
25   -
26 58 template<typename T>
27 59 class network{
28 60  
... ... @@ -33,16 +65,15 @@ class network{
33 65 public:
34 66 unsigned v[2]; //unique id's designating the starting and ending
35 67 // default constructor
36   - edge() : cylinder<T>()
37   - {
  68 + edge() : cylinder<T>() {
38 69 v[1] = (unsigned)(-1); v[0] = (unsigned)(-1);
39 70 }
40 71 /// Constructor - creates an edge from a list of points by calling the stim::fiber constructor
41 72  
42 73 ///@param p is an array of positions in space
43   - edge(std::vector< stim::vec3<T> > p) : cylinder<T>(p){}
  74 + edge(centerline p) : cylinder<T>(p){}
44 75  
45   - /// Copy constructor creates an edge from a fiber
  76 + /// Copy constructor creates an edge from a cylinder
46 77 edge(stim::cylinder<T> f) : cylinder<T>(f) {}
47 78  
48 79 /// Resamples an edge by calling the fiber resampling function
... ... @@ -61,6 +92,19 @@ class network{
61 92 return ss.str();
62 93 }
63 94  
  95 + std::vector<edge> split(unsigned int idx){
  96 +
  97 + std::vector< stim::cylinder<T> > C;
  98 + C.resize(2);
  99 + C = (*this).cylinder<T>::split(idx);
  100 + std::vector<edge> E(C.size());
  101 +
  102 + for(unsigned e = 0; e < E.size(); e++){
  103 + E[e] = C[e];
  104 + }
  105 + return E;
  106 + }
  107 +
64 108 };
65 109  
66 110 ///Node class that stores the physical position of the node as well as the edges it is connected to (edges that connect to it), As well as any additional data necessary.
... ... @@ -291,7 +335,7 @@ public:
291 335 std::vector< stim::vec<T> > c; //allocate an array of points for the vessel centerline
292 336 O.getLine(l, c); //get the fiber centerline
293 337  
294   - std::vector< stim::vec3<T> > c3(c.size());
  338 + stim::centerline<T> c3(c.size());
295 339 for(size_t j = 0; j < c.size(); j++)
296 340 c3[j] = c[j];
297 341  
... ... @@ -377,7 +421,8 @@ public:
377 421 return n; //return the resampled network
378 422 }
379 423  
380   -
  424 + // host gaussian function
  425 + __host__ float gaussianFunction(float x, float std = 25){ return exp(-x/(2*std*std));} // std default value is 25
381 426  
382 427 /// Calculate the total number of points on all edges.
383 428 unsigned total_points(){
... ... @@ -403,9 +448,6 @@ public:
403 448 }
404 449 }
405 450  
406   - // gaussian function
407   - float gaussianFunction(float x, float std=25){ return exp(-x/(2*std*std));} // by default std = 25
408   -
409 451 // convert vec3 to array
410 452 void stim2array(float *a, stim::vec3<T> b){
411 453 a[0] = b[0];
... ... @@ -413,6 +455,16 @@ public:
413 455 a[2] = b[2];
414 456 }
415 457  
  458 + // convert vec3 to array in bunch
  459 + void edge2array(T* a, std::vector< typename stim::vec3<T> > b){
  460 + size_t n = b.size();
  461 + for(size_t i = 0; i < n; i++){
  462 + a[i * 3 + 0] = b[i][0];
  463 + a[i * 3 + 1] = b[i][1];
  464 + a[i * 3 + 2] = b[i][2];
  465 + }
  466 + }
  467 +
416 468 /// Calculate the average magnitude across the entire network.
417 469 /// @param m is the magnitude value to use. The default is 0 (usually radius).
418 470 T average(unsigned m = 0){
... ... @@ -420,7 +472,7 @@ public:
420 472 T M, L; //allocate space for the total magnitude and length
421 473 M = L = 0; //initialize both the initial magnitude and length to zero
422 474 for(unsigned e = 0; e < E.size(); e++){ //for each edge in the network
423   - M += E[e].integrate(m); //get the integrated magnitude
  475 + M += E[e].integrate(); //get the integrated magnitude
424 476 L += E[e].length(); //get the edge length
425 477 }
426 478  
... ... @@ -428,9 +480,9 @@ public:
428 480 }
429 481  
430 482 /// This function compares two networks and returns the percentage of the current network that is missing from A.
431   -
432 483 /// @param A is the network to compare to - the field is generated for A
433 484 /// @param sigma is the user-defined tolerance value - smaller values provide a stricter comparison
  485 + /// @param device is the device that user want to use
434 486 stim::network<T> compare(stim::network<T> A, float sigma, int device){
435 487  
436 488 stim::network<T> R; //generate a network storing the result of the comparison
... ... @@ -452,61 +504,363 @@ public:
452 504 }
453 505  
454 506 //generate a KD-tree for network A
455   - //float metric = 0.0; // initialize metric to be returned after comparing the network
456 507 size_t MaxTreeLevels = 3; // max tree level
457 508  
458 509 #ifdef __CUDACC__
459 510 cudaSetDevice(device);
460   - stim::cuda_kdtree<T, 3> kdt; // initialize a pointer to a kd tree
  511 + stim::kdtree<T, 3> kdt; // initialize a pointer to a kd tree
  512 +
  513 + kdt.create(c, n_data, MaxTreeLevels); // build a KD tree
  514 +
  515 + for(unsigned e = 0; e < R.E.size(); e++){ //for each edge in A
  516 + R.E[e].add_mag(0); //add a new magnitude for the metric
  517 + size_t errormag_id = R.E[e].nmags() - 1; //get the id for the new magnitude
  518 +
  519 + size_t n = R.E[e].size(); // the number of points in current edge
  520 + T* queryPt = new T[n];
  521 + T* m1 = new T[n];
  522 + T* dists = new T[n];
  523 + size_t* nnIdx = new size_t[n];
  524 +
  525 + T* d_dists;
  526 + T* d_m1;
  527 + cudaMalloc((void**)&d_dists, n * sizeof(T));
  528 + cudaMalloc((void**)&d_m1, n * sizeof(T));
  529 +
  530 + edge2array(queryPt, R.E[e]);
  531 + kdt.search(queryPt, n, nnIdx, dists);
  532 +
  533 + cudaMemcpy(d_dists, dists, n * sizeof(T), cudaMemcpyHostToDevice); // copy dists from host to device
  534 +
  535 + // configuration parameters
  536 + size_t threads = (1024>n)?n:1024;
  537 + size_t blocks = n/threads + (n%threads)?1:0;
  538 +
  539 + d_metric<<<blocks, threads>>>(d_m1, n, d_dists, sigma); //calculate the metric value based on the distance
  540 +
  541 + cudaMemcpy(m1, d_m1, n * sizeof(T), cudaMemcpyDeviceToHost);
  542 +
  543 + for(unsigned p = 0; p < n; p++){
  544 + R.E[e].set_mag(errormag_id, p, m1[p]);
  545 + }
  546 +
  547 + //d_set_mag<<<blocks, threads>>>(R.E[e].M, errormag_id, n, m1);
  548 + }
  549 +
  550 +#else
  551 + stim::kdtree<T, 3> kdt;
  552 + kdt.create(c, n_data, MaxTreeLevels);
  553 +
  554 + for(unsigned e = 0; e < R.E.size(); e++){ //for each edge in A
  555 + R.E[e].add_mag(0); //add a new magnitude for the metric
  556 + size_t errormag_id = R.E[e].nmags() - 1;
  557 +
  558 + size_t n = R.E[e].size(); // the number of points in current edge
  559 + T* query = new T[n];
  560 + T* m1 = new T[n];
  561 + T* dists = new T[n];
  562 + size* nnIdx = new size_t[n];
  563 +
  564 + edge2array(queryPt, R.E[e]);
  565 +
  566 + kdt.cpu_search(queryPt, n, nnIdx, dists); //find the distance between A and the current network
  567 +
  568 + for(unsigned p = 0; p < R.E[e].size(); p++){
  569 + m1[p] = 1.0f - gaussianFunction((T)dists[p], sigma); //calculate the metric value based on the distance
  570 + R.E[e].set_mag(errormag_id, p, m1[p]); //set the error for the second point in the segment
  571 + }
  572 + }
  573 +#endif
  574 + return R; //return the resulting network
  575 + }
  576 +
  577 + /// This function compares two networks and split the current one according to the nearest neighbor of each point in each edge
  578 + /// @param A is the network to split
  579 + /// @param B is the corresponding mapping network
  580 + /// @param sigma is the user-defined tolerance value - smaller values provide a stricter comparison
  581 + /// @param device is the device that user want to use
  582 + void split(stim::network<T> A, stim::network<T> B, float sigma, int device){
  583 +
  584 + T *c;
  585 + size_t n_data = B.total_points();
  586 + c = (T*) malloc(sizeof(T) * n_data * 3);
  587 +
  588 + size_t NB = B.E.size(); // the number of edges in B
  589 + unsigned t = 0;
  590 + for(unsigned e = 0; e < NB; e++){ // for every edge in B
  591 + for(unsigned p = 0; p < B.E[e].size(); p++){ // for every points in B.E[e]
  592 + for(unsigned d = 0; d < 3; d++){
  593 +
  594 + c[t * 3 + d] = B.E[e][p][d]; // convert to array
  595 + }
  596 + t++;
  597 + }
  598 + }
  599 + size_t MaxTreeLevels = 3; // max tree level
  600 +
  601 +#ifdef __CUDACC__
  602 + cudaSetDevice(device);
  603 + stim::kdtree<T, 3> kdt; // initialize a pointer to a kd tree
461 604  
462 605 //compare each point in the current network to the field produced by A
463 606 kdt.create(c, n_data, MaxTreeLevels); // build a KD tree
464   - T *dists = new T[1]; // near neighbor distances
465   - size_t *nnIdx = new size_t[1]; // near neighbor indices // allocate near neigh indices
466 607  
467   - stim::vec3<T> p0, p1;
468   - T m1;
469   - //float M = 0; //stores the total metric value
470   - //float L = 0; //stores the total network length
  608 + std::vector<std::vector<unsigned>> relation; // the relationship between GT and T corresponding to NN
  609 + relation.resize(A.E.size());
  610 +
  611 + for(unsigned e = 0; e < A.E.size(); e++){ //for each edge in A
  612 + A.E[e].add_mag(0); //add a new magnitude for the metric
  613 + size_t errormag_id = A.E[e].nmags() - 1;
  614 +
  615 + size_t n = A.E[e].size(); // the number of edges in A
  616 +
  617 + T* queryPt = new T[n]; // set of all the points in current edge
  618 + T* m1 = new T[n]; // array of metrics for every point in current edge
  619 + T* dists = new T[n]; // store the distances for every point in current edge
  620 + size_t* nnIdx = new size_t[n]; // store the indices for every point in current edge
  621 +
  622 + // define pointers in device
  623 + T* d_dists;
  624 + T* d_m1;
  625 + size_t* d_nnIdx;
  626 +
  627 + // allocate memory for defined pointers
  628 + cudaMalloc((void**)&d_dists, n * sizeof(T));
  629 + cudaMalloc((void**)&d_m1, n * sizeof(T));
  630 + cudaMalloc((void**)&d_nnIdx, n * sizeof(size_t));
  631 +
  632 + edge2array(queryPt, A.E[e]); // convert edge to array
  633 + kdt.search(queryPt, n, nnIdx, dists); // search the tree to find the NN for every point in current edge
  634 +
  635 + cudaMemcpy(d_dists, dists, n * sizeof(T), cudaMemcpyHostToDevice); // copy dists from host to device
  636 + cudaMemcpy(d_nnIdx, nnIdx, n * sizeof(size_t), cudaMemcpyHostToDevice); // copy Idx from host to device
  637 +
  638 + // configuration parameters
  639 + size_t threads = (1024>n)?n:1024; // test to see whether the number of point in current edge is more than 1024
  640 + size_t blocks = n/threads + (n%threads)?1:0;
  641 +
  642 + d_metric<<<blocks, threads>>>(d_m1, n, d_dists, sigma); // calculate the metrics in parallel
  643 +
  644 + cudaMemcpy(m1, d_m1, n * sizeof(T), cudaMemcpyDeviceToHost);
  645 +
  646 + for(unsigned p = 0; p < n; p++){
  647 + A.E[e].set_mag(errormag_id, p, m1[p]); // set the error(radius) value to every point in current edge
  648 + }
  649 +
  650 + relation[e].resize(n); // resize every edge relation size
  651 +
  652 + unsigned* d_relation;
  653 + cudaMalloc((void**)&d_relation, n * sizeof(unsigned)); // allocate memory
  654 +
  655 + std::vector<size_t> edge_point_num(NB); // %th element is the number of points that %th edge has
  656 + for(unsigned ee = 0; ee < NB; ee++)
  657 + edge_point_num[ee] = B.E[ee].size();
  658 +
  659 + size_t* d_edge_point_num;
  660 + cudaMalloc((void**)&d_edge_point_num, NB * sizeof(size_t));
  661 + cudaMemcpy(d_edge_point_num, &edge_point_num[0], NB * sizeof(size_t), cudaMemcpyHostToDevice);
  662 +
  663 + d_findedge<<<blocks, threads>>>(d_nnIdx, n, d_relation, d_edge_point_num, NB); // find the edge corresponding to the array index in parallel
  664 +
  665 + cudaMemcpy(&relation[e][0], d_relation, n * sizeof(unsigned), cudaMemcpyDeviceToHost); //copy relationship from device to host
  666 + }
  667 +#else
  668 + stim::kdtree<T, 3> kdt;
  669 + kdt.create(c, n_data, MaxTreeLevels);
  670 +
  671 + std::vector<std::vector<unsigned>> relation; // the mapping relationship between two networks
  672 + relation.resize(A.E.size());
  673 + for(unsigned i = 0; i < A.E.size(); i++)
  674 + relation[i].resize(A.E[i].size());
  675 +
  676 + std::vector<size_t> edge_point_num(NB); //%th element is the number of points that %th edge has
  677 + for(unsigned ee = 0; ee < NB; ee++)
  678 + edge_point_num[ee] = B.E[ee].size();
  679 +
471 680 T* queryPt = new T[3];
472   - for(unsigned e = 0; e < R.E.size(); e++){ //for each edge in A
473   - R.E[e].add_mag(0); //add a new magnitude for the metric
  681 + for(unsigned e = 0; e < A.E.size(); e++){ //for each edge in A
  682 + A.E[e].add_mag(0); //add a new magnitude for the metric
  683 + size_t errormag_id = A.E[e].nmags() - 1;
  684 +
  685 + size_t n = A.E[e].size(); // the number of edges in A
  686 +
  687 + T* queryPt = new T[n];
  688 + T* m1 = new T[n];
  689 + T* dists = new T[n]; //store the distances
  690 + size_t* nnIdx = new size_t[n]; //store the indices
  691 +
  692 + edge2array(queryPt, A.E[e]);
  693 + kdt.search(queryPt, n, nnIdx, dists);
  694 +
  695 + for(unsigned p = 0; p < A.E[e].size(); p++){
  696 + m1[p] = 1.0f - gaussianFunction((T)dists[p], sigma); //calculate the metric value based on the distance
  697 + A.E[e].set_mag(errormag_id, p, m1[p]); //set the error for the second point in the segment
  698 +
  699 + unsigned id = 0; //mapping edge's idx
  700 + size_t num = 0; //total number of points before #th edge
  701 + for(unsigned i = 0; i < NB; i++){
  702 + num += B.E[i].size();
  703 + if(nnIdx[p] < num){ //find the edge it belongs to
  704 + relation[e][p] = id;
  705 + break;
  706 + }
  707 + id++; //current edge won't be the one, move to next edge
  708 + }
  709 + }
  710 + }
  711 +#endif
  712 + E = A.E;
  713 + V = A.V;
  714 +
  715 + unsigned int id = 0; // split value
  716 + for(unsigned e = 0; e < E.size(); e++){ // for every edge
  717 + for(unsigned p = 0; p < E[e].size() - 1; p++){ // for every point in each edge
  718 + if(relation[e][p] != relation[e][p + 1]){ // find the nearest edge changing point
  719 + id = p + 1; // if there is no change in NN
  720 + if(id < E[e].size()/threshold_fac || (E[e].size() - id) < E[e].size()/threshold_fac) // set tolerance to 10, tentatively--should find out the mathematical threshold!
  721 + id = E[e].size() - 1; // extreme situation is not acceptable
  722 + else
  723 + break;
  724 + }
  725 + if(p == E[e].size() - 2) // if there is no splitting index, set the id to the last point index of current edge
  726 + id = p + 1;
  727 + }
  728 + unsigned errormag_id = E[e].nmags() - 1;
  729 + T G = 0; // test to see whether it has its nearest neighbor
  730 + for(unsigned i = 0; i < E[e].size(); i++)
  731 + G += E[e].m(i, errormag_id); // won't split special edges
  732 + if(G / E[e].size() > metric_fac) // should based on the color map
  733 + id = E[e].size() - 1; // set split idx to outgoing direction vertex
  734 +
  735 + std::vector<edge> tmpe;
  736 + tmpe.resize(2);
  737 + tmpe = E[e].split(id);
  738 + vertex tmpv = stim::vec3<T>(-1, -1, 0); // store the split point as vertex
  739 + if(tmpe.size() == 2){
  740 + relation.resize(relation.size() + 1);
  741 + for(unsigned d = id; d < E[e].size(); d++)
  742 + relation[relation.size() - 1].push_back(relation[e][d]);
  743 + tmpe[0].v[0] = E[e].v[0]; // begining vertex of first half edge -> original begining vertex
  744 + tmpe[1].v[1] = E[e].v[1]; // ending vertex of second half edge -> original ending vertex
  745 + tmpv = E[e][id];
  746 + V.push_back(tmpv);
  747 + tmpe[0].v[1] = (unsigned)V.size() - 1; // ending vertex of first half edge -> new vertex
  748 + tmpe[1].v[0] = (unsigned)V.size() - 1; // begining vertex of second half edge -> new vertex
  749 + edge tmp(E[e]);
  750 + E[e] = tmpe[0]; // replace original edge by first half edge
  751 + E.push_back(tmpe[1]); // push second half edge to the last
  752 + V[V.size() - 1].e[1].push_back(e); // push first half edge to the incoming of new vertex
  753 + V[V.size() - 1].e[0].push_back((unsigned)E.size() - 1); // push second half edge to the outgoing of new vertex
  754 + for(unsigned i = 0; i < V[tmp.v[1]].e[1].size(); i++) // find the incoming edge of original ending vertex
  755 + if(V[tmp.v[1]].e[1][i] == e)
  756 + V[tmp.v[1]].e[1][i] = (unsigned)V.size() - 1;
  757 + }
  758 + }
  759 + }
474 760  
475   - for(unsigned p = 0; p < R.E[e].size(); p++){ //for each point in the edge
  761 + /// This function compares two splitted networks and yields a mapping relationship between them according to NN
  762 + /// @param B is the network that the current network is going to map to
  763 + /// @param C is the mapping relationship: C[e1] = _e1 means e1 edge in current network is mapping the _e1 edge in B
  764 + /// @param device is the device that user want to use
  765 + void mapping(stim::network<T> B, std::vector<unsigned> &C, int device){
  766 + stim::network<T> A; //generate a network storing the result of the comparison
  767 + A = (*this);
476 768  
477   - p1 = R.E[e][p]; //get the next point in the edge
478   - stim2array(queryPt, p1);
479   - kdt.search(queryPt, 1, nnIdx, dists); //find the distance between A and the current network
  769 + size_t n = A.E.size(); // the number of edges in A
  770 + size_t NB = B.E.size(); // the number of edges in B
  771 +
  772 + C.resize(A.E.size());
  773 +
  774 + T *c; // centerline (array of double pointers) - points on kdtree must be double
  775 + size_t n_data = B.total_points(); // set the number of points
  776 + c = (T*) malloc(sizeof(T) * n_data * 3);
  777 +
  778 + unsigned t = 0;
  779 + for(unsigned e = 0; e < NB; e++){ // for each edge in the network
  780 + for(unsigned p = 0; p < B.E[e].size(); p++){ // for each point in the edge
  781 + for(unsigned d = 0; d < 3; d++){ // for each coordinate
  782 +
  783 + c[t * 3 + d] = B.E[e][p][d];
  784 + }
  785 + t++;
  786 + }
  787 + }
480 788  
481   - m1 = 1.0f - gaussianFunction((T)dists[0], sigma); //calculate the metric value based on the distance
482   - R.E[e].set_mag(m1, p, 1); //set the error for the second point in the segment
  789 + //generate a KD-tree for network A
  790 + //float metric = 0.0; // initialize metric to be returned after comparing the network
  791 + size_t MaxTreeLevels = 3; // max tree level
  792 +
  793 +#ifdef __CUDACC__
  794 + cudaSetDevice(device);
  795 + stim::kdtree<T, 3> kdt; // initialize a pointer to a kd tree
  796 +
  797 + kdt.create(c, n_data, MaxTreeLevels); // build a KD tree
483 798  
  799 + for(unsigned e = 0; e < n; e++){ //for each edge in A
  800 + size_t errormag_id = A.E[e].nmags() - 1; //get the id for the new magnitude
  801 +
  802 + //pre-judge to get rid of impossibly mapping edges
  803 + T M = 0;
  804 + for(unsigned p = 0; p < A.E[e].size(); p++)
  805 + M += A.E[e].m(p, errormag_id);
  806 + M = M / A.E[e].size();
  807 + if(M > metric_fac)
  808 + C[e] = (unsigned)-1; //set the nearest edge of impossibly mapping edges to maximum of unsigned
  809 + else{
  810 + T* queryPt = new T[1];
  811 + T* dists = new T[1];
  812 + size_t* nnIdx = new size_t[1];
  813 +
  814 + stim2array(queryPt, A.E[e][A.E[e].size()/2]);
  815 + kdt.search(queryPt, 1, nnIdx, dists);
  816 +
  817 + unsigned id = 0; //mapping edge's idx
  818 + size_t num = 0; //total number of points before #th edge
  819 + for(unsigned i = 0; i < NB; i++){
  820 + num += B.E[i].size();
  821 + if(nnIdx[0] < num){
  822 + C[e] = id;
  823 + break;
  824 + }
  825 + id++;
  826 + }
484 827 }
485 828 }
486 829 #else
487   - stim::cpu_kdtree<T, 3> kdt;
  830 + stim::kdtree<T, 3> kdt;
488 831 kdt.create(c, n_data, MaxTreeLevels);
489 832 T *dists = new T[1]; // near neighbor distances
490 833 size_t *nnIdx = new size_t[1]; // near neighbor indices // allocate near neigh indices
491 834  
492 835 stim::vec3<T> p0, p1;
493   - T m1;
494 836 T* queryPt = new T[3];
495   - for(unsigned e = 0; e < R.E.size(); e++){ //for each edge in A
496   - R.E[e].add_mag(0); //add a new magnitude for the metric
497 837  
498   - for(unsigned p = 0; p < R.E[e].size(); p++){ //for each point in the edge
499   -
500   - p1 = R.E[e][p]; //get the next point in the edge
  838 + for(unsigned e = 0; e < R.E.size(); e++){ // for each edge in A
  839 + T M; // the sum of metrics of current edge
  840 + unsigned errormag_id = R.E[e].nmags() - 1;
  841 + for(unsigned p = 0; p < R.E[e].size(); p++)
  842 + M += A.E[e].m(p, errormag_id);
  843 + M = M / A.E[e].size();
  844 + if(M > metric_fac) // if the sum is larger than the metric_fac, we assume that it doesn't has corresponding edge in B
  845 + C[e] = (unsigned)-1;
  846 + else{ // if it should have corresponding edge in B, then...
  847 + p1 = R.E[e][R.E[e].size()/2];
501 848 stim2array(queryPt, p1);
502   - kdt.cpu_search(queryPt, 1, nnIdx, dists); //find the distance between A and the current network
503   -
504   - m1 = 1.0f - gaussianFunction((T)dists[0], sigma); //calculate the metric value based on the distance
505   - R.E[e].set_mag(m1, p, 1); //set the error for the second point in the segment
  849 + kdt.cpu_search(queryPt, 1, nnIdx, dists); // search the tree
  850 +
  851 + unsigned id = 0; //mapping edge's idx
  852 + size_t num = 0; //total number of points before #th edge
  853 + for(unsigned i = 0; i < NB; i++){
  854 + num += B.E[i].size();
  855 + if(nnIdx[0] < num){
  856 + C[e] = id;
  857 + break;
  858 + }
  859 + id++;
  860 + }
506 861 }
507 862 }
508 863 #endif
509   - return R; //return the resulting network
510 864 }
511 865  
512 866 /// Returns the number of magnitude values stored in each edge. This should be uniform across the network.
... ... @@ -616,4 +970,4 @@ public:
616 970 }
617 971 }; //end stim::network class
618 972 }; //end stim namespace
619 973 -#endif
  974 +#endif
620 975 \ No newline at end of file
... ...
stim/math/circle.h
... ... @@ -18,13 +18,14 @@ class circle : plane&lt;T&gt;
18 18  
19 19 private:
20 20  
21   - stim::vec3<T> Y;
  21 + //stim::vec3<T> Y;
  22 + T R; //radius of the circle
22 23  
23   - CUDA_CALLABLE void
  24 + /*CUDA_CALLABLE void
24 25 init()
25 26 {
26 27 Y = U.cross(N).norm();
27   - }
  28 + }*/
28 29  
29 30 public:
30 31 using stim::plane<T>::n;
... ... @@ -42,26 +43,28 @@ public:
42 43 init();
43 44 }
44 45  
45   - ///create a rectangle given a size and position in Z space.
  46 + ///create a circle given a size and position in Z space.
46 47 ///@param size: size of the rectangle in ND space.
47 48 ///@param z_pos z coordinate of the rectangle.
48 49 CUDA_CALLABLE
49   - circle(T size, T z_pos = (T)0) : plane<T>()
  50 + circle(T radius, T z_pos = (T)0) : plane<T>(z_pos)
50 51 {
51   - center(stim::vec3<T>(0,0,z_pos));
52   - scale(size);
53   - init();
  52 + //center(stim::vec3<T>(0, 0, z_pos));
  53 + //scale(size);
  54 + //init();
  55 + R = radius;
54 56 }
55 57  
56 58 ///create a rectangle from a center point, normal
57 59 ///@param c: x,y,z location of the center.
58 60 ///@param n: x,y,z direction of the normal.
59 61 CUDA_CALLABLE
60   - circle(vec3<T> c, vec3<T> n = vec3<T>(0,0,1)) : plane<T>()
  62 + circle(vec3<T> c, vec3<T> n = vec3<T>(0,0,1)) : plane<T>(n, c)
61 63 {
62   - center(c);
63   - normal(n);
64   - init();
  64 + //center(c);
  65 + //normal(n);
  66 + //init();
  67 + R = (T)1;
65 68 }
66 69  
67 70 /*///create a rectangle from a center point, normal, and size
... ... @@ -84,14 +87,18 @@ public:
84 87 ///@param n: x,y,z direction of the normal.
85 88 ///@param u: x,y,z direction for the zero vector (from where the rotation starts)
86 89 CUDA_CALLABLE
87   - circle(vec3<T> c, T s, vec3<T> n = vec3<T>(0,0,1), vec3<T> u = vec3<T>(1, 0, 0)) : plane<T>()
  90 + circle(vec3<T> c, T r, vec3<T> n = vec3<T>(0,0,1), vec3<T> u = vec3<T>(1, 0, 0)) : plane<T>()
88 91 {
89   - init();
  92 + P = c;
  93 + N = n;
90 94 setU(u);
  95 + R = r;
  96 + //init();
  97 + //setU(u);
91 98 // U = u;
92   - center(c);
93   - normal(n);
94   - scale(s);
  99 + //center(c);
  100 + //normal(n);
  101 + //scale(s);
95 102 }
96 103  
97 104 ///scales the circle by a certain factor
... ... @@ -99,23 +106,23 @@ public:
99 106 CUDA_CALLABLE
100 107 void scale(T factor)
101 108 {
102   - U *= factor;
103   - Y *= factor;
  109 + //U *= factor;
  110 + //Y *= factor;
  111 + R *= factor;
104 112 }
105 113  
106 114 ///sets the normal for the cirlce
107 115 ///@param n: x,y,z direction of the normal.
108 116 CUDA_CALLABLE void
109   - normal(vec3<T> n)
110   - {
111   - rotate(n, Y);
  117 + normal(vec3<T> n){
  118 + rotate(n);
112 119 }
113 120  
114 121 ///sets the center of the circle.
115 122 ///@param n: x,y,z location of the center.
116 123 CUDA_CALLABLE void
117 124 center(vec3<T> p){
118   - this->P = p;
  125 + P = p;
119 126 }
120 127  
121 128 ///boolean comparison
... ... @@ -128,57 +135,63 @@ public:
128 135 return false;
129 136 }
130 137  
  138 + //returns the point in world space corresponding to the polar coordinate (r, theta)
  139 + CUDA_CALLABLE stim::vec3<T>
  140 + p(T r, T theta) {
  141 + T u = r * cos(theta); //calculate the coordinates in the planar space defined by the circle
  142 + T v = r * sin(theta);
  143 +
  144 + vec3<T> V = U.cross(N); //calculate the orthogonal vector V
  145 + return P + U * u + V * v; //calculate the cartesian coordinate of the specified point
  146 + }
  147 +
  148 + //returns the point in world space corresponding to the value theta at radius R
  149 + CUDA_CALLABLE stim::vec3<T>
  150 + p(T theta) {
  151 + return p(R, theta);
  152 + }
  153 +
  154 + //get the world space value given the polar coordinates (r, theta)
  155 +
131 156 ///get the world space value given the planar coordinates a, b in [0, 1]
132   - CUDA_CALLABLE stim::vec3<T> p(T a, T b)
  157 + /*CUDA_CALLABLE stim::vec3<T> p(T a, T b)
133 158 {
134 159 stim::vec3<T> result;
135 160  
136 161 vec3<T> A = this->P - this->U * (T)0.5 - Y * (T)0.5;
137 162 result = A + this->U * a + Y * b;
138 163 return result;
139   - }
  164 + }*/
140 165  
141 166 ///parenthesis operator returns the world space given rectangular coordinates a and b in [0 1]
142   - CUDA_CALLABLE stim::vec3<T> operator()(T a, T b)
  167 + CUDA_CALLABLE stim::vec3<T> operator()(T r, T theta)
143 168 {
144   - return p(a,b);
  169 + return p(r, theta);
  170 + }
  171 +
  172 + //parenthesis operator returns the world space coordinate at the edge of the circle given theta
  173 + CUDA_CALLABLE stim::vec3<T> operator()(T theta) {
  174 + return p(theta);
145 175 }
146 176  
147 177 ///returns a vector with the points on the initialized circle.
148 178 ///connecting the points results in a circle.
149 179 ///@param n: integer for the number of points representing the circle.
150   - std::vector<stim::vec3<T> >
151   - getPoints(int n)
152   - {
153   - std::vector<stim::vec3<T> > result;
154   - stim::vec3<T> point;
155   - T x,y;
156   - float step = 360.0/(float) n;
157   - for(float j = 0; j <= 360.0; j += step)
158   - {
159   - y = 0.5*cos(j*stim::TAU/360.0)+0.5;
160   - x = 0.5*sin(j*stim::TAU/360.0)+0.5;
161   - result.push_back(p(x,y));
162   - }
  180 + std::vector< stim::vec3<T> > points(unsigned n) {
  181 + std::vector< stim::vec3<T> > result(n); //initialize a vector of n points
  182 +
  183 + float dt = stim::TAU / n;
  184 + for (unsigned i = 0; i < n; i++)
  185 + result[i] = p(i * dt); //calculate a point on the edge of the circle
163 186 return result;
164 187 }
165 188  
166   - ///returns a vector with the points on the initialized circle.
167   - ///connecting the points results in a circle.
168   - ///@param n: integer for the number of points representing the circle.
169   - CUDA_CALLABLE stim::vec3<T>
170   - p(T theta)
171   - {
172   - T x,y;
173   - y = 0.5*cos(theta*STIM_TAU/360.0)+0.5;
174   - x = 0.5*sin(theta*STIM_TAU/360.0)+0.5;
175   - return p(x,y);
176   - }
  189 +
177 190  
178 191 std::string str() const
179 192 {
180 193 std::stringstream ss;
181   - ss << "(P=" << P.str() << ", N=" << N.str() << ", U=" << U.str() << ", Y=" << Y.str();
  194 + ss << "r = "<<R<<" (P=" << P.str() << ", N=" << N.str() << ", U=" << U.str() << ")";
182 195 return ss.str();
183 196 }
184 197  
... ...
stim/math/circle_dep.h 0 → 100644
  1 +#ifndef STIM_CIRCLE_H
  2 +#define STIM_CIRCLE_H
  3 +
  4 +#include <stim/cuda/cudatools/callable.h>
  5 +#include <stim/math/plane.h>
  6 +#include <stim/math/vector.h>
  7 +#include <stim/math/triangle.h>
  8 +#include <stim/math/constants.h>
  9 +#include <assert.h>
  10 +#include <algorithm>
  11 +#include <iostream>
  12 +
  13 +namespace stim{
  14 +
  15 +template <typename T>
  16 +class circle : plane<T>
  17 +{
  18 +
  19 +private:
  20 +
  21 + stim::vec3<T> Y;
  22 +
  23 + CUDA_CALLABLE void
  24 + init()
  25 + {
  26 + Y = U.cross(N).norm();
  27 + }
  28 +
  29 +public:
  30 + using stim::plane<T>::n;
  31 + using stim::plane<T>::P;
  32 + using stim::plane<T>::N;
  33 + using stim::plane<T>::U;
  34 + using stim::plane<T>::rotate;
  35 + using stim::plane<T>::setU;
  36 +
  37 + ///base constructor
  38 + ///@param th value of the angle of the starting point from 0 to 360.
  39 + CUDA_CALLABLE
  40 + circle() : plane<T>()
  41 + {
  42 + init();
  43 + }
  44 +
  45 + ///create a rectangle given a size and position in Z space.
  46 + ///@param size: size of the rectangle in ND space.
  47 + ///@param z_pos z coordinate of the rectangle.
  48 + CUDA_CALLABLE
  49 + circle(T size, T z_pos = (T)0) : plane<T>()
  50 + {
  51 + center(stim::vec3<T>(0,0,z_pos));
  52 + scale(size);
  53 + init();
  54 + }
  55 +
  56 + ///create a rectangle from a center point, normal
  57 + ///@param c: x,y,z location of the center.
  58 + ///@param n: x,y,z direction of the normal.
  59 + CUDA_CALLABLE
  60 + circle(vec3<T> c, vec3<T> n = vec3<T>(0,0,1)) : plane<T>()
  61 + {
  62 + center(c);
  63 + normal(n);
  64 + init();
  65 + }
  66 +
  67 + /*///create a rectangle from a center point, normal, and size
  68 + ///@param c: x,y,z location of the center.
  69 + ///@param s: size of the rectangle.
  70 + ///@param n: x,y,z direction of the normal.
  71 + CUDA_CALLABLE
  72 + circle(vec3<T> c, T s, vec3<T> n = vec3<T>(0,0,1)) : plane<T>()
  73 + {
  74 + init();
  75 + center(c);
  76 + rotate(n, U, Y);
  77 + scale(s);
  78 + }
  79 + */
  80 +
  81 + ///create a rectangle from a center point, normal, and size
  82 + ///@param c: x,y,z location of the center.
  83 + ///@param s: size of the rectangle.
  84 + ///@param n: x,y,z direction of the normal.
  85 + ///@param u: x,y,z direction for the zero vector (from where the rotation starts)
  86 + CUDA_CALLABLE
  87 + circle(vec3<T> c, T s, vec3<T> n = vec3<T>(0,0,1), vec3<T> u = vec3<T>(1, 0, 0)) : plane<T>()
  88 + {
  89 + init();
  90 + setU(u);
  91 +// U = u;
  92 + center(c);
  93 + normal(n);
  94 + scale(s);
  95 + }
  96 +
  97 + ///scales the circle by a certain factor
  98 + ///@param factor: the factor by which the dimensions of the shape are scaled.
  99 + CUDA_CALLABLE
  100 + void scale(T factor)
  101 + {
  102 + U *= factor;
  103 + Y *= factor;
  104 + }
  105 +
  106 + ///sets the normal for the cirlce
  107 + ///@param n: x,y,z direction of the normal.
  108 + CUDA_CALLABLE void
  109 + normal(vec3<T> n)
  110 + {
  111 + rotate(n, Y);
  112 + }
  113 +
  114 + ///sets the center of the circle.
  115 + ///@param n: x,y,z location of the center.
  116 + CUDA_CALLABLE void
  117 + center(vec3<T> p){
  118 + this->P = p;
  119 + }
  120 +
  121 + ///boolean comparison
  122 + bool
  123 + operator==(const circle<T> & rhs)
  124 + {
  125 + if(P == rhs.P && U == rhs.U && Y == rhs.Y)
  126 + return true;
  127 + else
  128 + return false;
  129 + }
  130 +
  131 + ///get the world space value given the planar coordinates a, b in [0, 1]
  132 + CUDA_CALLABLE stim::vec3<T> p(T a, T b)
  133 + {
  134 + stim::vec3<T> result;
  135 +
  136 + vec3<T> A = this->P - this->U * (T)0.5 - Y * (T)0.5;
  137 + result = A + this->U * a + Y * b;
  138 + return result;
  139 + }
  140 +
  141 + ///parenthesis operator returns the world space given rectangular coordinates a and b in [0 1]
  142 + CUDA_CALLABLE stim::vec3<T> operator()(T a, T b)
  143 + {
  144 + return p(a,b);
  145 + }
  146 +
  147 + ///returns a vector with the points on the initialized circle.
  148 + ///connecting the points results in a circle.
  149 + ///@param n: integer for the number of points representing the circle.
  150 + std::vector<stim::vec3<T> >
  151 + getPoints(int n)
  152 + {
  153 + std::vector<stim::vec3<T> > result;
  154 + stim::vec3<T> point;
  155 + T x,y;
  156 + float step = 360.0/(float) n;
  157 + for(float j = 0; j <= 360.0; j += step)
  158 + {
  159 + y = 0.5*cos(j*stim::TAU/360.0)+0.5;
  160 + x = 0.5*sin(j*stim::TAU/360.0)+0.5;
  161 + result.push_back(p(x,y));
  162 + }
  163 + return result;
  164 + }
  165 +
  166 + ///returns a vector with the points on the initialized circle.
  167 + ///connecting the points results in a circle.
  168 + ///@param n: integer for the number of points representing the circle.
  169 + CUDA_CALLABLE stim::vec3<T>
  170 + p(T theta)
  171 + {
  172 + T x,y;
  173 + y = 0.5*cos(theta*STIM_TAU/360.0)+0.5;
  174 + x = 0.5*sin(theta*STIM_TAU/360.0)+0.5;
  175 + return p(x,y);
  176 + }
  177 +
  178 + std::string str() const
  179 + {
  180 + std::stringstream ss;
  181 + ss << "(P=" << P.str() << ", N=" << N.str() << ", U=" << U.str() << ", Y=" << Y.str();
  182 + return ss.str();
  183 + }
  184 +
  185 +};
  186 +}
  187 +#endif
... ...
stim/math/filters/conv2.h
... ... @@ -46,7 +46,7 @@ namespace stim {
46 46 }
47 47  
48 48 //Performs a convolution of a 2D image using the GPU. All pointers are assumed to be to memory on the current device.
49   - //@param out is a pointer to the output image
  49 + //@param out is a pointer to the output image, which is of size (sx - kx + 1) x (sy - ky + 1)
50 50 //@param in is a pointer to the input image
51 51 //@param sx is the size of the input image along X
52 52 //@param sy is the size of the input image along Y
... ...
stim/visualization/aabbn.h
... ... @@ -30,12 +30,18 @@ struct aabbn{
30 30 high[0] = x1;
31 31 }
32 32  
33   - CUDA_CALLABLE aabbn(T x0, T y0, T x1, T y1) : aabbn(x0, x1) {
  33 + CUDA_CALLABLE aabbn(T x0, T y0, T x1, T y1) {
  34 + low[0] = x0;
  35 + high[0] = x1;
34 36 low[1] = y0;
35 37 high[1] = y1;
36 38 }
37 39  
38   - CUDA_CALLABLE aabbn(T x0, T y0, T z0, T x1, T y1, T z1) : aabbn(x0, y0, x1, y1) {
  40 + CUDA_CALLABLE aabbn(T x0, T y0, T z0, T x1, T y1, T z1) {
  41 + low[0] = x0;
  42 + high[0] = x1;
  43 + low[1] = y0;
  44 + high[1] = y1;
39 45 low[2] = z0;
40 46 high[2] = z1;
41 47 }
... ...
stim/visualization/cylinder.h
... ... @@ -3,56 +3,255 @@
3 3 #include <iostream>
4 4 #include <stim/math/circle.h>
5 5 #include <stim/biomodels/centerline.h>
  6 +#include <stim/visualization/obj.h>
6 7  
7   -/*
8   -
9   -*/
10 8  
11 9 namespace stim
12 10 {
13 11 template<typename T>
14   -class cylinder
15   - : public centerline<T>
16   -{
17   - private:
18   - stim::circle<T> s; //an arbitrary circle
19   - std::vector<stim::circle<T> > e; //an array of circles that store the centerline
  12 +class cylinder : public centerline<T> {
  13 +protected:
  14 +
  15 + std::vector< stim::vec3<T> > U; //stores the array of U vectors defining the Frenet frame
  16 + std::vector< std::vector<T> > M; //stores a list of magnitudes for each point in the centerline (assuming mags[0] is the radius)
  17 +
  18 + using stim::centerline<T>::findIdx;
  19 +
  20 + //calculates the U values for each point to initialize the frenet frame
  21 + // this function assumes that the centerline has already been set
  22 + void init() {
  23 + U.resize(size()); //allocate space for the frenet frame vectors
  24 +
  25 + stim::circle<T> c; //create a circle
  26 + stim::vec3<T> d0, d1;
  27 + for (size_t i = 0; i < size() - 1; i++) { //for each line segment in the centerline
  28 + c.rotate(d(i)); //rotate the circle to match that normal