Commit ce1a6f5e411a92726fc1887f604fc18df15ebe01

Authored by Jiaming Guo
1 parent b710cea4

add functions for incorporating nwt files and prepare for computing largest connected component

Showing 2 changed files with 416 additions and 286 deletions   Show diff stats
@@ -355,6 +355,24 @@ namespace stim { @@ -355,6 +355,24 @@ namespace stim {
355 return E[i].r(j); 355 return E[i].r(j);
356 } 356 }
357 357
  358 + // get the pendant vertices
  359 + std::vector<unsigned> get_pendant_vertex() {
  360 + std::vector<unsigned> result;
  361 + int count = 0;
  362 +
  363 + for (unsigned i = 0; i < V.size(); i++) { // for every vertex
  364 + for (unsigned j = 0; j < E.size(); j++) { // for every edge
  365 + if (i == E[j].v[0] || i == E[j].v[1]) // check whether current vertex terminates one edge
  366 + count++;
  367 + }
  368 + if (count == 1) // is pendant vertex
  369 + result.push_back(i);
  370 + count = 0; // reset count
  371 + }
  372 +
  373 + return result;
  374 + }
  375 +
358 // get the velocity of pendant vertex i 376 // get the velocity of pendant vertex i
359 T get_velocity(unsigned i) { 377 T get_velocity(unsigned i) {
360 378
@@ -378,6 +396,12 @@ namespace stim { @@ -378,6 +396,12 @@ namespace stim {
378 P[i] = value; 396 P[i] = value;
379 } 397 }
380 398
  399 + // extrct the largest connected component
  400 + void extract_lcc() {
  401 +
  402 +
  403 + }
  404 +
381 // solve the linear system to get stable flow state 405 // solve the linear system to get stable flow state
382 void solve_flow(T viscosity) { 406 void solve_flow(T viscosity) {
383 407
@@ -385,7 +409,7 @@ namespace stim { @@ -385,7 +409,7 @@ namespace stim {
385 clear(); 409 clear();
386 410
387 // get the pendant vertex indices 411 // get the pendant vertex indices
388 - pendant_vertex = get_boundary_vertex(); 412 + pendant_vertex = get_pendant_vertex();
389 413
390 // get bounding box 414 // get bounding box
391 bb = (*this).boundingbox(); 415 bb = (*this).boundingbox();
@@ -749,7 +773,7 @@ namespace stim { @@ -749,7 +773,7 @@ namespace stim {
749 } 773 }
750 774
751 // draw solid sphere at every vertex 775 // draw solid sphere at every vertex
752 - void glSolidSphere(T max_pressure, T scale, GLint subdivision) { 776 + void glSolidSphere(T max_pressure, GLint subdivision, T scale = 1.0f) {
753 777
754 // waste? 778 // waste?
755 for (unsigned i = 0; i < num_edge; i++) { 779 for (unsigned i = 0; i < num_edge; i++) {
@@ -808,7 +832,7 @@ namespace stim { @@ -808,7 +832,7 @@ namespace stim {
808 } 832 }
809 833
810 // draw edges as series of cylinders 834 // draw edges as series of cylinders
811 - void glSolidCylinder(unsigned index, std::vector<unsigned char> color, T scale, GLint subdivision) { 835 + void glSolidCylinder(unsigned index, std::vector<unsigned char> color, GLint subdivision, T scale = 1.0f) {
812 836
813 stim::vec3<float> tmp_d; 837 stim::vec3<float> tmp_d;
814 stim::vec3<float> center1; 838 stim::vec3<float> center1;
@@ -895,7 +919,7 @@ namespace stim { @@ -895,7 +919,7 @@ namespace stim {
895 } 919 }
896 920
897 // draw the flow direction as cone, the size of the cone depends on the length of that edge 921 // draw the flow direction as cone, the size of the cone depends on the length of that edge
898 - void glSolidCone(unsigned i, T scale, GLint subdivision) { 922 + void glSolidCone(unsigned i, GLint subdivision, T scale = 1.0f, T threshold = 0.01f) {
899 923
900 stim::vec3<T> tmp_d; // direction 924 stim::vec3<T> tmp_d; // direction
901 stim::vec3<T> center; // cone hat center 925 stim::vec3<T> center; // cone hat center
@@ -909,27 +933,28 @@ namespace stim { @@ -909,27 +933,28 @@ namespace stim {
909 933
910 unsigned index = E[i].size() / 2 - 1; 934 unsigned index = E[i].size() / 2 - 1;
911 tmp_d = E[i][index + 1] - E[i][index]; 935 tmp_d = E[i][index + 1] - E[i][index];
912 - h = tmp_d.len() / 3.0f; // get the height base by factor 3 936 + h = tmp_d.len() / 1.5f; // get the height base by factor 3
913 tmp_d = tmp_d.norm(); 937 tmp_d = tmp_d.norm();
914 center = (E[i][index + 1] + E[i][index]) / 2; 938 center = (E[i][index + 1] + E[i][index]) / 2;
915 tmp_c.rotate(tmp_d); 939 tmp_c.rotate(tmp_d);
916 radius = (E[i].r(index + 1) + E[i].r(index)) / 2 * scale; 940 radius = (E[i].r(index + 1) + E[i].r(index)) / 2 * scale;
917 radius = (h / sqrt(3) < radius) ? h / sqrt(3) : radius; // update radius 941 radius = (h / sqrt(3) < radius) ? h / sqrt(3) : radius; // update radius
918 - if (v[i] > 0) 942 + if (v[i] > threshold)
919 head = center + tmp_d * h; 943 head = center + tmp_d * h;
920 - else 944 + else if (v[i] < -threshold)
921 head = center - tmp_d * h; 945 head = center - tmp_d * h;
922 946
923 stim::circle<float> c(center, radius, tmp_d, tmp_c.U); 947 stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
924 cp = c.glpoints(subdivision); 948 cp = c.glpoints(subdivision);
925 949
926 - glBegin(GL_TRIANGLE_FAN);  
927 - glVertex3f(head[0], head[1], head[2]);  
928 - for (unsigned k = 0; k < cp.size(); k++)  
929 - glVertex3f(cp[k][0], cp[k][1], cp[k][2]);  
930 - glEnd();  
931 - glFlush();  
932 - 950 + if (v[i] > threshold || v[i] < -threshold) {
  951 + glBegin(GL_TRIANGLE_FAN);
  952 + glVertex3f(head[0], head[1], head[2]);
  953 + for (unsigned k = 0; k < cp.size(); k++)
  954 + glVertex3f(cp[k][0], cp[k][1], cp[k][2]);
  955 + glEnd();
  956 + glFlush();
  957 + }
933 // draw a cone for every edge to indicate 958 // draw a cone for every edge to indicate
934 //for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge 959 //for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge
935 // tmp_d = E[i][j + 1] - E[i][j]; 960 // tmp_d = E[i][j + 1] - E[i][j];
@@ -953,7 +978,7 @@ namespace stim { @@ -953,7 +978,7 @@ namespace stim {
953 //} 978 //}
954 //glFlush(); 979 //glFlush();
955 } 980 }
956 - void glSolidCone(GLint subdivision) { 981 + void glSolidCone(GLint subdivision, T scale = 1.0f, T threhold = 0.01f) {
957 982
958 stim::vec3<T> tmp_d; // direction 983 stim::vec3<T> tmp_d; // direction
959 stim::vec3<T> center; // cone hat center 984 stim::vec3<T> center; // cone hat center
@@ -973,21 +998,22 @@ namespace stim { @@ -973,21 +998,22 @@ namespace stim {
973 tmp_d = tmp_d.norm(); 998 tmp_d = tmp_d.norm();
974 center = (E[i][k2] + E[i][k1]) / 2; 999 center = (E[i][k2] + E[i][k1]) / 2;
975 tmp_c.rotate(tmp_d); 1000 tmp_c.rotate(tmp_d);
976 - radius = (E[i].r(k2) + E[i].r(k1)) / 2; 1001 + radius = (E[i].r(k2) + E[i].r(k1)) / 2 * scale;
977 radius = (h / sqrt(3) < radius) ? h / sqrt(3) : radius; // update radius by height base if necessary 1002 radius = (h / sqrt(3) < radius) ? h / sqrt(3) : radius; // update radius by height base if necessary
978 - if (v[i] > 0) // if flow flows from k1 to k2 1003 + if (v[i] > threhold) // if flow flows from k1 to k2
979 head = center + tmp_d * h; 1004 head = center + tmp_d * h;
980 - else 1005 + else if(v[i] < -threhold)
981 head = center - tmp_d * h; 1006 head = center - tmp_d * h;
982 stim::circle<float> c(center, radius, tmp_d, tmp_c.U); 1007 stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
983 cp = c.glpoints(subdivision); 1008 cp = c.glpoints(subdivision);
984 1009
985 - glBegin(GL_TRIANGLE_FAN);  
986 - glVertex3f(head[0], head[1], head[2]);  
987 - for (unsigned k = 0; k < cp.size(); k++)  
988 - glVertex3f(cp[k][0], cp[k][1], cp[k][2]);  
989 - glEnd();  
990 - 1010 + if (v[i] > threhold || v[i] < -threhold) {
  1011 + glBegin(GL_TRIANGLE_FAN);
  1012 + glVertex3f(head[0], head[1], head[2]);
  1013 + for (unsigned k = 0; k < cp.size(); k++)
  1014 + glVertex3f(cp[k][0], cp[k][1], cp[k][2]);
  1015 + glEnd();
  1016 + }
991 //for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge 1017 //for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge
992 // tmp_d = E[i][j + 1] - E[i][j]; 1018 // tmp_d = E[i][j + 1] - E[i][j];
993 // tmp_d = tmp_d.norm(); 1019 // tmp_d = tmp_d.norm();
@@ -1013,7 +1039,7 @@ namespace stim { @@ -1013,7 +1039,7 @@ namespace stim {
1013 } 1039 }
1014 1040
1015 // draw main feeder as solid cube 1041 // draw main feeder as solid cube
1016 - void glSolidCuboid(bool arrow, GLint subdivision, bool manufacture = false, T length = 40.0f, T height = 10.0f) { 1042 + void glSolidCuboid(GLint subdivision, bool manufacture = false, T length = 40.0f, T height = 10.0f) {
1017 1043
1018 T width; 1044 T width;
1019 stim::vec3<T> L = bb.A; // get the bottom left corner 1045 stim::vec3<T> L = bb.A; // get the bottom left corner
@@ -1073,51 +1099,10 @@ namespace stim { @@ -1073,51 +1099,10 @@ namespace stim {
1073 glVertex3f(main_feeder[i][0] + length / 2, main_feeder[i][1] - height / 2, main_feeder[i][2] + width / 2); 1099 glVertex3f(main_feeder[i][0] + length / 2, main_feeder[i][1] - height / 2, main_feeder[i][2] + width / 2);
1074 glEnd(); 1100 glEnd();
1075 } 1101 }
1076 -  
1077 - // render total flow direction  
1078 - if (arrow) {  
1079 - stim::vec3<T> d = main_feeder[1] - main_feeder[0];  
1080 - d = d.norm();  
1081 - stim::vec3<T> v1, v2, v3;  
1082 - stim::vec3<T> center = bb.center();  
1083 - stim::vec3<T> size = bb.size();  
1084 - stim::circle<float> tmp_c;  
1085 - tmp_c.rotate(d);  
1086 - std::vector<typename stim::vec3<float> > cp1(subdivision + 1);  
1087 - std::vector<typename stim::vec3<float> > cp2(subdivision + 1);  
1088 - v2 = center - stim::vec3<T>(0.0f, size[1] + 10.0f, 0.0f);  
1089 - v1 = v2 - stim::vec3<T>(30.0f, 0.0f, 0.0f);  
1090 - v3 = v2 + stim::vec3<T>(30.0f, 0.0f, 0.0f);  
1091 - v2 = v2 + stim::vec3<T>(20.0f, 0.0f, 0.0f);  
1092 -  
1093 - // draw the total flow direciton indicating arrow  
1094 - stim::circle<T> c1(v1, 5.0f / 2, d, tmp_c.U);  
1095 - cp1 = c1.glpoints(subdivision);  
1096 - stim::circle<T> c2(v2, 5.0f / 2, d, tmp_c.U);  
1097 - cp2 = c2.glpoints(subdivision);  
1098 -  
1099 - glColor3f(0.0f, 1.0f, 0.0f);  
1100 - glBegin(GL_QUAD_STRIP);  
1101 - for (unsigned k = 0; k < cp1.size(); k++) {  
1102 - glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]);  
1103 - glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);  
1104 - }  
1105 - glEnd();  
1106 -  
1107 - // render the cone part  
1108 - stim::circle<T> c3(v2, 5.0f, d, tmp_c.U);  
1109 - cp2 = c3.glpoints(subdivision);  
1110 - glBegin(GL_TRIANGLE_FAN);  
1111 - glVertex3f(v3[0], v3[1], v3[2]);  
1112 - for (unsigned k = 0; k < cp2.size(); k++)  
1113 - glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);  
1114 - glEnd();  
1115 - }  
1116 - glFlush();  
1117 } 1102 }
1118 1103
1119 // draw flow velocity field, glyph 1104 // draw flow velocity field, glyph
1120 - void glyph(std::vector<unsigned char> color, GLint subdivision, T r = 4.0f) { 1105 + void glyph(std::vector<unsigned char> color, GLint subdivision, T scale = 1.0f, bool frame = false, T r = 4.0f, T threshold = 0.01f) {
1121 1106
1122 // v1----v2-->v3 1107 // v1----v2-->v3
1123 T k = 4.0f; // quartering 1108 T k = 4.0f; // quartering
@@ -1127,51 +1112,124 @@ namespace stim { @@ -1127,51 +1112,124 @@ namespace stim {
1127 std::vector<typename stim::vec3<float> > cp1(subdivision + 1); 1112 std::vector<typename stim::vec3<float> > cp1(subdivision + 1);
1128 std::vector<typename stim::vec3<float> > cp2(subdivision + 1); 1113 std::vector<typename stim::vec3<float> > cp2(subdivision + 1);
1129 1114
  1115 + // rendering the arrows
1130 for (unsigned i = 0; i < num_edge; i++) { // for every edge 1116 for (unsigned i = 0; i < num_edge; i++) { // for every edge
1131 glColor3f((float)color[i * 3 + 0] / 255.0f, (float)color[i * 3 + 1] / 255.0f, (float)color[i * 3 + 2] / 255.0f); 1117 glColor3f((float)color[i * 3 + 0] / 255.0f, (float)color[i * 3 + 1] / 255.0f, (float)color[i * 3 + 2] / 255.0f);
1132 for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on that edge 1118 for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on that edge
1133 1119
1134 // consider the velocity valuence 1120 // consider the velocity valuence
1135 - if (v[i] > 0) { // positive, from start point to end point 1121 + if (v[i] > threshold) { // positive, from start point to end point
1136 v1 = E[i][j]; 1122 v1 = E[i][j];
1137 v3 = E[i][j + 1]; 1123 v3 = E[i][j + 1];
1138 } 1124 }
1139 - else { // negative, from end point to start point 1125 + else if (v[i] < -threshold) { // negative, from end point to start point
1140 v1 = E[i][j + 1]; 1126 v1 = E[i][j + 1];
1141 v3 = E[i][j]; 1127 v3 = E[i][j];
1142 } 1128 }
1143 - d = v3 - v1;  
1144 - // place the arrow in the middel of one edge  
1145 - v2 = v1 + (1.0f / k * 2.0f) * d; // looks like =->=  
1146 - v1 = v1 + (1.0f / k) * d;  
1147 - v3 = v3 - (1.0f / k) * d;  
1148 - d = d.norm();  
1149 - tmp_c.rotate(d);  
1150 -  
1151 - // render the cylinder part  
1152 - stim::circle<T> c1(v1, r / 2, d, tmp_c.U);  
1153 - cp1 = c1.glpoints(subdivision);  
1154 - stim::circle<T> c2(v2, r / 2, d, tmp_c.U);  
1155 - cp2 = c2.glpoints(subdivision);  
1156 -  
1157 - glBegin(GL_QUAD_STRIP);  
1158 - for (unsigned k = 0; k < cp1.size(); k++) {  
1159 - glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]);  
1160 - glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]); 1129 +
  1130 + if (v[i] > threshold || v[i] < -threshold) {
  1131 + d = v3 - v1;
  1132 + // place the arrow in the middel of one edge
  1133 + v2 = v1 + (1.0f / k * 2.0f) * d; // looks like =->=
  1134 + v1 = v1 + (1.0f / k) * d;
  1135 + v3 = v3 - (1.0f / k) * d;
  1136 + d = d.norm();
  1137 + tmp_c.rotate(d);
  1138 +
  1139 + // render the cylinder part
  1140 + stim::circle<T> c1(v1, r / 2 * scale, d, tmp_c.U);
  1141 + cp1 = c1.glpoints(subdivision);
  1142 + stim::circle<T> c2(v2, r / 2 * scale, d, tmp_c.U);
  1143 + cp2 = c2.glpoints(subdivision);
  1144 +
  1145 + glBegin(GL_QUAD_STRIP);
  1146 + for (unsigned k = 0; k < cp1.size(); k++) {
  1147 + glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]);
  1148 + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);
  1149 + }
  1150 + glEnd();
  1151 +
  1152 + // render the cone part
  1153 + stim::circle<T> c3(v2, r * scale, d, tmp_c.U);
  1154 + cp2 = c3.glpoints(subdivision);
  1155 + glBegin(GL_TRIANGLE_FAN);
  1156 + glVertex3f(v3[0], v3[1], v3[2]);
  1157 + for (unsigned k = 0; k < cp2.size(); k++)
  1158 + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);
  1159 + glEnd();
1161 } 1160 }
1162 - glEnd(); 1161 + }
  1162 + }
1163 1163
1164 - // render the cone part  
1165 - stim::circle<T> c3(v2, r, d, tmp_c.U);  
1166 - cp2 = c3.glpoints(subdivision);  
1167 - glBegin(GL_TRIANGLE_FAN);  
1168 - glVertex3f(v3[0], v3[1], v3[2]);  
1169 - for (unsigned k = 0; k < cp2.size(); k++)  
1170 - glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);  
1171 - glEnd(); 1164 + // rendering frames
  1165 + if (frame) {
  1166 + frame = false;
  1167 + stim::vec3<float> center1;
  1168 + stim::vec3<float> center2;
  1169 + stim::vec3<float> tmp_d; // flow direction
  1170 + float r1, r2;
  1171 +
  1172 + for (unsigned i = 0; i < num_edge; i++) {
  1173 + for (unsigned j = 0; j < E[i].size() - 1; j++) {
  1174 + center1 = E[i][j];
  1175 + center2 = E[i][j + 1];
  1176 +
  1177 + r1 = get_r(i, j) * scale;
  1178 + r2 = get_r(i, j + 1) * scale;
  1179 +
  1180 + subdivision = 5; // rough frames
  1181 +
  1182 + if (j == 0) {
  1183 + if (E[i].size() == 2)
  1184 + find_envelope(cp1, cp2, center1, center2, r1, r2, subdivision);
  1185 + else {
  1186 + tmp_d = center2 - center1;
  1187 + tmp_d = tmp_d.norm();
  1188 + tmp_c.rotate(tmp_d);
  1189 + stim::circle<float> c1(center1, r1, tmp_d, tmp_c.U);
  1190 + cp1 = c1.glpoints(subdivision);
  1191 + tmp_d = (E[i][j + 2] - center2) + (center2 - center1);
  1192 + tmp_d = tmp_d.norm();
  1193 + tmp_c.rotate(tmp_d);
  1194 + stim::circle<float> c2(center2, r2, tmp_d, tmp_c.U);
  1195 + cp2 = c2.glpoints(subdivision);
  1196 + }
  1197 + }
  1198 + else if (j == E[i].size() - 2) {
  1199 + tmp_d = (center2 - center1) + (center1 - E[i][j - 1]);
  1200 + tmp_d = tmp_d.norm();
  1201 + tmp_c.rotate(tmp_d);
  1202 + stim::circle<float> c1(center1, r1, tmp_d, tmp_c.U);
  1203 + cp1 = c1.glpoints(subdivision);
  1204 + tmp_d = center2 - center1;
  1205 + tmp_d = tmp_d.norm();
  1206 + tmp_c.rotate(tmp_d);
  1207 + stim::circle<float> c2(center2, r2, tmp_d, tmp_c.U);
  1208 + cp2 = c2.glpoints(subdivision);
  1209 + }
  1210 + else {
  1211 + tmp_d = (center2 - center1) + (center1 - E[i][j - 1]);
  1212 + tmp_d = tmp_d.norm();
  1213 + tmp_c.rotate(tmp_d);
  1214 + stim::circle<float> c1(center1, r1, tmp_d, tmp_c.U);
  1215 + cp1 = c1.glpoints(subdivision);
  1216 + tmp_d = (E[i][j + 2] - center2) + (center2 - center1);
  1217 + tmp_d = tmp_d.norm();
  1218 + tmp_c.rotate(tmp_d);
  1219 + stim::circle<float> c2(center2, r2, tmp_d, tmp_c.U);
  1220 + cp2 = c2.glpoints(subdivision);
  1221 + }
  1222 +
  1223 + glColor3f(140/255.0f, 81/255.0f, 10/255.0f);
  1224 + glBegin(GL_LINES);
  1225 + for (unsigned k = 0; k < cp1.size(); k++) {
  1226 + glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]);
  1227 + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);
  1228 + }
  1229 + glEnd();
  1230 + }
1172 } 1231 }
1173 } 1232 }
1174 - glFlush();  
1175 } 1233 }
1176 1234
1177 // display the total volume flow rate 1235 // display the total volume flow rate
@@ -1204,145 +1262,121 @@ namespace stim { @@ -1204,145 +1262,121 @@ namespace stim {
1204 } 1262 }
1205 1263
1206 // draw the bridge as lines or arrows 1264 // draw the bridge as lines or arrows
1207 - void line_bridge(bool &redisplay, bool arrow, T r = 4.0f) { 1265 + void line_bridge(bool &redisplay, T r = 4.0f) {
1208 1266
1209 - if (redisplay) 1267 + if (redisplay) { // check to see whether the display list needs to be updated
1210 glDeleteLists(dlist, 1); 1268 glDeleteLists(dlist, 1);
1211 - redisplay = false; 1269 + redisplay = false;
  1270 + }
1212 1271
1213 if (!glIsList(dlist)) { 1272 if (!glIsList(dlist)) {
1214 dlist = glGenLists(1); 1273 dlist = glGenLists(1);
1215 glNewList(dlist, GL_COMPILE); 1274 glNewList(dlist, GL_COMPILE);
1216 1275
1217 - // render flow direction arrows  
1218 - if (arrow) {  
1219 - // v1----v2-->v3  
1220 - T k = 4.0f; // quartering  
1221 - stim::vec3<T> v1, v2, v3; // three point  
1222 - stim::vec3<T> d; // direction vector  
1223 - stim::circle<float> tmp_c;  
1224 - std::vector<typename stim::vec3<float> > cp1(subdivision + 1);  
1225 - std::vector<typename stim::vec3<float> > cp2(subdivision + 1);  
1226 -  
1227 - // inlet, right-going  
1228 - for (unsigned i = 0; i < inlet.size(); i++) {  
1229 - if (inlet_feasibility[i])  
1230 - glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black  
1231 - else  
1232 - glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red  
1233 - for (unsigned j = 0; j < inlet[i].V.size() - 1; j++) {  
1234 - v1 = inlet[i].V[j];  
1235 - v3 = inlet[i].V[j + 1];  
1236 - d = v3 - v1;  
1237 - // place the arrow in the middel of one edge  
1238 - v2 = v1 + (1.0f / k * 2.0f) * d; // looks like =->=  
1239 - v1 = v1 + (1.0f / k) * d;  
1240 - v3 = v3 - (1.0f / k) * d;  
1241 - d = d.norm();  
1242 - tmp_c.rotate(d);  
1243 -  
1244 - // render the cylinder part  
1245 - stim::circle<T> c1(v1, r / 2, d, tmp_c.U);  
1246 - cp1 = c1.glpoints(subdivision);  
1247 - stim::circle<T> c2(v2, r / 2, d, tmp_c.U);  
1248 - cp2 = c2.glpoints(subdivision);  
1249 -  
1250 - glBegin(GL_QUAD_STRIP);  
1251 - for (unsigned k = 0; k < cp1.size(); k++) {  
1252 - glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]);  
1253 - glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);  
1254 - }  
1255 - glEnd();  
1256 -  
1257 - // render the cone part  
1258 - stim::circle<T> c3(v2, r, d, tmp_c.U);  
1259 - cp2 = c3.glpoints(subdivision);  
1260 - glBegin(GL_TRIANGLE_FAN);  
1261 - glVertex3f(v3[0], v3[1], v3[2]);  
1262 - for (unsigned k = 0; k < cp2.size(); k++)  
1263 - glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);  
1264 - glEnd();  
1265 - }  
1266 - }  
1267 -  
1268 - // outlet, right-going  
1269 - for (unsigned i = 0; i < outlet.size(); i++) {  
1270 - if (outlet_feasibility[i])  
1271 - glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black  
1272 - else  
1273 - glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red  
1274 - for (unsigned j = 0; j < outlet[i].V.size() - 1; j++) {  
1275 - v1 = outlet[i].V[j + 1];  
1276 - v3 = outlet[i].V[j];  
1277 - d = v3 - v1;  
1278 - // place the arrow in the middel of one edge  
1279 - v2 = v1 + (1.0f / k * 2.0f) * d; // looks like =->=  
1280 - v1 = v1 + (1.0f / k) * d;  
1281 - v3 = v3 - (1.0f / k) * d;  
1282 - d = d.norm();  
1283 - tmp_c.rotate(d);  
1284 -  
1285 - // render the cylinder part  
1286 - stim::circle<T> c1(v1, r / 2, d, tmp_c.U);  
1287 - cp1 = c1.glpoints(subdivision);  
1288 - stim::circle<T> c2(v2, r / 2, d, tmp_c.U);  
1289 - cp2 = c2.glpoints(subdivision);  
1290 -  
1291 - glBegin(GL_QUAD_STRIP);  
1292 - for (unsigned k = 0; k < cp1.size(); k++) {  
1293 - glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]);  
1294 - glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);  
1295 - }  
1296 - glEnd();  
1297 -  
1298 - // render the cone part  
1299 - stim::circle<T> c3(v2, r, d, tmp_c.U);  
1300 - cp2 = c3.glpoints(subdivision);  
1301 - glBegin(GL_TRIANGLE_FAN);  
1302 - glVertex3f(v3[0], v3[1], v3[2]);  
1303 - for (unsigned k = 0; k < cp2.size(); k++)  
1304 - glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);  
1305 - glEnd();  
1306 - }  
1307 - }  
1308 -  
1309 - // render transparent lines as indexing  
1310 - glEnable(GL_BLEND); // enable color blend  
1311 - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // set blend function  
1312 - glDisable(GL_DEPTH_TEST);  
1313 - glLineWidth(5);  
1314 - for (unsigned i = 0; i < inlet.size(); i++) {  
1315 - if (inlet_feasibility[i])  
1316 - glColor4f(0.0f, 0.0f, 0.0f, 0.2f); // feasible -> black  
1317 - else  
1318 - glColor4f(1.0f, 0.0f, 0.0f, 0.2f); // nonfeasible -> red  
1319 -  
1320 - glBegin(GL_LINE_STRIP);  
1321 - for (unsigned j = 0; j < inlet[i].V.size(); j++)  
1322 - glVertex3f(inlet[i].V[j][0], inlet[i].V[j][1], inlet[i].V[j][2]);  
1323 - glEnd();  
1324 - }  
1325 - for (unsigned i = 0; i < outlet.size(); i++) {  
1326 - if (outlet_feasibility[i])  
1327 - glColor4f(0.0f, 0.0f, 0.0f, 0.2f); // feasible -> black  
1328 - else  
1329 - glColor4f(1.0f, 0.0f, 0.0f, 0.2f); // nonfeasible -> red  
1330 - glBegin(GL_LINE_STRIP);  
1331 - for (unsigned j = 0; j < outlet[i].V.size(); j++)  
1332 - glVertex3f(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]);  
1333 - glEnd();  
1334 - }  
1335 - glDisable(GL_BLEND);  
1336 - glEnable(GL_DEPTH_TEST);  
1337 - }  
1338 - // render connection lines  
1339 - else { 1276 + //// render flow direction arrows
  1277 + //if (arrow) {
  1278 + // // v1----v2-->v3
  1279 + // T k = 4.0f; // quartering
  1280 + // stim::vec3<T> v1, v2, v3; // three point
  1281 + // stim::vec3<T> d; // direction vector
  1282 + // stim::circle<float> tmp_c;
  1283 + // std::vector<typename stim::vec3<float> > cp1(subdivision + 1);
  1284 + // std::vector<typename stim::vec3<float> > cp2(subdivision + 1);
  1285 +
  1286 + // // inlet, right-going
  1287 + // for (unsigned i = 0; i < inlet.size(); i++) {
  1288 + // if (inlet_feasibility[i])
  1289 + // glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black
  1290 + // else
  1291 + // glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red
  1292 + // for (unsigned j = 0; j < inlet[i].V.size() - 1; j++) {
  1293 + // v1 = inlet[i].V[j];
  1294 + // v3 = inlet[i].V[j + 1];
  1295 + // d = v3 - v1;
  1296 + // // place the arrow in the middel of one edge
  1297 + // v2 = v1 + (1.0f / k * 2.0f) * d; // looks like =->=
  1298 + // v1 = v1 + (1.0f / k) * d;
  1299 + // v3 = v3 - (1.0f / k) * d;
  1300 + // d = d.norm();
  1301 + // tmp_c.rotate(d);
  1302 +
  1303 + // // render the cylinder part
  1304 + // stim::circle<T> c1(v1, r / 2, d, tmp_c.U);
  1305 + // cp1 = c1.glpoints(subdivision);
  1306 + // stim::circle<T> c2(v2, r / 2, d, tmp_c.U);
  1307 + // cp2 = c2.glpoints(subdivision);
  1308 +
  1309 + // glBegin(GL_QUAD_STRIP);
  1310 + // for (unsigned k = 0; k < cp1.size(); k++) {
  1311 + // glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]);
  1312 + // glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);
  1313 + // }
  1314 + // glEnd();
  1315 +
  1316 + // // render the cone part
  1317 + // stim::circle<T> c3(v2, r, d, tmp_c.U);
  1318 + // cp2 = c3.glpoints(subdivision);
  1319 + // glBegin(GL_TRIANGLE_FAN);
  1320 + // glVertex3f(v3[0], v3[1], v3[2]);
  1321 + // for (unsigned k = 0; k < cp2.size(); k++)
  1322 + // glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);
  1323 + // glEnd();
  1324 + // }
  1325 + // }
  1326 +
  1327 + // // outlet, right-going
  1328 + // for (unsigned i = 0; i < outlet.size(); i++) {
  1329 + // if (outlet_feasibility[i])
  1330 + // glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black
  1331 + // else
  1332 + // glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red
  1333 + // for (unsigned j = 0; j < outlet[i].V.size() - 1; j++) {
  1334 + // v1 = outlet[i].V[j + 1];
  1335 + // v3 = outlet[i].V[j];
  1336 + // d = v3 - v1;
  1337 + // // place the arrow in the middel of one edge
  1338 + // v2 = v1 + (1.0f / k * 2.0f) * d; // looks like =->=
  1339 + // v1 = v1 + (1.0f / k) * d;
  1340 + // v3 = v3 - (1.0f / k) * d;
  1341 + // d = d.norm();
  1342 + // tmp_c.rotate(d);
  1343 +
  1344 + // // render the cylinder part
  1345 + // stim::circle<T> c1(v1, r / 2, d, tmp_c.U);
  1346 + // cp1 = c1.glpoints(subdivision);
  1347 + // stim::circle<T> c2(v2, r / 2, d, tmp_c.U);
  1348 + // cp2 = c2.glpoints(subdivision);
  1349 +
  1350 + // glBegin(GL_QUAD_STRIP);
  1351 + // for (unsigned k = 0; k < cp1.size(); k++) {
  1352 + // glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]);
  1353 + // glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);
  1354 + // }
  1355 + // glEnd();
  1356 +
  1357 + // // render the cone part
  1358 + // stim::circle<T> c3(v2, r, d, tmp_c.U);
  1359 + // cp2 = c3.glpoints(subdivision);
  1360 + // glBegin(GL_TRIANGLE_FAN);
  1361 + // glVertex3f(v3[0], v3[1], v3[2]);
  1362 + // for (unsigned k = 0; k < cp2.size(); k++)
  1363 + // glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]);
  1364 + // glEnd();
  1365 + // }
  1366 + // }
  1367 +
  1368 + // // render transparent lines as indexing
  1369 + // glEnable(GL_BLEND); // enable color blend
  1370 + // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // set blend function
  1371 + // glDisable(GL_DEPTH_TEST);
1340 glLineWidth(5); 1372 glLineWidth(5);
1341 for (unsigned i = 0; i < inlet.size(); i++) { 1373 for (unsigned i = 0; i < inlet.size(); i++) {
1342 if (inlet_feasibility[i]) 1374 if (inlet_feasibility[i])
1343 - glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black 1375 + glColor3f(0.0f, 0.0f, 0.0f);
  1376 + // glColor4f(0.0f, 0.0f, 0.0f, 0.2f); // feasible -> black
1344 else 1377 else
1345 - glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red 1378 + glColor3f(1.0f, 0.0f, 0.0f);
  1379 + // glColor4f(1.0f, 0.0f, 0.0f, 0.2f); // nonfeasible -> red
1346 1380
1347 glBegin(GL_LINE_STRIP); 1381 glBegin(GL_LINE_STRIP);
1348 for (unsigned j = 0; j < inlet[i].V.size(); j++) 1382 for (unsigned j = 0; j < inlet[i].V.size(); j++)
@@ -1351,23 +1385,31 @@ namespace stim { @@ -1351,23 +1385,31 @@ namespace stim {
1351 } 1385 }
1352 for (unsigned i = 0; i < outlet.size(); i++) { 1386 for (unsigned i = 0; i < outlet.size(); i++) {
1353 if (outlet_feasibility[i]) 1387 if (outlet_feasibility[i])
1354 - glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black 1388 + glColor3f(0.0f, 0.0f, 0.0f);
  1389 + // glColor4f(0.0f, 0.0f, 0.0f, 0.2f); // feasible -> black
1355 else 1390 else
1356 - glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red 1391 + glColor3f(1.0f, 0.0f, 0.0f);
  1392 + // glColor4f(1.0f, 0.0f, 0.0f, 0.2f); // nonfeasible -> red
1357 glBegin(GL_LINE_STRIP); 1393 glBegin(GL_LINE_STRIP);
1358 for (unsigned j = 0; j < outlet[i].V.size(); j++) 1394 for (unsigned j = 0; j < outlet[i].V.size(); j++)
1359 glVertex3f(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]); 1395 glVertex3f(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]);
1360 glEnd(); 1396 glEnd();
1361 } 1397 }
1362 - }  
1363 - glFlush(); 1398 + // glDisable(GL_BLEND);
  1399 + // glEnable(GL_DEPTH_TEST);
  1400 + //}
