Commit e21d10516d537afb3393cedd88cbd55697420722

Authored by David Mayerich
1 parent df171bd2

cylinder can build OBJ objects, simplified class hierarchy

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){
@@ -216,123 +143,84 @@ public: @@ -216,123 +143,84 @@ public:
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, d;
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, 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,
302 double sum=0; //distance summation 193 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 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/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/visualization/cylinder.h
@@ -3,56 +3,163 @@ @@ -3,56 +3,163 @@
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  
20 -  
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)  
25 -  
26 -  
27 - using stim::centerline<T>::c;  
28 - using stim::centerline<T>::N; 12 +class cylinder : public centerline<T> {
  13 +protected:
  14 + //stim::circle<T> s; //an arbitrary circle
  15 + //std::vector<stim::circle<T> > e; //an array of circles that store the centerline
  16 +
  17 + //std::vector<stim::vec3<T> > norms;
  18 + std::vector< stim::vec3<T> > U; //stores the array of U vectors defining the Frenet frame
  19 + std::vector< std::vector<T> > M; //stores a list of magnitudes for each point in the centerline (assuming mags[0] is the radius)
  20 + //std::vector< T > L; //length of the cylinder at each position (pre-integration)
  21 +
  22 +
  23 + //using stim::centerline<T>::c;
  24 + //using stim::centerline<T>::N;
  25 + using stim::centerline<T>::size;
  26 + using stim::centerline<T>::at;
  27 + using stim::centerline<T>::findIdx;
29 28
30 - ///default init  
31 - void  
32 - init()  
33 - {  
34 - 29 + //calculates the U values for each point to initialize the frenet frame
  30 + // this function assumes that the centerline has already been set
  31 + void init() {
  32 + U.resize(size()); //allocate space for the frenet frame vectors
  33 +
  34 + stim::circle<T> c; //create a circle
  35 + stim::vec3<T> d0, d1;
  36 + for (size_t i = 0; i < size() - 1; i++) { //for each line segment in the centerline
  37 + c.rotate(d(i)); //rotate the circle to match that normal
  38 + U[i] = c.U; //save the U vector from the circle
35 } 39 }
36 -  
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; 40 + U[size() - 1] = c.U; //for the last point, duplicate the final frenet frame vector
  41 + }
  42 +
  43 + ///adds a magnitude to each point in the cylinder
  44 + void add_mag(T val = 0) {
  45 + if (M.size() == 0) M.resize(size()); //if the magnitude vector isn't initialized, resize it to match the centerline
  46 + for (size_t i = 0; i < size(); i++) //for each point
  47 + M[i].push_back(val); //add this value to the magnitude vector at each point
  48 + }
  49 +
  50 + //adds a magnitude based on a list of magnitudes for each point
  51 + void add_mag(std::vector<T> val) {
  52 + if (M.size() == 0) M.resize(size()); //if the magnitude vector isn't initialized, resize it to match the centerline
  53 + for (size_t i = 0; i < size(); i++) //for each point
  54 + M[i].push_back(val[i]); //add this value to the magnitude vector at each point
  55 + }
  56 +
  57 +public:
  58 + std::string str() {
  59 + std::stringstream ss;
  60 + size_t N = std::vector< stim::vec3<T> >::size();
  61 + ss << "---------[" << N << "]---------" << std::endl;
  62 + for (size_t i = 0; i < N; i++)
  63 + ss << std::vector< stim::vec3<T> >::at(i) << " r = "<< M[i][0]<<" u = "<<U[i]<<std::endl;
  64 + ss << "--------------------" << std::endl;
  65 +
  66 + return ss.str();
  67 + }
  68 +
  69 + cylinder(centerline& c, T r = 0) : centerline(c) {
  70 + init();
  71 + add_mag(r);
  72 + }
  73 +
  74 + //initialize a cylinder with a list of points and magnitude values
  75 + cylinder(centerline& c, std::vector<T> r) : centerline(c){
  76 + init();
  77 + add_mag(r);
  78 + }
  79 +
  80 + ///Returns magnitude i at the given length into the fiber (based on the pvalue).
  81 + ///Interpolates the position along the line.
  82 + ///@param l: the location of the in the cylinder.
  83 + ///@param idx: integer location of the point closest to l but prior to it.
  84 + T m(T l, int idx, size_t i = 0) {
  85 + T a = (l - L[idx]) / (L[idx + 1] - L[idx]);
  86 + T v2 = (M[idx][i] + (M[idx + 1][i] - M[idx][i])*a);
  87 +
  88 + return v2;
  89 + }
  90 +
  91 + ///Returns the ith magnitude at the given p-value (p value ranges from 0 to 1).
  92 + ///interpolates the radius along the line.
  93 + ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
  94 + T m(T pvalue, size_t i = 0) {
  95 + if (pvalue <= 0.0) return M[0][i];
  96 + if (pvalue >= 1.0) return M[size() - 1][i];
  97 +
  98 + T l = pvalue*L[L.size() - 1];
  99 + int idx = findIdx(l);
  100 + return m(l, idx, i);
  101 + }
  102 +
  103 + ///Returns a circle representing the cylinder cross section at point i
  104 + stim::circle<T> circ(size_t i, size_t m = 0) {
  105 + return stim::circle<T>(at(i), M[i][m], d(i), U[i]);
  106 + }
  107 +
  108 + ///Returns an OBJ object representing the cylinder with a radial tesselation value of N using magnitude m
  109 + stim::obj<T> OBJ(size_t N, size_t m = 0) {
  110 + stim::obj<T> out; //create an OBJ object
  111 + stim::circle<T> c0, c1;
  112 + std::vector< stim::vec3<T> > p0, p1; //allocate space for the point sets representing the circles bounding each cylinder segment
  113 + T u0, u1, v0, v1; //allocate variables to store running texture coordinates
  114 + for (size_t i = 1; i < size(); i++) { //for each line segment in the cylinder
  115 + c0 = circ(i - 1); //get the two circles bounding the line segment
  116 + c1 = circ(i);
  117 +
  118 + p0 = c0.points(N); //get t points for each of the end caps
  119 + p1 = c1.points(N);
  120 +
  121 + u0 = L[i - 1] / length(); //calculate the texture coordinate (u, v) where u runs along the cylinder length
  122 + u1 = L[i] / length();
  123 +
  124 + for (size_t n = 1; n < N; n++) { //for each point in the circle
  125 + v0 = (double)(n-1) / (double)(N - 1); //v texture coordinate runs around the cylinder
  126 + v1 = (double)(n) / (double)(N - 1);
  127 + out.Begin(OBJ_FACE); //start a face (quad)
  128 + out.TexCoord(u0, v0);
  129 + 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
  130 + out.TexCoord(u1, v0);
  131 + out.Vertex(p1[n - 1][0], p1[n - 1][1], p1[n - 1][2]);
  132 +
  133 + out.TexCoord(u0, v1);
  134 + out.Vertex(p1[n][0], p1[n][1], p1[n][2]);
  135 + out.TexCoord(u1, v1);
  136 + out.Vertex(p0[n][0], p0[n][1], p0[n][2]);
  137 + out.End();
48 } 138 }
49 -*/ } 139 + v0 = (double)(N - 2) / (double)(N - 1); //v texture coordinate runs around the cylinder
  140 + v1 = 1.0;
  141 + out.Begin(OBJ_FACE);
  142 + out.TexCoord(u0, v0);
  143 + 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
  144 + out.TexCoord(u1, v0);
  145 + out.Vertex(p1[N - 1][0], p1[N - 1][1], p1[N - 1][2]);
  146 +
  147 + out.TexCoord(u0, v1);
  148 + out.Vertex(p1[0][0], p1[0][1], p1[0][2]);
  149 + out.TexCoord(u1, v1);
  150 + out.Vertex(p0[0][0], p0[0][1], p0[0][2]);
  151 + out.End();
  152 + }
  153 + return out;
  154 + }
