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 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 376 // get the velocity of pendant vertex i
359 377 T get_velocity(unsigned i) {
360 378  
... ... @@ -378,6 +396,12 @@ namespace stim {
378 396 P[i] = value;
379 397 }
380 398  
  399 + // extrct the largest connected component
  400 + void extract_lcc() {
  401 +
  402 +
  403 + }
  404 +
381 405 // solve the linear system to get stable flow state
382 406 void solve_flow(T viscosity) {
383 407  
... ... @@ -385,7 +409,7 @@ namespace stim {
385 409 clear();
386 410  
387 411 // get the pendant vertex indices
388   - pendant_vertex = get_boundary_vertex();
  412 + pendant_vertex = get_pendant_vertex();
389 413  
390 414 // get bounding box
391 415 bb = (*this).boundingbox();
... ... @@ -749,7 +773,7 @@ namespace stim {
749 773 }
750 774  
751 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 778 // waste?
755 779 for (unsigned i = 0; i < num_edge; i++) {
... ... @@ -808,7 +832,7 @@ namespace stim {
808 832 }
809 833  
810 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 837 stim::vec3<float> tmp_d;
814 838 stim::vec3<float> center1;
... ... @@ -895,7 +919,7 @@ namespace stim {
895 919 }
896 920  
897 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 924 stim::vec3<T> tmp_d; // direction
901 925 stim::vec3<T> center; // cone hat center
... ... @@ -909,27 +933,28 @@ namespace stim {
909 933  
910 934 unsigned index = E[i].size() / 2 - 1;
911 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 937 tmp_d = tmp_d.norm();
914 938 center = (E[i][index + 1] + E[i][index]) / 2;
915 939 tmp_c.rotate(tmp_d);
916 940 radius = (E[i].r(index + 1) + E[i].r(index)) / 2 * scale;
917 941 radius = (h / sqrt(3) < radius) ? h / sqrt(3) : radius; // update radius
918   - if (v[i] > 0)
  942 + if (v[i] > threshold)
919 943 head = center + tmp_d * h;
920   - else
  944 + else if (v[i] < -threshold)
921 945 head = center - tmp_d * h;
922 946  
923 947 stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
924 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 958 // draw a cone for every edge to indicate
934 959 //for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge
935 960 // tmp_d = E[i][j + 1] - E[i][j];
... ... @@ -953,7 +978,7 @@ namespace stim {
953 978 //}
954 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 983 stim::vec3<T> tmp_d; // direction
959 984 stim::vec3<T> center; // cone hat center
... ... @@ -973,21 +998,22 @@ namespace stim {
973 998 tmp_d = tmp_d.norm();
974 999 center = (E[i][k2] + E[i][k1]) / 2;
975 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 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 1004 head = center + tmp_d * h;
980   - else
  1005 + else if(v[i] < -threhold)
981 1006 head = center - tmp_d * h;
982 1007 stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
983 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 1017 //for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge
992 1018 // tmp_d = E[i][j + 1] - E[i][j];
993 1019 // tmp_d = tmp_d.norm();
... ... @@ -1013,7 +1039,7 @@ namespace stim {
1013 1039 }
1014 1040  
1015 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 1044 T width;
1019 1045 stim::vec3<T> L = bb.A; // get the bottom left corner
... ... @@ -1073,51 +1099,10 @@ namespace stim {
1073 1099 glVertex3f(main_feeder[i][0] + length / 2, main_feeder[i][1] - height / 2, main_feeder[i][2] + width / 2);
1074 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 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 1107 // v1----v2-->v3
1123 1108 T k = 4.0f; // quartering
... ... @@ -1127,51 +1112,124 @@ namespace stim {
1127 1112 std::vector<typename stim::vec3<float> > cp1(subdivision + 1);
1128 1113 std::vector<typename stim::vec3<float> > cp2(subdivision + 1);
1129 1114  
  1115 + // rendering the arrows
1130 1116 for (unsigned i = 0; i < num_edge; i++) { // for every edge
1131 1117 glColor3f((float)color[i * 3 + 0] / 255.0f, (float)color[i * 3 + 1] / 255.0f, (float)color[i * 3 + 2] / 255.0f);
1132 1118 for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on that edge
1133 1119  
1134 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 1122 v1 = E[i][j];
1137 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 1126 v1 = E[i][j + 1];
1141 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 1235 // display the total volume flow rate
... ... @@ -1204,145 +1262,121 @@ namespace stim {
1204 1262 }
1205 1263  
1206 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 1268 glDeleteLists(dlist, 1);
1211   - redisplay = false;
  1269 + redisplay = false;
  1270 + }
1212 1271  
1213 1272 if (!glIsList(dlist)) {
1214 1273 dlist = glGenLists(1);
1215 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 1372 glLineWidth(5);
1341 1373 for (unsigned i = 0; i < inlet.size(); i++) {
1342 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 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 1381 glBegin(GL_LINE_STRIP);
1348 1382 for (unsigned j = 0; j < inlet[i].V.size(); j++)
... ... @@ -1351,23 +1385,31 @@ namespace stim {
1351 1385 }
1352 1386 for (unsigned i = 0; i < outlet.size(); i++) {
1353 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 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 1393 glBegin(GL_LINE_STRIP);
1358 1394 for (unsigned j = 0; j < outlet[i].V.size(); j++)
1359 1395 glVertex3f(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]);
1360 1396 glEnd();
1361 1397 }
1362   - }
1363   - glFlush();
  1398 + // glDisable(GL_BLEND);
  1399 + // glEnable(GL_DEPTH_TEST);
  1400 + //}
1364 1401 glEndList();
1365 1402 }
1366 1403 glCallList(dlist);
1367 1404 }
1368 1405  
1369 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 1414 if (!glIsList(dlist + 1)) {
1373 1415 glNewList(dlist + 1, GL_COMPILE);
... ... @@ -1383,7 +1425,7 @@ namespace stim {
1383 1425 for (unsigned j = 1; j < inlet[i].V.size() - 1; j++) {
1384 1426 glPushMatrix();
1385 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 1429 glPopMatrix();
1388 1430 }
1389 1431 // render edge as cylinder
... ... @@ -1391,8 +1433,8 @@ namespace stim {
1391 1433 dir = inlet[i].V[j] - inlet[i].V[j + 1];
1392 1434 dir = dir.norm();
1393 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 1438 cp1 = c1.glpoints(subdivision);
1397 1439 cp2 = c2.glpoints(subdivision);
1398 1440  
... ... @@ -1410,7 +1452,7 @@ namespace stim {
1410 1452 for (unsigned j = 1; j < outlet[i].V.size() - 1; j++) {
1411 1453 glPushMatrix();
1412 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 1456 glPopMatrix();
1415 1457 }
1416 1458 // render edge as cylinder
... ... @@ -1418,8 +1460,8 @@ namespace stim {
1418 1460 dir = outlet[i].V[j] - outlet[i].V[j + 1];
1419 1461 dir = dir.norm();
1420 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 1465 cp1 = c1.glpoints(subdivision);
1424 1466 cp2 = c2.glpoints(subdivision);
1425 1467  
... ... @@ -1489,7 +1531,7 @@ namespace stim {
1489 1531 }
1490 1532  
1491 1533 // mark the vertex
1492   - void mark_vertex(T scale) {
  1534 + void mark_vertex(T scale = 1.0f) {
1493 1535  
1494 1536 glColor3f(0.0f, 0.0f, 0.0f);
1495 1537 for (unsigned i = 0; i < num_vertex; i++) {
... ... @@ -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 1557 // find the nearest vertex of current click position
1504 1558 // return true and a value if found
1505 1559 inline bool epsilon_vertex(T x, T y, T z, T eps, T scale, unsigned& v) {
... ... @@ -2381,7 +2435,7 @@ namespace stim {
2381 2435 for (unsigned j = 0; j < num; j++) {
2382 2436 if (i != j) {
2383 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 2439 inlet_feasibility[i] = false;
2386 2440 break;
2387 2441 }
... ... @@ -2398,7 +2452,7 @@ namespace stim {
2398 2452 for (unsigned j = 0; j < num; j++) {
2399 2453 if (i != j) {
2400 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 2456 outlet_feasibility[i] = false;
2403 2457 break;
2404 2458 }
... ... @@ -2661,6 +2715,11 @@ namespace stim {
2661 2715 top = A[i].c[1];
2662 2716 if (A[i].c[1] < bottom)
2663 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 2723 if (A[i].r > max_radius)
2665 2724 max_radius = A[i].r;
2666 2725 }
... ...
... ... @@ -49,7 +49,7 @@ int mods; // special keyboard input
49 49 std::vector<unsigned char> color; // velocity color map
50 50 std::vector<int> velocity_bar; // velocity bar
51 51 float length = 40.0f; // cuboid length
52   -float scale = 1.0f; // render scale factor
  52 +float scale = 1.0f; // scale factor
53 53 bool image_stack = false; // flag indicates an image stack been loaded
54 54 stim::image_stack<unsigned char, float> S; // image stack
55 55 float binary_threshold = 128; // threshold for binary transformation
... ... @@ -57,6 +57,8 @@ float in = 0.0f; // total input volume flow rate
57 57 float out = 0.0f;
58 58 float Rt = 0.0f; // total resistance
59 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 63 // hard-coded parameters
62 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 87 bool color_bound = false; // flag indicates velocity color map bound
86 88 bool to_select_pressure = false; // flag indicates having selected a vertex to modify pressure
87 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 92 unsigned pressure_index; // the index of vertex that is clicked
90 93 unsigned direction_index = -1; // the index of edge that is pointed at
91 94 unsigned index_index = -1; // the index of the vertex
... ... @@ -99,6 +102,7 @@ bool picked_connection = false; // flag indicates picked one connection
99 102 bool render_new_connection = false; // flag indicates rendering new line connection in trasparency
100 103 bool redisplay = false; // flag indicates redisplay rendering
101 104 bool connection_done = false; // flag indicates finishing connections
  105 +bool render_flow_rate = false; // flag indicates rendering total volume flow rate
102 106 unsigned connection_index = -1; // the index of connection that is picked
103 107 unsigned port_index = 0; // inlet (0) or outlet (1)
104 108 stim::vec3<float> tmp_v1, tmp_v2; // temp vertex
... ... @@ -112,7 +116,7 @@ bool manufacture = false; // flag indicates manufacture mode
112 116 // get the network basic information
113 117 inline void get_background() {
114 118  
115   - pendant_vertex = flow.get_boundary_vertex();
  119 + pendant_vertex = flow.get_pendant_vertex();
116 120 num_edge = flow.edges();
117 121 num_vertex = flow.vertices();
118 122  
... ... @@ -153,9 +157,9 @@ __global__ void binary_transform(unsigned N, T* ptr, F threshold) {
153 157 if (ix >= N) return; // avoid seg-fault
154 158  
155 159 if (ptr[ix] >= threshold) // binary transformation
156   - ptr[ix] = 255;
157   - else
158 160 ptr[ix] = 0;
  161 + else
  162 + ptr[ix] = 255;
159 163 }
160 164 #endif
161 165  
... ... @@ -252,33 +256,60 @@ void glut_render() {
252 256  
253 257 if (!simulation && !build_inlet_outlet || manufacture) {
254 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 307 if (build_inlet_outlet)
277   - flow.line_bridge(redisplay, flow_direction);
  308 + flow.line_bridge(redisplay);
278 309  
279 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 315 if (picked_connection && render_new_connection) {
... ... @@ -422,14 +453,14 @@ void glut_render() {
422 453 glEnd();
423 454 glFlush();
424 455  
425   - // pressure bar text
  456 + // ratio bar text
426 457 glColor3f(0.0f, 0.0f, 0.0f);
427 458 glRasterPos2f(0.0f, vY - border_factor);
428 459 std::stringstream ss_p;
429 460 ss_p << "Ratio bar";
430 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 464 float step = vY - 3.0f * border_factor;
434 465 step /= 10;
435 466 for (unsigned i = 0; i < 11; i++) {
... ... @@ -444,7 +475,8 @@ void glut_render() {
444 475 }
445 476  
446 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 481 glutSwapBuffers();
450 482 }
... ... @@ -456,12 +488,15 @@ void glut_menu(int value) {
456 488 if (value == 1) {
457 489 simulation = true;
458 490 build_inlet_outlet = false;
  491 + render_flow_rate = false;
459 492 manufacture = false;
460 493 modified_bridge = false;
  494 + change_fragment = false;
461 495 connection_done = false;
462 496 // first time
463 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 500 menu_option[0] = "resimulation";
466 501 }
467 502  
... ... @@ -469,7 +504,7 @@ void glut_menu(int value) {
469 504 flow_stable_state(); // main function of solving the linear system
470 505 flow.print_flow();
471 506  
472   - if (!flow_direction)
  507 + if (!glyph_mode)
473 508 glut_set_menu(num, 2);
474 509 }
475 510  
... ... @@ -496,13 +531,14 @@ void glut_menu(int value) {
496 531 simulation = false;
497 532 build_inlet_outlet = false;
498 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 535 redisplay = true;
501 536 }
502 537  
503 538 if (value == 4) {
504 539 simulation = true;
505 540 build_inlet_outlet = false;
  541 + render_flow_rate = false;
506 542 manufacture = false;
507 543  
508 544 adjustment(); // adjust network flow accordingly
... ... @@ -541,9 +577,9 @@ void glut_passive_motion(int x, int y) {
541 577  
542 578 if (simulation || build_inlet_outlet && !mods) {
543 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 581 render_direction = true;
546   - else if (!flag && !flow_direction) {
  582 + else if (!flag && !glyph_mode) {
547 583 if (render_direction) // if the direction is displaying currently, do a short delay
548 584 Sleep(300);
549 585 render_direction = false;
... ... @@ -654,6 +690,7 @@ void glut_mouse(int button, int state, int x, int y) {
654 690 fragment_ratio = 0.0f;
655 691  
656 692 change_fragment = false;
  693 + render_flow_rate = true;
657 694 flow.modify_synthetic_connection(u, rou, hilbert_curve, height_threshold, in, out, fragment_ratio, default_radius);
658 695 }
659 696 // move connections along y-axis
... ... @@ -799,7 +836,7 @@ void glut_wheel(int wheel, int direction, int x, int y) {
799 836  
800 837 if (!to_select_pressure) {
801 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 840 float tmp_r;
804 841 if (direction > 0) { // increase radii
805 842 tmp_r = flow.get_radius(pressure_index);
... ... @@ -812,6 +849,7 @@ void glut_wheel(int wheel, int direction, int x, int y) {
812 849 tmp_r = default_radius;
813 850 }
814 851 flow.set_radius(pressure_index, tmp_r);
  852 + undo = true; // undo rendering
815 853 }
816 854 else if (!mods) {
817 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 877 else
840 878 scale = 1.0f;
841 879 }
  880 + undo = true;
  881 + redisplay = true;
842 882 }
843 883  
844 884 glutPostRedisplay();
... ... @@ -855,22 +895,44 @@ void glut_keyboard(unsigned char key, int x, int y) {
855 895 flow.save_network();
856 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 908 // flow vector field visualization, Glyphs
859 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 913 redisplay = true; // lines and arrows rendering use the same display list
863 914 int num = glutGet(GLUT_MENU_NUM_ITEMS);
864 915 if (num == 1)
865 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 920 redisplay = true;
870 921 int num = glutGet(GLUT_MENU_NUM_ITEMS);
871 922 if (num == 2)
872 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 936 break;
875 937  
876 938 // open/close index marks
... ... @@ -879,6 +941,7 @@ void glut_keyboard(unsigned char key, int x, int y) {
879 941 mark_index = false;
880 942 else
881 943 mark_index = true;
  944 + undo = true;
882 945 break;
883 946  
884 947 // output image stack
... ... @@ -947,8 +1010,10 @@ void advertise() {
947 1010  
948 1011 std::cout << "Usage(keyboard): e -> open/close indexing" << std::endl;
949 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 1018 std::cout << args.str();
954 1019 }
... ... @@ -966,6 +1031,8 @@ int main(int argc, char* argv[]) {
966 1031 args.add("stack", "load the image stack");
967 1032 args.add("stackres", "spacing between pixel samples in each dimension(in units/pixel)", "1 1 1", "real value > 0");
968 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 1037 args.parse(argc, argv); // parse the command line
971 1038  
... ... @@ -983,6 +1050,8 @@ int main(int argc, char* argv[]) {
983 1050 std::vector<std::string> tmp = stim::parser::split(args.arg(0), '.');
984 1051 if ("obj" == tmp[1])
985 1052 flow.load_obj(args.arg(0));
  1053 + else if ("nwt" == tmp[1]) // stim network binary format
  1054 + flow.loadNwt(args.arg(0));
986 1055 else if ("swc" == tmp[1])
987 1056 flow.load_swc(args.arg(0));
988 1057 else {
... ... @@ -990,7 +1059,8 @@ int main(int argc, char* argv[]) {
990 1059 std::exit(1);
991 1060 }
992 1061 }
993   - get_background();
  1062 +
  1063 + // extract the largest connected component
994 1064  
995 1065 // get the units to work on
996 1066 units = args["units"].as_string();
... ... @@ -1016,22 +1086,19 @@ int main(int argc, char* argv[]) {
1016 1086 S.load_images(args["stack"].as_string());
1017 1087 // binary transformation
1018 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 1091 unsigned char* h_S = (unsigned char*)malloc(N * sizeof(unsigned char)); // image stack stored in host
1022 1092 cudaMalloc((void**)&d_S, N * sizeof(unsigned char));
1023 1093 cudaMemcpy(d_S, S.data(), N * sizeof(unsigned char), cudaMemcpyHostToDevice);
1024 1094  
1025   -
1026 1095 unsigned thread = 1024;
1027 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 1099 cudaMemcpy(h_S, d_S, N * sizeof(unsigned char), cudaMemcpyDeviceToHost);
1031 1100  
1032 1101 S.copy(h_S);
1033   -
1034   - S.save_images("image????.bmp");
1035 1102 #endif
1036 1103 }
1037 1104  
... ... @@ -1044,6 +1111,10 @@ int main(int argc, char* argv[]) {
1044 1111 if (args["stackdir"].is_set())
1045 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 1118 // glut main loop
1048 1119 bb = flow.boundingbox();
1049 1120 glut_initialize();
... ...