diff --git a/flow.h b/flow.h index 83229e3..c9cdce5 100644 --- a/flow.h +++ b/flow.h @@ -1013,7 +1013,7 @@ namespace stim { } // draw main feeder as solid cube - void glSolidCuboid(bool manufacture = false, T length = 40.0f, T height = 10.0f) { + void glSolidCuboid(bool arrow, GLint subdivision, bool manufacture = false, T length = 40.0f, T height = 10.0f) { T width; stim::vec3 L = bb.A; // get the bottom left corner @@ -1073,6 +1073,46 @@ namespace stim { glVertex3f(main_feeder[i][0] + length / 2, main_feeder[i][1] - height / 2, main_feeder[i][2] + width / 2); glEnd(); } + + // render total flow direction + if (arrow) { + stim::vec3 d = main_feeder[1] - main_feeder[0]; + d = d.norm(); + stim::vec3 v1, v2, v3; + stim::vec3 center = bb.center(); + stim::vec3 size = bb.size(); + stim::circle tmp_c; + tmp_c.rotate(d); + std::vector > cp1(subdivision + 1); + std::vector > cp2(subdivision + 1); + v2 = center - stim::vec3(0.0f, size[1] + 10.0f, 0.0f); + v1 = v2 - stim::vec3(30.0f, 0.0f, 0.0f); + v3 = v2 + stim::vec3(30.0f, 0.0f, 0.0f); + v2 = v2 + stim::vec3(20.0f, 0.0f, 0.0f); + + // draw the total flow direciton indicating arrow + stim::circle c1(v1, 5.0f / 2, d, tmp_c.U); + cp1 = c1.glpoints(subdivision); + stim::circle c2(v2, 5.0f / 2, d, tmp_c.U); + cp2 = c2.glpoints(subdivision); + + glColor3f(0.0f, 1.0f, 0.0f); + glBegin(GL_QUAD_STRIP); + for (unsigned k = 0; k < cp1.size(); k++) { + glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]); + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]); + } + glEnd(); + + // render the cone part + stim::circle c3(v2, 5.0f, d, tmp_c.U); + cp2 = c3.glpoints(subdivision); + glBegin(GL_TRIANGLE_FAN); + glVertex3f(v3[0], v3[1], v3[2]); + for (unsigned k = 0; k < cp2.size(); k++) + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]); + glEnd(); + } glFlush(); } @@ -1163,8 +1203,8 @@ namespace stim { glPopMatrix(); } - // draw the bridge as lines - void line_bridge(bool &redisplay) { + // draw the bridge as lines or arrows + void line_bridge(bool &redisplay, bool arrow, T r = 4.0f) { if (redisplay) glDeleteLists(dlist, 1); @@ -1173,28 +1213,152 @@ namespace stim { if (!glIsList(dlist)) { dlist = glGenLists(1); glNewList(dlist, GL_COMPILE); - - glLineWidth(5); - for (unsigned i = 0; i < inlet.size(); i++) { - if (inlet_feasibility[i]) - glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black - else - glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red - glBegin(GL_LINE_STRIP); - for (unsigned j = 0; j < inlet[i].V.size(); j++) - glVertex3f(inlet[i].V[j][0], inlet[i].V[j][1], inlet[i].V[j][2]); - glEnd(); + // render flow direction arrows + if (arrow) { + // v1----v2-->v3 + T k = 4.0f; // quartering + stim::vec3 v1, v2, v3; // three point + stim::vec3 d; // direction vector + stim::circle tmp_c; + std::vector > cp1(subdivision + 1); + std::vector > cp2(subdivision + 1); + + // inlet, right-going + for (unsigned i = 0; i < inlet.size(); i++) { + if (inlet_feasibility[i]) + glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black + else + glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red + for (unsigned j = 0; j < inlet[i].V.size() - 1; j++) { + v1 = inlet[i].V[j]; + v3 = inlet[i].V[j + 1]; + d = v3 - v1; + // place the arrow in the middel of one edge + v2 = v1 + (1.0f / k * 2.0f) * d; // looks like =->= + v1 = v1 + (1.0f / k) * d; + v3 = v3 - (1.0f / k) * d; + d = d.norm(); + tmp_c.rotate(d); + + // render the cylinder part + stim::circle c1(v1, r / 2, d, tmp_c.U); + cp1 = c1.glpoints(subdivision); + stim::circle c2(v2, r / 2, d, tmp_c.U); + cp2 = c2.glpoints(subdivision); + + glBegin(GL_QUAD_STRIP); + for (unsigned k = 0; k < cp1.size(); k++) { + glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]); + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]); + } + glEnd(); + + // render the cone part + stim::circle c3(v2, r, d, tmp_c.U); + cp2 = c3.glpoints(subdivision); + glBegin(GL_TRIANGLE_FAN); + glVertex3f(v3[0], v3[1], v3[2]); + for (unsigned k = 0; k < cp2.size(); k++) + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]); + glEnd(); + } + } + + // outlet, right-going + for (unsigned i = 0; i < outlet.size(); i++) { + if (outlet_feasibility[i]) + glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black + else + glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red + for (unsigned j = 0; j < outlet[i].V.size() - 1; j++) { + v1 = outlet[i].V[j + 1]; + v3 = outlet[i].V[j]; + d = v3 - v1; + // place the arrow in the middel of one edge + v2 = v1 + (1.0f / k * 2.0f) * d; // looks like =->= + v1 = v1 + (1.0f / k) * d; + v3 = v3 - (1.0f / k) * d; + d = d.norm(); + tmp_c.rotate(d); + + // render the cylinder part + stim::circle c1(v1, r / 2, d, tmp_c.U); + cp1 = c1.glpoints(subdivision); + stim::circle c2(v2, r / 2, d, tmp_c.U); + cp2 = c2.glpoints(subdivision); + + glBegin(GL_QUAD_STRIP); + for (unsigned k = 0; k < cp1.size(); k++) { + glVertex3f(cp1[k][0], cp1[k][1], cp1[k][2]); + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]); + } + glEnd(); + + // render the cone part + stim::circle c3(v2, r, d, tmp_c.U); + cp2 = c3.glpoints(subdivision); + glBegin(GL_TRIANGLE_FAN); + glVertex3f(v3[0], v3[1], v3[2]); + for (unsigned k = 0; k < cp2.size(); k++) + glVertex3f(cp2[k][0], cp2[k][1], cp2[k][2]); + glEnd(); + } + } + + // render transparent lines as indexing + glEnable(GL_BLEND); // enable color blend + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // set blend function + glDisable(GL_DEPTH_TEST); + glLineWidth(5); + for (unsigned i = 0; i < inlet.size(); i++) { + if (inlet_feasibility[i]) + glColor4f(0.0f, 0.0f, 0.0f, 0.2f); // feasible -> black + else + glColor4f(1.0f, 0.0f, 0.0f, 0.2f); // nonfeasible -> red + + glBegin(GL_LINE_STRIP); + for (unsigned j = 0; j < inlet[i].V.size(); j++) + glVertex3f(inlet[i].V[j][0], inlet[i].V[j][1], inlet[i].V[j][2]); + glEnd(); + } + for (unsigned i = 0; i < outlet.size(); i++) { + if (outlet_feasibility[i]) + glColor4f(0.0f, 0.0f, 0.0f, 0.2f); // feasible -> black + else + glColor4f(1.0f, 0.0f, 0.0f, 0.2f); // nonfeasible -> red + glBegin(GL_LINE_STRIP); + for (unsigned j = 0; j < outlet[i].V.size(); j++) + glVertex3f(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]); + glEnd(); + } + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); } - for (unsigned i = 0; i < outlet.size(); i++) { - if (outlet_feasibility[i]) - glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black - else - glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red - glBegin(GL_LINE_STRIP); - for (unsigned j = 0; j < outlet[i].V.size(); j++) - glVertex3f(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]); - glEnd(); + // render connection lines + else { + glLineWidth(5); + for (unsigned i = 0; i < inlet.size(); i++) { + if (inlet_feasibility[i]) + glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black + else + glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red + + glBegin(GL_LINE_STRIP); + for (unsigned j = 0; j < inlet[i].V.size(); j++) + glVertex3f(inlet[i].V[j][0], inlet[i].V[j][1], inlet[i].V[j][2]); + glEnd(); + } + for (unsigned i = 0; i < outlet.size(); i++) { + if (outlet_feasibility[i]) + glColor3f(0.0f, 0.0f, 0.0f); // feasible -> black + else + glColor3f(1.0f, 0.0f, 0.0f); // nonfeasible -> red + glBegin(GL_LINE_STRIP); + for (unsigned j = 0; j < outlet[i].V.size(); j++) + glVertex3f(outlet[i].V[j][0], outlet[i].V[j][1], outlet[i].V[j][2]); + glEnd(); + } } glFlush(); glEndList(); @@ -1617,10 +1781,10 @@ namespace stim { // find the number of U-shape or square-shape structure for extending length of connection // @param t: width = t * radius - int find_number_square(T origin_l, T desire_l, T radius = 5.0f, int times = 4) { + int find_number_square(T origin_l, T desire_l, T radius = 5.0f, int times = 10) { bool done = false; // flag indicates the current number of square shape structure is feasible - int n = origin_l / (times * 4 * radius);// number of square shape structure + int n = origin_l / (times * 4 * radius); // number of square shape structure T need_l = desire_l - origin_l; T height; // height of the square shapce structure @@ -1638,7 +1802,7 @@ namespace stim { } // build square connections - void build_square_connection(int i, T width, T height, T origin_l, T desire_l, int n, int feeder, T threshold, bool z, bool left = true, bool up = true, int times = 4, T ratio = 0, T radius = 5.0f) { + void build_square_connection(int i, T width, T height, T origin_l, T desire_l, int n, int feeder, T threshold, bool z, bool left = true, bool up = true, int times = 10, T ratio = 0, T radius = 5.0f) { int coef_up = (up) ? 1 : -1; // y coefficient int coef_left = (left) ? 1 : -1; // x coefficient @@ -1669,8 +1833,8 @@ namespace stim { // there are cases that the fragment can not satisfy the requirement for width if (width < times * radius || n == 0) { // check feasibility - ratio = 0.0f; // load - desire_l = tmp_d; + ratio = 0.0f; // load original lengths + desire_l = tmp_d; origin_l = tmp_l; std::cout << "Warning: current ratio is not feasible, use full original line." << std::endl; @@ -2134,7 +2298,7 @@ namespace stim { width = (T)origin_l / (2 * n); height = (desire_l - origin_l) / (2 * n); - build_square_connection(i, width, height, origin_l, desire_l, n, 1, threshold, z, true, upper, 5, ratio); + build_square_connection(i, width, height, origin_l, desire_l, n, 1, threshold, z, true, upper, 2, ratio); inlet[i].V.push_back(bus_v); std::reverse(inlet[i].V.begin(), inlet[i].V.end()); // from bus to pendant vertex @@ -2183,7 +2347,7 @@ namespace stim { width = (T)origin_l / (2 * n); height = (desire_l - origin_l) / (2 * n); - build_square_connection(i, width, height, origin_l, desire_l, n, 0, threshold, z, false, upper, 5, ratio); + build_square_connection(i, width, height, origin_l, desire_l, n, 0, threshold, z, false, upper, 2, ratio); outlet[i].V.push_back(bus_v); std::reverse(outlet[i].V.begin(), outlet[i].V.end()); // from bus to pendant vertex diff --git a/main.cu b/main.cu index 81da29b..966358a 100644 --- a/main.cu +++ b/main.cu @@ -268,17 +268,16 @@ void glut_render() { else flow.glyph(color, subdivision); - flow.glSolidCuboid(manufacture, length); + flow.glSolidCuboid(flow_direction, subdivision, manufacture, length); if (render_direction) flow.glSolidCone(direction_index, scale, subdivision); } - if (build_inlet_outlet) { - flow.line_bridge(redisplay); - } - + if (build_inlet_outlet) + flow.line_bridge(redisplay, flow_direction); + if (manufacture) { - flow.glSolidCuboid(manufacture, length); + flow.glSolidCuboid(flow_direction, subdivision, manufacture, length); flow.tube_bridge(subdivision); } @@ -470,7 +469,8 @@ void glut_menu(int value) { flow_stable_state(); // main function of solving the linear system flow.print_flow(); - glut_set_menu(num, 2); + if (!flow_direction) + glut_set_menu(num, 2); } if (value == 2) { @@ -496,6 +496,7 @@ void glut_menu(int value) { simulation = false; build_inlet_outlet = false; manufacture = true; + flow_direction = false; // manufacuture mode doesn't need flow direction } if (value == 4) { @@ -855,10 +856,20 @@ void glut_keyboard(unsigned char key, int x, int y) { // flow vector field visualization, Glyphs case 'f': - if (flow_direction && !manufacture && (simulation || build_inlet_outlet)) + if (flow_direction && !manufacture && (simulation || build_inlet_outlet)) { flow_direction = false; - else if(!flow_direction && !manufacture && (simulation || build_inlet_outlet)) + redisplay = true; // lines and arrows rendering use the same display list + int num = glutGet(GLUT_MENU_NUM_ITEMS); + if (num == 1) + glut_set_menu(num, 2); + } + else if (!flow_direction && !manufacture && (simulation || build_inlet_outlet)) { flow_direction = true; + redisplay = true; + int num = glutGet(GLUT_MENU_NUM_ITEMS); + if (num == 2) + glut_set_menu(num, 1); + } break; // open/close index marks -- libgit2 0.21.4