1364 glEndList(); 1401 glEndList();
1365 } 1402 }
1366 glCallList(dlist); 1403 glCallList(dlist);
1367 } 1404 }
1368 1405
1369 // draw the bridge as tubes 1406 // draw the bridge as tubes
1370 - void tube_bridge(T subdivision, T radius = 5.0f) { 1407 + void tube_bridge(bool &redisplay, T subdivision, T scale = 1.0f, T radius = 5.0f) {
  1408 +
  1409 + if (redisplay) {
  1410 + glDeleteLists(dlist + 1, 1);
  1411 + redisplay = false;
  1412 + }
1371 1413
1372 if (!glIsList(dlist + 1)) { 1414 if (!glIsList(dlist + 1)) {
1373 glNewList(dlist + 1, GL_COMPILE); 1415 glNewList(dlist + 1, GL_COMPILE);
@@ -1383,7 +1425,7 @@ namespace stim { @@ -1383,7 +1425,7 @@ namespace stim {
1383 for (unsigned j = 1; j < inlet[i].V.size() - 1; j++) { 1425 for (unsigned j = 1; j < inlet[i].V.size() - 1; j++) {
1384 glPushMatrix(); 1426 glPushMatrix();
1385 glTranslatef(inlet[i].V[j][0], inlet[i].V[j][1], inlet[i].V[j][2]); 1427 glTranslatef(inlet[i].V[j][0], inlet[i].V[j][1], inlet[i].V[j][2]);
1386 - glutSolidSphere(radius, subdivision, subdivision); 1428 + glutSolidSphere(radius * scale, subdivision, subdivision);
1387 glPopMatrix(); 1429 glPopMatrix();
1388 } 1430 }
1389 // render edge as cylinder 1431 // render edge as cylinder
@@ -1391,8 +1433,8 @@ namespace stim { @@ -1391,8 +1433,8 @@ namespace stim {
1391 dir = inlet[i].V[j] - inlet[i].V[j + 1]; 1433 dir = inlet[i].V[j] - inlet[i].V[j + 1];
1392 dir = dir.norm(); 1434 dir = dir.norm();
1393 unit_c.rotate(dir); 1435 unit_c.rotate(dir);
1394 - stim::circle<T> c1(inlet[i].V[j], inlet[i].r, dir, unit_c.U);  
1395 - stim::circle<T> c2(inlet[i].V[j + 1], inlet[i].r, dir, unit_c.U); 1436 + stim::circle<T> c1(inlet[i].V[j], inlet[i].r * scale, dir, unit_c.U);
  1437 + stim::circle<T> c2(inlet[i].V[j + 1], inlet[i].r * scale, dir, unit_c.U);
1396 cp1 = c1.glpoints(subdivision); 1438 cp1 = c1.glpoints(subdivision);
1397 cp2 = c2.glpoints(subdivision); 1439 cp2 = c2.glpoints(subdivision);
1398 1440
@@ -1410,7 +1452,7 @@ namespace stim { @@ -1410,7 +1452,7 @@ namespace stim {
1410 for (unsigned j = 1; j < outlet[i].V.size() - 1; j++) { 1452 for (unsigned j = 1; j < outlet[i].V.size() - 1; j++) {
1411 glPushMatrix(); 1453 glPushMatrix();
1412 glTranslatef(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]); 1454 glTranslatef(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]);
1413 - glutSolidSphere(radius, subdivision, subdivision); 1455 + glutSolidSphere(radius * scale, subdivision, subdivision);
1414 glPopMatrix(); 1456 glPopMatrix();
1415 } 1457 }
1416 // render edge as cylinder 1458 // render edge as cylinder
@@ -1418,8 +1460,8 @@ namespace stim { @@ -1418,8 +1460,8 @@ namespace stim {
1418 dir = outlet[i].V[j] - outlet[i].V[j + 1]; 1460 dir = outlet[i].V[j] - outlet[i].V[j + 1];
1419 dir = dir.norm(); 1461 dir = dir.norm();
1420 unit_c.rotate(dir); 1462 unit_c.rotate(dir);
1421 - stim::circle<T> c1(outlet[i].V[j], outlet[i].r, dir, unit_c.U);  
1422 - stim::circle<T> c2(outlet[i].V[j + 1], outlet[i].r, dir, unit_c.U); 1463 + stim::circle<T> c1(outlet[i].V[j], outlet[i].r * scale, dir, unit_c.U);
  1464 + stim::circle<T> c2(outlet[i].V[j + 1], outlet[i].r * scale, dir, unit_c.U);
1423 cp1 = c1.glpoints(subdivision); 1465 cp1 = c1.glpoints(subdivision);
1424 cp2 = c2.glpoints(subdivision); 1466 cp2 = c2.glpoints(subdivision);
1425 1467
@@ -1489,7 +1531,7 @@ namespace stim { @@ -1489,7 +1531,7 @@ namespace stim {
1489 } 1531 }
1490 1532
1491 // mark the vertex 1533 // mark the vertex
1492 - void mark_vertex(T scale) { 1534 + void mark_vertex(T scale = 1.0f) {
1493 1535
1494 glColor3f(0.0f, 0.0f, 0.0f); 1536 glColor3f(0.0f, 0.0f, 0.0f);
1495 for (unsigned i = 0; i < num_vertex; i++) { 1537 for (unsigned i = 0; i < num_vertex; i++) {
@@ -1500,6 +1542,18 @@ namespace stim { @@ -1500,6 +1542,18 @@ namespace stim {
1500 } 1542 }
1501 } 1543 }
1502 1544
  1545 + // mark the edge
  1546 + void mark_edge() {
  1547 +
  1548 + glColor3f(0.0f, 1.0f, 0.0f);
  1549 + for (unsigned i = 0; i < num_edge; i++) {
  1550 + glRasterPos3f((V[E[i].v[0]] + V[E[i].v[1]])[0]/2, (V[E[i].v[0]] + V[E[i].v[1]])[1] / 2, (V[E[i].v[0]] + V[E[i].v[1]])[2] / 2);
  1551 + std::stringstream ss;
  1552 + ss << i;
  1553 + glutBitmapString(GLUT_BITMAP_HELVETICA_18, (const unsigned char*)(ss.str().c_str()));
  1554 + }
  1555 + }
  1556 +
1503 // find the nearest vertex of current click position 1557 // find the nearest vertex of current click position
1504 // return true and a value if found 1558 // return true and a value if found
1505 inline bool epsilon_vertex(T x, T y, T z, T eps, T scale, unsigned& v) { 1559 inline bool epsilon_vertex(T x, T y, T z, T eps, T scale, unsigned& v) {
@@ -2381,7 +2435,7 @@ namespace stim { @@ -2381,7 +2435,7 @@ namespace stim {
2381 for (unsigned j = 0; j < num; j++) { 2435 for (unsigned j = 0; j < num; j++) {
2382 if (i != j) { 2436 if (i != j) {
2383 if (inlet[i].V[0][1] == inlet[j].V[0][1]) { 2437 if (inlet[i].V[0][1] == inlet[j].V[0][1]) {
2384 - if ((inlet[i].V[1][0] >= inlet[j].V[1][0]) && (fabs(inlet[i].V[1][1]) >= fabs(inlet[j].V[1][1])) && (((inlet[i].V[1][1] - main_feeder[0][1]) * (inlet[j].V[1][1] - main_feeder[0][1])) > 0 ? 1 : 0)) { 2438 + if ((inlet[i].V[1][0] >= inlet[j].V[1][0]) && (fabs(inlet[i].V[1][1]) >= fabs(inlet[j].V[1][1])) && (((inlet[i].V[1][1] - main_feeder[0][1]) * (inlet[j].V[1][1] - main_feeder[0][1])) > 0 ? 1 : 0) && inlet[i].V[1][2] == inlet[j].V[1][2]) {
2385 inlet_feasibility[i] = false; 2439 inlet_feasibility[i] = false;
2386 break; 2440 break;
2387 } 2441 }
@@ -2398,7 +2452,7 @@ namespace stim { @@ -2398,7 +2452,7 @@ namespace stim {
2398 for (unsigned j = 0; j < num; j++) { 2452 for (unsigned j = 0; j < num; j++) {
2399 if (i != j) { 2453 if (i != j) {
2400 if (outlet[i].V[0][2] == outlet[j].V[0][2]) { 2454 if (outlet[i].V[0][2] == outlet[j].V[0][2]) {
2401 - if ((outlet[i].V[1][0] <= outlet[j].V[1][0]) && (fabs(outlet[i].V[1][1]) >= fabs(outlet[j].V[1][1])) && (((outlet[i].V[1][1] - main_feeder[1][1]) * (outlet[j].V[1][1] - main_feeder[1][1])) > 0 ? 1 : 0)) { 2455 + if ((outlet[i].V[1][0] <= outlet[j].V[1][0]) && (fabs(outlet[i].V[1][1]) >= fabs(outlet[j].V[1][1])) && (((outlet[i].V[1][1] - main_feeder[1][1]) * (outlet[j].V[1][1] - main_feeder[1][1])) > 0 ? 1 : 0) && outlet[i].V[1][2] == outlet[j].V[1][2]) {
2402 outlet_feasibility[i] = false; 2456 outlet_feasibility[i] = false;
2403 break; 2457 break;
2404 } 2458 }
@@ -2661,6 +2715,11 @@ namespace stim { @@ -2661,6 +2715,11 @@ namespace stim {
2661 top = A[i].c[1]; 2715 top = A[i].c[1];
2662 if (A[i].c[1] < bottom) 2716 if (A[i].c[1] < bottom)
2663 bottom = A[i].c[1]; 2717 bottom = A[i].c[1];
  2718 + // extend the network boundingbox if the additional connections are outside
  2719 + if (A[i].c[2] > bb.B[2])
  2720 + bb.B[2] = A[i].c[2];
  2721 + if (A[i].c[2] < bb.A[2])
  2722 + bb.A[2] = A[i].c[2];
2664 if (A[i].r > max_radius) 2723 if (A[i].r > max_radius)
2665 max_radius = A[i].r; 2724 max_radius = A[i].r;
2666 } 2725 }
@@ -49,7 +49,7 @@ int mods; // special keyboard input @@ -49,7 +49,7 @@ int mods; // special keyboard input
49 std::vector<unsigned char> color; // velocity color map 49 std::vector<unsigned char> color; // velocity color map
50 std::vector<int> velocity_bar; // velocity bar 50 std::vector<int> velocity_bar; // velocity bar
51 float length = 40.0f; // cuboid length 51 float length = 40.0f; // cuboid length
52 -float scale = 1.0f; // render scale factor 52 +float scale = 1.0f; // scale factor
53 bool image_stack = false; // flag indicates an image stack been loaded 53 bool image_stack = false; // flag indicates an image stack been loaded
54 stim::image_stack<unsigned char, float> S; // image stack 54 stim::image_stack<unsigned char, float> S; // image stack
55 float binary_threshold = 128; // threshold for binary transformation 55 float binary_threshold = 128; // threshold for binary transformation
@@ -57,6 +57,8 @@ float in = 0.0f; // total input volume flow rate @@ -57,6 +57,8 @@ float in = 0.0f; // total input volume flow rate
57 float out = 0.0f; 57 float out = 0.0f;
58 float Rt = 0.0f; // total resistance 58 float Rt = 0.0f; // total resistance
59 float Qn = 0.0f; // required input total volume flow rate 59 float Qn = 0.0f; // required input total volume flow rate
  60 +GLint dlist; // simulation display list
  61 +bool undo = false; // delete display list
60 62
61 // hard-coded parameters 63 // hard-coded parameters
62 float camera_factor = 1.2f; // start point of the camera as a function of X and Y size 64 float camera_factor = 1.2f; // start point of the camera as a function of X and Y size
@@ -85,7 +87,8 @@ bool simulation = false; // flag indicates simulation mode @@ -85,7 +87,8 @@ bool simulation = false; // flag indicates simulation mode
85 bool color_bound = false; // flag indicates velocity color map bound 87 bool color_bound = false; // flag indicates velocity color map bound
86 bool to_select_pressure = false; // flag indicates having selected a vertex to modify pressure 88 bool to_select_pressure = false; // flag indicates having selected a vertex to modify pressure
87 bool mark_index = true; // flag indicates marking the index near the vertex 89 bool mark_index = true; // flag indicates marking the index near the vertex
88 -bool flow_direction = false; // flag indicates rendering glyph for flow velocity field 90 +bool glyph_mode = false; // flag indicates rendering glyph for flow velocity field
  91 +bool frame_mode = false; // flag indicates rendering filament framing structrues
89 unsigned pressure_index; // the index of vertex that is clicked 92 unsigned pressure_index; // the index of vertex that is clicked
90 unsigned direction_index = -1; // the index of edge that is pointed at 93 unsigned direction_index = -1; // the index of edge that is pointed at
91 unsigned index_index = -1; // the index of the vertex 94 unsigned index_index = -1; // the index of the vertex
@@ -99,6 +102,7 @@ bool picked_connection = false; // flag indicates picked one connection @@ -99,6 +102,7 @@ bool picked_connection = false; // flag indicates picked one connection
99 bool render_new_connection = false; // flag indicates rendering new line connection in trasparency 102 bool render_new_connection = false; // flag indicates rendering new line connection in trasparency
100 bool redisplay = false; // flag indicates redisplay rendering 103 bool redisplay = false; // flag indicates redisplay rendering
101 bool connection_done = false; // flag indicates finishing connections 104 bool connection_done = false; // flag indicates finishing connections
  105 +bool render_flow_rate = false; // flag indicates rendering total volume flow rate
102 unsigned connection_index = -1; // the index of connection that is picked 106 unsigned connection_index = -1; // the index of connection that is picked
103 unsigned port_index = 0; // inlet (0) or outlet (1) 107 unsigned port_index = 0; // inlet (0) or outlet (1)
104 stim::vec3<float> tmp_v1, tmp_v2; // temp vertex 108 stim::vec3<float> tmp_v1, tmp_v2; // temp vertex
@@ -112,7 +116,7 @@ bool manufacture = false; // flag indicates manufacture mode @@ -112,7 +116,7 @@ bool manufacture = false; // flag indicates manufacture mode
112 // get the network basic information 116 // get the network basic information
113 inline void get_background() { 117 inline void get_background() {
114 118
115 - pendant_vertex = flow.get_boundary_vertex(); 119 + pendant_vertex = flow.get_pendant_vertex();
116 num_edge = flow.edges(); 120 num_edge = flow.edges();
117 num_vertex = flow.vertices(); 121 num_vertex = flow.vertices();
118 122
@@ -153,9 +157,9 @@ __global__ void binary_transform(unsigned N, T* ptr, F threshold) { @@ -153,9 +157,9 @@ __global__ void binary_transform(unsigned N, T* ptr, F threshold) {
153 if (ix >= N) return; // avoid seg-fault 157 if (ix >= N) return; // avoid seg-fault
154 158
155 if (ptr[ix] >= threshold) // binary transformation 159 if (ptr[ix] >= threshold) // binary transformation
156 - ptr[ix] = 255;  
157 - else  
158 ptr[ix] = 0; 160 ptr[ix] = 0;
  161 + else
  162 + ptr[ix] = 255;
159 } 163 }
160 #endif 164 #endif
161 165
@@ -252,33 +256,60 @@ void glut_render() { @@ -252,33 +256,60 @@ void glut_render() {
252 256
253 if (!simulation && !build_inlet_outlet || manufacture) { 257 if (!simulation && !build_inlet_outlet || manufacture) {
254 glColor3f(0.0f, 0.0f, 0.0f); 258 glColor3f(0.0f, 0.0f, 0.0f);
255 - flow.glCylinder0(); 259 + flow.glCylinder0(scale, undo);
256 } 260 }
257 - else {  
258 - flow.bounding_box();  
259 - // render network  
260 - if (!flow_direction) {  
261 - flow.glSolidSphere(max_pressure, scale, subdivision);  
262 - if (mark_index)  
263 - flow.mark_vertex(scale);  
264 - //flow.glSolidCone(subdivision);  
265 - flow.glSolidCylinder(direction_index, color, scale, subdivision); 261 + else {
  262 + flow.bounding_box(); // bounding box
  263 + if (num_vertex > 100) { // if the network is big enough (say 100), use display list
  264 + if (undo) { // undo rendering list
  265 + undo = false;
  266 + glDeleteLists(dlist, 1);
  267 + }
  268 + if (!glIsList(dlist)) {
  269 + dlist = glGenLists(1);
  270 + glNewList(dlist, GL_COMPILE);
  271 + // render network
  272 + if (!glyph_mode) {
  273 + flow.glSolidSphere(max_pressure, subdivision, scale);
  274 + if (mark_index)
  275 + flow.mark_vertex(scale);
  276 + //flow.glSolidCone(subdivision);
  277 + flow.glSolidCylinder(direction_index, color, subdivision, scale);
  278 + }
  279 + // render glyphs
  280 + else
  281 + flow.glyph(color, subdivision, scale, frame_mode);
  282 +
  283 + glEndList();
  284 + }
  285 + glCallList(dlist);
266 } 286 }
267 - // render glyphs  
268 - else  
269 - flow.glyph(color, subdivision);  
270 -  
271 - flow.glSolidCuboid(flow_direction && build_inlet_outlet, subdivision, manufacture, length);  
272 - if (render_direction)  
273 - flow.glSolidCone(direction_index, scale, subdivision); 287 + else { // small network
  288 + // render network
  289 + if (!glyph_mode) {
  290 + flow.glSolidSphere(max_pressure, subdivision, scale);
  291 + if (mark_index) {
  292 + flow.mark_vertex(scale);
  293 + //flow.mark_edge();
  294 + }
  295 + //flow.glSolidCone(subdivision);
  296 + flow.glSolidCylinder(direction_index, color, subdivision, scale);
  297 + }
  298 + // render glyphs
  299 + else
  300 + flow.glyph(color, subdivision, scale, frame_mode);
  301 + }
  302 + flow.glSolidCuboid(subdivision, manufacture, length); // render bus source
  303 + if (render_direction) // render the flow direction of the vertex pointed
  304 + flow.glSolidCone(direction_index, subdivision, scale);
274 } 305 }
275 306
276 if (build_inlet_outlet) 307 if (build_inlet_outlet)
277 - flow.line_bridge(redisplay, flow_direction); 308 + flow.line_bridge(redisplay);
278 309
279 if (manufacture) { 310 if (manufacture) {
280 - flow.glSolidCuboid(flow_direction, subdivision, manufacture, length);  
281 - flow.tube_bridge(subdivision); 311 + flow.glSolidCuboid(subdivision, manufacture, length);
  312 + flow.tube_bridge(redisplay, subdivision, scale);
282 } 313 }
283 314
284 if (picked_connection && render_new_connection) { 315 if (picked_connection && render_new_connection) {
@@ -422,14 +453,14 @@ void glut_render() { @@ -422,14 +453,14 @@ void glut_render() {
422 glEnd(); 453 glEnd();
423 glFlush(); 454 glFlush();
424 455
425 - // pressure bar text 456 + // ratio bar text
426 glColor3f(0.0f, 0.0f, 0.0f); 457 glColor3f(0.0f, 0.0f, 0.0f);
427 glRasterPos2f(0.0f, vY - border_factor); 458 glRasterPos2f(0.0f, vY - border_factor);
428 std::stringstream ss_p; 459 std::stringstream ss_p;
429 ss_p << "Ratio bar"; 460 ss_p << "Ratio bar";
430 glutBitmapString(GLUT_BITMAP_HELVETICA_18, (const unsigned char*)(ss_p.str().c_str())); 461 glutBitmapString(GLUT_BITMAP_HELVETICA_18, (const unsigned char*)(ss_p.str().c_str()));
431 462
432 - // pressure range text 463 + // ratio range text
433 float step = vY - 3.0f * border_factor; 464 float step = vY - 3.0f * border_factor;
434 step /= 10; 465 step /= 10;
435 for (unsigned i = 0; i < 11; i++) { 466 for (unsigned i = 0; i < 11; i++) {
@@ -444,7 +475,8 @@ void glut_render() { @@ -444,7 +475,8 @@ void glut_render() {
444 } 475 }
445 476
446 if (build_inlet_outlet) 477 if (build_inlet_outlet)
447 - flow.display_flow_rate(in, out); 478 + if (render_flow_rate)
  479 + flow.display_flow_rate(in, out);
448 480
449 glutSwapBuffers(); 481 glutSwapBuffers();
450 } 482 }
@@ -456,12 +488,15 @@ void glut_menu(int value) { @@ -456,12 +488,15 @@ void glut_menu(int value) {
456 if (value == 1) { 488 if (value == 1) {
457 simulation = true; 489 simulation = true;
458 build_inlet_outlet = false; 490 build_inlet_outlet = false;
  491 + render_flow_rate = false;
459 manufacture = false; 492 manufacture = false;
460 modified_bridge = false; 493 modified_bridge = false;
  494 + change_fragment = false;
461 connection_done = false; 495 connection_done = false;
462 // first time 496 // first time
463 if (!flow.set) { // only first time simulation called "simulation", ^_^ 497 if (!flow.set) { // only first time simulation called "simulation", ^_^
464 - flow_initialize(); 498 + get_background(); // get the graph information
  499 + flow_initialize(); // initialize flow condition
465 menu_option[0] = "resimulation"; 500 menu_option[0] = "resimulation";
466 } 501 }
467 502
@@ -469,7 +504,7 @@ void glut_menu(int value) { @@ -469,7 +504,7 @@ void glut_menu(int value) {
469 flow_stable_state(); // main function of solving the linear system 504 flow_stable_state(); // main function of solving the linear system
470 flow.print_flow(); 505 flow.print_flow();
471 506
472 - if (!flow_direction) 507 + if (!glyph_mode)
473 glut_set_menu(num, 2); 508 glut_set_menu(num, 2);
474 } 509 }
475 510
@@ -496,13 +531,14 @@ void glut_menu(int value) { @@ -496,13 +531,14 @@ void glut_menu(int value) {
496 simulation = false; 531 simulation = false;
497 build_inlet_outlet = false; 532 build_inlet_outlet = false;
498 manufacture = true; 533 manufacture = true;
499 - flow_direction = false; // manufacuture mode doesn't need flow direction 534 + glyph_mode = false; // manufacuture mode doesn't need flow direction
500 redisplay = true; 535 redisplay = true;
501 } 536 }
502 537
503 if (value == 4) { 538 if (value == 4) {
504 simulation = true; 539 simulation = true;
505 build_inlet_outlet = false; 540 build_inlet_outlet = false;
  541 + render_flow_rate = false;
506 manufacture = false; 542 manufacture = false;
507 543
508 adjustment(); // adjust network flow accordingly 544 adjustment(); // adjust network flow accordingly
@@ -541,9 +577,9 @@ void glut_passive_motion(int x, int y) { @@ -541,9 +577,9 @@ void glut_passive_motion(int x, int y) {
541 577
542 if (simulation || build_inlet_outlet && !mods) { 578 if (simulation || build_inlet_outlet && !mods) {
543 bool flag = flow.epsilon_edge((float)posX, (float)posY, (float)posZ, eps, direction_index); 579 bool flag = flow.epsilon_edge((float)posX, (float)posY, (float)posZ, eps, direction_index);
544 - if (flag && !flow_direction) 580 + if (flag && !glyph_mode)
545 render_direction = true; 581 render_direction = true;
546 - else if (!flag && !flow_direction) { 582 + else if (!flag && !glyph_mode) {
547 if (render_direction) // if the direction is displaying currently, do a short delay 583 if (render_direction) // if the direction is displaying currently, do a short delay
548 Sleep(300); 584 Sleep(300);
549 render_direction = false; 585 render_direction = false;
@@ -654,6 +690,7 @@ void glut_mouse(int button, int state, int x, int y) { @@ -654,6 +690,7 @@ void glut_mouse(int button, int state, int x, int y) {
654 fragment_ratio = 0.0f; 690 fragment_ratio = 0.0f;
655 691
656 change_fragment = false; 692 change_fragment = false;
  693 + render_flow_rate = true;
657 flow.modify_synthetic_connection(u, rou, hilbert_curve, height_threshold, in, out, fragment_ratio, default_radius); 694 flow.modify_synthetic_connection(u, rou, hilbert_curve, height_threshold, in, out, fragment_ratio, default_radius);
658 } 695 }
659 // move connections along y-axis 696 // move connections along y-axis
@@ -799,7 +836,7 @@ void glut_wheel(int wheel, int direction, int x, int y) { @@ -799,7 +836,7 @@ void glut_wheel(int wheel, int direction, int x, int y) {
799 836
800 if (!to_select_pressure) { 837 if (!to_select_pressure) {
801 bool flag = flow.epsilon_vertex((float)posX, (float)posY, (float)posZ, eps, scale, pressure_index); 838 bool flag = flow.epsilon_vertex((float)posX, (float)posY, (float)posZ, eps, scale, pressure_index);
802 - if (flag && simulation) { 839 + if (flag && simulation && !glyph_mode) {
803 float tmp_r; 840 float tmp_r;
804 if (direction > 0) { // increase radii 841 if (direction > 0) { // increase radii
805 tmp_r = flow.get_radius(pressure_index); 842 tmp_r = flow.get_radius(pressure_index);
@@ -812,6 +849,7 @@ void glut_wheel(int wheel, int direction, int x, int y) { @@ -812,6 +849,7 @@ void glut_wheel(int wheel, int direction, int x, int y) {
812 tmp_r = default_radius; 849 tmp_r = default_radius;
813 } 850 }
814 flow.set_radius(pressure_index, tmp_r); 851 flow.set_radius(pressure_index, tmp_r);
  852 + undo = true; // undo rendering
815 } 853 }
816 else if (!mods) { 854 else if (!mods) {
817 if (direction > 0) // if it is button 3(up), move closer 855 if (direction > 0) // if it is button 3(up), move closer
@@ -839,6 +877,8 @@ void glut_wheel(int wheel, int direction, int x, int y) { @@ -839,6 +877,8 @@ void glut_wheel(int wheel, int direction, int x, int y) {
839 else 877 else
840 scale = 1.0f; 878 scale = 1.0f;
841 } 879 }
  880 + undo = true;
  881 + redisplay = true;
842 } 882 }
843 883
844 glutPostRedisplay(); 884 glutPostRedisplay();
@@ -855,22 +895,44 @@ void glut_keyboard(unsigned char key, int x, int y) { @@ -855,22 +895,44 @@ void glut_keyboard(unsigned char key, int x, int y) {
855 flow.save_network(); 895 flow.save_network();
856 break; 896 break;
857 897
  898 + // convert network to binary format (.nwt)
  899 + case 'c': {
  900 + std::vector<std::string> tmp = stim::parser::split(args.arg(0), '.');
  901 + std::stringstream ss;
  902 + ss << tmp[0] << ".nwt";
  903 + std::string filename = ss.str();
  904 + flow.saveNwt(filename);
  905 + break;
  906 + }
  907 +
858 // flow vector field visualization, Glyphs 908 // flow vector field visualization, Glyphs
859 case 'f': 909 case 'f':
860 - if (flow_direction && !manufacture && (simulation || build_inlet_outlet)) {  
861 - flow_direction = false; 910 + if (glyph_mode && !manufacture && (simulation || build_inlet_outlet)) {
  911 + glyph_mode = false;
  912 + frame_mode = false;
862 redisplay = true; // lines and arrows rendering use the same display list 913 redisplay = true; // lines and arrows rendering use the same display list
863 int num = glutGet(GLUT_MENU_NUM_ITEMS); 914 int num = glutGet(GLUT_MENU_NUM_ITEMS);
864 if (num == 1) 915 if (num == 1)
865 glut_set_menu(num, 2); 916 glut_set_menu(num, 2);
866 } 917 }
867 - else if (!flow_direction && !manufacture && (simulation || build_inlet_outlet)) {  
868 - flow_direction = true; 918 + else if (!glyph_mode && !manufacture && (simulation || build_inlet_outlet)) {
  919 + glyph_mode = true;
869 redisplay = true; 920 redisplay = true;
870 int num = glutGet(GLUT_MENU_NUM_ITEMS); 921 int num = glutGet(GLUT_MENU_NUM_ITEMS);
871 if (num == 2) 922 if (num == 2)
872 glut_set_menu(num, 1); 923 glut_set_menu(num, 1);
873 } 924 }
  925 + undo = true;
  926 + break;
  927 +
  928 + // filaments around arrows
  929 + case 'g':
  930 + if (glyph_mode) {
  931 + if (frame_mode)
  932 + frame_mode = false;
  933 + else
  934 + frame_mode = true;
  935 + }
874 break; 936 break;
875 937
876 // open/close index marks 938 // open/close index marks
@@ -879,6 +941,7 @@ void glut_keyboard(unsigned char key, int x, int y) { @@ -879,6 +941,7 @@ void glut_keyboard(unsigned char key, int x, int y) {
879 mark_index = false; 941 mark_index = false;
880 else 942 else
881 mark_index = true; 943 mark_index = true;
  944 + undo = true;
882 break; 945 break;
883 946
884 // output image stack 947 // output image stack
@@ -947,8 +1010,10 @@ void advertise() { @@ -947,8 +1010,10 @@ void advertise() {
947 1010
948 std::cout << "Usage(keyboard): e -> open/close indexing" << std::endl; 1011 std::cout << "Usage(keyboard): e -> open/close indexing" << std::endl;
949 std::cout << " m -> build synthetic connections(connection mode)/output augmented network as image stack (manufacture mode)" << std::endl; 1012 std::cout << " m -> build synthetic connections(connection mode)/output augmented network as image stack (manufacture mode)" << std::endl;
950 - std::cout << " s -> save network flow profiles in result folder as cvs files" << std::endl;  
951 - std::cout << " f -> open/close vector field visualization" << std::endl; 1013 + std::cout << " s -> save network flow profiles in profile folder as cvs files" << std::endl;
  1014 + std::cout << " c -> convert .obj network to .nwt network and stores in main folder" << std::endl;
  1015 + std::cout << " f -> open/close vector field visualization mode" << std::endl;
  1016 + std::cout << " g -> render filament frames in vector fiedl visualization mode" << std::endl;
952 1017
953 std::cout << args.str(); 1018 std::cout << args.str();
954 } 1019 }
@@ -966,6 +1031,8 @@ int main(int argc, char* argv[]) { @@ -966,6 +1031,8 @@ int main(int argc, char* argv[]) {
966 args.add("stack", "load the image stack"); 1031 args.add("stack", "load the image stack");
967 args.add("stackres", "spacing between pixel samples in each dimension(in units/pixel)", "1 1 1", "real value > 0"); 1032 args.add("stackres", "spacing between pixel samples in each dimension(in units/pixel)", "1 1 1", "real value > 0");
968 args.add("stackdir", "set the directory of the output image stack", "", "any existing directory (ex. /home/name/network)"); 1033 args.add("stackdir", "set the directory of the output image stack", "", "any existing directory (ex. /home/name/network)");
  1034 + args.add("scale", "scale down rendering fibers");
  1035 + args.add("lcc", "extract the largest connected component");
969 1036
970 args.parse(argc, argv); // parse the command line 1037 args.parse(argc, argv); // parse the command line
971 1038
@@ -983,6 +1050,8 @@ int main(int argc, char* argv[]) { @@ -983,6 +1050,8 @@ int main(int argc, char* argv[]) {
983 std::vector<std::string> tmp = stim::parser::split(args.arg(0), '.'); 1050 std::vector<std::string> tmp = stim::parser::split(args.arg(0), '.');
984 if ("obj" == tmp[1]) 1051 if ("obj" == tmp[1])
985 flow.load_obj(args.arg(0)); 1052 flow.load_obj(args.arg(0));
  1053 + else if ("nwt" == tmp[1]) // stim network binary format
  1054 + flow.loadNwt(args.arg(0));
986 else if ("swc" == tmp[1]) 1055 else if ("swc" == tmp[1])
987 flow.load_swc(args.arg(0)); 1056 flow.load_swc(args.arg(0));
988 else { 1057 else {
@@ -990,7 +1059,8 @@ int main(int argc, char* argv[]) { @@ -990,7 +1059,8 @@ int main(int argc, char* argv[]) {
990 std::exit(1); 1059 std::exit(1);
991 } 1060 }
992 } 1061 }
993 - get_background(); 1062 +
  1063 + // extract the largest connected component
994 1064
995 // get the units to work on 1065 // get the units to work on
996 units = args["units"].as_string(); 1066 units = args["units"].as_string();
@@ -1016,22 +1086,19 @@ int main(int argc, char* argv[]) { @@ -1016,22 +1086,19 @@ int main(int argc, char* argv[]) {
1016 S.load_images(args["stack"].as_string()); 1086 S.load_images(args["stack"].as_string());
1017 // binary transformation 1087 // binary transformation
1018 #ifdef __CUDACC__ 1088 #ifdef __CUDACC__
1019 - unsigned N = S.samples(); // number of pixels loaded  
1020 - unsigned char* d_S; // image stack stored in device 1089 + unsigned N = S.samples(); // number of pixels loaded
  1090 + unsigned char* d_S; // image stack stored in device
1021 unsigned char* h_S = (unsigned char*)malloc(N * sizeof(unsigned char)); // image stack stored in host 1091 unsigned char* h_S = (unsigned char*)malloc(N * sizeof(unsigned char)); // image stack stored in host
1022 cudaMalloc((void**)&d_S, N * sizeof(unsigned char)); 1092 cudaMalloc((void**)&d_S, N * sizeof(unsigned char));
1023 cudaMemcpy(d_S, S.data(), N * sizeof(unsigned char), cudaMemcpyHostToDevice); 1093 cudaMemcpy(d_S, S.data(), N * sizeof(unsigned char), cudaMemcpyHostToDevice);
1024 1094
1025 -  
1026 unsigned thread = 1024; 1095 unsigned thread = 1024;
1027 unsigned block = N / thread + 1; 1096 unsigned block = N / thread + 1;
1028 - binary_transform <<<block, thread>>> (N, d_S, binary_threshold); 1097 + binary_transform <<<block, thread>>> (N, d_S, binary_threshold); // binaryzation
1029 1098
1030 cudaMemcpy(h_S, d_S, N * sizeof(unsigned char), cudaMemcpyDeviceToHost); 1099 cudaMemcpy(h_S, d_S, N * sizeof(unsigned char), cudaMemcpyDeviceToHost);
1031 1100
1032 S.copy(h_S); 1101 S.copy(h_S);
1033 -  
1034 - S.save_images("image????.bmp");  
1035 #endif 1102 #endif
1036 } 1103 }
1037 1104
@@ -1044,6 +1111,10 @@ int main(int argc, char* argv[]) { @@ -1044,6 +1111,10 @@ int main(int argc, char* argv[]) {
1044 if (args["stackdir"].is_set()) 1111 if (args["stackdir"].is_set())
1045 stackdir = args["stackdir"].as_string(); 1112 stackdir = args["stackdir"].as_string();
1046 1113
  1114 + // get the scale-down factor is provided
  1115 + if (args["scale"].is_set())
  1116 + scale = args["scale"].as_float();
  1117 +
1047 // glut main loop 1118 // glut main loop
1048 bb = flow.boundingbox(); 1119 bb = flow.boundingbox();
1049 glut_initialize(); 1120 glut_initialize();