50 155
51 - ///inits the cylinder from a list of points (std::vector of stim::vec3 --inP) and radii (inM) 156 +
  157 + /*
  158 + ///inits the cylinder from a list of points (std::vector of stim::vec3 --inP) and magnitudes (inM)
52 void 159 void
53 - init(std::vector<stim::vec3<T> > inP, std::vector<stim::vec<T> > inM)  
54 - {  
55 - mags = inM; 160 + init(centerline inP, std::vector< std::vector<T> > inM) {
  161 + M = inM; //the magnitude vector can be copied directly
  162 + (*this) = inP; //the centerline can be copied to this class directly
56 stim::vec3<float> v1; 163 stim::vec3<float> v1;
57 stim::vec3<float> v2; 164 stim::vec3<float> v2;
58 e.resize(inP.size()); 165 e.resize(inP.size());
@@ -246,13 +353,18 @@ class cylinder @@ -246,13 +353,18 @@ class cylinder
246 init(inP, inM); 353 init(inP, inM);
247 } 354 }
248 355
  356 + //assignment operator creates a cylinder from a centerline (default radius is zero)
  357 + cylinder& operator=(stim::centerline<T> c) {
  358 + init(c);
  359 + }
  360 +
249 ///Returns the number of points on the cylinder centerline 361 ///Returns the number of points on the cylinder centerline
250 362
251 unsigned int size(){ 363 unsigned int size(){
252 return N; 364 return N;
253 } 365 }
254 366
255 - 367 +
256 ///Returns a position vector at the given p-value (p value ranges from 0 to 1). 368 ///Returns a position vector at the given p-value (p value ranges from 0 to 1).
257 ///interpolates the position along the line. 369 ///interpolates the position along the line.
258 ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1). 370 ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
@@ -266,22 +378,7 @@ class cylinder @@ -266,22 +378,7 @@ class cylinder
266 T l = pvalue*L[L.size()-1]; 378 T l = pvalue*L[L.size()-1];
267 int idx = findIdx(l); 379 int idx = findIdx(l);
268 return (p(l,idx)); 380 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 -*/ } 381 + }
285 382
286 ///Returns a position vector at the given length into the fiber (based on the pvalue). 383 ///Returns a position vector at the given length into the fiber (based on the pvalue).
287 ///Interpolates the radius along the line. 384 ///Interpolates the radius along the line.
@@ -321,10 +418,7 @@ class cylinder @@ -321,10 +418,7 @@ class cylinder
321 T l = pvalue*L[L.size()-1]; 418 T l = pvalue*L[L.size()-1];
322 int idx = findIdx(l); 419 int idx = findIdx(l);
323 return (r(l,idx)); 420 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 -*/ } 421 + }
328 422
329 ///Returns a radius at the given length into the fiber (based on the pvalue). 423 ///Returns a radius at the given length into the fiber (based on the pvalue).
330 ///Interpolates the position along the line. 424 ///Interpolates the position along the line.
@@ -506,7 +600,7 @@ class cylinder @@ -506,7 +600,7 @@ class cylinder
506 600
507 return cylinder<T>(result); 601 return cylinder<T>(result);
508 602
509 - } 603 + }*/
510 604
511 605
512 }; 606 };
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