Commit 1599ae65702af1249455c2e98c09ec5f247d1752
1 parent
4f63a044
add swc.h and functions for loading networks from swc files
Showing
4 changed files
with
331 additions
and
6 deletions
Show diff stats
stim/biomodels/centerline.h
@@ -194,8 +194,8 @@ public: | @@ -194,8 +194,8 @@ public: | ||
194 | 194 | ||
195 | ////resample a fiber in the network | 195 | ////resample a fiber in the network |
196 | stim::centerline<T> resample(T spacing) | 196 | stim::centerline<T> resample(T spacing) |
197 | - { | ||
198 | - std::cout<<"fiber::resample()"<<std::endl; | 197 | + { |
198 | + //std::cout<<"fiber::resample()"<<std::endl; | ||
199 | 199 | ||
200 | stim::vec3<T> v; //v-direction vector of the segment | 200 | stim::vec3<T> v; //v-direction vector of the segment |
201 | stim::vec3<T> p; //- intermediate point to be added | 201 | stim::vec3<T> p; //- intermediate point to be added |
stim/biomodels/network.h
@@ -10,6 +10,7 @@ | @@ -10,6 +10,7 @@ | ||
10 | #include <math.h> | 10 | #include <math.h> |
11 | #include <stim/math/vec3.h> | 11 | #include <stim/math/vec3.h> |
12 | #include <stim/visualization/obj.h> | 12 | #include <stim/visualization/obj.h> |
13 | +#include <stim/visualization/swc.h> | ||
13 | #include <stim/visualization/cylinder.h> | 14 | #include <stim/visualization/cylinder.h> |
14 | #include <stim/structures/kdtree.cuh> | 15 | #include <stim/structures/kdtree.cuh> |
15 | #include <stim/cuda/cudatools/timer.h> | 16 | #include <stim/cuda/cudatools/timer.h> |
@@ -142,7 +143,8 @@ class network{ | @@ -142,7 +143,8 @@ class network{ | ||
142 | protected: | 143 | protected: |
143 | 144 | ||
144 | std::vector<edge> E; //list of edges | 145 | std::vector<edge> E; //list of edges |
145 | - std::vector<vertex> V; //list of vertices. | 146 | + std::vector<vertex> V; //list of vertices. |
147 | + std::vector<int> NT; //stores a list of neuronal type for each point in the centerline (will set value only when centerline is built from swc file) | ||
146 | 148 | ||
147 | public: | 149 | public: |
148 | 150 | ||
@@ -388,6 +390,65 @@ public: | @@ -388,6 +390,65 @@ public: | ||
388 | } | 390 | } |
389 | } | 391 | } |
390 | 392 | ||
393 | + void load_swc(std::string filename) { | ||
394 | + stim::swc<T> S; // create swc variable | ||
395 | + S.load(filename); // load the node information | ||
396 | + S.create_tree(); // link those node according to their linking relationships as a tree | ||
397 | + | ||
398 | + NT.push_back(S.node[0].type); // set the neuronal_type value to the first vertex in the network | ||
399 | + std::vector<unsigned> id2vert; // this list stores the SWC vertex ID associated with each network vertex | ||
400 | + unsigned i[2]; // temporary, IDs associated with the first and last points | ||
401 | + for (unsigned int l = 1; l < S.numL(); l++) { // for every node starts from second one | ||
402 | + NT.push_back(S.node[l].type); | ||
403 | + stim::centerline<T> c3(2); // every fiber contains two vertices | ||
404 | + int id = S.node[l].parent_idx - 1; | ||
405 | + c3[0] = S.node[id].point; // store the begin vertex | ||
406 | + c3[1] = S.node[l].point; // store the end vertex | ||
407 | + | ||
408 | + c3.update(); // update the L information | ||
409 | + | ||
410 | + edge new_edge(c3); // contains two points | ||
411 | + | ||
412 | + //get the first and last vertex IDs for the line | ||
413 | + i[0] = S.node[id].idx; //get the SWC ID for the start point | ||
414 | + i[1] = S.node[l].idx; //get the SWC ID for the end point | ||
415 | + | ||
416 | + std::vector<unsigned>::iterator it; //create an iterator for searching the id2vert array | ||
417 | + unsigned it_idx; //create an integer for the id2vert entry index | ||
418 | + | ||
419 | + //find out if the nodes for this fiber have already been created | ||
420 | + it = find(id2vert.begin(), id2vert.end(), i[0]); //look for the first node | ||
421 | + if (it == id2vert.end()) { //if i[0] hasn't already been used | ||
422 | + vertex new_vertex = new_edge[0]; //create a new vertex, assign it a position | ||
423 | + new_vertex.e[0].push_back(E.size()); //add the current edge as outgoing | ||
424 | + new_edge.v[0] = V.size(); //add the new edge to the edge | ||
425 | + V.push_back(new_vertex); //add the new vertex to the vertex list | ||
426 | + id2vert.push_back(i[0]); //add the ID to the ID->vertex conversion list | ||
427 | + } | ||
428 | + else { //if the vertex already exists | ||
429 | + it_idx = std::distance(id2vert.begin(), it); | ||
430 | + V[it_idx].e[0].push_back(E.size()); //add the current edge as outgoing | ||
431 | + new_edge.v[0] = it_idx; | ||
432 | + } | ||
433 | + | ||
434 | + it = find(id2vert.begin(), id2vert.end(), i[1]); //look for the second ID | ||
435 | + if (it == id2vert.end()) { //if i[1] hasn't already been used | ||
436 | + vertex new_vertex = new_edge[1]; //create a new vertex, assign it a position | ||
437 | + new_vertex.e[1].push_back(E.size()); //add the current edge as incoming | ||
438 | + new_edge.v[1] = V.size(); //add the new vertex to the edge | ||
439 | + V.push_back(new_vertex); //add the new vertex to the vertex list | ||
440 | + id2vert.push_back(i[1]); //add the ID to the ID->vertex conversion list | ||
441 | + } | ||
442 | + else { //if the vertex already exists | ||
443 | + it_idx = std::distance(id2vert.begin(), it); | ||
444 | + V[it_idx].e[1].push_back(E.size()); //add the current edge as incoming | ||
445 | + new_edge.v[1] = it_idx; | ||
446 | + } | ||
447 | + | ||
448 | + E.push_back(new_edge); //push the edge to the list | ||
449 | + } | ||
450 | + } | ||
451 | + | ||
391 | /// Output the network as a string | 452 | /// Output the network as a string |
392 | std::string str(){ | 453 | std::string str(){ |
393 | 454 |
stim/visualization/gl_network.h
@@ -107,6 +107,88 @@ public: | @@ -107,6 +107,88 @@ public: | ||
107 | glCallList(dlist); // render the display list | 107 | glCallList(dlist); // render the display list |
108 | } | 108 | } |
109 | 109 | ||
110 | + /// render the network centerline from swc file as a series of strips in different colors based on the neuronal type | ||
111 | + /// glCenterline0_swc is for only one input | ||
112 | + void glCenterline0_swc() { | ||
113 | + if (!glIsList(dlist)) { // if dlist isn't a display list, create it | ||
114 | + dlist = glGenLists(1); // generate a display list | ||
115 | + glNewList(dlist, GL_COMPILE); // start a new display list | ||
116 | + for (unsigned e = 0; e < E.size(); e++) { | ||
117 | + int type = NT[e]; | ||
118 | + switch (type) { | ||
119 | + case 0: | ||
120 | + glColor3f(1.0f, 1.0f, 1.0f); // white for undefined | ||
121 | + glBegin(GL_LINE_STRIP); | ||
122 | + for (unsigned p = 0; p < E[e].size(); p++) { | ||
123 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | ||
124 | + } | ||
125 | + glEnd(); | ||
126 | + break; | ||
127 | + case 1: | ||
128 | + glColor3f(1.0f, 0.0f, 0.0f); // red for soma | ||
129 | + glBegin(GL_LINE_STRIP); | ||
130 | + for (unsigned p = 0; p < E[e].size(); p++) { | ||
131 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | ||
132 | + } | ||
133 | + glEnd(); | ||
134 | + break; | ||
135 | + case 2: | ||
136 | + glColor3f(1.0f, 0.5f, 0.0f); // orange for axon | ||
137 | + glBegin(GL_LINE_STRIP); | ||
138 | + for (unsigned p = 0; p < E[e].size(); p++) { | ||
139 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | ||
140 | + } | ||
141 | + glEnd(); | ||
142 | + break; | ||
143 | + case 3: | ||
144 | + glColor3f(1.0f, 1.0f, 0.0f); // yellow for undefined | ||
145 | + glBegin(GL_LINE_STRIP); | ||
146 | + for (unsigned p = 0; p < E[e].size(); p++) { | ||
147 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | ||
148 | + } | ||
149 | + glEnd(); | ||
150 | + break; | ||
151 | + case 4: | ||
152 | + glColor3f(0.0f, 1.0f, 0.0f); // green for undefined | ||
153 | + glBegin(GL_LINE_STRIP); | ||
154 | + for (unsigned p = 0; p < E[e].size(); p++) { | ||
155 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | ||
156 | + } | ||
157 | + glEnd(); | ||
158 | + break; | ||
159 | + case 5: | ||
160 | + glColor3f(0.0f, 1.0f, 1.0f); // verdant for undefined | ||
161 | + glBegin(GL_LINE_STRIP); | ||
162 | + for (unsigned p = 0; p < E[e].size(); p++) { | ||
163 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | ||
164 | + } | ||
165 | + glEnd(); | ||
166 | + break; | ||
167 | + case 6: | ||
168 | + glColor3f(0.0f, 0.0f, 1.0f); // blue for undefined | ||
169 | + glBegin(GL_LINE_STRIP); | ||
170 | + for (unsigned p = 0; p < E[e].size(); p++) { | ||
171 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | ||
172 | + } | ||
173 | + glEnd(); | ||
174 | + break; | ||
175 | + case 7: | ||
176 | + glColor3f(0.5f, 0.0f, 1.0f); // purple for undefined | ||
177 | + glBegin(GL_LINE_STRIP); | ||
178 | + for (unsigned p = 0; p < E[e].size(); p++) { | ||
179 | + glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); | ||
180 | + } | ||
181 | + glEnd(); | ||
182 | + break; | ||
183 | + } | ||
184 | + } | ||
185 | + glEndList(); //end the display list | ||
186 | + } | ||
187 | + glCallList(dlist); // render the display list | ||
188 | + } | ||
189 | + | ||
190 | + ///render the network centerline as a series of line strips | ||
191 | + ///colors is based on metric values | ||
110 | void glCenterline(){ | 192 | void glCenterline(){ |
111 | 193 | ||
112 | if(!glIsList(dlist)){ //if dlist isn't a display list, create it | 194 | if(!glIsList(dlist)){ //if dlist isn't a display list, create it |
@@ -117,7 +199,7 @@ public: | @@ -117,7 +199,7 @@ public: | ||
117 | glBegin(GL_LINE_STRIP); | 199 | glBegin(GL_LINE_STRIP); |
118 | for(unsigned p = 0; p < E[e].size(); p++){ //for each point on that edge | 200 | for(unsigned p = 0; p < E[e].size(); p++){ //for each point on that edge |
119 | glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); //set the vertex position based on the current point | 201 | glVertex3f(E[e][p][0], E[e][p][1], E[e][p][2]); //set the vertex position based on the current point |
120 | - glTexCoord1f(E[e].r(p)); //set the texture coordinate based on the specified magnitude index | 202 | + glTexCoord1f(E[e].r(p)); //set the texture coordinate based on the specified magnitude index |
121 | } | 203 | } |
122 | glEnd(); | 204 | glEnd(); |
123 | } | 205 | } |
@@ -140,7 +222,7 @@ public: | @@ -140,7 +222,7 @@ public: | ||
140 | for (unsigned p = 1; p < E[e].size(); p++) {// for each point on that edge | 222 | for (unsigned p = 1; p < E[e].size(); p++) {// for each point on that edge |
141 | stim::circle<T> C1 = E[e].circ(p - 1); | 223 | stim::circle<T> C1 = E[e].circ(p - 1); |
142 | stim::circle<T> C2 = E[e].circ(p); | 224 | stim::circle<T> C2 = E[e].circ(p); |
143 | - C1.set_R(10); // scale the circle to the same | 225 | + C1.set_R(10); // scale the circle to the same |
144 | C2.set_R(10); | 226 | C2.set_R(10); |
145 | std::vector< stim::vec3<T> >Cp1 = C1.points(20); | 227 | std::vector< stim::vec3<T> >Cp1 = C1.points(20); |
146 | std::vector< stim::vec3<T> >Cp2 = C2.points(20); | 228 | std::vector< stim::vec3<T> >Cp2 = C2.points(20); |
@@ -149,7 +231,7 @@ public: | @@ -149,7 +231,7 @@ public: | ||
149 | } | 231 | } |
150 | else { | 232 | else { |
151 | glColor3f(1.0f, 1.0f, 1.0f); // white color for the un-mapping edges | 233 | glColor3f(1.0f, 1.0f, 1.0f); // white color for the un-mapping edges |
152 | - for (unsigned p = 1; p < E[e].size(); p++) {// for each point on that edge | 234 | + for (unsigned p = 1; p < E[e].size(); p++) { // for each point on that edge |
153 | stim::circle<T> C1 = E[e].circ(p - 1); | 235 | stim::circle<T> C1 = E[e].circ(p - 1); |
154 | stim::circle<T> C2 = E[e].circ(p); | 236 | stim::circle<T> C2 = E[e].circ(p); |
155 | C1.set_R(10); // scale the circle to the same | 237 | C1.set_R(10); // scale the circle to the same |
1 | +#ifndef STIM_SWC_H | ||
2 | +#define STIM_SWC_H | ||
3 | + | ||
4 | +#include <vector> | ||
5 | +#include <fstream> | ||
6 | +#include <sstream> | ||
7 | +#include <iostream> | ||
8 | + | ||
9 | +//STIM includes | ||
10 | +#include <stim/math/vec3.h> | ||
11 | +#include <stim/parser/parser.h> | ||
12 | + | ||
13 | +namespace stim { | ||
14 | + namespace swc_tree { | ||
15 | + template <typename T> | ||
16 | + class swc_node { | ||
17 | + | ||
18 | + protected: | ||
19 | + enum neuronal_type { SWC_UNDEFINED, SWC_SOMA, SWC_AXON, SWC_DENDRITE, SWC_APICAL_DENDRITE, SWC_FORK_POINT, SWC_END_POINT, SWC_CUSTOM }; // eight types | ||
20 | + enum node_information { INTEGER_LABEL, NEURONAL_TYPE, X_COORDINATE, Y_COORDINATE, Z_COORDINATE, RADIUS, PARENT_LABEL }; | ||
21 | + | ||
22 | + public: | ||
23 | + int idx; // the index of current node start from 1(ambiguity) | ||
24 | + neuronal_type type; // the type of neuronal segmemt | ||
25 | + stim::vec3<T> point; // the point coordinates | ||
26 | + T radius; // the radius at current node | ||
27 | + int parent_idx; // parent idx of current node, -1 when it is origin(soma) | ||
28 | + int level; // tree level | ||
29 | + std::vector<int> son_idx; // son idx of current node | ||
30 | + | ||
31 | + swc_node() { // default constructor | ||
32 | + idx = -1; // set to default -1 | ||
33 | + parent_idx = -1; // set to origin -1 | ||
34 | + level = -1; // set to default -1 | ||
35 | + type = SWC_UNDEFINED; // set to undefined type | ||
36 | + radius = 0; // set to 0 | ||
37 | + } | ||
38 | + | ||
39 | + void get_node(std::string line) { // get information from the node point we got | ||
40 | + | ||
41 | + // create a vector to store the information of one node point | ||
42 | + std::vector<std::string> p = stim::parser::split(line, ' '); | ||
43 | + | ||
44 | + // for each information contained in the node point we got | ||
45 | + for (unsigned int i = 0; i < p.size(); i++) { | ||
46 | + std::stringstream ss(p[i]); // create a stringstream object for casting | ||
47 | + | ||
48 | + // store different information | ||
49 | + switch (i) { | ||
50 | + case INTEGER_LABEL: | ||
51 | + ss >> idx; // cast the stringstream to the correct numerical value | ||
52 | + break; | ||
53 | + case NEURONAL_TYPE: | ||
54 | + int tmp_type; | ||
55 | + ss >> tmp_type; // cast the stringstream to the correct numerical value | ||
56 | + type = (neuronal_type)tmp_type; | ||
57 | + break; | ||
58 | + case X_COORDINATE: | ||
59 | + T tmp_X; | ||
60 | + ss >> tmp_X; // cast the stringstream to the correct numerical value | ||
61 | + point[0] = tmp_X; // store the X_coordinate in vec3[0] | ||
62 | + break; | ||
63 | + case Y_COORDINATE: | ||
64 | + T tmp_Y; | ||
65 | + ss >> tmp_Y; // cast the stringstream to the correct numerical value | ||
66 | + point[1] = tmp_Y; // store the Y_coordinate in vec3[1] | ||
67 | + break; | ||
68 | + case Z_COORDINATE: | ||
69 | + T tmp_Z; | ||
70 | + ss >> tmp_Z; // cast the stringstream to the correct numerical value | ||
71 | + point[2] = tmp_Z; // store the Z_coordinate in vec3[2] | ||
72 | + break; | ||
73 | + case RADIUS: | ||
74 | + ss >> radius; // cast the stringstream to the correct numerical value | ||
75 | + break; | ||
76 | + case PARENT_LABEL: | ||
77 | + ss >> parent_idx; // cast the stringstream to the correct numerical value | ||
78 | + break; | ||
79 | + } | ||
80 | + } | ||
81 | + } | ||
82 | + }; | ||
83 | + } // end of namespace swc_tree | ||
84 | + | ||
85 | + template <typename T> | ||
86 | + class swc { | ||
87 | + public: | ||
88 | + std::vector< typename swc_tree::swc_node<T>> node; | ||
89 | + swc() {}; // default constructor | ||
90 | + | ||
91 | + // load the swc as tree nodes | ||
92 | + void load(std::string filename) { | ||
93 | + | ||
94 | + // load the file | ||
95 | + std::ifstream infile(filename.c_str()); | ||
96 | + | ||
97 | + // if the file is invalid, throw an error | ||
98 | + if (!infile) { | ||
99 | + std::cerr << "STUN::SWC Error loading file" << filename << std::endl; | ||
100 | + exit(-1); | ||
101 | + } | ||
102 | + | ||
103 | + std::string line; | ||
104 | + // skip comment | ||
105 | + while (getline(infile, line)) { | ||
106 | + if ('#' == line[0]) // if it is comment line | ||
107 | + continue; | ||
108 | + else | ||
109 | + break; | ||
110 | + } | ||
111 | + | ||
112 | + unsigned int l = 0; // number of nodes | ||
113 | + | ||
114 | + // get rid of the first/origin node | ||
115 | + swc_tree::swc_node<T> new_node; | ||
116 | + new_node.get_node(line); | ||
117 | + l++; | ||
118 | + node.push_back(new_node); // push back the first node | ||
119 | + | ||
120 | + getline(infile, line); // get a new line | ||
121 | + // keep reading the following node point information as string | ||
122 | + while (!line.empty()) { // test for the last empty line | ||
123 | + l++; // still remaining node to be read | ||
124 | + | ||
125 | + swc_tree::swc_node<T> next_node; | ||
126 | + next_node.get_node(line); | ||
127 | + node.push_back(next_node); | ||
128 | + | ||
129 | + getline(infile, line); // get a new line | ||
130 | + } | ||
131 | + } | ||
132 | + | ||
133 | + // read the head comment from swc file | ||
134 | + void read_comment(std::string filename) { | ||
135 | + | ||
136 | + // load the file | ||
137 | + std::ifstream infile(filename.c_str()); | ||
138 | + | ||
139 | + // if the file is invalid, throw an error | ||
140 | + if (!infile) { | ||
141 | + std::cerr << "STUN::SWC Error loading file" << filename << std::endl; | ||
142 | + exit(1); | ||
143 | + } | ||
144 | + | ||
145 | + std::string line; | ||
146 | + while (getline(infile, line)) { | ||
147 | + if ('#' == line[0]) { | ||
148 | + std::cout << line << std::endl; // print the comment line by line | ||
149 | + } | ||
150 | + else | ||
151 | + break; // break when reaches to node information | ||
152 | + } | ||
153 | + } | ||
154 | + | ||
155 | + // link those nodes to create a tree | ||
156 | + void create_tree() { | ||
157 | + unsigned n = node.size(); // get the total number of node point | ||
158 | + int cur_level = 0; | ||
159 | + | ||
160 | + // build the origin(soma) | ||
161 | + node[0].level = cur_level; | ||
162 | + | ||
163 | + // go through follow nodes | ||
164 | + for (unsigned i = 1; i < n; i++) { | ||
165 | + if (node[i].parent_idx != node[i - 1].parent_idx) | ||
166 | + cur_level = node[node[i].parent_idx - 1].level + 1; | ||
167 | + node[i].level = cur_level; | ||
168 | + int tmp_parent_idx = node[i].parent_idx - 1; // get the parent node loop idx of current node | ||
169 | + node[tmp_parent_idx].son_idx.push_back(i + 1); // son_idx stores the real idx = loop idx + 1 | ||
170 | + } | ||
171 | + } | ||
172 | + | ||
173 | + // return the number of point in swc | ||
174 | + unsigned int numL() { | ||
175 | + return node.size(); | ||
176 | + } | ||
177 | + | ||
178 | + | ||
179 | + }; | ||
180 | +} // end of namespace stim | ||
181 | + | ||
182 | +#endif | ||
0 | \ No newline at end of file | 183 | \ No newline at end of file |