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 3  
4 4 #include <vector>
5 5 #include <stim/math/vec3.h>
6   -//#include <ANN/ANN.h>
7 6  
8 7 namespace stim{
9 8  
... ... @@ -12,195 +11,123 @@ namespace stim{
12 11 * class to describe an interconnected (often biological) network.
13 12 */
14 13 template<typename T>
15   -class centerline{
  14 +class centerline : public std::vector< stim::vec3<T> >{
16 15  
17 16 protected:
18   - unsigned int N; //number of points in the fiber
19   - double **c; //centerline (array of double pointers)
20   -// ANNkd_tree* kdt; //kd-tree stores all points in the fiber for fast searching
21 17  
22   - /// Initialize an empty fiber
23   - void init()
24   - {
25   - N=0;
26   - c=NULL;
27   -// kdt = NULL;
28   - }
29   -
30   - /// Initialize a fiber with N centerline points (all located at [0, 0, 0] with radius 0)
31   - void init(unsigned int n)
32   - {
  18 + std::vector<T> L; //stores the integrated length along the fiber (used for parameterization)
33 19  
34   - N = n; //set the number of points
35   -// kdt = NULL;
36   - c = (double**) malloc(sizeof(double*) * N); //allocate the array pointer
  20 + ///Return the normalized direction vector at point i (average of the incoming and outgoing directions)
  21 + vec3<T> d(size_t i) {
  22 + if (size() <= 1) return vec3<T>(0, 0, 0); //if there is insufficient information to calculate the direction, return a null vector
  23 + if (size() == 2) return (at(1) - at(0)).norm(); //if there are only two points, the direction vector at both is the direction of the line segment
  24 + if (i == 0) return (at(1) - at(0)).norm(); //the first direction vector is oriented towards the first line segment
  25 + if (i == size() - 1) return at(size() - 1) - at(size() - 2); //the last direction vector is oriented towards the last line segment
37 26  
38   - for(unsigned int i = 0; i < N; i++) //allocate space for each point
39   - c[i] = (double*) malloc(sizeof(double) * 3);
  27 + //all other direction vectors are the average direction of the two joined line segments
  28 + return ((at(i) - at(i - 1)).norm() + (at(i + 1) - at(i)).norm()).norm();
40 29 }
41   -
42   - /// Copies an existing fiber to the current fiber
43   -
44   - /// @param cpy stores the new copy of the fiber
45   - void copy( const stim::centerline<T>& cpy, bool kd = 0){
46   -
47   - ///allocate space for the new fiber
48   - init(cpy.N);
49   -
50   - ///copy the points
51   - for(unsigned int i = 0; i < N; i++){
52   - for(unsigned int d = 0; d < 3; d++) //for each dimension
53   - c[i][d] = cpy.c[i][d]; //copy the coordinate
  30 + //initializes the integrated length vector to make parameterization easier, starting with index idx (all previous indices are assumed to be correct)
  31 + void update_L(size_t start = 0) {
  32 + L.resize(size()); //allocate space for the L array
  33 + if (start == 0) {
  34 + L[0] = 0; //initialize the length value for the first point to zero (0)
  35 + start++;
54 36 }
55   -// if(kd)
56   -// gen_kdtree(); //generate the kd tree for the new fiber
57   - }
58 37  
59   - /// generate a KD tree for points on fiber
60   -// void gen_kdtree()
61   -// {
62   -// int n_data = N; //create an array of data points
63   -// ANNpointArray pts = (ANNpointArray)c; //cast the centerline list to an ANNpointArray
64   -// kdt = new ANNkd_tree(pts, n_data, 3); //build a KD tree
65   -// }
66   -
67   - /// find distance between two points
68   - double dist(double* p0, double* p1){
69   -
70   - double sum = 0; // initialize variables
71   - float v;
72   - for(unsigned int d = 0; d < 3; d++)
73   - {
74   - v = p1[d] - p0[d];
75   - sum +=v * v;
  38 + stim::vec3<T> d;
  39 + for (size_t i = start; i < size(); i++) { //for each line segment in the centerline
  40 + d = at(i) - at(i - 1);
  41 + L[i] = L[i - 1] + d.len(); //calculate the running length total
76 42 }
77   - return sqrt(sum);
78 43 }
79 44  
80   - /// This function retreives the index for the fiber point closest to q
81   -
82   - /// @param q is a reference point used to find the closest point on the fiber center line
83   -// unsigned int ann( stim::vec<double> q ){
84   -// ANNidxArray idx = new ANNidx[1]; //variable used to hold the nearest point
85   -// ANNdistArray sq_dist = new ANNdist[1]; //variable used to hold the squared distance to the nearest point
86   -// kdt->annkSearch(q.data(), 1, idx, sq_dist); //search the KD tree for the nearest neighbor
87   -// return *idx;
88   -// }
  45 + void init() {
  46 + if (size() == 0) return; //return if there aren't any points
  47 + update_L();
  48 + }
89 49  
90 50 /// Returns a stim::vec representing the point at index i
91 51  
92 52 /// @param i is an index of the desired centerline point
93 53 stim::vec<T> get_vec(unsigned i){
94   - stim::vec3<T> r;
95   - r.resize(3);
96   - r[0] = c[i][0];
97   - r[1] = c[i][1];
98   - r[2] = c[i][2];
  54 + return std::vector< stim::vec3<T> >::at(i);
  55 + }
  56 +
  57 + ///finds the index of the point closest to the length l on the lower bound.
  58 + ///binary search.
  59 + size_t findIdx(T l) {
  60 + size_t i = L.size() / 2;
  61 + size_t max = L.size() - 1;
  62 + size_t min = 0;
  63 + while (i > 0 && i < L.size() - 1){
  64 + if (l < L[i]) {
  65 + max = i;
  66 + i = min + (max - min) / 2;
  67 + }
  68 + else if (L[i] <= l && L[i + 1] >= l) {
  69 + break;
  70 + }
  71 + else {
  72 + min = i;
  73 + i = min + (max - min) / 2;
  74 + }
  75 + }
  76 + return i;
  77 + }
99 78  
100   - return r;
  79 + ///Returns a position vector at the given length into the fiber (based on the pvalue).
  80 + ///Interpolates the radius along the line.
  81 + ///@param l: the location of the in the cylinder.
  82 + ///@param idx: integer location of the point closest to l but prior to it.
  83 + stim::vec3<T> p(T l, int idx) {
  84 + T rat = (l - L[idx]) / (L[idx + 1] - L[idx]);
  85 + stim::vec3<T> v1 = at(idx);
  86 + stim::vec3<T> v2 = at(idx + 1);
  87 + return(v1 + (v2 - v1)*rat);
101 88 }
102 89  
103 90  
104 91 public:
105 92  
106   - centerline(){
107   - init();
108   - }
  93 + using std::vector< stim::vec3<T> >::at;
  94 + using std::vector< stim::vec3<T> >::size;
109 95  
110   - /// Copy constructor
111   - centerline(const stim::centerline<T> &obj){
112   - copy(obj);
  96 + centerline() : std::vector< stim::vec3<T> >() {
  97 + init();
113 98 }
114   -
115   - //temp constructor for graph visualization
116   - centerline(int n)
117   - {
118   - init(n);
  99 + centerline(size_t n) : std::vector< stim::vec3<T> >(n){
  100 + init();
119 101 }
120 102  
121   - /// Constructor takes a list of stim::vec points, the radius at each point is set to zero
122   - centerline(std::vector< stim::vec<T> > p, bool kd = 0){
123   - init(p.size()); //initialize the fiber
124   -
125   - //for each point, set the centerline position and radius
126   - for(unsigned int i = 0; i < N; i++){
127   -
128   - //set the centerline position
129   - for(unsigned int d = 0; d < 3; d++)
130   - c[i][d] = (double) p[i][d];
131   -
132   - //set the radius
133   - }
134   - //generate a kd tree
135   -// if(kd)
136   -// gen_kdtree();
  103 + //overload the push_back function to update the length vector
  104 + void push_back(stim::vec3<T> p) {
  105 + std::vector< stim::vec3<T> >::push_back(p);
  106 + update_L(size() - 1);
137 107 }
138 108  
139   - /// constructor takes a list of points
140   - centerline(std::vector< stim::vec3< T > > pos, bool kd = 0){
141   - init(pos.size()); //initialize the fiber
  109 + ///Returns a position vector at the given p-value (p value ranges from 0 to 1).
  110 + ///interpolates the position along the line.
  111 + ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
  112 + stim::vec3<T> p(T pvalue) {
  113 + if (pvalue <= 0.0) return at(0); //return the first element
  114 + if (pvalue >= 1.0) return back(); //return the last element
142 115  
143   - //for each point, set the centerline position and radius
144   - for(unsigned int i = 0; i < N; i++){
145   - //set the centerline position
146   - for(unsigned int d = 0; d < 3; d++)
147   - c[i][d] = (double) pos[i][d];
148   - //set the radius
149   - }
150   -
151   - //generate a kd tree
152   - //if(kd)
153   - // gen_kdtree();
  116 + T l = pvalue*L[L.size() - 1];
  117 + int idx = findIdx(l);
  118 + return p(l, idx);
154 119 }
155 120  
156   - /// Assignment operation
157   - centerline& operator=(const centerline &rhs){
158   - if(this == &rhs) return *this; //test for and handle self-assignment
159   - copy(rhs);
160   - return *this;
161   - }
162   -
163   -
164   - /// Return the point on the fiber closest to q
165   - /// @param q is the query point used to locate the nearest point on the fiber centerline
166   -// stim::vec<T> nearest(stim::vec<T> q){
167   -//
168   -// stim::vec<double> temp( (double) q[0], (double) q[1], (double) q[2]);
169   -//
170   -// unsigned int idx = ann(temp); //determine the index of the nearest neighbor
171   -//
172   -// return stim::vec<T>((T) c[idx][0], (T) c[idx][1], (T) c[idx][2]); //return the nearest centerline point
173   -// }
174   -
175   - /// Return the point index on the fiber closest to q
176   - /// @param q is the query point used to locate the nearest point on the fiber centerline
177   -// unsigned int nearest_idx(stim::vec<T> q){
178   -//
179   -// stim::vec<double> temp((double) q[0], (double) q[1], (double) q[2]);
180   -//
181   -// unsigned int idx = ann(temp); //determine the index of the nearest neighbor
182   -//
183   -// return idx; //return the nearest centerline point index
184   -// }
185   -
186   - /// Returns the fiber centerline as an array of stim::vec points
187   - std::vector< stim::vec<T> > get_centerline(){
188   -
189   - //create an array of stim vectors
190   - std::vector< stim::vec3<T> > pts(N);
191   -
192   - //cast each point to a stim::vec, keeping only the position information
193   - for(unsigned int i = 0; i < N; i++)
194   - pts[i] = stim::vec3<T>((T) c[i][0], (T) c[i][1], (T) c[i][2]);
195   -
196   - //return the centerline array
197   - return pts;
  121 + ///Return the length of the entire centerline
  122 + T length() {
  123 + return L.back();
198 124 }
199 125  
200 126 /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned
201 127 std::vector< stim::centerline<T> > split(unsigned int idx){
202 128  
203   - std::vector< stim::centerline<T> > fl; //create an array to store up to two fibers
  129 + std::vector< stim::centerline<T> > fl; //create an array to store up to two fibers
  130 + size_t N = size();
204 131  
205 132 //if the index is an end point, only the existing fiber is returned
206 133 if(idx == 0 || idx == N-1){
... ... @@ -216,123 +143,84 @@ public:
216 143  
217 144 fl.resize(2); //set the array size to 2
218 145  
219   - fl[0].init(N1); //set the size of each fiber
220   - fl[1].init(N2);
  146 + fl[0] = stim::centerline<T>(N1); //set the size of each fiber
  147 + fl[1] = stim::centerline<T>(N2);
221 148  
222 149 //copy both halves of the fiber
223 150 unsigned int i, d;
224 151  
225 152 //first half
226   - for(i = 0; i < N1; i++){ //for each centerline point
227   - for(d = 0; d < 3; d++)
228   - fl[0].c[i][d] = c[i][d]; //copy each coordinate
229   - }
  153 + for(i = 0; i < N1; i++) //for each centerline point
  154 + fl[0][i] = std::vector< stim::vec3<T> >::at(i);
  155 + fl[0].init(); //initialize the length vector
230 156  
231 157 //second half
232   - for(i = 0; i < N2; i++){
233   - for(d = 0; d < 3; d++)
234   - fl[1].c[i][d] = c[idx + i][d];
235   -
236   - }
  158 + for(i = 0; i < N2; i++)
  159 + fl[1][i] = std::vector< stim::vec3<T> >::at(idx+i);
  160 + fl[1].init(); //initialize the length vector
237 161 }
238 162  
239 163 return fl; //return the array
240 164  
241 165 }
242 166  
243   - /// Calculates the set of fibers resulting from a connection between the current fiber and a fiber f
244   -
245   - /// @param f is the fiber that will be connected to the current fiber
246   -/* std::vector< stim::centerline<T> > connect( stim::centerline<T> &f, double dist){
247   -
248   - double min_dist;
249   - unsigned int idx0, idx1;
250   -
251   - //go through each point in the query fiber, looking for the indices for the closest points
252   - for(unsigned int i = 0; i < f.n_pts(); i++){
253   - //Run through all points and find the index with the closest point, then partition the fiber and return two fibers.
254   -
255   - }
256   -
257   -
258   -
259   - }
260   -*/
261 167 /// Outputs the fiber as a string
262 168 std::string str(){
263 169 std::stringstream ss;
264   -
265   - //create an iterator for the point list
266   - //typename std::list< point<T> >::iterator i;
267   - for(unsigned int i = 0; i < N; i++){
268   - ss<<" [ ";
269   - for(unsigned int d = 0; d < 3; d++){
270   - ss<<c[i][d]<<" ";
271   - }
272   - }
  170 + size_t N = std::vector< stim::vec3<T> >::size();
  171 + ss << "---------[" << N << "]---------" << std::endl;
  172 + for (size_t i = 0; i < N; i++)
  173 + ss << std::vector< stim::vec3<T> >::at(i) << std::endl;
  174 + ss << "--------------------" << std::endl;
273 175  
274 176 return ss.str();
275 177 }
276   - /// Returns the number of centerline points in the fiber
277   - unsigned int size(){
278   - return N;
279   - }
280   -
281   -
282   - /// Bracket operator returns the element at index i
283   -
284   - /// @param i is the index of the element to be returned as a stim::vec
285   - stim::vec<T> operator[](unsigned i){
286   - return get_vec(i);
287   - }
288 178  
289 179 /// Back method returns the last point in the fiber
290   - stim::vec<T> back(){
291   - return get_vec(N-1);
  180 + stim::vec3<T> back(){
  181 + return std::vector< stim::vec3<T> >::back();
292 182 }
  183 +
293 184 ////resample a fiber in the network
294 185 stim::centerline<T> resample(T spacing)
295 186 {
296 187 std::cout<<"fiber::resample()"<<std::endl;
297 188  
298   - std::vector<T> v(3); //v-direction vector of the segment
299   - stim::vec<T> p(3); //- intermediate point to be added
300   - stim::vec<T> p1(3); // p1 - starting point of an segment on the fiber,
301   - stim::vec<T> p2(3); // p2 - ending point,
  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 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 198 // for each point on the centerline (skip if it is the last point on centerline)
306   - //unsigned int N = fiberPositions.size(); // number of points on the fiber
307 199 for(unsigned int f=0; f< N-1; f++)
308   - {
  200 + {
  201 + p1 = at(f);
  202 + p2 = at(f+1);
  203 + v = p2 - p1;
309 204  
310   - p1 = fiberPositions[f]; p2 = fiberPositions[f + 1]; v = p2 - p1;
311   - for(unsigned int d = 0; d < 3; d++){
312   - sum +=v[d] * v[d];} //length of segment-distance between starting and ending point
313   -
314   - T lengthSegment = sqrt(sum); //find Length of the segment as distance between the starting and ending points of the segment
315   -
316   - if(lengthSegment >= spacing) // if length of the segment is greater than standard deviation resample
317   - {
318   - // repeat resampling until accumulated stepsize is equsl to length of the segment
319   - for(T step=0.0; step<lengthSegment; step+=spacing)
320   - {
321   - // calculate the resampled point by travelling step size in the direction of normalized gradient vector
322   - for(unsigned int i=0; i<3;i++)
323   - {
324   - p[i] = p1[i] + v[i]*(step/lengthSegment);
325   - } //for each dimension
326   - // add this resampled points to the new fiber list
327   - newPointList.push_back(p);
328   - }
  205 + T lengthSegment = v.len(); //find Length of the segment as distance between the starting and ending points of the segment
  206 +
  207 + if(lengthSegment >= spacing){ // if length of the segment is greater than standard deviation resample
  208 +
  209 + // repeat resampling until accumulated stepsize is equsl to length of the segment
  210 + for(T step=0.0; step<lengthSegment; step+=spacing){
  211 + // calculate the resampled point by travelling step size in the direction of normalized gradient vector
  212 + p = p1 + v * (step / lengthSegment);
  213 +
  214 + // add this resampled points to the new fiber list
  215 + new_c.push_back(p);
329 216 }
330   - else // length of the segment is now less than standard deviation, push the ending point of the segment and proceed to the next point in the fiber
331   - newPointList.push_back(fiberPositions[f+1]);
332 217 }
333   - newPointList.push_back(fiberPositions[N-1]); //add the last point on the fiber to the new fiber list
334   - centerline newFiber(newPointList);
335   - return newFiber;
  218 + else // length of the segment is now less than standard deviation, push the ending point of the segment and proceed to the next point in the fiber
  219 + new_c.push_back(at(f+1));
  220 + }
  221 + new_c.push_back(at(N-1)); //add the last point on the fiber to the new fiber list
  222 + //centerline newFiber(newPointList);
  223 + return new_c;
336 224 }
337 225  
338 226 };
... ...
stim/biomodels/centerline_dep.h 0 โ†’ 100644
  1 +#ifndef STIM_CENTERLINE_H
  2 +#define STIM_CENTERLINE_H
  3 +
  4 +#include <vector>
  5 +#include <stim/math/vec3.h>
  6 +
  7 +namespace stim{
  8 +
  9 +/** This class stores information about a single fiber represented as a set of geometric points
  10 + * between two branch or end points. This class is used as a fundamental component of the stim::network
  11 + * class to describe an interconnected (often biological) network.
  12 + */
  13 +template<typename T>
  14 +class centerline{
  15 +
  16 +protected:
  17 + unsigned int N; //number of points in the fiber
  18 + double **c; //centerline (array of double pointers)
  19 +
  20 + /// Initialize an empty fiber
  21 + void init(){
  22 + N=0;
  23 + c=NULL;
  24 + }
  25 +
  26 + /// Initialize a fiber with N centerline points (all located at [0, 0, 0] with radius 0)
  27 + void init(unsigned int n){
  28 +
  29 + N = n; //set the number of points
  30 + c = (double**) malloc(sizeof(double*) * N); //allocate the array pointer
  31 +
  32 + for(unsigned int i = 0; i < N; i++) //allocate space for each point
  33 + c[i] = (double*) malloc(sizeof(double) * 3);
  34 + }
  35 +
  36 + /// Copies an existing fiber to the current fiber
  37 +
  38 + /// @param cpy stores the new copy of the fiber
  39 + void copy( const stim::centerline<T>& cpy, bool kd = 0){
  40 +
  41 + ///allocate space for the new fiber
  42 + init(cpy.N);
  43 +
  44 + ///copy the points
  45 + for(unsigned int i = 0; i < N; i++){
  46 + for(unsigned int d = 0; d < 3; d++) //for each dimension
  47 + c[i][d] = cpy.c[i][d]; //copy the coordinate
  48 + }
  49 + }
  50 +
  51 + /// find distance between two points
  52 + double dist(double* p0, double* p1){
  53 +
  54 + double sum = 0; // initialize variables
  55 + float v;
  56 + for(unsigned int d = 0; d < 3; d++)
  57 + {
  58 + v = p1[d] - p0[d];
  59 + sum +=v * v;
  60 + }
  61 + return sqrt(sum);
  62 + }
  63 +
  64 + /// Returns a stim::vec representing the point at index i
  65 +
  66 + /// @param i is an index of the desired centerline point
  67 + stim::vec<T> get_vec(unsigned i){
  68 + stim::vec3<T> r;
  69 + r.resize(3);
  70 + r[0] = c[i][0];
  71 + r[1] = c[i][1];
  72 + r[2] = c[i][2];
  73 +
  74 + return r;
  75 + }
  76 +
  77 +
  78 +public:
  79 +
  80 + centerline(){
  81 + init();
  82 + }
  83 +
  84 + /// Copy constructor
  85 + centerline(const stim::centerline<T> &obj){
  86 + copy(obj);
  87 + }
  88 +
  89 + //initialize a centerline with n points
  90 + centerline(int n){
  91 + init(n);
  92 + }
  93 +
  94 + /// Constructor takes a list of stim::vec points, the radius at each point is set to zero
  95 + centerline(std::vector< stim::vec<T> > p, bool kd = 0){
  96 + init(p.size()); //initialize the fiber
  97 +
  98 + //for each point, set the centerline position and radius
  99 + for(unsigned int i = 0; i < N; i++){
  100 +
  101 + //set the centerline position
  102 + for(unsigned int d = 0; d < 3; d++)
  103 + c[i][d] = (double) p[i][d];
  104 + }
  105 + }
  106 +
  107 + /// constructor takes a list of points
  108 + centerline(std::vector< stim::vec3< T > > pos, bool kd = 0){
  109 + init(pos.size()); //initialize the fiber
  110 +
  111 + //for each point, set the centerline position and radius
  112 + for(unsigned int i = 0; i < N; i++){
  113 + //set the centerline position
  114 + for(unsigned int d = 0; d < 3; d++)
  115 + c[i][d] = (double) pos[i][d];
  116 + }
  117 + }
  118 +
  119 + /// Assignment operation
  120 + centerline& operator=(const centerline &rhs){
  121 + if(this == &rhs) return *this; //test for and handle self-assignment
  122 + copy(rhs);
  123 + return *this;
  124 + }
  125 +
  126 +
  127 + /// Returns the fiber centerline as an array of stim::vec points
  128 + std::vector< stim::vec<T> > get_centerline(){
  129 +
  130 + //create an array of stim vectors
  131 + std::vector< stim::vec3<T> > pts(N);
  132 +
  133 + //cast each point to a stim::vec, keeping only the position information
  134 + for(unsigned int i = 0; i < N; i++)
  135 + pts[i] = stim::vec3<T>((T) c[i][0], (T) c[i][1], (T) c[i][2]);
  136 +
  137 + //return the centerline array
  138 + return pts;
  139 + }
  140 +
  141 + /// Split the fiber at the specified index. If the index is an end point, only one fiber is returned
  142 + std::vector< stim::centerline<T> > split(unsigned int idx){
  143 +
  144 + std::vector< stim::centerline<T> > fl; //create an array to store up to two fibers
  145 +
  146 + //if the index is an end point, only the existing fiber is returned
  147 + if(idx == 0 || idx == N-1){
  148 + fl.resize(1); //set the size of the fiber to 1
  149 + fl[0] = *this; //copy the current fiber
  150 + }
  151 +
  152 + //if the index is not an end point
  153 + else{
  154 +
  155 + unsigned int N1 = idx + 1; //calculate the size of both fibers
  156 + unsigned int N2 = N - idx;
  157 +
  158 + fl.resize(2); //set the array size to 2
  159 +
  160 + fl[0].init(N1); //set the size of each fiber
  161 + fl[1].init(N2);
  162 +
  163 + //copy both halves of the fiber
  164 + unsigned int i, d;
  165 +
  166 + //first half
  167 + for(i = 0; i < N1; i++){ //for each centerline point
  168 + for(d = 0; d < 3; d++)
  169 + fl[0].c[i][d] = c[i][d]; //copy each coordinate
  170 + }
  171 +
  172 + //second half
  173 + for(i = 0; i < N2; i++){
  174 + for(d = 0; d < 3; d++)
  175 + fl[1].c[i][d] = c[idx + i][d];
  176 +
  177 + }
  178 + }
  179 +
  180 + return fl; //return the array
  181 +
  182 + }
  183 +
  184 + /// Outputs the fiber as a string
  185 + std::string str(){
  186 + std::stringstream ss;
  187 +
  188 + //create an iterator for the point list
  189 + //typename std::list< point<T> >::iterator i;
  190 + for(unsigned int i = 0; i < N; i++){
  191 + ss<<" [ ";
  192 + for(unsigned int d = 0; d < 3; d++){
  193 + ss<<c[i][d]<<" ";
  194 + }
  195 + }
  196 +
  197 + return ss.str();
  198 + }
  199 + /// Returns the number of centerline points in the fiber
  200 + unsigned int size(){
  201 + return N;
  202 + }
  203 +
  204 +
  205 + /// Bracket operator returns the element at index i
  206 +
  207 + /// @param i is the index of the element to be returned as a stim::vec
  208 + stim::vec<T> operator[](unsigned i){
  209 + return get_vec(i);
  210 + }
  211 +
  212 + /// Back method returns the last point in the fiber
  213 + stim::vec<T> back(){
  214 + return get_vec(N-1);
  215 + }
  216 + ////resample a fiber in the network
  217 + stim::centerline<T> resample(T spacing)
  218 + {
  219 + std::cout<<"fiber::resample()"<<std::endl;
  220 +
  221 + std::vector<T> v(3); //v-direction vector of the segment
  222 + stim::vec<T> p(3); //- intermediate point to be added
  223 + stim::vec<T> p1(3); // p1 - starting point of an segment on the fiber,
  224 + stim::vec<T> p2(3); // p2 - ending point,
  225 + double sum=0; //distance summation
  226 + std::vector<stim::vec<T> > fiberPositions = centerline();
  227 + std::vector<stim::vec<T> > newPointList; // initialize list of new resampled points on the fiber
  228 + // for each point on the centerline (skip if it is the last point on centerline)
  229 + for(unsigned int f=0; f< N-1; f++)
  230 + {
  231 +
  232 + p1 = fiberPositions[f]; p2 = fiberPositions[f + 1]; v = p2 - p1;
  233 + for(unsigned int d = 0; d < 3; d++){
  234 + sum +=v[d] * v[d];} //length of segment-distance between starting and ending point
  235 +
  236 + T lengthSegment = sqrt(sum); //find Length of the segment as distance between the starting and ending points of the segment
  237 +
  238 + if(lengthSegment >= spacing) // if length of the segment is greater than standard deviation resample
  239 + {
  240 + // repeat resampling until accumulated stepsize is equsl to length of the segment
  241 + for(T step=0.0; step<lengthSegment; step+=spacing)
  242 + {
  243 + // calculate the resampled point by travelling step size in the direction of normalized gradient vector
  244 + for(unsigned int i=0; i<3;i++)
  245 + {
  246 + p[i] = p1[i] + v[i]*(step/lengthSegment);
  247 + } //for each dimension
  248 + // add this resampled points to the new fiber list
  249 + newPointList.push_back(p);
  250 + }
  251 + }
  252 + else // length of the segment is now less than standard deviation, push the ending point of the segment and proceed to the next point in the fiber
  253 + newPointList.push_back(fiberPositions[f+1]);
  254 + }
  255 + newPointList.push_back(fiberPositions[N-1]); //add the last point on the fiber to the new fiber list
  256 + centerline newFiber(newPointList);
  257 + return newFiber;
  258 + }
  259 +
  260 +};
  261 +
  262 +
  263 +
  264 +} //end namespace stim
  265 +
  266 +
  267 +
  268 +#endif
... ...
stim/math/circle.h
... ... @@ -18,13 +18,14 @@ class circle : plane&lt;T&gt;
18 18  
19 19 private:
20 20  
21   - stim::vec3<T> Y;
  21 + //stim::vec3<T> Y;
  22 + T R; //radius of the circle
22 23  
23   - CUDA_CALLABLE void
  24 + /*CUDA_CALLABLE void
24 25 init()
25 26 {
26 27 Y = U.cross(N).norm();
27   - }
  28 + }*/
28 29  
29 30 public:
30 31 using stim::plane<T>::n;
... ... @@ -42,26 +43,28 @@ public:
42 43 init();
43 44 }
44 45  
45   - ///create a rectangle given a size and position in Z space.
  46 + ///create a circle given a size and position in Z space.
46 47 ///@param size: size of the rectangle in ND space.
47 48 ///@param z_pos z coordinate of the rectangle.
48 49 CUDA_CALLABLE
49   - circle(T size, T z_pos = (T)0) : plane<T>()
  50 + circle(T radius, T z_pos = (T)0) : plane<T>(z_pos)
50 51 {
51   - center(stim::vec3<T>(0,0,z_pos));
52   - scale(size);
53   - init();
  52 + //center(stim::vec3<T>(0, 0, z_pos));
  53 + //scale(size);
  54 + //init();
  55 + R = radius;
54 56 }
55 57  
56 58 ///create a rectangle from a center point, normal
57 59 ///@param c: x,y,z location of the center.
58 60 ///@param n: x,y,z direction of the normal.
59 61 CUDA_CALLABLE
60   - circle(vec3<T> c, vec3<T> n = vec3<T>(0,0,1)) : plane<T>()
  62 + circle(vec3<T> c, vec3<T> n = vec3<T>(0,0,1)) : plane<T>(n, c)
61 63 {
62   - center(c);
63   - normal(n);
64   - init();
  64 + //center(c);
  65 + //normal(n);
  66 + //init();
  67 + R = (T)1;
65 68 }
66 69  
67 70 /*///create a rectangle from a center point, normal, and size
... ... @@ -84,14 +87,18 @@ public:
84 87 ///@param n: x,y,z direction of the normal.
85 88 ///@param u: x,y,z direction for the zero vector (from where the rotation starts)
86 89 CUDA_CALLABLE
87   - circle(vec3<T> c, T s, vec3<T> n = vec3<T>(0,0,1), vec3<T> u = vec3<T>(1, 0, 0)) : plane<T>()
  90 + circle(vec3<T> c, T r, vec3<T> n = vec3<T>(0,0,1), vec3<T> u = vec3<T>(1, 0, 0)) : plane<T>()
88 91 {
89   - init();
  92 + P = c;
  93 + N = n;
90 94 setU(u);
  95 + R = r;
  96 + //init();
  97 + //setU(u);
91 98 // U = u;
92   - center(c);
93   - normal(n);
94   - scale(s);
  99 + //center(c);
  100 + //normal(n);
  101 + //scale(s);
95 102 }
96 103  
97 104 ///scales the circle by a certain factor
... ... @@ -99,23 +106,23 @@ public:
99 106 CUDA_CALLABLE
100 107 void scale(T factor)
101 108 {
102   - U *= factor;
103   - Y *= factor;
  109 + //U *= factor;
  110 + //Y *= factor;
  111 + R *= factor;
104 112 }
105 113  
106 114 ///sets the normal for the cirlce
107 115 ///@param n: x,y,z direction of the normal.
108 116 CUDA_CALLABLE void
109   - normal(vec3<T> n)
110   - {
111   - rotate(n, Y);
  117 + normal(vec3<T> n){
  118 + rotate(n);
112 119 }
113 120  
114 121 ///sets the center of the circle.
115 122 ///@param n: x,y,z location of the center.
116 123 CUDA_CALLABLE void
117 124 center(vec3<T> p){
118   - this->P = p;
  125 + P = p;
119 126 }
120 127  
121 128 ///boolean comparison
... ... @@ -128,57 +135,63 @@ public:
128 135 return false;
129 136 }
130 137  
  138 + //returns the point in world space corresponding to the polar coordinate (r, theta)
  139 + CUDA_CALLABLE stim::vec3<T>
  140 + p(T r, T theta) {
  141 + T u = r * cos(theta); //calculate the coordinates in the planar space defined by the circle
  142 + T v = r * sin(theta);
  143 +
  144 + vec3<T> V = U.cross(N); //calculate the orthogonal vector V
  145 + return P + U * u + V * v; //calculate the cartesian coordinate of the specified point
  146 + }
  147 +
  148 + //returns the point in world space corresponding to the value theta at radius R
  149 + CUDA_CALLABLE stim::vec3<T>
  150 + p(T theta) {
  151 + return p(R, theta);
  152 + }
  153 +
  154 + //get the world space value given the polar coordinates (r, theta)
  155 +
131 156 ///get the world space value given the planar coordinates a, b in [0, 1]
132   - CUDA_CALLABLE stim::vec3<T> p(T a, T b)
  157 + /*CUDA_CALLABLE stim::vec3<T> p(T a, T b)
133 158 {
134 159 stim::vec3<T> result;
135 160  
136 161 vec3<T> A = this->P - this->U * (T)0.5 - Y * (T)0.5;
137 162 result = A + this->U * a + Y * b;
138 163 return result;
139   - }
  164 + }*/
140 165  
141 166 ///parenthesis operator returns the world space given rectangular coordinates a and b in [0 1]
142   - CUDA_CALLABLE stim::vec3<T> operator()(T a, T b)
  167 + CUDA_CALLABLE stim::vec3<T> operator()(T r, T theta)
143 168 {
144   - return p(a,b);
  169 + return p(r, theta);
  170 + }
  171 +
  172 + //parenthesis operator returns the world space coordinate at the edge of the circle given theta
  173 + CUDA_CALLABLE stim::vec3<T> operator()(T theta) {
  174 + return p(theta);
145 175 }
146 176  
147 177 ///returns a vector with the points on the initialized circle.
148 178 ///connecting the points results in a circle.
149 179 ///@param n: integer for the number of points representing the circle.
150   - std::vector<stim::vec3<T> >
151   - getPoints(int n)
152   - {
153   - std::vector<stim::vec3<T> > result;
154   - stim::vec3<T> point;
155   - T x,y;
156   - float step = 360.0/(float) n;
157   - for(float j = 0; j <= 360.0; j += step)
158   - {
159   - y = 0.5*cos(j*stim::TAU/360.0)+0.5;
160   - x = 0.5*sin(j*stim::TAU/360.0)+0.5;
161   - result.push_back(p(x,y));
162   - }
  180 + std::vector< stim::vec3<T> > points(unsigned n) {
  181 + std::vector< stim::vec3<T> > result(n); //initialize a vector of n points
  182 +
  183 + float dt = stim::TAU / n;
  184 + for (unsigned i = 0; i < n; i++)
  185 + result[i] = p(i * dt); //calculate a point on the edge of the circle
163 186 return result;
164 187 }
165 188  
166   - ///returns a vector with the points on the initialized circle.
167   - ///connecting the points results in a circle.
168   - ///@param n: integer for the number of points representing the circle.
169   - CUDA_CALLABLE stim::vec3<T>
170   - p(T theta)
171   - {
172   - T x,y;
173   - y = 0.5*cos(theta*STIM_TAU/360.0)+0.5;
174   - x = 0.5*sin(theta*STIM_TAU/360.0)+0.5;
175   - return p(x,y);
176   - }
  189 +
177 190  
178 191 std::string str() const
179 192 {
180 193 std::stringstream ss;
181   - ss << "(P=" << P.str() << ", N=" << N.str() << ", U=" << U.str() << ", Y=" << Y.str();
  194 + ss << "r = "<<R<<" (P=" << P.str() << ", N=" << N.str() << ", U=" << U.str() << ")";
182 195 return ss.str();
183 196 }
184 197  
... ...
stim/math/circle_dep.h 0 โ†’ 100644
  1 +#ifndef STIM_CIRCLE_H
  2 +#define STIM_CIRCLE_H
  3 +
  4 +#include <stim/cuda/cudatools/callable.h>
  5 +#include <stim/math/plane.h>
  6 +#include <stim/math/vector.h>
  7 +#include <stim/math/triangle.h>
  8 +#include <stim/math/constants.h>
  9 +#include <assert.h>
  10 +#include <algorithm>
  11 +#include <iostream>
  12 +
  13 +namespace stim{
  14 +
  15 +template <typename T>
  16 +class circle : plane<T>
  17 +{
  18 +
  19 +private:
  20 +
  21 + stim::vec3<T> Y;
  22 +
  23 + CUDA_CALLABLE void
  24 + init()
  25 + {
  26 + Y = U.cross(N).norm();
  27 + }
  28 +
  29 +public:
  30 + using stim::plane<T>::n;
  31 + using stim::plane<T>::P;
  32 + using stim::plane<T>::N;
  33 + using stim::plane<T>::U;
  34 + using stim::plane<T>::rotate;
  35 + using stim::plane<T>::setU;
  36 +
  37 + ///base constructor
  38 + ///@param th value of the angle of the starting point from 0 to 360.
  39 + CUDA_CALLABLE
  40 + circle() : plane<T>()
  41 + {
  42 + init();
  43 + }
  44 +
  45 + ///create a rectangle given a size and position in Z space.
  46 + ///@param size: size of the rectangle in ND space.
  47 + ///@param z_pos z coordinate of the rectangle.
  48 + CUDA_CALLABLE
  49 + circle(T size, T z_pos = (T)0) : plane<T>()
  50 + {
  51 + center(stim::vec3<T>(0,0,z_pos));
  52 + scale(size);
  53 + init();
  54 + }
  55 +
  56 + ///create a rectangle from a center point, normal
  57 + ///@param c: x,y,z location of the center.
  58 + ///@param n: x,y,z direction of the normal.
  59 + CUDA_CALLABLE
  60 + circle(vec3<T> c, vec3<T> n = vec3<T>(0,0,1)) : plane<T>()
  61 + {
  62 + center(c);
  63 + normal(n);
  64 + init();
  65 + }
  66 +
  67 + /*///create a rectangle from a center point, normal, and size
  68 + ///@param c: x,y,z location of the center.
  69 + ///@param s: size of the rectangle.
  70 + ///@param n: x,y,z direction of the normal.
  71 + CUDA_CALLABLE
  72 + circle(vec3<T> c, T s, vec3<T> n = vec3<T>(0,0,1)) : plane<T>()
  73 + {
  74 + init();
  75 + center(c);
  76 + rotate(n, U, Y);
  77 + scale(s);
  78 + }
  79 + */
  80 +
  81 + ///create a rectangle from a center point, normal, and size
  82 + ///@param c: x,y,z location of the center.
  83 + ///@param s: size of the rectangle.
  84 + ///@param n: x,y,z direction of the normal.
  85 + ///@param u: x,y,z direction for the zero vector (from where the rotation starts)
  86 + CUDA_CALLABLE
  87 + circle(vec3<T> c, T s, vec3<T> n = vec3<T>(0,0,1), vec3<T> u = vec3<T>(1, 0, 0)) : plane<T>()
  88 + {
  89 + init();
  90 + setU(u);
  91 +// U = u;
  92 + center(c);
  93 + normal(n);
  94 + scale(s);
  95 + }
  96 +
  97 + ///scales the circle by a certain factor
  98 + ///@param factor: the factor by which the dimensions of the shape are scaled.
  99 + CUDA_CALLABLE
  100 + void scale(T factor)
  101 + {
  102 + U *= factor;
  103 + Y *= factor;
  104 + }
  105 +
  106 + ///sets the normal for the cirlce
  107 + ///@param n: x,y,z direction of the normal.
  108 + CUDA_CALLABLE void
  109 + normal(vec3<T> n)
  110 + {
  111 + rotate(n, Y);
  112 + }
  113 +
  114 + ///sets the center of the circle.
  115 + ///@param n: x,y,z location of the center.
  116 + CUDA_CALLABLE void
  117 + center(vec3<T> p){
  118 + this->P = p;
  119 + }
  120 +
  121 + ///boolean comparison
  122 + bool
  123 + operator==(const circle<T> & rhs)
  124 + {
  125 + if(P == rhs.P && U == rhs.U && Y == rhs.Y)
  126 + return true;
  127 + else
  128 + return false;
  129 + }
  130 +
  131 + ///get the world space value given the planar coordinates a, b in [0, 1]
  132 + CUDA_CALLABLE stim::vec3<T> p(T a, T b)
  133 + {
  134 + stim::vec3<T> result;
  135 +
  136 + vec3<T> A = this->P - this->U * (T)0.5 - Y * (T)0.5;
  137 + result = A + this->U * a + Y * b;
  138 + return result;
  139 + }
  140 +
  141 + ///parenthesis operator returns the world space given rectangular coordinates a and b in [0 1]
  142 + CUDA_CALLABLE stim::vec3<T> operator()(T a, T b)
  143 + {
  144 + return p(a,b);
  145 + }
  146 +
  147 + ///returns a vector with the points on the initialized circle.
  148 + ///connecting the points results in a circle.
  149 + ///@param n: integer for the number of points representing the circle.
  150 + std::vector<stim::vec3<T> >
  151 + getPoints(int n)
  152 + {
  153 + std::vector<stim::vec3<T> > result;
  154 + stim::vec3<T> point;
  155 + T x,y;
  156 + float step = 360.0/(float) n;
  157 + for(float j = 0; j <= 360.0; j += step)
  158 + {
  159 + y = 0.5*cos(j*stim::TAU/360.0)+0.5;
  160 + x = 0.5*sin(j*stim::TAU/360.0)+0.5;
  161 + result.push_back(p(x,y));
  162 + }
  163 + return result;
  164 + }
  165 +
  166 + ///returns a vector with the points on the initialized circle.
  167 + ///connecting the points results in a circle.
  168 + ///@param n: integer for the number of points representing the circle.
  169 + CUDA_CALLABLE stim::vec3<T>
  170 + p(T theta)
  171 + {
  172 + T x,y;
  173 + y = 0.5*cos(theta*STIM_TAU/360.0)+0.5;
  174 + x = 0.5*sin(theta*STIM_TAU/360.0)+0.5;
  175 + return p(x,y);
  176 + }
  177 +
  178 + std::string str() const
  179 + {
  180 + std::stringstream ss;
  181 + ss << "(P=" << P.str() << ", N=" << N.str() << ", U=" << U.str() << ", Y=" << Y.str();
  182 + return ss.str();
  183 + }
  184 +
  185 +};
  186 +}
  187 +#endif
... ...
stim/visualization/cylinder.h
... ... @@ -3,56 +3,163 @@
3 3 #include <iostream>
4 4 #include <stim/math/circle.h>
5 5 #include <stim/biomodels/centerline.h>
  6 +#include <stim/visualization/obj.h>
6 7  
7   -/*
8   -
9   -*/
10 8  
11 9 namespace stim
12 10 {
13 11 template<typename T>
14   -class cylinder
15   - : public centerline<T>
16   -{
17   - private:
18   - stim::circle<T> s; //an arbitrary circle
19   - std::vector<stim::circle<T> > e; //an array of circles that store the centerline
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 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 163 stim::vec3<float> v1;
57 164 stim::vec3<float> v2;
58 165 e.resize(inP.size());
... ... @@ -246,13 +353,18 @@ class cylinder
246 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 361 ///Returns the number of points on the cylinder centerline
250 362  
251 363 unsigned int size(){
252 364 return N;
253 365 }
254 366  
255   -
  367 +
256 368 ///Returns a position vector at the given p-value (p value ranges from 0 to 1).
257 369 ///interpolates the position along the line.
258 370 ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1).
... ... @@ -266,22 +378,7 @@ class cylinder
266 378 T l = pvalue*L[L.size()-1];
267 379 int idx = findIdx(l);
268 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 383 ///Returns a position vector at the given length into the fiber (based on the pvalue).
287 384 ///Interpolates the radius along the line.
... ... @@ -321,10 +418,7 @@ class cylinder
321 418 T l = pvalue*L[L.size()-1];
322 419 int idx = findIdx(l);
323 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 423 ///Returns a radius at the given length into the fiber (based on the pvalue).
330 424 ///Interpolates the position along the line.
... ... @@ -506,7 +600,7 @@ class cylinder
506 600  
507 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
... ...