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,7 +3,6 @@
3 3
4 #include <vector> 4 #include <vector>
5 #include <stim/math/vec3.h> 5 #include <stim/math/vec3.h>
6 -//#include <ANN/ANN.h>  
7 6
8 namespace stim{ 7 namespace stim{
9 8
@@ -12,195 +11,123 @@ namespace stim{ @@ -12,195 +11,123 @@ namespace stim{
12 * class to describe an interconnected (often biological) network. 11 * class to describe an interconnected (often biological) network.
13 */ 12 */
14 template<typename T> 13 template<typename T>
15 -class centerline{ 14 +class centerline : public std::vector< stim::vec3<T> >{
16 15
17 protected: 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 /// Returns a stim::vec representing the point at index i 50 /// Returns a stim::vec representing the point at index i
91 51
92 /// @param i is an index of the desired centerline point 52 /// @param i is an index of the desired centerline point
93 stim::vec<T> get_vec(unsigned i){ 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 public: 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 /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned 126 /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned
201 std::vector< stim::centerline<T> > split(unsigned int idx){ 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 //if the index is an end point, only the existing fiber is returned 132 //if the index is an end point, only the existing fiber is returned
206 if(idx == 0 || idx == N-1){ 133 if(idx == 0 || idx == N-1){
@@ -211,128 +138,89 @@ public: @@ -211,128 +138,89 @@ public:
211 //if the index is not an end point 138 //if the index is not an end point
212 else{ 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 unsigned int N2 = N - idx; 142 unsigned int N2 = N - idx;
216 143
217 fl.resize(2); //set the array size to 2 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 //copy both halves of the fiber 149 //copy both halves of the fiber
223 - unsigned int i, d; 150 + unsigned int i;
224 151
225 //first half 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 //second half 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 return fl; //return the array 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 /// Outputs the fiber as a string 167 /// Outputs the fiber as a string
262 std::string str(){ 168 std::string str(){
263 std::stringstream ss; 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 return ss.str(); 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 /// Back method returns the last point in the fiber 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 ////resample a fiber in the network 184 ////resample a fiber in the network
294 stim::centerline<T> resample(T spacing) 185 stim::centerline<T> resample(T spacing)
295 { 186 {
296 std::cout<<"fiber::resample()"<<std::endl; 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 // for each point on the centerline (skip if it is the last point on centerline) 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 for(unsigned int f=0; f< N-1; f++) 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,6 +15,39 @@
15 #include <stim/cuda/cudatools/timer.h> 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 namespace stim{ 51 namespace stim{
19 /** This is the a class that interfaces with gl_spider in order to store the currently 52 /** This is the a class that interfaces with gl_spider in order to store the currently
20 * segmented network. The following data is stored and can be extracted: 53 * segmented network. The following data is stored and can be extracted:
@@ -22,7 +55,6 @@ namespace stim{ @@ -22,7 +55,6 @@ namespace stim{
22 * 2)Network connectivity (a graph of nodes and edges), reconstructed using ANN library. 55 * 2)Network connectivity (a graph of nodes and edges), reconstructed using ANN library.
23 */ 56 */
24 57
25 -  
26 template<typename T> 58 template<typename T>
27 class network{ 59 class network{
28 60
@@ -33,16 +65,15 @@ class network{ @@ -33,16 +65,15 @@ class network{
33 public: 65 public:
34 unsigned v[2]; //unique id's designating the starting and ending 66 unsigned v[2]; //unique id's designating the starting and ending
35 // default constructor 67 // default constructor
36 - edge() : cylinder<T>()  
37 - { 68 + edge() : cylinder<T>() {
38 v[1] = (unsigned)(-1); v[0] = (unsigned)(-1); 69 v[1] = (unsigned)(-1); v[0] = (unsigned)(-1);
39 } 70 }
40 /// Constructor - creates an edge from a list of points by calling the stim::fiber constructor 71 /// Constructor - creates an edge from a list of points by calling the stim::fiber constructor
41 72
42 ///@param p is an array of positions in space 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 edge(stim::cylinder<T> f) : cylinder<T>(f) {} 77 edge(stim::cylinder<T> f) : cylinder<T>(f) {}
47 78
48 /// Resamples an edge by calling the fiber resampling function 79 /// Resamples an edge by calling the fiber resampling function
@@ -61,6 +92,19 @@ class network{ @@ -61,6 +92,19 @@ class network{
61 return ss.str(); 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 ///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. 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,7 +335,7 @@ public:
291 std::vector< stim::vec<T> > c; //allocate an array of points for the vessel centerline 335 std::vector< stim::vec<T> > c; //allocate an array of points for the vessel centerline
292 O.getLine(l, c); //get the fiber centerline 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 for(size_t j = 0; j < c.size(); j++) 339 for(size_t j = 0; j < c.size(); j++)
296 c3[j] = c[j]; 340 c3[j] = c[j];
297 341
@@ -377,7 +421,8 @@ public: @@ -377,7 +421,8 @@ public:
377 return n; //return the resampled network 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 /// Calculate the total number of points on all edges. 427 /// Calculate the total number of points on all edges.
383 unsigned total_points(){ 428 unsigned total_points(){
@@ -403,9 +448,6 @@ public: @@ -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 // convert vec3 to array 451 // convert vec3 to array
410 void stim2array(float *a, stim::vec3<T> b){ 452 void stim2array(float *a, stim::vec3<T> b){
411 a[0] = b[0]; 453 a[0] = b[0];
@@ -413,6 +455,16 @@ public: @@ -413,6 +455,16 @@ public:
413 a[2] = b[2]; 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 /// Calculate the average magnitude across the entire network. 468 /// Calculate the average magnitude across the entire network.
417 /// @param m is the magnitude value to use. The default is 0 (usually radius). 469 /// @param m is the magnitude value to use. The default is 0 (usually radius).
418 T average(unsigned m = 0){ 470 T average(unsigned m = 0){
@@ -420,7 +472,7 @@ public: @@ -420,7 +472,7 @@ public:
420 T M, L; //allocate space for the total magnitude and length 472 T M, L; //allocate space for the total magnitude and length
421 M = L = 0; //initialize both the initial magnitude and length to zero 473 M = L = 0; //initialize both the initial magnitude and length to zero
422 for(unsigned e = 0; e < E.size(); e++){ //for each edge in the network 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 L += E[e].length(); //get the edge length 476 L += E[e].length(); //get the edge length
425 } 477 }
426 478
@@ -428,9 +480,9 @@ public: @@ -428,9 +480,9 @@ public:
428 } 480 }
429 481
430 /// This function compares two networks and returns the percentage of the current network that is missing from A. 482 /// This function compares two networks and returns the percentage of the current network that is missing from A.
431 -  
432 /// @param A is the network to compare to - the field is generated for A 483 /// @param A is the network to compare to - the field is generated for A
433 /// @param sigma is the user-defined tolerance value - smaller values provide a stricter comparison 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 stim::network<T> compare(stim::network<T> A, float sigma, int device){ 486 stim::network<T> compare(stim::network<T> A, float sigma, int device){
435 487
436 stim::network<T> R; //generate a network storing the result of the comparison 488 stim::network<T> R; //generate a network storing the result of the comparison
@@ -452,61 +504,363 @@ public: @@ -452,61 +504,363 @@ public:
452 } 504 }
453 505
454 //generate a KD-tree for network A 506 //generate a KD-tree for network A
455 - //float metric = 0.0; // initialize metric to be returned after comparing the network  
456 size_t MaxTreeLevels = 3; // max tree level 507 size_t MaxTreeLevels = 3; // max tree level
457 508
458 #ifdef __CUDACC__ 509 #ifdef __CUDACC__
459 cudaSetDevice(device); 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 //compare each point in the current network to the field produced by A 605 //compare each point in the current network to the field produced by A
463 kdt.create(c, n_data, MaxTreeLevels); // build a KD tree 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 T* queryPt = new T[3]; 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 #else 829 #else
487 - stim::cpu_kdtree<T, 3> kdt; 830 + stim::kdtree<T, 3> kdt;
488 kdt.create(c, n_data, MaxTreeLevels); 831 kdt.create(c, n_data, MaxTreeLevels);
489 T *dists = new T[1]; // near neighbor distances 832 T *dists = new T[1]; // near neighbor distances
490 size_t *nnIdx = new size_t[1]; // near neighbor indices // allocate near neigh indices 833 size_t *nnIdx = new size_t[1]; // near neighbor indices // allocate near neigh indices
491 834
492 stim::vec3<T> p0, p1; 835 stim::vec3<T> p0, p1;
493 - T m1;  
494 T* queryPt = new T[3]; 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 stim2array(queryPt, p1); 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 #endif 863 #endif
509 - return R; //return the resulting network  
510 } 864 }
511 865
512 /// Returns the number of magnitude values stored in each edge. This should be uniform across the network. 866 /// Returns the number of magnitude values stored in each edge. This should be uniform across the network.
@@ -616,4 +970,4 @@ public: @@ -616,4 +970,4 @@ public:
616 } 970 }
617 }; //end stim::network class 971 }; //end stim::network class
618 }; //end stim namespace 972 }; //end stim namespace
619 -#endif 973 -#endif
  974 +#endif
620 \ No newline at end of file 975 \ No newline at end of file
stim/math/circle.h
@@ -18,13 +18,14 @@ class circle : plane&lt;T&gt; @@ -18,13 +18,14 @@ class circle : plane&lt;T&gt;
18 18
19 private: 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 init() 25 init()
25 { 26 {
26 Y = U.cross(N).norm(); 27 Y = U.cross(N).norm();
27 - } 28 + }*/
28 29
29 public: 30 public:
30 using stim::plane<T>::n; 31 using stim::plane<T>::n;
@@ -42,26 +43,28 @@ public: @@ -42,26 +43,28 @@ public:
42 init(); 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 ///@param size: size of the rectangle in ND space. 47 ///@param size: size of the rectangle in ND space.
47 ///@param z_pos z coordinate of the rectangle. 48 ///@param z_pos z coordinate of the rectangle.
48 CUDA_CALLABLE 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 ///create a rectangle from a center point, normal 58 ///create a rectangle from a center point, normal
57 ///@param c: x,y,z location of the center. 59 ///@param c: x,y,z location of the center.
58 ///@param n: x,y,z direction of the normal. 60 ///@param n: x,y,z direction of the normal.
59 CUDA_CALLABLE 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 /*///create a rectangle from a center point, normal, and size 70 /*///create a rectangle from a center point, normal, and size
@@ -84,14 +87,18 @@ public: @@ -84,14 +87,18 @@ public:
84 ///@param n: x,y,z direction of the normal. 87 ///@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) 88 ///@param u: x,y,z direction for the zero vector (from where the rotation starts)
86 CUDA_CALLABLE 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 setU(u); 94 setU(u);
  95 + R = r;
  96 + //init();
  97 + //setU(u);
91 // U = u; 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 ///scales the circle by a certain factor 104 ///scales the circle by a certain factor
@@ -99,23 +106,23 @@ public: @@ -99,23 +106,23 @@ public:
99 CUDA_CALLABLE 106 CUDA_CALLABLE
100 void scale(T factor) 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 ///sets the normal for the cirlce 114 ///sets the normal for the cirlce
107 ///@param n: x,y,z direction of the normal. 115 ///@param n: x,y,z direction of the normal.
108 CUDA_CALLABLE void 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 ///sets the center of the circle. 121 ///sets the center of the circle.
115 ///@param n: x,y,z location of the center. 122 ///@param n: x,y,z location of the center.
116 CUDA_CALLABLE void 123 CUDA_CALLABLE void
117 center(vec3<T> p){ 124 center(vec3<T> p){
118 - this->P = p; 125 + P = p;
119 } 126 }
120 127
121 ///boolean comparison 128 ///boolean comparison
@@ -128,57 +135,63 @@ public: @@ -128,57 +135,63 @@ public:
128 return false; 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 ///get the world space value given the planar coordinates a, b in [0, 1] 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 stim::vec3<T> result; 159 stim::vec3<T> result;
135 160
136 vec3<T> A = this->P - this->U * (T)0.5 - Y * (T)0.5; 161 vec3<T> A = this->P - this->U * (T)0.5 - Y * (T)0.5;
137 result = A + this->U * a + Y * b; 162 result = A + this->U * a + Y * b;
138 return result; 163 return result;
139 - } 164 + }*/
140 165
141 ///parenthesis operator returns the world space given rectangular coordinates a and b in [0 1] 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 ///returns a vector with the points on the initialized circle. 177 ///returns a vector with the points on the initialized circle.
148 ///connecting the points results in a circle. 178 ///connecting the points results in a circle.
149 ///@param n: integer for the number of points representing the circle. 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 return result; 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 std::string str() const 191 std::string str() const
179 { 192 {
180 std::stringstream ss; 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 return ss.str(); 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,7 +46,7 @@ namespace stim {
46 } 46 }
47 47
48 //Performs a convolution of a 2D image using the GPU. All pointers are assumed to be to memory on the current device. 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 //@param in is a pointer to the input image 50 //@param in is a pointer to the input image
51 //@param sx is the size of the input image along X 51 //@param sx is the size of the input image along X
52 //@param sy is the size of the input image along Y 52 //@param sy is the size of the input image along Y
stim/visualization/aabbn.h
@@ -30,12 +30,18 @@ struct aabbn{ @@ -30,12 +30,18 @@ struct aabbn{
30 high[0] = x1; 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 low[1] = y0; 36 low[1] = y0;
35 high[1] = y1; 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 low[2] = z0; 45 low[2] = z0;
40 high[2] = z1; 46 high[2] = z1;
41 } 47 }
stim/visualization/cylinder.h
@@ -3,56 +3,255 @@ @@ -3,56 +3,255 @@
3 #include <iostream> 3 #include <iostream>
4 #include <stim/math/circle.h> 4 #include <stim/math/circle.h>
5 #include <stim/biomodels/centerline.h> 5 #include <stim/biomodels/centerline.h>
  6 +#include <stim/visualization/obj.h>
6 7
7 -/*  
8 -  
9 -*/  
10 8
11 namespace stim 9 namespace stim
12 { 10 {
13 template<typename T> 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
  29 + U[i] = c.U; //save the U vector from the circle
  30 + }
  31 + U[size() - 1] = c.U; //for the last point, duplicate the final frenet frame vector
  32 + }
20 33
21 - std::vector<stim::vec3<T> > norms;  
22 - std::vector<stim::vec<T> > Us;  
23 - std::vector<stim::vec<T> > mags; //stores a list of magnitudes for each point in the centerline (assuming mags[0] is the radius)  
24 - std::vector< T > L; //length of the cylinder at each position (pre-integration) 34 +public:
25 35
  36 + using stim::centerline<T>::size;
  37 + using stim::centerline<T>::at;
26 38
27 - using stim::centerline<T>::c;  
28 - using stim::centerline<T>::N; 39 + cylinder() : centerline(){}
29 40
30 - ///default init  
31 - void  
32 - init()  
33 - { 41 + cylinder(centerline& c) : centerline(c) {
  42 + init();
  43 + }
  44 +
  45 + cylinder(centerline& c, T r) : centerline(c) {
  46 + init();
  47 + add_mag(r);
  48 + }
  49 +
  50 + //initialize a cylinder with a list of points and magnitude values
  51 + cylinder(centerline& c, std::vector<T> r) : centerline(c){
  52 + init();
  53 + add_mag(r);
  54 + }
  55 +
  56 + ///Returns magnitude i at the given length into the fiber (based on the pvalue).
  57 + ///Interpolates the position along the line.
  58 + ///@param l: the location of the in the cylinder.
  59 + ///@param idx: integer location of the point closest to l but prior to it.
  60 + T m(T l, int idx, size_t i) {
  61 + T a = (l - L[idx]) / (L[idx + 1] - L[idx]);
  62 + T v2 = (M[idx][i] + (M[idx + 1][i] - M[idx][i])*a);
  63 +
  64 + return v2;
  65 + }
  66 +
  67 + ///Returns the ith magnitude at the given p-value (p value ranges from 0 to 1).
  68 + ///interpolates the radius along the line.
  69 + ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
  70 + T m(T pvalue, unsigned i = 0) {
  71 + if (pvalue <= 0.0) return M[0][i];
  72 + if (pvalue >= 1.0) return M[size() - 1][i];
  73 +
  74 + T l = pvalue*L[L.size() - 1];
  75 + int idx = findIdx(l);
  76 + return m(l, idx, i);
  77 + }
  78 +
  79 + /// Returns the magnitude at the given index
  80 + /// @param i is the index of the desired point
  81 + /// @param m is the index of the magnitude value
  82 + T m(unsigned i, unsigned m) {
  83 + return M[i][m];
  84 + }
  85 +
  86 + ///adds a magnitude to each point in the cylinder
  87 + void add_mag(T val = 0) {
  88 + if (M.size() == 0) M.resize(size()); //if the magnitude vector isn't initialized, resize it to match the centerline
  89 + for (size_t i = 0; i < size(); i++) //for each point
  90 + M[i].push_back(val); //add this value to the magnitude vector at each point
  91 + }
  92 +
  93 + //adds a magnitude based on a list of magnitudes for each point
  94 + void add_mag(std::vector<T> val) {
  95 + if (M.size() == 0) M.resize(size()); //if the magnitude vector isn't initialized, resize it to match the centerline
  96 + for (size_t i = 0; i < size(); i++) //for each point
  97 + M[i].push_back(val[i]); //add this value to the magnitude vector at each point
  98 + }
  99 +
  100 + //sets the value of magnitude m at point i
  101 + void set_mag(size_t m, size_t i, T v) {
  102 + M[i][m] = v;
  103 + }
  104 +
  105 + size_t nmags() {
  106 + if (M.size() == 0) return 0;
  107 + else return M[0].size();
  108 + }
  109 +
  110 + ///Returns a circle representing the cylinder cross section at point i
  111 + stim::circle<T> circ(size_t i, size_t m = 0) {
  112 + return stim::circle<T>(at(i), M[i][m], d(i), U[i]);
  113 + }
  114 +
  115 + ///Returns an OBJ object representing the cylinder with a radial tesselation value of N using magnitude m
  116 + stim::obj<T> OBJ(size_t N, size_t m = 0) {
  117 + stim::obj<T> out; //create an OBJ object
  118 + stim::circle<T> c0, c1;
  119 + std::vector< stim::vec3<T> > p0, p1; //allocate space for the point sets representing the circles bounding each cylinder segment
  120 + T u0, u1, v0, v1; //allocate variables to store running texture coordinates
  121 + for (size_t i = 1; i < size(); i++) { //for each line segment in the cylinder
  122 + c0 = circ(i - 1); //get the two circles bounding the line segment
  123 + c1 = circ(i);
  124 +
  125 + p0 = c0.points(N); //get t points for each of the end caps
  126 + p1 = c1.points(N);
  127 +
  128 + u0 = L[i - 1] / length(); //calculate the texture coordinate (u, v) where u runs along the cylinder length
  129 + u1 = L[i] / length();
  130 +
  131 + for (size_t n = 1; n < N; n++) { //for each point in the circle
  132 + v0 = (double)(n-1) / (double)(N - 1); //v texture coordinate runs around the cylinder
  133 + v1 = (double)(n) / (double)(N - 1);
  134 + out.Begin(OBJ_FACE); //start a face (quad)
  135 + out.TexCoord(u0, v0);
  136 + out.Vertex(p0[n - 1][0], p0[n - 1][1], p0[n - 1][2]); //output the points composing a strip of quads wrapping the cylinder segment
  137 + out.TexCoord(u1, v0);
  138 + out.Vertex(p1[n - 1][0], p1[n - 1][1], p1[n - 1][2]);
  139 +
  140 + out.TexCoord(u0, v1);
  141 + out.Vertex(p1[n][0], p1[n][1], p1[n][2]);
  142 + out.TexCoord(u1, v1);
  143 + out.Vertex(p0[n][0], p0[n][1], p0[n][2]);
  144 + out.End();
  145 + }
  146 + v0 = (double)(N - 2) / (double)(N - 1); //v texture coordinate runs around the cylinder
  147 + v1 = 1.0;
  148 + out.Begin(OBJ_FACE);
  149 + out.TexCoord(u0, v0);
  150 + out.Vertex(p0[N - 1][0], p0[N - 1][1], p0[N - 1][2]); //output the points composing a strip of quads wrapping the cylinder segment
  151 + out.TexCoord(u1, v0);
  152 + out.Vertex(p1[N - 1][0], p1[N - 1][1], p1[N - 1][2]);
  153 +
  154 + out.TexCoord(u0, v1);
  155 + out.Vertex(p1[0][0], p1[0][1], p1[0][2]);
  156 + out.TexCoord(u1, v1);
  157 + out.Vertex(p0[0][0], p0[0][1], p0[0][2]);
  158 + out.End();
  159 + }
  160 + return out;
  161 + }
  162 +
  163 + std::string str() {
  164 + std::stringstream ss;
  165 + size_t N = std::vector< stim::vec3<T> >::size();
  166 + ss << "---------[" << N << "]---------" << std::endl;
  167 + for (size_t i = 0; i < N; i++)
  168 + ss << std::vector< stim::vec3<T> >::at(i) << " r = " << M[i][0] << " u = " << U[i] << std::endl;
  169 + ss << "--------------------" << std::endl;
  170 +
  171 + return ss.str();
  172 + }
  173 +
  174 + /// Integrates a magnitude value along the cylinder.
  175 + /// @param m is the magnitude value to be integrated (this is usually the radius)
  176 + T integrate(size_t m = 0) {
  177 +
  178 + T sum = 0; //initialize the integral to zero
  179 + T m0, m1; //allocate space for both magnitudes in a single segment
  180 + m0 = M[0][m]; //initialize the first point and magnitude to the first point in the cylinder
  181 + T len = L[0]; //allocate space for the segment length
  182 +
  183 +
  184 + for (unsigned p = 1; p < size(); p++) { //for every consecutive point in the cylinder
  185 + m1 = M[p][m];
  186 + if (p > 1) len = (L[p - 1] - L[p - 2]); //calculate the segment length using the L array
  187 + sum += (m0 + m1) / (T)2.0 * len; //add the average magnitude, weighted by the segment length
  188 + m0 = m1; //move to the next segment by shifting points
  189 + }
  190 + return sum; //return the integral
  191 + }
  192 +
  193 + /// Resamples the cylinder to provide a maximum distance of "spacing" between centerline points. All current
  194 + /// centerline points are guaranteed to exist in the new cylinder
  195 + /// @param spacing is the maximum spacing allowed between sample points
  196 + cylinder<T> resample(T spacing) {
  197 + cylinder<T> c = stim::centerline<T>::resample(spacing); //resample the centerline and use it to create a new cylinder
  198 +
  199 + size_t nm = nmags(); //get the number of magnitude values in the current cylinder
  200 + if (nm > 0) { //if there are magnitude values
  201 + std::vector<T> magvec(nm, 0); //create a magnitude vector for a single point
  202 + c.M.resize(c.size(), magvec); //allocate space for a magnitude vector at each point of the new cylinder
  203 + }
34 204
  205 + T l, t;
  206 + for (size_t i = 0; i < c.size(); i++) { //for each point in the new cylinder
  207 + l = c.L[i]; //get the length along the new cylinder
  208 + t = l / length(); //calculate the parameter value along the new cylinder
  209 + for (size_t mag = 0; mag < nm; mag++) { //for each magnitude value
  210 + c.M[i][mag] = m(t, mag); //retrieve the interpolated magnitude from the current cylinder and store it in the new one
  211 + }
35 } 212 }
36 213
37 - ///Calculate the physical length of the fiber at each point in the fiber.  
38 - void  
39 - calculateL()  
40 - {  
41 -/* L.resize(inP.size());  
42 - T temp = (T)0;  
43 - L[0] = 0;  
44 - for(size_t i = 1; i < L.size(); i++)  
45 - {  
46 - temp += (inP[i-1] - inP[i]).len();  
47 - L[i] = temp; 214 +
  215 + return c;
  216 + }
  217 +
  218 + std::vector< stim::cylinder<T> > split(unsigned int idx){
  219 +
  220 + unsigned N = size();
  221 + std::vector< stim::centerline<T> > LL;
  222 + LL.resize(2);
  223 + LL = (*this).centerline<T>::split(idx);
  224 + std::vector< stim::cylinder<T> > C(LL.size());
  225 + unsigned i = 0;
  226 + C[0] = LL[0];
  227 + C[0].M.resize(idx);
  228 + for( ; i < idx; i++){
  229 + //for(unsigned d = 0; d < 3; d++)
  230 + //C[0][i][d] = LL[0].c[i][d];
  231 + C[0].M[i] = M[i];
  232 + C[0].M[i].resize(1);
  233 + }
  234 + if(C.size() == 2){
  235 + C[1] = LL[1];
  236 + C[1].M.resize(N - idx);
  237 + for( ; i < N; i++){
  238 + //for(unsigned d = 0; d < 3; d++)
  239 + //C[1][i - idx][d] = LL[1].c[i - idx][d];
  240 + C[1].M[i - idx] = M[i];
  241 + C[1].M[i - idx].resize(1);
48 } 242 }
49 -*/ } 243 + }
  244 +
  245 + return C;
  246 + }
  247 +
50 248
51 - ///inits the cylinder from a list of points (std::vector of stim::vec3 --inP) and radii (inM) 249 + /*
  250 + ///inits the cylinder from a list of points (std::vector of stim::vec3 --inP) and magnitudes (inM)
52 void 251 void
53 - init(std::vector<stim::vec3<T> > inP, std::vector<stim::vec<T> > inM)  
54 - {  
55 - mags = inM; 252 + init(centerline inP, std::vector< std::vector<T> > inM) {
  253 + M = inM; //the magnitude vector can be copied directly
  254 + (*this) = inP; //the centerline can be copied to this class directly
56 stim::vec3<float> v1; 255 stim::vec3<float> v1;
57 stim::vec3<float> v2; 256 stim::vec3<float> v2;
58 e.resize(inP.size()); 257 e.resize(inP.size());
@@ -246,13 +445,18 @@ class cylinder @@ -246,13 +445,18 @@ class cylinder
246 init(inP, inM); 445 init(inP, inM);
247 } 446 }
248 447
  448 + //assignment operator creates a cylinder from a centerline (default radius is zero)
  449 + cylinder& operator=(stim::centerline<T> c) {
  450 + init(c);
  451 + }
  452 +
249 ///Returns the number of points on the cylinder centerline 453 ///Returns the number of points on the cylinder centerline
250 454
251 unsigned int size(){ 455 unsigned int size(){
252 return N; 456 return N;
253 } 457 }
254 458
255 - 459 +
256 ///Returns a position vector at the given p-value (p value ranges from 0 to 1). 460 ///Returns a position vector at the given p-value (p value ranges from 0 to 1).
257 ///interpolates the position along the line. 461 ///interpolates the position along the line.
258 ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1). 462 ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
@@ -266,22 +470,7 @@ class cylinder @@ -266,22 +470,7 @@ class cylinder
266 T l = pvalue*L[L.size()-1]; 470 T l = pvalue*L[L.size()-1];
267 int idx = findIdx(l); 471 int idx = findIdx(l);
268 return (p(l,idx)); 472 return (p(l,idx));
269 -/* T rat = (l-L[idx])/(L[idx+1]-L[idx]);  
270 - stim::vec3<T> v1(  
271 - c[idx][0],  
272 - c[idx][1],  
273 - c[idx][2]  
274 - );  
275 -  
276 - stim::vec3<T> v2(  
277 - c[idx+1][0],  
278 - c[idx+1][1],  
279 - c[idx+1][2]  
280 - );  
281 -  
282 -// return( e[idx].P + (e[idx+1].P-e[idx].P)*rat);  
283 - return( v1 + (v2 - v1)*rat);  
284 -*/ } 473 + }
285 474
286 ///Returns a position vector at the given length into the fiber (based on the pvalue). 475 ///Returns a position vector at the given length into the fiber (based on the pvalue).
287 ///Interpolates the radius along the line. 476 ///Interpolates the radius along the line.
@@ -321,10 +510,7 @@ class cylinder @@ -321,10 +510,7 @@ class cylinder
321 T l = pvalue*L[L.size()-1]; 510 T l = pvalue*L[L.size()-1];
322 int idx = findIdx(l); 511 int idx = findIdx(l);
323 return (r(l,idx)); 512 return (r(l,idx));
324 -/* T rat = (l-L[idx])/(L[idx+1]-L[idx]);  
325 -// return (mags[idx][0] + (mags[idx+1][0]-mags[idx][0])*rat);  
326 - return (e[idx].U.len() + (e[idx+1].U.len() - e[idx].U.len())*rat);  
327 -*/ } 513 + }
328 514
329 ///Returns a radius at the given length into the fiber (based on the pvalue). 515 ///Returns a radius at the given length into the fiber (based on the pvalue).
330 ///Interpolates the position along the line. 516 ///Interpolates the position along the line.
@@ -506,10 +692,10 @@ class cylinder @@ -506,10 +692,10 @@ class cylinder
506 692
507 return cylinder<T>(result); 693 return cylinder<T>(result);
508 694
509 - } 695 + }*/
510 696
511 697
512 }; 698 };
513 699
514 } 700 }
515 -#endif 701 -#endif
  702 +#endif
516 \ No newline at end of file 703 \ No newline at end of file
stim/visualization/cylinder_dep.h 0 โ†’ 100644
  1 +#ifndef STIM_CYLINDER_H
  2 +#define STIM_CYLINDER_H
  3 +#include <iostream>
  4 +#include <stim/math/circle.h>
  5 +#include <stim/biomodels/centerline.h>
  6 +
  7 +
  8 +namespace stim
  9 +{
  10 +template<typename T>
  11 +class cylinder
  12 + : public centerline<T>
  13 +{
  14 + private:
  15 + stim::circle<T> s; //an arbitrary circle
  16 + std::vector<stim::circle<T> > e; //an array of circles that store the centerline
  17 +
  18 + std::vector<stim::vec3<T> > norms;
  19 + std::vector<stim::vec<T> > Us;
  20 + std::vector<stim::vec<T> > mags; //stores a list of magnitudes for each point in the centerline (assuming mags[0] is the radius)
  21 + std::vector< T > L; //length of the cylinder at each position (pre-integration)
  22 +
  23 +
  24 + using stim::centerline<T>::c;
  25 + using stim::centerline<T>::N;
  26 +
  27 + ///default init
  28 + void
  29 + init()
  30 + {
  31 +
  32 + }
  33 +
  34 + ///inits the cylinder from a list of points (std::vector of stim::vec3 --inP) and radii (inM)
  35 + void
  36 + init(std::vector<stim::vec3<T> > inP, std::vector<stim::vec<T> > inM)
  37 + {
  38 + mags = inM;
  39 + stim::vec3<float> v1;
  40 + stim::vec3<float> v2;
  41 + e.resize(inP.size());
  42 +
  43 + norms.resize(inP.size());
  44 + Us.resize(inP.size());
  45 +
  46 + if(inP.size() < 2)
  47 + return;
  48 +
  49 + //calculate each L.
  50 + L.resize(inP.size()); //the number of precomputed lengths will equal the number of points
  51 + T temp = (T)0; //length up to that point
  52 + L[0] = temp;
  53 + for(size_t i = 1; i < L.size(); i++)
  54 + {
  55 + temp += (inP[i-1] - inP[i]).len();
  56 + L[i] = temp;
  57 + }
  58 +
  59 + stim::vec3<T> dr = (inP[1] - inP[0]).norm();
  60 + s = stim::circle<T>(inP[0], inM[0][0], dr, stim::vec3<T>(1,0,0));
  61 + norms[0] = s.N;
  62 + e[0] = s;
  63 + Us[0] = e[0].U;
  64 + for(size_t i = 1; i < inP.size()-1; i++)
  65 + {
  66 + s.center(inP[i]);
  67 + v1 = (inP[i] - inP[i-1]).norm();
  68 + v2 = (inP[i+1] - inP[i]).norm();
  69 + dr = (v1+v2).norm();
  70 + s.normal(dr);
  71 +
  72 + norms[i] = s.N;
  73 +
  74 + s.scale(inM[i][0]/inM[i-1][0]);
  75 + e[i] = s;
  76 + Us[i] = e[i].U;
  77 + }
  78 +
  79 + int j = inP.size()-1;
  80 + s.center(inP[j]);
  81 + dr = (inP[j] - inP[j-1]).norm();
  82 + s.normal(dr);
  83 +
  84 + norms[j] = s.N;
  85 +
  86 + s.scale(inM[j][0]/inM[j-1][0]);
  87 + e[j] = s;
  88 + Us[j] = e[j].U;
  89 + }
  90 +
  91 + ///returns the direction vector at point idx.
  92 + stim::vec3<T>
  93 + d(int idx)
  94 + {
  95 + if(idx == 0)
  96 + {
  97 + stim::vec3<T> temp(
  98 + c[idx+1][0]-c[idx][0],
  99 + c[idx+1][1]-c[idx][1],
  100 + c[idx+1][2]-c[idx][2]
  101 + );
  102 +// return (e[idx+1].P - e[idx].P).norm();
  103 + return (temp.norm());
  104 + }
  105 + else if(idx == N-1)
  106 + {
  107 + stim::vec3<T> temp(
  108 + c[idx][0]-c[idx+1][0],
  109 + c[idx][1]-c[idx+1][1],
  110 + c[idx][2]-c[idx+1][2]
  111 + );
  112 + // return (e[idx].P - e[idx-1].P).norm();
  113 + return (temp.norm());
  114 + }
  115 + else
  116 + {
  117 +// return (e[idx+1].P - e[idx].P).norm();
  118 +// stim::vec3<float> v1 = (e[idx].P-e[idx-1].P).norm();
  119 + stim::vec3<T> v1(
  120 + c[idx][0]-c[idx-1][0],
  121 + c[idx][1]-c[idx-1][1],
  122 + c[idx][2]-c[idx-1][2]
  123 + );
  124 +
  125 +// stim::vec3<float> v2 = (e[idx+1].P-e[idx].P).norm();
  126 + stim::vec3<T> v2(
  127 + c[idx+1][0]-c[idx][0],
  128 + c[idx+1][1]-c[idx][1],
  129 + c[idx+1][2]-c[idx][2]
  130 + );
  131 +
  132 + return (v1.norm()+v2.norm()).norm();
  133 + }
  134 + // return e[idx].N;
  135 +
  136 + }
  137 +
  138 + stim::vec3<T>
  139 + d(T l, int idx)
  140 + {
  141 + if(idx == 0 || idx == N-1)
  142 + {
  143 + return norms[idx];
  144 +// return e[idx].N;
  145 + }
  146 + else
  147 + {
  148 +
  149 + T rat = (l-L[idx])/(L[idx+1]-L[idx]);
  150 + return( norms[idx] + (norms[idx+1] - norms[idx])*rat);
  151 +// return( e[idx].N + (e[idx+1].N - e[idx].N)*rat);
  152 + }
  153 + }
  154 +
  155 +
  156 + ///finds the index of the point closest to the length l on the lower bound.
  157 + ///binary search.
  158 + int
  159 + findIdx(T l)
  160 + {
  161 + unsigned int i = L.size()/2;
  162 + unsigned int max = L.size()-1;
  163 + unsigned int min = 0;
  164 + while(i > 0 && i < L.size()-1)
  165 + {
  166 +// std::cerr << "Trying " << i << std::endl;
  167 +// std::cerr << "l is " << l << ", L[" << i << "]" << L[i] << std::endl;
  168 + if(l < L[i])
  169 + {
  170 + max = i;
  171 + i = min+(max-min)/2;
  172 + }
  173 + else if(L[i] <= l && L[i+1] >= l)
  174 + {
  175 + break;
  176 + }
  177 + else
  178 + {
  179 + min = i;
  180 + i = min+(max-min)/2;
  181 + }
  182 + }
  183 + return i;
  184 + }
  185 +
  186 + public:
  187 + ///default constructor
  188 + cylinder()
  189 + // : centerline<T>()
  190 + {
  191 +
  192 + }
  193 +
  194 + ///constructor to create a cylinder from a set of points, radii, and the number of sides for the cylinder.
  195 + ///@param inP: Vector of stim vec3 composing the points of the centerline.
  196 + ///@param inM: Vector of stim vecs composing the radii of the centerline.
  197 + cylinder(std::vector<stim::vec3<T> > inP, std::vector<stim::vec<T> > inM)
  198 + : centerline<T>(inP)
  199 + {
  200 + init(inP, inM);
  201 + }
  202 +
  203 + ///constructor to create a cylinder from a set of points, radii, and the number of sides for the cylinder.
  204 + ///@param inP: Vector of stim vec3 composing the points of the centerline.
  205 + ///@param inM: Vector of stim vecs composing the radii of the centerline.
  206 + cylinder(std::vector<stim::vec3<T> > inP, std::vector< T > inM)
  207 + : centerline<T>(inP)
  208 + {
  209 + std::vector<stim::vec<T> > temp;
  210 + stim::vec<T> zero(0.0,0.0);
  211 + temp.resize(inM.size(), zero);
  212 + for(int i = 0; i < inM.size(); i++)
  213 + temp[i][0] = inM[i];
  214 + init(inP, temp);
  215 + }
  216 +
  217 +
  218 + ///Constructor defines a cylinder with centerline inP and magnitudes of zero
  219 + ///@param inP: Vector of stim vec3 composing the points of the centerline
  220 + cylinder(std::vector< stim::vec3<T> > inP)
  221 + : centerline<T>(inP)
  222 + {
  223 + std::vector< stim::vec<T> > inM; //create an array of arbitrary magnitudes
  224 +
  225 + stim::vec<T> zero;
  226 + zero.push_back(0);
  227 +
  228 + inM.resize(inP.size(), zero); //initialize the magnitude values to zero
  229 + init(inP, inM);
  230 + }
  231 +
  232 + ///Returns the number of points on the cylinder centerline
  233 +
  234 + unsigned int size(){
  235 + return N;
  236 + }
  237 +
  238 +
  239 + ///Returns a position vector at the given p-value (p value ranges from 0 to 1).
  240 + ///interpolates the position along the line.
  241 + ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
  242 + stim::vec3<T>
  243 + p(T pvalue)
  244 + {
  245 + if(pvalue < 0.0 || pvalue > 1.0)
  246 + {
  247 + return stim::vec3<float>(-1,-1,-1);
  248 + }
  249 + T l = pvalue*L[L.size()-1];
  250 + int idx = findIdx(l);
  251 + return (p(l,idx));
  252 +/* T rat = (l-L[idx])/(L[idx+1]-L[idx]);
  253 + stim::vec3<T> v1(
  254 + c[idx][0],
  255 + c[idx][1],
  256 + c[idx][2]
  257 + );
  258 +
  259 + stim::vec3<T> v2(
  260 + c[idx+1][0],
  261 + c[idx+1][1],
  262 + c[idx+1][2]
  263 + );
  264 +
  265 +// return( e[idx].P + (e[idx+1].P-e[idx].P)*rat);
  266 + return( v1 + (v2 - v1)*rat);
  267 +*/ }
  268 +
  269 + ///Returns a position vector at the given length into the fiber (based on the pvalue).
  270 + ///Interpolates the radius along the line.
  271 + ///@param l: the location of the in the cylinder.
  272 + ///@param idx: integer location of the point closest to l but prior to it.
  273 + stim::vec3<T>
  274 + p(T l, int idx)
  275 + {
  276 + T rat = (l-L[idx])/(L[idx+1]-L[idx]);
  277 + stim::vec3<T> v1(
  278 + c[idx][0],
  279 + c[idx][1],
  280 + c[idx][2]
  281 + );
  282 +
  283 + stim::vec3<T> v2(
  284 + c[idx+1][0],
  285 + c[idx+1][1],
  286 + c[idx+1][2]
  287 + );
  288 +// return( e[idx].P + (e[idx+1].P-e[idx].P)*rat);
  289 + return( v1 + (v2-v1)*rat);
  290 +// return(
  291 +// return (pos[idx] + (pos[idx+1]-pos[idx])*((l-L[idx])/(L[idx+1]- L[idx])));
  292 + }
  293 +
  294 + ///Returns a radius at the given p-value (p value ranges from 0 to 1).
  295 + ///interpolates the radius along the line.
  296 + ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
  297 + T
  298 + r(T pvalue)
  299 + {
  300 + if(pvalue < 0.0 || pvalue > 1.0){
  301 + std::cerr<<"Error, value "<<pvalue<<" is outside of [0 1]."<<std::endl;
  302 + exit(1);
  303 + }
  304 + T l = pvalue*L[L.size()-1];
  305 + int idx = findIdx(l);
  306 + return (r(l,idx));
  307 +/* T rat = (l-L[idx])/(L[idx+1]-L[idx]);
  308 +// return (mags[idx][0] + (mags[idx+1][0]-mags[idx][0])*rat);
  309 + return (e[idx].U.len() + (e[idx+1].U.len() - e[idx].U.len())*rat);
  310 +*/ }
  311 +
  312 + ///Returns a radius at the given length into the fiber (based on the pvalue).
  313 + ///Interpolates the position along the line.
  314 + ///@param l: the location of the in the cylinder.
  315 + ///@param idx: integer location of the point closest to l but prior to it.
  316 + T
  317 + r(T l, int idx)
  318 + {
  319 + T rat = (l-L[idx])/(L[idx+1]-L[idx]);
  320 + T v1 = (e[idx].U.len() + (e[idx+1].U.len() - e[idx].U.len())*rat);
  321 + T v3 = (Us[idx].len() + (Us[idx+1].len() - Us[idx].len())*rat);
  322 + T v2 = (mags[idx][0] + (mags[idx+1][0]-mags[idx][0])*rat);
  323 +// std::cout << (float)v1 = (float) v2 << std::endl;
  324 + if(abs(v3 - v1) >= 10e-6)
  325 + {
  326 + std::cout << "-------------------------" << std::endl;
  327 + std::cout << e[idx].str() << std::endl << std::endl;
  328 + std::cout << Us[idx].str() << std::endl;
  329 + std::cout << (float)v1 - (float) v2 << std::endl;
  330 + std::cout << "failed" << std::endl;
  331 + }
  332 +// std::cout << e[idx].U.len() << " " << mags[idx][0] << std::endl;
  333 +// std::cout << v2 << std::endl;
  334 + return(v2);
  335 +// return (mags[idx][0] + (mags[idx+1][0]-mags[idx][0])*rat);
  336 + // (
  337 + }
  338 +
  339 + /// Returns the magnitude at the given index
  340 + /// @param i is the index of the desired point
  341 + /// @param m is the index of the magnitude value
  342 + T ri(unsigned i, unsigned m = 0){
  343 + return mags[i][m];
  344 + }
  345 +
  346 + /// Adds a new magnitude value to all points
  347 + /// @param m is the starting value for the new magnitude
  348 + void add_mag(T m = 0){
  349 + for(unsigned int p = 0; p < N; p++)
  350 + mags[p].push_back(m);
  351 + }
  352 +
  353 + /// Sets a magnitude value
  354 + /// @param val is the new value for the magnitude
  355 + /// @param p is the point index for the magnitude to be set
  356 + /// @param m is the index for the magnitude
  357 + void set_mag(T val, unsigned p, unsigned m = 0){
  358 + mags[p][m] = val;
  359 + }
  360 +
  361 + /// Returns the number of magnitude values at each point
  362 + unsigned nmags(){
  363 + return mags[0].size();
  364 + }
  365 +
  366 + ///returns the position of the point with a given pvalue and theta on the surface
  367 + ///in x, y, z coordinates. Theta is in degrees from 0 to 360.
  368 + ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
  369 + ///@param theta: the angle to the point of a circle.
  370 + stim::vec3<T>
  371 + surf(T pvalue, T theta)
  372 + {
  373 + if(pvalue < 0.0 || pvalue > 1.0)
  374 + {
  375 + return stim::vec3<float>(-1,-1,-1);
  376 + } else {
  377 + T l = pvalue*L[L.size()-1];
  378 + int idx = findIdx(l);
  379 + stim::vec3<T> ps = p(l, idx);
  380 + T m = r(l, idx);
  381 + s = e[idx];
  382 + s.center(ps);
  383 + s.normal(d(l, idx));
  384 + s.scale(m/e[idx].U.len());
  385 + return(s.p(theta));
  386 + }
  387 + }
  388 +
  389 + ///returns a vector of points necessary to create a circle at every position in the fiber.
  390 + ///@param sides: the number of sides of each circle.
  391 + std::vector<std::vector<vec3<T> > >
  392 + getPoints(int sides)
  393 + {
  394 + std::vector<std::vector <vec3<T> > > points;
  395 + points.resize(N);
  396 + for(int i = 0; i < N; i++)
  397 + {
  398 + points[i] = e[i].getPoints(sides);
  399 + }
  400 + return points;
  401 + }
  402 +
  403 + ///returns the total length of the line at index j.
  404 + T
  405 + getl(int j)
  406 + {
  407 + return (L[j]);
  408 + }
  409 + /// Allows a point on the centerline to be accessed using bracket notation
  410 +
  411 + vec3<T> operator[](unsigned int i){
  412 + return e[i].P;
  413 + }
  414 +
  415 + /// Returns the total length of the cylinder centerline
  416 + T length(){
  417 + return L.back();
  418 + }
  419 +
  420 + /// Integrates a magnitude value along the cylinder.
  421 + /// @param m is the magnitude value to be integrated (this is usually the radius)
  422 + T integrate(unsigned m = 0){
  423 +
  424 + T M = 0; //initialize the integral to zero
  425 + T m0, m1; //allocate space for both magnitudes in a single segment
  426 +
  427 + //vec3<T> p0, p1; //allocate space for both points in a single segment
  428 +
  429 + m0 = mags[0][m]; //initialize the first point and magnitude to the first point in the cylinder
  430 + //p0 = pos[0];
  431 +
  432 + T len = L[0]; //allocate space for the segment length
  433 +
  434 + //for every consecutive point in the cylinder
  435 + for(unsigned p = 1; p < N; p++){
  436 +
  437 + //p1 = pos[p]; //get the position and magnitude for the next point
  438 + m1 = mags[p][m];
  439 +
  440 + if(p > 1) len = (L[p-1] - L[p-2]); //calculate the segment length using the L array
  441 +
  442 + //add the average magnitude, weighted by the segment length
  443 + M += (m0 + m1)/(T)2.0 * len;
  444 +
  445 + m0 = m1; //move to the next segment by shifting points
  446 + }
  447 + return M; //return the integral
  448 + }
  449 +
  450 + /// Averages a magnitude value across the cylinder
  451 + /// @param m is the magnitude value to be averaged (this is usually the radius)
  452 + T average(unsigned m = 0){
  453 +
  454 + //return the average magnitude
  455 + return integrate(m) / L.back();
  456 + }
  457 +
  458 + /// Resamples the cylinder to provide a maximum distance of "spacing" between centerline points. All current
  459 + /// centerline points are guaranteed to exist in the new cylinder
  460 + /// @param spacing is the maximum spacing allowed between sample points
  461 + cylinder<T> resample(T spacing){
  462 +
  463 + std::vector< vec3<T> > result;
  464 +
  465 + vec3<T> p0 = e[0].P; //initialize p0 to the first point on the centerline
  466 + vec3<T> p1;
  467 + unsigned N = size(); //number of points in the current centerline
  468 +
  469 + //for each line segment on the centerline
  470 + for(unsigned int i = 1; i < N; i++){
  471 + p1 = e[i].P; //get the second point in the line segment
  472 +
  473 + vec3<T> v = p1 - p0; //calculate the vector between these two points
  474 + T d = v.len(); //calculate the distance between these two points (length of the line segment)
  475 +
  476 + size_t nsteps = (size_t)std::ceil(d / spacing); //calculate the number of steps to take along the segment to meet the spacing criteria
  477 + T stepsize = (T)1.0 / nsteps; //calculate the parametric step size between new centerline points
  478 +
  479 + //for each step along the line segment
  480 + for(unsigned s = 0; s < nsteps; s++){
  481 + T alpha = stepsize * s; //calculate the fraction of the distance along the line segment covered
  482 + result.push_back(p0 + alpha * v); //push the point at alpha position along the line segment
  483 + }
  484 +
  485 + p0 = p1; //shift the points to move to the next line segment
  486 + }
  487 +
  488 + result.push_back(e[size() - 1].P); //push the last point in the centerline
  489 +
  490 + return cylinder<T>(result);
  491 +
  492 + }
  493 +
  494 +
  495 +};
  496 +
  497 +}
  498 +#endif
stim/visualization/gl_network.h
@@ -49,20 +49,72 @@ public: @@ -49,20 +49,72 @@ public:
49 void glCenterline(unsigned m = 0){ 49 void glCenterline(unsigned m = 0){
50 50
51 if(!glIsList(dlist)){ //if dlist isn't a display list, create it 51 if(!glIsList(dlist)){ //if dlist isn't a display list, create it
52 - dlist = glGenLists(1); //generate a display list 52 + dlist = glGenLists(3); //generate a display list
53 glNewList(dlist, GL_COMPILE); //start a new display list 53 glNewList(dlist, GL_COMPILE); //start a new display list
54 for(unsigned e = 0; e < E.size(); e++){ //for each edge in the network 54 for(unsigned e = 0; e < E.size(); e++){ //for each edge in the network
  55 + unsigned errormag_id = E[e].nmags() - 1;
55 glBegin(GL_LINE_STRIP); 56 glBegin(GL_LINE_STRIP);
56 for(unsigned p = 0; p < E[e].size(); p++){ //for each point on that edge 57 for(unsigned p = 0; p < E[e].size(); p++){ //for each point on that edge
57 glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); //set the vertex position based on the current point 58 glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); //set the vertex position based on the current point
58 - glTexCoord1f(E[e].ri(p, m)); //set the texture coordinate based on the specified magnitude index 59 + glTexCoord1f(E[e].m(p, errormag_id)); //set the texture coordinate based on the specified magnitude index
59 } 60 }
60 glEnd(); 61 glEnd();
61 } 62 }
62 glEndList(); //end the display list 63 glEndList(); //end the display list
63 } 64 }
64 glCallList(dlist); // render the display list 65 glCallList(dlist); // render the display list
  66 + }
