Commit 9c97e1269d19a12411c904106718e478b1324efd
1 parent
58ee2b21
added an axis-aligned bounding box class, as well as classes for rendering networks
Showing
8 changed files
with
348 additions
and
89 deletions
Show diff stats
stim/biomodels/network.h
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | #define STIM_NETWORK_H |
3 | 3 | |
4 | 4 | #include <stdlib.h> |
5 | -#include <assert.h> | |
5 | +#include <assert.h> | |
6 | 6 | #include <sstream> |
7 | 7 | #include <fstream> |
8 | 8 | #include <algorithm> |
... | ... | @@ -50,7 +50,7 @@ class network{ |
50 | 50 | |
51 | 51 | return e; //return the new edge |
52 | 52 | } |
53 | - | |
53 | + | |
54 | 54 | /// Output the edge information as a string |
55 | 55 | std::string str(){ |
56 | 56 | std::stringstream ss; |
... | ... | @@ -58,8 +58,8 @@ class network{ |
58 | 58 | return ss.str(); |
59 | 59 | } |
60 | 60 | |
61 | - }; | |
62 | - | |
61 | + }; | |
62 | + | |
63 | 63 | ///Node class that stores the physical position of the node as well as the edges it is connected to (edges that connect to it), As well as any additional data necessary. |
64 | 64 | class vertex : public stim::vec<T> |
65 | 65 | { |
... | ... | @@ -89,15 +89,15 @@ class network{ |
89 | 89 | |
90 | 90 | return ss.str(); |
91 | 91 | } |
92 | - | |
92 | + | |
93 | 93 | }; |
94 | 94 | |
95 | - private: | |
95 | +protected: | |
96 | 96 | |
97 | 97 | std::vector<edge> E; //list of edges |
98 | 98 | std::vector<vertex> V; //list of vertices. |
99 | - | |
100 | - public: | |
99 | + | |
100 | +public: | |
101 | 101 | |
102 | 102 | ///Returns the number of edges in the network. |
103 | 103 | unsigned int edges(){ |
... | ... | @@ -134,7 +134,7 @@ class network{ |
134 | 134 | |
135 | 135 | //get the first and last vertex IDs for the line |
136 | 136 | std::vector< unsigned > id; //create an array to store the centerline point IDs |
137 | - O.getLinei(l, id); //get the list of point IDs for the line | |
137 | + O.getLinei(l, id); //get the list of point IDs for the line | |
138 | 138 | i[0] = id.front(); //get the OBJ ID for the first element of the line |
139 | 139 | i[1] = id.back(); //get the OBJ ID for the last element of the line |
140 | 140 | |
... | ... | @@ -169,7 +169,7 @@ class network{ |
169 | 169 | V[it_idx].e[1].push_back(E.size()); //add the current edge as incoming |
170 | 170 | new_edge.v[1] = it_idx; |
171 | 171 | } |
172 | - | |
172 | + | |
173 | 173 | E.push_back(new_edge); //push the edge to the list |
174 | 174 | |
175 | 175 | } |
... | ... | @@ -193,6 +193,7 @@ class network{ |
193 | 193 | } |
194 | 194 | |
195 | 195 | /// This function resamples all fibers in a network given a desired minimum spacing |
196 | + /// @param spacing is the minimum distance between two points on the network | |
196 | 197 | stim::network<T> resample(T spacing){ |
197 | 198 | stim::network<T> n; //create a new network that will be an exact copy, with resampled fibers |
198 | 199 | n.V = V; //copy all vertices |
... | ... | @@ -209,7 +210,7 @@ class network{ |
209 | 210 | |
210 | 211 | |
211 | 212 | |
212 | - // total number of points on all fibers after resampling -- function used only on a resampled network | |
213 | + /// Calculate the total number of points on all edges. | |
213 | 214 | unsigned total_points(){ |
214 | 215 | unsigned n = 0; |
215 | 216 | for(unsigned e = 0; e < E.size(); e++) |
... | ... | @@ -227,28 +228,50 @@ class network{ |
227 | 228 | a[2] = b[2]; |
228 | 229 | } |
229 | 230 | |
231 | + /// Calculate the average magnitude across the entire network. | |
232 | + /// @param m is the magnitude value to use. The default is 0 (usually radius). | |
233 | + T average(unsigned m = 0){ | |
234 | + | |
235 | + T M, L; //allocate space for the total magnitude and length | |
236 | + M = L = 0; //initialize both the initial magnitude and length to zero | |
237 | + for(unsigned e = 0; e < E.size(); e++){ //for each edge in the network | |
238 | + M += E[e].integrate(m); //get the integrated magnitude | |
239 | + L += E[e].length(); //get the edge length | |
240 | + } | |
230 | 241 | |
231 | - /// This function compares two networks and returns a metric | |
232 | - float compare(stim::network<T> A, float sigma){ | |
242 | + return M / L; //return the average magnitude | |
243 | + } | |
244 | + | |
245 | + /// This function compares two networks and returns the percentage of the current network that is missing from A. | |
246 | + | |
247 | + /// @param A is the network to compare to - the field is generated for A | |
248 | + /// @param sigma is the user-defined tolerance value - smaller values provide a stricter comparison | |
249 | + stim::network<T> compare(stim::network<T> A, float sigma){ | |
250 | + | |
251 | + stim::network<T> R; //generate a network storing the result of the comparison | |
252 | + R = (*this); //initialize the result with the current network | |
253 | + | |
254 | + //generate a KD-tree for network A | |
233 | 255 | float metric = 0.0; // initialize metric to be returned after comparing the networks |
234 | 256 | ANNkd_tree* kdt; // initialize a pointer to a kd tree |
235 | 257 | double **c; // centerline (array of double pointers) - points on kdtree must be double |
236 | - unsigned int n_data = total_points(); // set the number of points | |
258 | + unsigned int n_data = A.total_points(); // set the number of points | |
237 | 259 | c = (double**) malloc(sizeof(double*) * n_data); // allocate the array pointer |
238 | 260 | for(unsigned int i = 0; i < n_data; i++) // allocate space for each point of 3 dimensions |
239 | 261 | c[i] = (double*) malloc(sizeof(double) * 3); |
240 | - //std::vector<stim::vec<T> > pointsVector = points_afterResampling(); //get vertices in the network after resampling | |
262 | + | |
241 | 263 | unsigned t = 0; |
242 | - for(unsigned e = 0; e < E.size(); e++){ //for each edge in the network | |
243 | - for(unsigned p = 0; p < E[e].size(); p++){ //for each point in the edge | |
264 | + for(unsigned e = 0; e < A.E.size(); e++){ //for each edge in the network | |
265 | + for(unsigned p = 0; p < A.E[e].size(); p++){ //for each point in the edge | |
244 | 266 | for(unsigned d = 0; d < 3; d++){ //for each coordinate |
245 | 267 | |
246 | - c[t][d] = E[e][p][d]; | |
268 | + c[t][d] = A.E[e][p][d]; | |
247 | 269 | } |
248 | 270 | t++; |
249 | 271 | } |
250 | 272 | } |
251 | 273 | |
274 | + //compare each point in the current network to the field produced by A | |
252 | 275 | ANNpointArray pts = (ANNpointArray)c; // create an array of data points of type double |
253 | 276 | kdt = new ANNkd_tree(pts, n_data, 3); // build a KD tree using the annpointarray |
254 | 277 | double eps = 0; // error bound |
... | ... | @@ -261,33 +284,24 @@ class network{ |
261 | 284 | float l; //stores the segment length |
262 | 285 | float L = 0; //stores the total network length |
263 | 286 | ANNpoint queryPt = annAllocPt(3); |
264 | - for(unsigned e = 0; e < A.E.size(); e++){ //for each edge in A | |
265 | - M = 0; //total metric value for the fiber | |
266 | - p0 = A.E[e][0]; //get the first point in the edge | |
267 | - stim2ann(queryPt, p0); | |
268 | - kdt->annkSearch( queryPt, 1, nnIdx, dists, eps); //find the distance between A and the current network | |
269 | - m0 = 1.0f - gaussianFunction(dists[0], sigma); //calculate the metric value based on the distance | |
287 | + for(unsigned e = 0; e < R.E.size(); e++){ //for each edge in A | |
288 | + R.E[e].add_mag(0); //add a new magnitude for the metric | |
270 | 289 | |
271 | - for(unsigned p = 1; p < A.E[e].size(); p++){ //for each point in the edge | |
290 | + for(unsigned p = 0; p < R.E[e].size(); p++){ //for each point in the edge | |
272 | 291 | |
273 | - p1 = A.E[e][p]; //get the next point in the edge | |
292 | + p1 = R.E[e][p]; //get the next point in the edge | |
274 | 293 | stim2ann(queryPt, p1); |
275 | 294 | kdt->annkSearch( queryPt, 1, nnIdx, dists, eps); //find the distance between A and the current network |
276 | 295 | m1 = 1.0f - gaussianFunction(dists[0], sigma); //calculate the metric value based on the distance |
296 | + R.E[e].set_mag(m1, p, 1); //set the error for the second point in the segment | |
277 | 297 | |
278 | - //average the metric and scale | |
279 | - l = (p1 - p0).len(); //calculate the length of the segment | |
280 | - L += l; //add the length of this segment to the total network length | |
281 | - M += (m0 + m1)/2 * l; //scale the metric based on segment length | |
282 | - | |
283 | - //swap points | |
284 | - p0 = p1; | |
285 | - m0 = m1; | |
286 | 298 | } |
287 | 299 | } |
288 | 300 | |
289 | - return M/L; | |
301 | + return R; //return the resulting network | |
290 | 302 | } |
303 | + | |
304 | + | |
291 | 305 | }; //end stim::network class |
292 | 306 | }; //end stim namespace |
293 | 307 | #endif | ... | ... |
stim/parser/arguments.h
... | ... | @@ -239,35 +239,29 @@ namespace stim{ |
239 | 239 | |
240 | 240 | /**The arglist class implements command line arguments. |
241 | 241 | Example: |
242 | - | |
243 | - 1) Create an arglist instance: | |
244 | - | |
245 | - stim::arglist args; | |
246 | 242 | |
247 | - 2) Test to see if ANSI output is supported (arguments will use color if it is). Generally, Windows consoles don't support ANSI. | |
243 | + 1) Create an arglist instance: | |
248 | 244 | |
249 | - #ifdef _WIN32 | |
250 | - args.set_ansi(false); | |
251 | - #endif | |
245 | + stim::arglist args; | |
252 | 246 | |
253 | - 3) Add arguments: | |
247 | + 2) Add arguments: | |
254 | 248 | |
255 | 249 | args.add("help", "prints this help"); |
256 | 250 | args.add("foo", "foo takes a single integer value", "", "[intval]"); |
257 | 251 | args.add("bar", "bar takes two floating point values", "", "[value1], [value2]"); |
258 | 252 | |
259 | - 4) Parse the command line: | |
253 | + 3) Parse the command line: | |
260 | 254 | |
261 | 255 | args.parse(argc, argv); |
262 | 256 | |
263 | - 5) You generally want to immediately test for help and output available arguments: | |
257 | + 4) You generally want to immediately test for help and output available arguments: | |
264 | 258 | |
265 | 259 | if(args["help"].is_set()) |
266 | 260 | std::cout<<args.str(); |
267 | 261 | |
268 | - | |
269 | 262 | |
270 | - 6) Retrieve values: | |
263 | + | |
264 | + 5) Retrieve values: | |
271 | 265 | |
272 | 266 | int foo; |
273 | 267 | float bar1, bar2; |
... | ... | @@ -300,7 +294,15 @@ namespace stim{ |
300 | 294 | |
301 | 295 | arglist(){ |
302 | 296 | col_width = 0; |
303 | - ansi = true; | |
297 | + | |
298 | + ansi = true; | |
299 | + | |
300 | + //set ansi to false by default if this is a Windows system | |
301 | + // (console doesn't support ANSI colors) | |
302 | + #ifdef _WIN32 | |
303 | + ansi=false; | |
304 | + #endif | |
305 | + | |
304 | 306 | } |
305 | 307 | |
306 | 308 | ///Sets ANSI support (default is on), which allows colored values in the help output. | ... | ... |
1 | +#ifndef STIM_AABB | |
2 | +#define STIM_AABB | |
3 | + | |
4 | +namespace stim{ | |
5 | + | |
6 | + | |
7 | +/// This class describes a structure for an axis-aligned bounding box | |
8 | +template< typename T > | |
9 | +class aabb{ | |
10 | + | |
11 | +public: | |
12 | + bool set; //has the bounding box been set to include any points? | |
13 | + stim::vec<T> A; //minimum point in the bounding box | |
14 | + stim::vec<T> B; //maximum point in the bounding box | |
15 | + | |
16 | + aabb(){ //constructor generates an empty bounding box | |
17 | + set = false; | |
18 | + } | |
19 | + | |
20 | + | |
21 | + /// Test if a point is inside of the bounding box and returns true if it is. | |
22 | + | |
23 | + /// @param p is the point to be tested | |
24 | + bool test(stim::vec<T> p){ | |
25 | + | |
26 | + for(unsigned d = 0; d < p.size(); p++){ //for each dimension | |
27 | + if(p[d] < A[d]) return false; //if the point is less than the minimum bound, return false | |
28 | + if(p[d] > B[d]) return false; //if the point is greater than the max bound, return false | |
29 | + } | |
30 | + return true; | |
31 | + } | |
32 | + | |
33 | + /// Expand the bounding box to include the specified point. | |
34 | + | |
35 | + /// @param p is the point to be included | |
36 | + void expand(stim::vec<T> p){ | |
37 | + | |
38 | + if(!set){ //if the bounding box is empty, fill it with the current point | |
39 | + A = B = p; | |
40 | + set = true; | |
41 | + } | |
42 | + | |
43 | + for(unsigned d = 0; d < p.size(); d++){ //for each dimension | |
44 | + if(p[d] < A[d]) A[d] = p[d]; //expand the bounding box as necessary | |
45 | + if(p[d] > B[d]) B[d] = p[d]; | |
46 | + } | |
47 | + } | |
48 | + | |
49 | + /// Return the center point of the bounding box as a stim::vec | |
50 | + stim::vec<T> center(){ | |
51 | + return (B + A) * 0.5; | |
52 | + } | |
53 | + | |
54 | + /// Return the size of the bounding box as a stim::vec | |
55 | + stim::vec<T> size(){ | |
56 | + return (B - A); | |
57 | + } | |
58 | + | |
59 | + /// Generate a string for the bounding box | |
60 | + std::string str(){ | |
61 | + std::stringstream ss; | |
62 | + ss<<A.str()<<"----->"<<B.str(); | |
63 | + return ss.str(); | |
64 | + } | |
65 | + | |
66 | + | |
67 | +}; //end stim::aabb | |
68 | + | |
69 | + | |
70 | +}; //end namespace stim | |
71 | + | |
72 | +#endif | |
0 | 73 | \ No newline at end of file | ... | ... |
stim/visualization/camera.h
... | ... | @@ -188,6 +188,13 @@ public: |
188 | 188 | focus = 1; |
189 | 189 | |
190 | 190 | } |
191 | + | |
192 | + /// Outputs the camera information as a string | |
193 | + std::string str(){ | |
194 | + std::stringstream ss; | |
195 | + ss<<p.str()<<"----->"<<(p + d * focus).str(); | |
196 | + return ss.str(); | |
197 | + } | |
191 | 198 | }; |
192 | 199 | |
193 | 200 | } | ... | ... |
stim/visualization/cylinder.h
... | ... | @@ -15,45 +15,38 @@ class cylinder |
15 | 15 | std::vector< stim::vec<T> > pos; //positions of the cylinder. |
16 | 16 | std::vector< stim::vec<T> > mags; //radii at each position |
17 | 17 | std::vector< T > L; //length of the cylinder at each position. |
18 | - | |
19 | - ///default init | |
18 | + | |
19 | + ///default init | |
20 | 20 | void |
21 | - init() | |
22 | - { | |
21 | + init(){ | |
23 | 22 | |
24 | 23 | } |
25 | 24 | |
26 | 25 | ///inits the cylinder from a list of points (inP) and radii (inM) |
27 | 26 | void |
28 | - init(std::vector<stim::vec<T> > inP, std::vector<stim::vec<T> > inM) | |
29 | - { | |
27 | + init(std::vector<stim::vec<T> > inP, std::vector<stim::vec<T> > inM){ | |
30 | 28 | pos = inP; |
31 | 29 | mags = inM; |
32 | 30 | |
33 | 31 | //calculate each L. |
34 | 32 | L.resize(pos.size()-1); |
35 | 33 | T temp = (T)0; |
36 | - for(int i = 0; i < L.size()-1; i++) | |
34 | + for(int i = 0; i < L.size(); i++) | |
37 | 35 | { |
38 | 36 | temp += (pos[i] - pos[i+1]).len(); |
39 | 37 | L[i] = temp; |
40 | 38 | } |
41 | 39 | } |
42 | - | |
40 | + | |
43 | 41 | ///returns the direction vector at point idx. |
44 | 42 | stim::vec<T> |
45 | - d(int idx) | |
46 | - { | |
43 | + d(int idx){ | |
47 | 44 | return (pos[idx] - pos[idx+1]).norm(); |
48 | - | |
49 | 45 | } |
50 | 46 | |
51 | - | |
52 | - | |
53 | 47 | ///returns the total length of the line at index j. |
54 | 48 | T |
55 | - getl(int j) | |
56 | - { | |
49 | + getl(int j){ | |
57 | 50 | for(int i = 0; i < j-1; ++i) |
58 | 51 | { |
59 | 52 | temp += (pos[i] - pos[i+1]).len(); |
... | ... | @@ -64,8 +57,7 @@ class cylinder |
64 | 57 | ///finds the index of the point closest to the length l on the lower bound. |
65 | 58 | ///binary search. |
66 | 59 | int |
67 | - findIdx(T l) | |
68 | - { | |
60 | + findIdx(T l){ | |
69 | 61 | int i = pos.size()/2; |
70 | 62 | while(i > 0 && i < pos.size()) |
71 | 63 | { |
... | ... | @@ -85,18 +77,29 @@ class cylinder |
85 | 77 | return i; |
86 | 78 | } |
87 | 79 | |
88 | - public: | |
89 | - ///default constructor | |
90 | - cylinder() | |
91 | - { | |
80 | + //initializes the length array given the current set of positions | |
81 | + void init_length(){ | |
82 | + vec<T> p0, p1; | |
83 | + p0 = pos[0]; //initialize the first point in the segment to the first point in the cylinder | |
84 | + T l; //allocate space for the segment length | |
85 | + for(unsigned p = 1; p < pos.size(); p++){ //for each point in the cylinder | |
86 | + p1 = pos[p]; //get the second point in the segment | |
87 | + l = (p1 - p0).len(); //calculate the length of the segment | |
88 | + | |
89 | + if(p == 1) L[0] = l; //set the length for the first segment | |
90 | + else L[p-1] = L[p-2] + l; //calculate and set the running length for each additional segment | |
91 | + } | |
92 | 92 | |
93 | 93 | } |
94 | 94 | |
95 | + public: | |
96 | + ///default constructor | |
97 | + cylinder(){} | |
98 | + | |
95 | 99 | ///constructor to create a cylinder from a set of points, radii, and the number of sides for the cylinder. |
96 | 100 | ///@param inP: Vector of stim vecs composing the points of the centerline. |
97 | 101 | ///@param inM: Vector of stim vecs composing the radii of the centerline. |
98 | - cylinder(std::vector<stim::vec<T> > inP, std::vector<stim::vec<T> > inM) | |
99 | - { | |
102 | + cylinder(std::vector<stim::vec<T> > inP, std::vector<stim::vec<T> > inM){ | |
100 | 103 | init(inP, inM); |
101 | 104 | } |
102 | 105 | |
... | ... | @@ -104,7 +107,11 @@ class cylinder |
104 | 107 | ///@param inP: Vector of stim vecs composing the points of the centerline |
105 | 108 | cylinder(std::vector< stim::vec<T> > inP){ |
106 | 109 | std::vector< stim::vec<T> > inM; //create an array of arbitrary magnitudes |
107 | - inM.resize(inP.size(), 0); //initialize the magnitude values to zero | |
110 | + | |
111 | + stim::vec<T> zero; | |
112 | + zero.push_back(0); | |
113 | + | |
114 | + inM.resize(inP.size(), zero); //initialize the magnitude values to zero | |
108 | 115 | init(inP, inM); |
109 | 116 | } |
110 | 117 | |
... | ... | @@ -120,8 +127,7 @@ class cylinder |
120 | 127 | ///interpolates the position along the line. |
121 | 128 | ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1). |
122 | 129 | stim::vec<T> |
123 | - p(T pvalue) | |
124 | - { | |
130 | + p(T pvalue){ | |
125 | 131 | if(pvalue < 0.0 || pvalue > 1.0) |
126 | 132 | return; |
127 | 133 | T l = pvalue*L[L.size()-1]; |
... | ... | @@ -134,8 +140,7 @@ class cylinder |
134 | 140 | ///@param l: the location of the in the cylinder. |
135 | 141 | ///@param idx: integer location of the point closest to l but prior to it. |
136 | 142 | stim::vec<T> |
137 | - p(T l, int idx) | |
138 | - { | |
143 | + p(T l, int idx){ | |
139 | 144 | return (pos[idx] + (pos[idx+1]-pos[idx])*((l-L[idx])/(L[idx+1]- L[idx]))); |
140 | 145 | } |
141 | 146 | |
... | ... | @@ -143,8 +148,7 @@ class cylinder |
143 | 148 | ///interpolates the radius along the line. |
144 | 149 | ///@param pvalue: the location of the in the cylinder, from 0 (beginning to 1). |
145 | 150 | T |
146 | - r(T pvalue) | |
147 | - { | |
151 | + r(T pvalue){ | |
148 | 152 | if(pvalue < 0.0 || pvalue > 1.0) |
149 | 153 | return; |
150 | 154 | T l = pvalue*L[L.size()-1]; |
... | ... | @@ -157,11 +161,33 @@ class cylinder |
157 | 161 | ///@param l: the location of the in the cylinder. |
158 | 162 | ///@param idx: integer location of the point closest to l but prior to it. |
159 | 163 | T |
160 | - r(T l, int idx) | |
161 | - { | |
164 | + r(T l, int idx){ | |
162 | 165 | return (mags[idx] + (mags[idx+1]-mags[idx])*((l-L[idx])/(L[idx+1]- L[idx]))); |
163 | 166 | } |
164 | 167 | |
168 | + /// Returns the magnitude at the given index | |
169 | + /// @param i is the index of the desired point | |
170 | + /// @param m is the index of the magnitude value | |
171 | + T ri(unsigned i, unsigned m = 0){ | |
172 | + return mags[i][m]; | |
173 | + } | |
174 | + | |
175 | + /// Adds a new magnitude value to all points | |
176 | + /// @param m is the starting value for the new magnitude | |
177 | + void add_mag(T m = 0){ | |
178 | + for(unsigned int p = 0; p < pos.size(); p++) | |
179 | + mags[p].push_back(m); | |
180 | + } | |
181 | + | |
182 | + /// Sets a magnitude value | |
183 | + /// @param val is the new value for the magnitude | |
184 | + /// @param p is the point index for the magnitude to be set | |
185 | + /// @param m is the index for the magnitude | |
186 | + void set_mag(T val, unsigned p, unsigned m = 0){ | |
187 | + mags[p][m] = val; | |
188 | + } | |
189 | + | |
190 | + | |
165 | 191 | |
166 | 192 | ///returns the position of the point with a given pvalue and theta on the surface |
167 | 193 | ///in x, y, z coordinates. Theta is in degrees from 0 to 360. |
... | ... | @@ -174,7 +200,7 @@ class cylinder |
174 | 200 | return; |
175 | 201 | T l = pvalue*L[L.size()-1]; |
176 | 202 | int idx = findIdx(l); |
177 | - stim::vec<T> ps = p(l, idx); | |
203 | + stim::vec<T> ps = p(l, idx); | |
178 | 204 | T m = r(l, idx); |
179 | 205 | stim::vec<T> dr = d(idx); |
180 | 206 | s = stim::circle<T>(ps, m, dr); |
... | ... | @@ -182,7 +208,7 @@ class cylinder |
182 | 208 | } |
183 | 209 | |
184 | 210 | ///returns a vector of points necessary to create a circle at every position in the fiber. |
185 | - ///@param sides: the number of sides of each circle. | |
211 | + ///@param sides: the number of sides of each circle. | |
186 | 212 | std::vector<std::vector<vec<T> > > |
187 | 213 | getPoints(int sides) |
188 | 214 | { |
... | ... | @@ -210,9 +236,7 @@ class cylinder |
210 | 236 | /// Allows a point on the centerline to be accessed using bracket notation |
211 | 237 | |
212 | 238 | vec<T> operator[](unsigned int i){ |
213 | - | |
214 | 239 | return pos[i]; |
215 | - | |
216 | 240 | } |
217 | 241 | |
218 | 242 | /// Returns the total length of the cylinder centerline |
... | ... | @@ -220,13 +244,51 @@ class cylinder |
220 | 244 | return L.back(); |
221 | 245 | } |
222 | 246 | |
247 | + /// Integrates a magnitude value along the cylinder. | |
248 | + /// @param m is the magnitude value to be integrated (this is usually the radius) | |
249 | + T integrate(unsigned m = 0){ | |
250 | + | |
251 | + T M = 0; //initialize the integral to zero | |
252 | + T m0, m1; //allocate space for both magnitudes in a single segment | |
253 | + | |
254 | + //vec<T> p0, p1; //allocate space for both points in a single segment | |
255 | + | |
256 | + m0 = mags[0][m]; //initialize the first point and magnitude to the first point in the cylinder | |
257 | + //p0 = pos[0]; | |
258 | + | |
259 | + T len = L[0]; //allocate space for the segment length | |
260 | + | |
261 | + //for every consecutive point in the cylinder | |
262 | + for(unsigned p = 1; p < pos.size(); p++){ | |
263 | + | |
264 | + //p1 = pos[p]; //get the position and magnitude for the next point | |
265 | + m1 = mags[p][m]; | |
266 | + | |
267 | + if(p > 1) len = (L[p-1] - L[p-2]); //calculate the segment length using the L array | |
268 | + | |
269 | + //add the average magnitude, weighted by the segment length | |
270 | + M += (m0 + m1)/2.0 * len; | |
271 | + | |
272 | + m0 = m1; //move to the next segment by shifting points | |
273 | + } | |
274 | + return M; //return the integral | |
275 | + } | |
276 | + | |
277 | + /// Averages a magnitude value across the cylinder | |
278 | + /// @param m is the magnitude value to be averaged (this is usually the radius) | |
279 | + T average(unsigned m = 0){ | |
280 | + | |
281 | + //return the average magnitude | |
282 | + return integrate(m) / L.back(); | |
283 | + } | |
284 | + | |
223 | 285 | /// Resamples the cylinder to provide a maximum distance of "spacing" between centerline points. All current |
224 | 286 | /// centerline points are guaranteed to exist in the new cylinder |
225 | 287 | /// @param spacing is the maximum spacing allowed between sample points |
226 | 288 | cylinder<T> resample(T spacing){ |
227 | 289 | |
228 | 290 | std::vector< vec<T> > result; |
229 | - | |
291 | + | |
230 | 292 | vec<T> p0 = pos[0]; //initialize p0 to the first point on the centerline |
231 | 293 | vec<T> p1; |
232 | 294 | unsigned N = size(); //number of points in the current centerline |
... | ... | @@ -238,7 +300,7 @@ class cylinder |
238 | 300 | vec<T> v = p1 - p0; //calculate the vector between these two points |
239 | 301 | T d = v.len(); //calculate the distance between these two points (length of the line segment) |
240 | 302 | |
241 | - unsigned nsteps = d / spacing; //calculate the number of steps to take along the segment to meet the spacing criteria | |
303 | + unsigned nsteps = d / spacing+1; //calculate the number of steps to take along the segment to meet the spacing criteria | |
242 | 304 | T stepsize = 1.0 / nsteps; //calculate the parametric step size between new centerline points |
243 | 305 | |
244 | 306 | //for each step along the line segment |
... | ... | @@ -251,11 +313,11 @@ class cylinder |
251 | 313 | } |
252 | 314 | |
253 | 315 | result.push_back(pos[size() - 1]); //push the last point in the centerline |
254 | - | |
316 | + | |
255 | 317 | return cylinder<T>(result); |
256 | 318 | |
257 | 319 | } |
258 | - | |
320 | + | |
259 | 321 | }; |
260 | 322 | |
261 | 323 | } | ... | ... |
1 | +#ifndef STIM_GL_AABB | |
2 | +#define STIM_GL_AABB | |
3 | + | |
4 | +#include "aabb.h" | |
5 | +#include "GL/gl.h" | |
6 | + | |
7 | +namespace stim{ | |
8 | + | |
9 | +template <typename T> | |
10 | +class gl_aabb : public aabb<T>{ | |
11 | + | |
12 | +public: | |
13 | + | |
14 | + //default constructor | |
15 | + gl_aabb() : stim::aabb<T>(){} | |
16 | + | |
17 | + //constructor takes an AABB | |
18 | + gl_aabb(stim::aabb<T> b) : stim::aabb<T>(b){} | |
19 | + | |
20 | + | |
21 | + /// Specifies vertices of the bounding box using CW winding. Use GL_LINE_LOOP for wireframe or GL_QUADS for a solid. | |
22 | + void glPointsCW(){ | |
23 | + | |
24 | + //front plane (in A[2]) | |
25 | + glVertex3f(A[0], A[1], A[2]); | |
26 | + glVertex3f(A[0], B[1], A[2]); | |
27 | + glVertex3f(B[0], B[1], A[2]); | |
28 | + glVertex3f(B[0], A[1], A[2]); | |
29 | + | |
30 | + //back plane (in B[2]) | |
31 | + glVertex3f(B[0], B[1], B[2]); | |
32 | + glVertex3f(A[0], B[1], B[2]); | |
33 | + glVertex3f(A[0], A[1], B[2]); | |
34 | + glVertex3f(B[0], A[1], B[2]); | |
35 | + } | |
36 | + | |
37 | + | |
38 | +}; //end stim::gl_aabb | |
39 | + | |
40 | + | |
41 | +}; //end namespace stim | |
42 | + | |
43 | +#endif | |
0 | 44 | \ No newline at end of file | ... | ... |
1 | +#ifndef STIM_GL_NETWORK | |
2 | +#define STIM_GL_NETWORK | |
3 | + | |
4 | +#include <stim/biomodels/network.h> | |
5 | +#include "aabb.h" | |
6 | + | |
7 | +namespace stim{ | |
8 | + | |
9 | +template <typename T> | |
10 | +class gl_network : public stim::network<T>{ | |
11 | + | |
12 | +protected: | |
13 | + using stim::network<T>::E; | |
14 | + using stim::network<T>::V; | |
15 | + | |
16 | +public: | |
17 | + | |
18 | + /// Default constructor | |
19 | + gl_network() : stim::network<T>(){} | |
20 | + | |
21 | + /// Constructor creates a gl_network from a stim::network | |
22 | + gl_network(stim::network<T> N) : stim::network<T>(N){} | |
23 | + | |
24 | + /// Fills the parameters with the minimum and maximum spatial positions in the network, | |
25 | + /// specifying a bounding box for the network geometry | |
26 | + aabb<T> boundingbox(){ | |
27 | + | |
28 | + aabb<T> bb; //create a bounding box | |
29 | + | |
30 | + //loop through every edge | |
31 | + for(unsigned e = 0; e < E.size(); e++){ | |
32 | + //loop through every point | |
33 | + for(unsigned p = 0; p < E[e].size(); p++) | |
34 | + bb.expand(E[e][p]); //expand the bounding box to include the point | |
35 | + } | |
36 | + | |
37 | + return bb; //return the bounding box | |
38 | + } | |
39 | + | |
40 | + /// Render the network centerline as a series of line strips. | |
41 | + void glCenterline(){ | |
42 | + | |
43 | + for(unsigned e = 0; e < E.size(); e++){ //for each edge in the network | |
44 | + glBegin(GL_LINE_STRIP); | |
45 | + for(unsigned p = 0; p < E[e].size(); p++){ //for each point on that edge | |
46 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | |
47 | + glTexCoord1f(E[e].ri(p)); | |
48 | + } | |
49 | + glEnd(); | |
50 | + } | |
51 | + | |
52 | + } | |
53 | + | |
54 | +}; //end stim::gl_network class | |
55 | +}; //end stim namespace | |
56 | + | |
57 | + | |
58 | + | |
59 | +#endif | |
0 | 60 | \ No newline at end of file | ... | ... |
stim/visualization/glnetwork.h renamed to stim/visualization/glnetwork-dep.h