Commit e21d10516d537afb3393cedd88cbd55697420722
1 parent
df171bd2
cylinder can build OBJ objects, simplified class hierarchy
Showing
6 changed files
with
1300 additions
and
352 deletions
Show diff stats
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 | }; |
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<T> | @@ -18,13 +18,14 @@ class circle : plane<T> | ||
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 |
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 | }; |
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 |