65 67
  68 + void glRandColorCenterlineGT(GLuint &dlist1, std::vector<unsigned> map, std::vector<T> colormap){
  69 + if(!glIsList(dlist1)){
  70 + glNewList(dlist1, GL_COMPILE);
  71 + for(unsigned e = 0; e < E.size(); e++){
  72 + if(map[e] != unsigned(-1)){
  73 + glColor3f(colormap[e * 3 + 0], colormap[e * 3 + 1], colormap[e * 3 + 2]);
  74 + glBegin(GL_LINE_STRIP);
  75 + for(unsigned p = 0; p < E[e].size(); p++){
  76 + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]);
  77 + }
  78 + glEnd();
  79 + }
  80 + else{
  81 + glColor3f(1.0, 1.0, 1.0);
  82 + glBegin(GL_LINE_STRIP);
  83 + for(unsigned p = 0; p < E[e].size(); p++){
  84 + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]);
  85 + }
  86 + glEnd();
  87 + }
  88 + }
  89 + glEndList();
  90 + }
  91 + glCallList(dlist1);
  92 + }
  93 +
  94 + void glRandColorCenterlineT(GLuint &dlist2, std::vector<unsigned> map, std::vector<T> colormap){
  95 + if(!glIsList(dlist2)){
  96 + glNewList(dlist2, GL_COMPILE);
  97 + for(unsigned e = 0; e < E.size(); e++){
  98 + if(map[e] != unsigned(-1)){
  99 + glColor3f(colormap[map[e] * 3 + 0], colormap[map[e] * 3 + 1], colormap[map[e] * 3 + 2]);
  100 + glBegin(GL_LINE_STRIP);
  101 + for(unsigned p = 0; p < E[e].size(); p++){
  102 + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]);
  103 + }
  104 + glEnd();
  105 + }
  106 + else{
  107 + glColor3f(1.0, 1.0, 1.0);
  108 + glBegin(GL_LINE_STRIP);
  109 + for(unsigned p = 0; p < E[e].size(); p++){
  110 + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]);
  111 + }
  112 + glEnd();
  113 + }
  114 + }
  115 + glEndList();
  116 + }
  117 + glCallList(dlist2);
66 } 118 }
67 119
68 }; //end stim::gl_network class 120 }; //end stim::gl_network class