Commit 9e60c6a754f8cefc11dfc2cb509b6274405c4f17

Authored by Jiaming Guo
1 parent 8334680a

fixed minor bug in edge detection

Showing 2 changed files with 328 additions and 61 deletions   Show diff stats
... ... @@ -331,6 +331,11 @@ namespace stim {
331 331 return E[tmp_e].r(tmp_v);
332 332 }
333 333  
  334 + // get the radius of index j of edge i
  335 + T get_radius(unsigned i, unsigned j) {
  336 + return E[i].r(j);
  337 + }
  338 +
334 339 // get the velocity of pendant vertex i
335 340 T get_velocity(unsigned i) {
336 341  
... ... @@ -495,6 +500,7 @@ namespace stim {
495 500 order = o;
496 501 }
497 502  
  503 + // move hilbert curves
498 504 void move(unsigned i, T *c, direction dir, T dl, int feeder, bool invert) {
499 505  
500 506 int cof = (invert) ? -1 : 1;
... ... @@ -524,6 +530,7 @@ namespace stim {
524 530 outlet[i].V.push_back(tmp);
525 531 }
526 532  
  533 + // form hilbert curves
527 534 void hilbert_curve(unsigned i, T *c, int order, T dl, int feeder, bool invert, direction dir = DOWN) {
528 535  
529 536 if (order == 1) {
... ... @@ -727,51 +734,84 @@ namespace stim {
727 734  
728 735 // waste?
729 736 for (unsigned i = 0; i < num_edge; i++) {
730   - for (unsigned j = 0; j < E[i].size(); j++) {
731   - if (j == 0) { // for start vertex
732   - if (P[E[i].v[0]] != 0) {
733   - stim::vec3<float> new_color;
734   - new_color[0] = (P[E[i].v[0]] / max_pressure) > 0.5f ? 1.0f : 2.0f * P[E[i].v[0]] / max_pressure; // red
735   - new_color[1] = 0.0f; // green
736   - new_color[2] = (P[E[i].v[0]] / max_pressure) > 0.5f ? 1.0f - 2.0f * (P[E[i].v[0]] / max_pressure - 0.5f) : 1.0f; // blue
737   - glColor3f(new_color[0], new_color[1], new_color[2]);
738   - }
739   - }
740   - else if (j == E[i].size() - 1) { // for end vertex
741   - if (P[E[i].v[1]] != 0) {
742   - stim::vec3<float> new_color;
743   - new_color[0] = (P[E[i].v[1]] / max_pressure) > 0.5f ? 1.0f : 2.0f * P[E[i].v[1]] / max_pressure; // red
744   - new_color[1] = 0.0f; // green
745   - new_color[2] = (P[E[i].v[1]] / max_pressure) > 0.5f ? 1.0f - 2.0f * (P[E[i].v[1]] / max_pressure - 0.5f) : 1.0f; // blue
746   - glColor3f(new_color[0], new_color[1], new_color[2]);
747   - }
748   - }
749   - else
750   - glColor3f(0.5f, 0.5f, 0.5f); // gray point
  737 + // draw the starting vertex
  738 + if (P[E[i].v[0]] != 0) {
  739 + stim::vec3<float> new_color;
  740 + new_color[0] = (P[E[i].v[0]] / max_pressure) > 0.5f ? 1.0f : 2.0f * P[E[i].v[0]] / max_pressure; // red
  741 + new_color[1] = 0.0f; // green
  742 + new_color[2] = (P[E[i].v[0]] / max_pressure) > 0.5f ? 1.0f - 2.0f * (P[E[i].v[0]] / max_pressure - 0.5f) : 1.0f; // blue
  743 + glColor3f(new_color[0], new_color[1], new_color[2]);
751 744  
752 745 glPushMatrix();
753   - glTranslatef(E[i][j][0], E[i][j][1], E[i][j][2]);
754   - glutSolidSphere(get_r(i, j), subdivision, subdivision);
  746 + glTranslatef(E[i][0][0], E[i][0][1], E[i][0][2]);
  747 + glutSolidSphere(get_r(i, 0), subdivision, subdivision);
755 748 glPopMatrix();
756 749 }
  750 +
  751 + // draw the ending vertex
  752 + if (P[E[i].v[1]] != 0) {
  753 + stim::vec3<float> new_color;
  754 + new_color[0] = (P[E[i].v[1]] / max_pressure) > 0.5f ? 1.0f : 2.0f * P[E[i].v[1]] / max_pressure; // red
  755 + new_color[1] = 0.0f; // green
  756 + new_color[2] = (P[E[i].v[1]] / max_pressure) > 0.5f ? 1.0f - 2.0f * (P[E[i].v[1]] / max_pressure - 0.5f) : 1.0f; // blue
  757 + glColor3f(new_color[0], new_color[1], new_color[2]);
  758 +
  759 + glPushMatrix();
  760 + glTranslatef(E[i][E[i].size() - 1][0], E[i][E[i].size() - 1][1], E[i][E[i].size() - 1][2]);
  761 + glutSolidSphere(get_r(i, E[i].size() - 1), subdivision, subdivision);
  762 + glPopMatrix();
  763 + }
  764 + //for (unsigned j = 0; j < E[i].size(); j++) {
  765 + // if (j == 0) { // for start vertex
  766 + // if (P[E[i].v[0]] != 0) {
  767 + // stim::vec3<float> new_color;
  768 + // new_color[0] = (P[E[i].v[0]] / max_pressure) > 0.5f ? 1.0f : 2.0f * P[E[i].v[0]] / max_pressure; // red
  769 + // new_color[1] = 0.0f; // green
  770 + // new_color[2] = (P[E[i].v[0]] / max_pressure) > 0.5f ? 1.0f - 2.0f * (P[E[i].v[0]] / max_pressure - 0.5f) : 1.0f; // blue
  771 + // glColor3f(new_color[0], new_color[1], new_color[2]);
  772 + // }
  773 + // }
  774 + // else if (j == E[i].size() - 1) { // for end vertex
  775 + // if (P[E[i].v[1]] != 0) {
  776 + // stim::vec3<float> new_color;
  777 + // new_color[0] = (P[E[i].v[1]] / max_pressure) > 0.5f ? 1.0f : 2.0f * P[E[i].v[1]] / max_pressure; // red
  778 + // new_color[1] = 0.0f; // green
  779 + // new_color[2] = (P[E[i].v[1]] / max_pressure) > 0.5f ? 1.0f - 2.0f * (P[E[i].v[1]] / max_pressure - 0.5f) : 1.0f; // blue
  780 + // glColor3f(new_color[0], new_color[1], new_color[2]);
  781 + // }
  782 + // }
  783 + // else
  784 + // glColor3f(0.5f, 0.5f, 0.5f); // gray point
  785 +
  786 + // glPushMatrix();
  787 + // glTranslatef(E[i][j][0], E[i][j][1], E[i][j][2]);
  788 + // glutSolidSphere(get_r(i, j), subdivision, subdivision);
  789 + // glPopMatrix();
  790 + //}
757 791 }
758 792 }
759 793  
760 794 // draw edges as series of cylinders
761   - void glSolidCylinder(GLint subdivision, std::vector<unsigned char> color) {
  795 + void glSolidCylinder(unsigned index, std::vector<unsigned char> color, GLint subdivision) {
762 796  
763 797 stim::vec3<float> tmp_d;
764 798 stim::vec3<float> center1;
765 799 stim::vec3<float> center2;
  800 + stim::circle<float> tmp_c;
766 801 float r1;
767 802 float r2;
768 803 std::vector<typename stim::vec3<float> > cp1(subdivision + 1);
769 804 std::vector<typename stim::vec3<float> > cp2(subdivision + 1);
770 805 for (unsigned i = 0; i < num_edge; i++) { // for every edge
771   - glEnable(GL_BLEND); // enable color blend
772   - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // set blend function
773   - glDisable(GL_DEPTH_TEST);
774   - glColor4f((float)color[i * 3 + 0] / 255, (float)color[i * 3 + 1] / 255, (float)color[i * 3 + 2] / 255, 0.5f);
  806 + if (i == index) { // render in tranparency for direction indication
  807 + glEnable(GL_BLEND); // enable color blend
  808 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // set blend function
  809 + glDisable(GL_DEPTH_TEST);
  810 + glColor4f((float)color[i * 3 + 0] / 255, (float)color[i * 3 + 1] / 255, (float)color[i * 3 + 2] / 255, 0.5f);
  811 + }
  812 + else
  813 + glColor3f((float)color[i * 3 + 0] / 255, (float)color[i * 3 + 1] / 255, (float)color[i * 3 + 2] / 255);
  814 +
775 815 for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on the edge
776 816 center1 = E[i][j];
777 817 center2 = E[i][j + 1];
... ... @@ -779,8 +819,48 @@ namespace stim {
779 819 r1 = get_r(i, j);
780 820 r2 = get_r(i, j + 1);
781 821  
782   - // calculate the envelope caps
783   - find_envelope(cp1, cp2, center1, center2, r1, r2, subdivision);
  822 + //// calculate the envelope caps
  823 + //find_envelope(cp1, cp2, center1, center2, r1, r2, subdivision);
  824 + if (j == 0) {
  825 + if (E[i].size() == 2)
  826 + find_envelope(cp1, cp2, center1, center2, r1, r2, subdivision);
  827 + else {
  828 + tmp_d = center2 - center1;
  829 + tmp_d = tmp_d.norm();
  830 + tmp_c.rotate(tmp_d);
  831 + stim::circle<float> c1(center1, r1, tmp_d, tmp_c.U);
  832 + cp1 = c1.glpoints(subdivision);
  833 + tmp_d = (E[i][j + 2] - center2) + (center2 - center1);
  834 + tmp_d = tmp_d.norm();
  835 + tmp_c.rotate(tmp_d);
  836 + stim::circle<float> c2(center2, r2, tmp_d, tmp_c.U);
  837 + cp2 = c2.glpoints(subdivision);
  838 + }
  839 + }
  840 + else if (j == E[i].size() - 2) {
  841 + tmp_d = (center2 - center1) + (center1 - E[i][j - 1]);
  842 + tmp_d = tmp_d.norm();
  843 + tmp_c.rotate(tmp_d);
  844 + stim::circle<float> c1(center1, r1, tmp_d, tmp_c.U);
  845 + cp1 = c1.glpoints(subdivision);
  846 + tmp_d = center2 - center1;
  847 + tmp_d = tmp_d.norm();
  848 + tmp_c.rotate(tmp_d);
  849 + stim::circle<float> c2(center2, r2, tmp_d, tmp_c.U);
  850 + cp2 = c2.glpoints(subdivision);
  851 + }
  852 + else {
  853 + tmp_d = (center2 - center1) + (center1 - E[i][j - 1]);
  854 + tmp_d = tmp_d.norm();
  855 + tmp_c.rotate(tmp_d);
  856 + stim::circle<float> c1(center1, r1, tmp_d, tmp_c.U);
  857 + cp1 = c1.glpoints(subdivision);
  858 + tmp_d = (E[i][j + 2] - center2) + (center2 - center1);
  859 + tmp_d = tmp_d.norm();
  860 + tmp_c.rotate(tmp_d);
  861 + stim::circle<float> c2(center2, r2, tmp_d, tmp_c.U);
  862 + cp2 = c2.glpoints(subdivision);
  863 + }
784 864  
785 865 glBegin(GL_QUAD_STRIP);
786 866 for (unsigned j = 0; j < cp1.size(); j++) {
... ... @@ -789,12 +869,71 @@ namespace stim {
789 869 }
790 870 glEnd();
791 871 }
  872 + if (i == index) {
  873 + glDisable(GL_BLEND);
  874 + glEnable(GL_DEPTH_TEST);
  875 + }
  876 +
792 877 }
793 878 glFlush();
794   - glDisable(GL_BLEND);
795 879 }
796 880  
797 881 // draw the flow direction as cone
  882 + void glSolidCone(unsigned i, GLint subdivision) {
  883 +
  884 + stim::vec3<T> tmp_d; // direction
  885 + stim::vec3<T> center; // cone hat center
  886 + stim::vec3<T> head; // cone hat top
  887 + stim::circle<T> tmp_c;
  888 + std::vector<typename stim::vec3<T> > cp;
  889 + T radius;
  890 +
  891 + glColor3f(0.0f, 0.0f, 0.0f);
  892 +
  893 + unsigned index = E[i].size() / 2 - 1;
  894 + tmp_d = E[i][index + 1] - E[i][index];
  895 + tmp_d = tmp_d.norm();
  896 + center = (E[i][index + 1] + E[i][index]) / 2;
  897 + tmp_c.rotate(tmp_d);
  898 + radius = (E[i].r(index + 1) + E[i].r(index)) / 2;
  899 + if (v[i] > 0)
  900 + head = center + tmp_d * 2 * sqrt(3) * radius;
  901 + else
  902 + head = center - tmp_d * 2 * sqrt(3) * radius;
  903 +
  904 + stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
  905 + cp = c.glpoints(subdivision);
  906 +
  907 + glBegin(GL_TRIANGLE_FAN);
  908 + glVertex3f(head[0], head[1], head[2]);
  909 + for (unsigned k = 0; k < cp.size(); k++)
  910 + glVertex3f(cp[k][0], cp[k][1], cp[k][2]);
  911 + glEnd();
  912 + glFlush();
  913 +
  914 + // draw a cone for every edge to indicate
  915 + //for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge
  916 + // tmp_d = E[i][j + 1] - E[i][j];
  917 + // tmp_d = tmp_d.norm();
  918 + // center = (E[i][j + 1] + E[i][j]) / 2;
  919 + // tmp_c.rotate(tmp_d);
  920 + // radius = (E[i].r(j + 1) + E[i].r(j)) / 2;
  921 + // if (v[i] > 0) // if flow flows from j to j+1
  922 + // head = center + tmp_d * 2 * sqrt(3) * radius;
  923 + // else
  924 + // head = center - tmp_d * 2 * sqrt(3) * radius;
  925 +
  926 + // stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
  927 + // cp = c.glpoints(subdivision);
  928 +
  929 + // glBegin(GL_TRIANGLE_FAN);
  930 + // glVertex3f(head[0], head[1], head[2]);
  931 + // for (unsigned k = 0; k < cp.size(); k++)
  932 + // glVertex3f(cp[k][0], cp[k][1], cp[k][2]);
  933 + // glEnd();
  934 + //}
  935 + //glFlush();
  936 + }
798 937 void glSolidCone(GLint subdivision) {
799 938  
800 939 stim::vec3<T> tmp_d; // direction
... ... @@ -805,27 +944,48 @@ namespace stim {
805 944 T radius;
806 945  
807 946 glColor3f(0.0f, 0.0f, 0.0f);
  947 + // draw a cone for every edge to indicate
808 948 for (unsigned i = 0; i < num_edge; i++) { // for every edge
809   - for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge
810   - tmp_d = E[i][j + 1] - E[i][j];
811   - tmp_d = tmp_d.norm();
812   - center = (E[i][j + 1] + E[i][j]) / 2;
813   - tmp_c.rotate(tmp_d);
814   - radius = (E[i].r(j + 1) + E[i].r(j)) / 2;
815   - if (v[i] > 0) // if flow flows from j to j+1
816   - head = center + tmp_d * 2 * sqrt(3) * radius;
817   - else
818   - head = center - tmp_d * 2 * sqrt(3) * radius;
819   -
820   - stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
821   - cp = c.glpoints(subdivision);
  949 + unsigned k1 = E[i].size() / 2 - 1; // start and end index
  950 + unsigned k2 = E[i].size() / 2;
  951 + tmp_d = E[i][k2] - E[i][k1];
  952 + tmp_d = tmp_d.norm();
  953 + center = (E[i][k2] + E[i][k1]) / 2;
  954 + tmp_c.rotate(tmp_d);
  955 + radius = (E[i].r(k2) + E[i].r(k1)) / 2;
  956 + if (v[i] > 0) // if flow flows from k1 to k2
  957 + head = center + tmp_d * 2 * sqrt(3) * radius;
  958 + else
  959 + head = center - tmp_d * 2 * sqrt(3) * radius;
  960 + stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
  961 + cp = c.glpoints(subdivision);
  962 +
  963 + glBegin(GL_TRIANGLE_FAN);
  964 + glVertex3f(head[0], head[1], head[2]);
  965 + for (unsigned k = 0; k < cp.size(); k++)
  966 + glVertex3f(cp[k][0], cp[k][1], cp[k][2]);
  967 + glEnd();
822 968  
823   - glBegin(GL_TRIANGLE_FAN);
824   - glVertex3f(head[0], head[1], head[2]);
825   - for (unsigned k = 0; k < cp.size(); k++)
826   - glVertex3f(cp[k][0], cp[k][1], cp[k][2]);
827   - glEnd();
828   - }
  969 + //for (unsigned j = 0; j < E[i].size() - 1; j++) { // for every point on current edge
  970 + // tmp_d = E[i][j + 1] - E[i][j];
  971 + // tmp_d = tmp_d.norm();
  972 + // center = (E[i][j + 1] + E[i][j]) / 2;
  973 + // tmp_c.rotate(tmp_d);
  974 + // radius = (E[i].r(j + 1) + E[i].r(j)) / 2;
  975 + // if (v[i] > 0) // if flow flows from j to j+1
  976 + // head = center + tmp_d * 2 * sqrt(3) * radius;
  977 + // else
  978 + // head = center - tmp_d * 2 * sqrt(3) * radius;
  979 +
  980 + // stim::circle<float> c(center, radius, tmp_d, tmp_c.U);
  981 + // cp = c.glpoints(subdivision);
  982 +
  983 + // glBegin(GL_TRIANGLE_FAN);
  984 + // glVertex3f(head[0], head[1], head[2]);
  985 + // for (unsigned k = 0; k < cp.size(); k++)
  986 + // glVertex3f(cp[k][0], cp[k][1], cp[k][2]);
  987 + // glEnd();
  988 + //}
829 989 }
830 990 glFlush();
831 991 }
... ... @@ -1054,14 +1214,14 @@ namespace stim {
1054 1214 // return true and a value if found
1055 1215 inline bool epsilon_vertex(T x, T y, T z, T eps, unsigned& v) {
1056 1216  
1057   - float d = FLT_MAX; // minimum distance between 2 vertices
1058   - float tmp_d = 0.0f; // temporary stores distance for loop
  1217 + T d = FLT_MAX; // minimum distance between 2 vertices
  1218 + T tmp_d = 0.0f; // temporary stores distance for loop
1059 1219 unsigned tmp_i = 0; // temporary stores connection index for loop
1060   - stim::vec3<float> tmp_v; // temporary stores current loop point
  1220 + stim::vec3<T> tmp_v; // temporary stores current loop point
1061 1221 d = FLT_MAX; // set to max of float number
1062 1222  
1063 1223 for (unsigned i = 0; i < V.size(); i++) {
1064   - tmp_v = stim::vec3<float>(x, y, z);
  1224 + tmp_v = stim::vec3<T>(x, y, z);
1065 1225  
1066 1226 tmp_v = tmp_v - V[i]; // calculate a vector between two vertices
1067 1227 tmp_d = tmp_v.len(); // calculate length of that vector
... ... @@ -1079,6 +1239,61 @@ namespace stim {
1079 1239 return false;
1080 1240 }
1081 1241  
  1242 + // find the nearest inlet/outlet connection line of current click position
  1243 + // ab -> line segment, v -> point
  1244 + // return true and a value if found
  1245 + inline bool epsilon_edge(T x, T y, T z, T eps, unsigned &idx) {
  1246 +
  1247 + T d = FLT_MAX;
  1248 + T tmp_d;
  1249 + unsigned tmp_i = 0;
  1250 + unsigned tmp_j = 0;
  1251 + stim::vec3<T> v1;
  1252 + stim::vec3<T> v2;
  1253 + stim::vec3<T> v3;
  1254 + stim::vec3<T> v0 = stim::vec3<float>(x, y, z);
  1255 + bool online = false; // flag indicates the point is on the line-segment
  1256 + float a, b;
  1257 +
  1258 + for (unsigned i = 0; i < E.size(); i++) {
  1259 + for (unsigned j = 0; j < E[i].size() - 1; j++) {
  1260 + v1 = E[i][j + 1] - E[i][j]; // a -> b = ab
  1261 + v2 = v0 - E[i][j]; // a -> v = av
  1262 + v3 = v0 - E[i][j + 1]; // b -> v = bv
  1263 +
  1264 + tmp_d = v2.dot(v1); // av·ab
  1265 +
  1266 + // check the line relative position
  1267 + a = v2.dot(v1.norm());
  1268 + b = v3.dot(v1.norm());
  1269 + if (a < v1.len() && b < v1.len()) // if the length of projection fragment is longer than the line-segment
  1270 + online = true;
  1271 + else
  1272 + online = false;
  1273 +
  1274 + if (tmp_d <= 0.0 || tmp_d > std::pow(v1.len(), 2) && !online) // projection lies outside the line-segment
  1275 + continue;
  1276 + else {
  1277 + tmp_d = v1.cross(v2).len() / v1.len(); // perpendicular distance of point to segment: |v1 x v2| / |v1|
  1278 + if (tmp_d < d) {
  1279 + d = tmp_d;
  1280 + tmp_i = i;
  1281 + tmp_j = j;
  1282 + }
  1283 + }
  1284 + }
  1285 + }
  1286 +
  1287 + eps += get_radius(tmp_i, tmp_j);
  1288 +
  1289 + if (d < eps) {
  1290 + idx = tmp_i;
  1291 + return true;
  1292 + }
  1293 +
  1294 + return false;
  1295 + }
  1296 +
1082 1297 /// build main feeder connection
1083 1298 // set up main feeder and main port of both input and output
1084 1299 void set_main_feeder(T border = 400.0f) {
... ...
... ... @@ -54,7 +54,7 @@ float zoom_factor = 10.0f; // zooming factor
54 54 float border_factor = 20.0f; // border
55 55 float radii_factor = 1.0f; // radii changing factor
56 56 GLint subdivision = 20; // slices and stacks
57   -float default_radius = 5.0f; // default radii of network vertex
  57 +float default_radius = 5.0f; // default radii of network vertex
58 58 float delta = 0.01f; // small discrepancy
59 59 float eps = 20.0f; // epsilon threshold
60 60 float max_pressure = 0.0f; // maximum pressure that the channel can bear
... ... @@ -67,10 +67,12 @@ int mouse_y; // window y-coordinate
67 67 bool LTbutton = false; // true means down while false means up
68 68  
69 69 // simulation parameters
  70 +bool render_direction = false; // flag indicates rendering flow direction for one edge
70 71 bool simulation = false; // flag indicates simulation mode
71 72 bool color_bound = false; // flag indicates velocity color map bound
72 73 bool to_select_pressure = false; // flag indicates having selected a vertex to modify pressure
73 74 unsigned pressure_index; // the index of vertex that is clicked
  75 +unsigned direction_index = -1; // the index of edge that is pointed at
74 76  
75 77 // build inlet/outlet parameters
76 78 bool build_inlet_outlet = false; // flag indicates building inlets and outlets
... ... @@ -92,8 +94,11 @@ inline void get_background() {
92 94  
93 95 // set the initial radii
94 96 flow.init(num_edge, num_vertex); // initialize flow object
95   - for (unsigned i = 0; i < num_edge; i++)
96   - flow.set_r(i, default_radius);
  97 +
  98 + // if no radius information laoded
  99 + if (!flow.get_radius(0, 0))
  100 + for (unsigned i = 0; i < num_edge; i++)
  101 + flow.set_r(i, default_radius);
97 102 }
98 103  
99 104 // convert from window coordinates to world coordinates
... ... @@ -197,15 +202,18 @@ void glut_render() {
197 202 glut_modelview();
198 203  
199 204 if (!simulation && !build_inlet_outlet || manufacture) {
  205 + glColor3f(0.0f, 0.0f, 0.0f);
200 206 flow.glCylinder0();
201 207 }
202 208 else {
203 209 flow.bounding_box();
204 210 flow.glSolidSphere(max_pressure, subdivision);
205 211 flow.mark_vertex();
206   - flow.glSolidCone(subdivision);
207   - flow.glSolidCylinder(subdivision, color);
  212 + //flow.glSolidCone(subdivision);
  213 + flow.glSolidCylinder(direction_index, color, subdivision);
208 214 flow.glSolidCuboid();
  215 + if (render_direction)
  216 + flow.glSolidCone(direction_index, subdivision);
209 217 }
210 218  
211 219 if (build_inlet_outlet) {
... ... @@ -217,7 +225,6 @@ void glut_render() {
217 225 flow.tube_bridge(subdivision);
218 226 }
219 227  
220   -
221 228 // render bars
222 229 // bring up a pressure bar on left
223 230 if (to_select_pressure) {
... ... @@ -416,6 +423,31 @@ void glut_motion(int x, int y) {
416 423 glutPostRedisplay(); // re-draw the visualization
417 424 }
418 425  
  426 +// defines passive mouse motion function
  427 +void glut_passive_motion(int x, int y) {
  428 +
  429 + mouse_x = x;
  430 + mouse_y = y;
  431 +
  432 + // check whether the mouse point near to an edge
  433 + GLdouble posX, posY, posZ;
  434 + window_to_world(posX, posY, posZ); // get the world coordinates
  435 +
  436 + if (simulation || build_inlet_outlet) {
  437 + bool flag = flow.epsilon_edge((float)posX, (float)posY, (float)posZ, eps, direction_index);
  438 + if (flag)
  439 + render_direction = true;
  440 + else {
  441 + if (render_direction) // if the direction is displaying currently, do a short delay
  442 + Sleep(1000);
  443 + render_direction = false;
  444 + direction_index = -1;
  445 + }
  446 + }
  447 +
  448 + glutPostRedisplay(); // re-draw the visualization
  449 +}
  450 +
419 451 // get click window coordinates
420 452 void glut_mouse(int button, int state, int x, int y) {
421 453  
... ... @@ -552,6 +584,7 @@ void glut_initialize() {
552 584 glutDisplayFunc(glut_render);
553 585 glutMouseFunc(glut_mouse);
554 586 glutMotionFunc(glut_motion);
  587 + glutPassiveMotionFunc(glut_passive_motion);
555 588 glutMouseWheelFunc(glut_wheel);
556 589 glutKeyboardFunc(glut_keyboard);
557 590  
... ... @@ -565,6 +598,20 @@ void glut_initialize() {
565 598 cam.LookAt(c[0], c[1], c[2]);
566 599 }
567 600  
  601 +// output an advertisement for the lab, authors and usage information
  602 +void advertise() {
  603 + std::cout << std::endl << std::endl;
  604 + std::cout << " =======================================================================================" << std::endl;
  605 + std::cout << "|Thank you for using the synthetic microvascular model generator for microfluidics tool!|" << std::endl;
  606 + std::cout << "|Scalable Tissue Imaging and Modeling (STIM) Lab, University of Houston |" << std::endl;
  607 + std::cout << "|Developers: Jiaming Guo, David Mayerich |" << std::endl;
  608 + std::cout << "|Source: https://git.stim.ee.uh.edu/Jack/flow3.git |" << std::endl;
  609 + std::cout << " =======================================================================================" << std::endl << std::endl;
  610 +
  611 + std::cout << args.str();
  612 +}
  613 +
  614 +// main function: parse arguments and initialize GLUT
568 615 int main(int argc, char* argv[]) {
569 616  
570 617 // add arguments
... ... @@ -573,12 +620,17 @@ int main(int argc, char* argv[]) {
573 620 args.add("maxpress", "maximum allowed pressure in g / units / s^2, default 2 is for blood when units = um", "2", "real value > 0");
574 621 args.add("viscosity", "set the viscosity of the fluid (in g / units / s), default .00001 is for blood when units = um", ".00001", "real value > 0");
575 622 args.add("rou", "set the desity of the fluid (in g / units^3), default 1.06*10^-12 is for blood when units = um", ".00000000000106", "real value > 0");
576   - args.add("hilbert", "enable hilbert curves connections", "0", "value 1 for enablement");
  623 + args.add("hilbert", "activate hilbert curves connections", "0", "value 1 for enablement");
577 624 args.add("stackres", "spacing between pixel samples in each dimension(in units/pixel)", "1 1 1", "real value > 0");
578 625 args.add("stackdir", "set the directory of the output image stack", "", "any existing directory (ex. /home/name/network)");
579 626  
580 627 args.parse(argc, argv); // parse the command line
581 628  
  629 + if (args["help"].is_set()) {
  630 + advertise();
  631 + std::exit(1);
  632 + }
  633 +
582 634 // load network
583 635 if (args["network"].is_set()) { // load network from user
584 636 std::vector<std::string> tmp = stim::parser::split(args["network"].as_string(), '.');
... ...