From f4105b89553b247a70fe04555ee2a41a792899a8 Mon Sep 17 00:00:00 2001 From: Jiaming Guo Date: Wed, 24 May 2017 14:17:00 -0500 Subject: [PATCH] add new function: smooth colormap, manually change direct connection...etc --- flow.h | 357 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- main.cu | 262 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 573 insertions(+), 46 deletions(-) diff --git a/flow.h b/flow.h index ecaac39..f44b8ea 100644 --- a/flow.h +++ b/flow.h @@ -238,6 +238,8 @@ namespace stim { std::vector > Q; // volume flow rate std::vector QQ; // Q' vector std::vector pressure; // final pressure + std::vector > > in_backup; // inlet connection back up + std::vector > > out_backup; public: @@ -254,6 +256,10 @@ namespace stim { std::vector > B; // cone(cylinder) model for making image stack std::vector > CU; // cuboid model for making image stack stim::gl_aaboundingbox bb; // bounding box + std::vector inlet_feasibility; // list of flags indicate whether one inlet connection is feasible + std::vector outlet_feasibility; + std::vector, stim::vec3 > > inbb; // inlet connection bounding box + std::vector, stim::vec3 > > outbb; // outlet connection bounding box flow() {} // default constructor ~flow() { @@ -804,8 +810,8 @@ namespace stim { std::vector > cp2(subdivision + 1); for (unsigned i = 0; i < num_edge; i++) { // for every edge if (i == index) { // render in tranparency for direction indication - glEnable(GL_BLEND); // enable color blend - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // set blend function + glEnable(GL_BLEND); // enable color blend + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // set blend function glDisable(GL_DEPTH_TEST); glColor4f((float)color[i * 3 + 0] / 255, (float)color[i * 3 + 1] / 255, (float)color[i * 3 + 2] / 255, 0.5f); } @@ -1052,19 +1058,33 @@ namespace stim { } // draw the bridge as lines - void line_bridge() { + void line_bridge(bool &redisplay) { + + if (redisplay) + glDeleteLists(dlist, 1); + redisplay = false; if (!glIsList(dlist)) { dlist = glGenLists(1); glNewList(dlist, GL_COMPILE); - glColor3f(0.0f, 0.0f, 0.0f); + + glLineWidth(50); 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]); @@ -1255,6 +1275,7 @@ namespace stim { bool online = false; // flag indicates the point is on the line-segment float a, b; + // inner network for (unsigned i = 0; i < E.size(); i++) { for (unsigned j = 0; j < E[i].size() - 1; j++) { v1 = E[i][j + 1] - E[i][j]; // a -> b = ab @@ -1284,6 +1305,60 @@ namespace stim { } } + // inlet connection + for (unsigned i = 0; i < inlet.size(); i++) { + v1 = inlet[i].V[2] - inlet[i].V[1]; + v2 = v0 - inlet[i].V[1]; + v3 = v0 - inlet[i].V[2]; + + tmp_d = v2.dot(v1); // av·ab + + // check the line relative position + a = v2.dot(v1.norm()); + b = v3.dot(v1.norm()); + if (a < v1.len() && b < v1.len()) // if the length of projection fragment is longer than the line-segment + online = true; + else + online = false; + + if (tmp_d <= 0.0 || tmp_d > std::pow(v1.len(), 2) && !online) // projection lies outside the line-segment + continue; + else { + tmp_d = v1.cross(v2).len() / v1.len(); // perpendicular distance of point to segment: |v1 x v2| / |v1| + if (tmp_d < d) { + d = tmp_d; + tmp_i = i; + } + } + } + + // outlet connection + for (unsigned i = 0; i < outlet.size(); i++) { + v1 = outlet[i].V[2] - outlet[i].V[1]; + v2 = v0 - outlet[i].V[1]; + v3 = v0 - outlet[i].V[2]; + + tmp_d = v2.dot(v1); // av·ab + + // check the line relative position + a = v2.dot(v1.norm()); + b = v3.dot(v1.norm()); + if (a < v1.len() && b < v1.len()) // if the length of projection fragment is longer than the line-segment + online = true; + else + online = false; + + if (tmp_d <= 0.0 || tmp_d > std::pow(v1.len(), 2) && !online) // projection lies outside the line-segment + continue; + else { + tmp_d = v1.cross(v2).len() / v1.len(); // perpendicular distance of point to segment: |v1 x v2| / |v1| + if (tmp_d < d) { + d = tmp_d; + tmp_i = i; + } + } + } + eps += get_radius(tmp_i, tmp_j); if (d < eps) { @@ -1293,6 +1368,86 @@ namespace stim { return false; } + inline bool epsilon_edge(T x, T y, T z, T eps, unsigned &idx, unsigned &port) { + + T d = FLT_MAX; + T tmp_d; + unsigned tmp_i = 0; + stim::vec3 v1; + stim::vec3 v2; + stim::vec3 v3; + stim::vec3 v0 = stim::vec3(x, y, z); + bool online = false; // flag indicates the point is on the line-segment + float a, b; + + // inlet connection + for (unsigned i = 0; i < inlet.size(); i++) { + for (unsigned j = 0; j < inlet[i].V.size() - 1; j++) { + v1 = inlet[i].V[j + 1] - inlet[i].V[j]; + v2 = v0 - inlet[i].V[j]; + v3 = v0 - inlet[i].V[j + 1]; + + tmp_d = v2.dot(v1); // av·ab + + // check the line relative position + a = v2.dot(v1.norm()); + b = v3.dot(v1.norm()); + if (a < v1.len() && b < v1.len()) // if the length of projection fragment is longer than the line-segment + online = true; + else + online = false; + + if (tmp_d <= 0.0 || tmp_d > std::pow(v1.len(), 2) && !online) // projection lies outside the line-segment + continue; + else { + tmp_d = v1.cross(v2).len() / v1.len(); // perpendicular distance of point to segment: |v1 x v2| / |v1| + if (tmp_d < d) { + d = tmp_d; + tmp_i = i; + port = 0; + } + } + + } + } + + // outlet connection + for (unsigned i = 0; i < outlet.size(); i++) { + for (unsigned j = 0; j < outlet[i].V.size() - 1; j++) { + v1 = outlet[i].V[j + 1] - outlet[i].V[j]; + v2 = v0 - outlet[i].V[j]; + v3 = v0 - outlet[i].V[j + 1]; + + tmp_d = v2.dot(v1); // av·ab + + // check the line relative position + a = v2.dot(v1.norm()); + b = v3.dot(v1.norm()); + if (a < v1.len() && b < v1.len()) // if the length of projection fragment is longer than the line-segment + online = true; + else + online = false; + + if (tmp_d <= 0.0 || tmp_d > std::pow(v1.len(), 2) && !online) // projection lies outside the line-segment + continue; + else { + tmp_d = v1.cross(v2).len() / v1.len(); // perpendicular distance of point to segment: |v1 x v2| / |v1| + if (tmp_d < d) { + d = tmp_d; + tmp_i = i; + port = 1; + } + } + } + } + + if (d < eps) { + idx = tmp_i; + return true; + } + + return false; + } /// build main feeder connection // set up main feeder and main port of both input and output @@ -1404,6 +1559,8 @@ namespace stim { outlet.push_back(tmp_b); } + + backup(); } // find the number of U-shape or square-shape structure for extending length of connection @@ -1436,12 +1593,13 @@ namespace stim { int coef_z = (z) ? 1 : -1; // z coefficient int inverse = 1; // inverse flag stim::vec3 cor_v; // corner vertex - + std::pair, stim::vec3> tmp_bb; stim::vec3 tmp_v; - if (feeder == 1) + if (feeder == 1) tmp_v = inlet[i].V[0]; - else if (feeder == 0) + else if (feeder == 0) tmp_v = outlet[i].V[0]; + tmp_bb.first = tmp_v; // check whether the height of connections is acceptable if (height > threshold) { // acceptable @@ -1522,6 +1680,8 @@ namespace stim { inlet[i].V.push_back(tmp_v); else if (feeder == 0) outlet[i].V.push_back(tmp_v); + if (j == n - 1 && k == 0) // first time go "in" + tmp_bb.second = tmp_v; tmp_v = tmp_v + stim::vec3(0, inverse * coef_up * width, 0); if (feeder == 1) @@ -1555,7 +1715,7 @@ namespace stim { inverse = 1; } // if use fragment to do square wave connection, need to push_back the corner vertex - if (ratio > 0.0f && ratio <= 1.0f) { + if (ratio > 0.0f && ratio < 1.0f) { if (feeder == 1) inlet[i].V.push_back(cor_v); else if (feeder == 0) @@ -1565,25 +1725,30 @@ namespace stim { else { for (int j = 0; j < n; j++) { - // move in Z-shape + // up tmp_v = tmp_v + stim::vec3(0, coef_up * height, 0); if (feeder == 1) inlet[i].V.push_back(tmp_v); else if (feeder == 0) outlet[i].V.push_back(tmp_v); + // left tmp_v = tmp_v + stim::vec3(-coef_left * width, 0, 0); if (feeder == 1) inlet[i].V.push_back(tmp_v); else if (feeder == 0) outlet[i].V.push_back(tmp_v); + if (j == n - 1) + tmp_bb.second = tmp_v; + // down tmp_v = tmp_v + stim::vec3(0, -coef_up * height, 0); if (feeder == 1) inlet[i].V.push_back(tmp_v); else if (feeder == 0) outlet[i].V.push_back(tmp_v); + // left tmp_v = tmp_v + stim::vec3(-coef_left * width, 0, 0); if (feeder == 1) inlet[i].V.push_back(tmp_v); @@ -1591,6 +1756,10 @@ namespace stim { outlet[i].V.push_back(tmp_v); } } + if (feeder == 1) + inbb[i] = tmp_bb; + else if (feeder == 0) + outbb[i] = tmp_bb; } // automatically modify bridge to make it feasible @@ -1598,7 +1767,7 @@ namespace stim { glDeleteLists(dlist, 1); // delete display list for modify glDeleteLists(dlist + 1, 1); - + // because of radius change at the port vertex, there will be a pressure drop at that port // it follows the bernoulli equation // p1 + 1/2*rou*v1^2 + rou*g*h1 = p2 + 1/2*rou*v2^2 + rou*g*h2 @@ -1815,13 +1984,15 @@ namespace stim { // automatically modify inlet bridge using square shape constructions else { bool upper; // flag indicates the connection is upper than the bus - bool z; // flag indicates the connection direction along z-axis + bool z; // flag indicates the connection direction along z-axis T new_l; // new length stim::vec3 bus_v; // the port point on the bus stim::vec3 mid_v; // the original corner point stim::vec3 tmp_v; // the pendant point int n; T width, height; // width and height of the square + inbb.resize(inlet.size()); // resize bounding box of inlets/outlets connections + outbb.resize(outlet.size()); for (unsigned i = 0; i < inlet.size(); i++) { if (i != inlet_index) { @@ -1857,6 +2028,10 @@ namespace stim { std::reverse(inlet[i].V.begin(), inlet[i].V.end()); // from bus to pendant vertex } + else { + inbb[i].first = inlet[i].V[2]; + inbb[i].second = inlet[i].V[1]; + } } for (unsigned i = 0; i < outlet.size(); i++) { @@ -1893,35 +2068,159 @@ namespace stim { std::reverse(outlet[i].V.begin(), outlet[i].V.end()); // from bus to pendant vertex } + else { + outbb[i].first = outlet[i].V[2]; + outbb[i].second = outlet[i].V[1]; + } } } + + check_special_connection(); // check special connections } - // check current bridge to see feasibility - void check_synthetic_connection(T viscosity, T radius = 5.0f) { + /// check current connections to find overlapping + // phase 1 check -> direct connection intersection + void check_direct_connection() { - T eps = 0.01f; - T source_pressure = pressure[inlet[0].v[0]] + (8 * viscosity * inlet[0].l * inlet[0].Q) / ((float)stim::PI * std::pow(radius, 4)); - T tmp_p; - for (unsigned i = 1; i < inlet.size(); i++) { - tmp_p = pressure[inlet[i].v[0]] + (8 * viscosity * inlet[i].l * inlet[i].Q) / ((float)stim::PI * std::pow(radius, 4)); - T delta = fabs(tmp_p - source_pressure); - if (delta > eps) { - std::cout << "Nonfeasible connection!" << std::endl; - break; + unsigned num; + // check inlet + num = inlet.size(); + inlet_feasibility.resize(num, true); + for (unsigned i = 0; i < num; i++) { + for (unsigned j = 0; j < num; j++) { + if (i != j) { + if (inlet[i].V[0][2] == inlet[j].V[0][2]) { + 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][0] >= inlet[j].V[1][0] && fabs(inlet[i].V[1][1]) >= fabs(inlet[j].V[1][1]))) { + inlet_feasibility[i] = false; + break; + } + } + else + inlet_feasibility[i] = true; + } } } - source_pressure = pressure[outlet[0].v[0]] - (8 * viscosity * outlet[0].l * outlet[0].Q) / ((float)stim::PI * std::pow(radius, 4)); - for (unsigned i = 1; i < outlet.size(); i++) { - tmp_p = pressure[outlet[i].v[0]] - (8 * viscosity * outlet[i].l * outlet[i].Q) / ((float)stim::PI * std::pow(radius, 4)); - T delta = fabs(tmp_p - source_pressure); - if (delta > eps) { - std::cout << "Nonfeasible connection!" << std::endl; - break; + + // check outlet + num = outlet.size(); + outlet_feasibility.resize(num, true); + for (unsigned i = 0; i < num; i++) { + for (unsigned j = 0; j < num; j++) { + if (i != j) { + if (outlet[i].V[0][2] == outlet[j].V[0][2]) { + 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][0] >= outlet[j].V[1][0] && fabs(outlet[i].V[1][1]) <= fabs(outlet[j].V[1][1]))) { + outlet_feasibility[i] = false; + break; + } + } + else + outlet_feasibility[i] = true; + } + } + } + } + + // phase 2 check -> special connection intersection + void check_special_connection(T radius = 5.0f) { + + // temp AABB centers and halfwidths + stim::vec3 c1, c2; + stim::vec3 r1, r2; + // inlets' special connections checking + for (unsigned i = 0; i < inbb.size(); i++) { + for (unsigned j = 0; j < inbb.size(); j++) { + if (j != i) { + c1 = stim::vec3((inbb[i].first + inbb[i].second) / 2); + c2 = stim::vec3((inbb[j].first + inbb[j].second) / 2); + for (unsigned k = 0; k < 3; k++) { + r1[k] = fabs(inbb[i].first[k] - inbb[i].second[k]) / 2; + r2[k] = fabs(inbb[j].first[k] - inbb[j].second[k]) / 2; + } + // test AABBAABB + if (fabs(c1[0] - c2[0]) > (r1[0] + r2[0] + 2 * radius) || fabs(c1[1] - c2[1]) > (r1[1] + r2[1] + 2 * radius) || fabs(c1[2] - c2[2]) > (r1[2] + r2[2] + 2 * radius)) + inlet_feasibility[i] = true; + else + inlet_feasibility[i] = false; + } + } + } + + // outlets' special connections checking + for (unsigned i = 0; i < outbb.size(); i++) { + for (unsigned j = 0; j < outbb.size(); j++) { + if (j != i) { + c1 = stim::vec3((outbb[i].first + outbb[i].second) / 2); + c2 = stim::vec3((outbb[j].first + outbb[j].second) / 2); + for (unsigned k = 0; k < 3; k++) { + r1[k] = fabs(outbb[i].first[k] - outbb[i].second[k]) / 2; + r2[k] = fabs(outbb[j].first[k] - outbb[j].second[k]) / 2; + } + // test AABBAABB + if (fabs(c1[0] - c2[0]) > (r1[0] + r2[0] + 2 * radius) || fabs(c1[1] - c2[1]) > (r1[1] + r2[1] + 2 * radius) || fabs(c1[2] - c2[2]) > (r1[2] + r2[2] + 2 * radius)) + outlet_feasibility[i] = true; + else + outlet_feasibility[i] = false; + } + } + } + } + + // clear synthetic connections + void clear_synthetic_connection() { + + // restore direct synthetic connecions + T l = 0.0f; + for (unsigned i = 0; i < inlet.size(); i++) { + inlet[i].V.clear(); + for (unsigned j = 0; j < in_backup[i].size(); j++) { + inlet[i].V.push_back(in_backup[i][j]); + if (j != in_backup[i].size() - 1) + l += (in_backup[i][j + 1] - in_backup[i][j]).len(); + } + inlet[i].l = l; + l = 0.0f; + } + for (unsigned i = 0; i < outlet.size(); i++) { + outlet[i].V.clear(); + for (unsigned j = 0; j < out_backup[i].size(); j++) { + outlet[i].V.push_back(out_backup[i][j]); + if (j != out_backup[i].size() - 1) + l += (out_backup[i][j + 1] - out_backup[i][j]).len(); } + outlet[i].l = l; + l = 0.0f; } + + // clear up inlets/outlets connection bounding box + inbb.clear(); + outbb.clear(); } + // back up direct synthetic connection whenever modified + void backup() { + + in_backup.clear(); + out_backup.clear(); + + // back up direct synthetic connecions + std::vector > V; + for (unsigned i = 0; i < inlet.size(); i++) { + for (unsigned j = 0; j < inlet[i].V.size(); j++) { + V.push_back(inlet[i].V[j]); + } + in_backup.push_back(V); + V.clear(); + } + for (unsigned i = 0; i < outlet.size(); i++) { + for (unsigned j = 0; j < outlet[i].V.size(); j++) { + V.push_back(outlet[i].V[j]); + } + out_backup.push_back(V); + V.clear(); + } + } + + /// make binary image stack // prepare for image stack void preparation(T &Xl, T &Xr, T &Yt, T &Yb, T &Z, T length = 210.0f, T height = 10.0f) { diff --git a/main.cu b/main.cu index caac48a..d812ac7 100644 --- a/main.cu +++ b/main.cu @@ -46,6 +46,7 @@ float min_v; int mods; // special keyboard input std::vector color; // velocity color map std::vector velocity_bar; // velocity bar +float length = 210.0f; // cuboid length // hard-coded parameters float camera_factor = 1.2f; // start point of the camera as a function of X and Y size @@ -64,7 +65,9 @@ float fragment_ratio = 0.0f; // fragment ratio // glut event parameters int mouse_x; // window x-coordinate int mouse_y; // window y-coordinate -bool LTbutton = false; // true means down while false means up +int picked_x; // picked window x-coordinate +int picked_y; // picked window y-coordinate +bool LTbutton = false; // true means down while false means up // simulation parameters bool render_direction = false; // flag indicates rendering flow direction for one edge @@ -79,6 +82,14 @@ bool build_inlet_outlet = false; // flag indicates building inlets and outlets bool modified_bridge = false; // flag indicates having modified inlet/outlet connection bool hilbert_curve = false; // flag indicates enabling hilbert curves constructions bool change_fragment = false; // flag indicates changing fragment for square wave connections +bool picked_connection = false; // flag indicates picked one connection +bool render_new_connection = false; // flag indicates rendering new line connection in trasparency +bool redisplay = false; // flag indicates redisplay rendering +bool connection_done = false; // flag indicates finishing connections +unsigned connection_index = -1; // the index of connection that is picked +unsigned port_index = 0; // inlet (0) or outlet (1) +stim::vec3 tmp_v1, tmp_v2; // temp vertex +int coef; // computational coefficient factor // manufacture parameters bool manufacture = false; // flag indicates manufacture mode @@ -211,19 +222,41 @@ void glut_render() { flow.mark_vertex(); //flow.glSolidCone(subdivision); flow.glSolidCylinder(direction_index, color, subdivision); - flow.glSolidCuboid(); + flow.glSolidCuboid(length); if (render_direction) flow.glSolidCone(direction_index, subdivision); } if (build_inlet_outlet) { - flow.line_bridge(); + flow.line_bridge(redisplay); } if (manufacture) { flow.glSolidCuboid(); flow.tube_bridge(subdivision); } + + if (picked_connection && render_new_connection) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4f(0.0f, 0.0f, 0.0f, 0.4f); + glBegin(GL_LINE_STRIP); + if (!port_index) { + glVertex3f(flow.inlet[connection_index].V[1][0], flow.inlet[connection_index].V[1][1], flow.inlet[connection_index].V[1][2]); + glVertex3f(tmp_v1[0], tmp_v1[1], tmp_v1[2]); + glVertex3f(tmp_v2[0], tmp_v2[1], tmp_v2[2]); + glVertex3f(flow.inlet[connection_index].V[2][0], flow.inlet[connection_index].V[2][1], flow.inlet[connection_index].V[2][2]); + } + else { + glVertex3f(flow.outlet[connection_index].V[1][0], flow.outlet[connection_index].V[1][1], flow.outlet[connection_index].V[1][2]); + glVertex3f(tmp_v1[0], tmp_v1[1], tmp_v1[2]); + glVertex3f(tmp_v2[0], tmp_v2[1], tmp_v2[2]); + glVertex3f(flow.outlet[connection_index].V[2][0], flow.outlet[connection_index].V[2][1], flow.outlet[connection_index].V[2][2]); + } + glEnd(); + glFlush(); + glDisable(GL_BLEND); + } // render bars // bring up a pressure bar on left @@ -287,12 +320,13 @@ void glut_render() { glLoadIdentity(); float step = (vY - 3 * border_factor); - step /= num_edge; - for (unsigned i = 0; i < num_edge; i++) { + step /= BREWER_CTRL_PTS - 1; + for (unsigned i = 0; i < BREWER_CTRL_PTS - 1; i++) { glLineWidth(border_factor); glBegin(GL_LINES); - glColor3f((float)color[velocity_bar[i] * 3 + 0] / 255, (float)color[velocity_bar[i] * 3 + 1] / 255, (float)color[velocity_bar[i] * 3 + 2] / 255); + glColor3f(BREWERCP[i * 4 + 0], BREWERCP[i * 4 + 1], BREWERCP[i * 4 + 2]); glVertex2f(border_factor, border_factor + i * step); + glColor3f(BREWERCP[(i + 1) * 4 + 0], BREWERCP[(i + 1) * 4 + 1], BREWERCP[(i + 1) * 4 + 2]); glVertex2f(border_factor, border_factor + (i + 1) * step); glEnd(); } @@ -376,6 +410,7 @@ void glut_menu(int value) { build_inlet_outlet = false; manufacture = false; modified_bridge = false; + connection_done = false; if (!flow.set) flow_initialize(); flow_stable_state(); // main function of solving the linear system @@ -388,9 +423,16 @@ void glut_menu(int value) { simulation = false; build_inlet_outlet = true; manufacture = false; - if (!modified_bridge) { + if (!modified_bridge && !connection_done) { flow.set_main_feeder(); flow.build_synthetic_connection(u, default_radius); + flow.check_direct_connection(); // check whether direct connections intersect each other + connection_done = true; + } + else if (modified_bridge) { + modified_bridge = false; + redisplay = true; + flow.clear_synthetic_connection(); } glut_set_menu(num, 3); @@ -400,7 +442,6 @@ void glut_menu(int value) { simulation = false; build_inlet_outlet = false; manufacture = true; - flow.check_synthetic_connection(u, default_radius); } glutPostRedisplay(); @@ -426,40 +467,99 @@ void glut_motion(int x, int y) { // defines passive mouse motion function void glut_passive_motion(int x, int y) { - mouse_x = x; - mouse_y = y; + mods = glutGetModifiers(); // check whether the mouse point near to an edge GLdouble posX, posY, posZ; window_to_world(posX, posY, posZ); // get the world coordinates - if (simulation || build_inlet_outlet) { + if (simulation || build_inlet_outlet && !mods) { bool flag = flow.epsilon_edge((float)posX, (float)posY, (float)posZ, eps, direction_index); if (flag) render_direction = true; else { if (render_direction) // if the direction is displaying currently, do a short delay - Sleep(1000); + Sleep(300); render_direction = false; direction_index = -1; } } - glutPostRedisplay(); // re-draw the visualization + if (mods == GLUT_ACTIVE_SHIFT && picked_connection) { + render_new_connection = true; + unsigned i; + if (!port_index) { + tmp_v1 = stim::vec3(flow.inlet[connection_index].V[1][0], flow.inlet[connection_index].V[1][1] + (float)(picked_y - y), flow.inlet[connection_index].V[1][2]); + tmp_v2 = stim::vec3(flow.inlet[connection_index].V[2][0], flow.inlet[connection_index].V[2][1] + (float)(picked_y - y), flow.inlet[connection_index].V[2][2]); + i = flow.inlet[connection_index].V.size(); + if (coef * tmp_v1[1] < coef * flow.inlet[connection_index].V[i - 1][1]) { + tmp_v1[1] = flow.inlet[connection_index].V[i - 1][1]; + tmp_v2[1] = flow.inlet[connection_index].V[i - 1][1]; + } + } + else { + tmp_v1 = stim::vec3(flow.outlet[connection_index].V[1][0], flow.outlet[connection_index].V[1][1] + (float)(picked_y - y), flow.outlet[connection_index].V[1][2]); + tmp_v2 = stim::vec3(flow.outlet[connection_index].V[2][0], flow.outlet[connection_index].V[2][1] + (float)(picked_y - y), flow.outlet[connection_index].V[2][2]); + i = flow.outlet[connection_index].V.size(); + if (coef * tmp_v1[1] < coef * flow.outlet[connection_index].V[i - 1][1]) { + tmp_v1[1] = flow.outlet[connection_index].V[i - 1][1]; + tmp_v2[1] = flow.outlet[connection_index].V[i - 1][1]; + } + } + } + else if (mods == GLUT_ACTIVE_CTRL && picked_connection) { + render_new_connection = true; + if (!port_index) { + tmp_v1 = stim::vec3(flow.inlet[connection_index].V[0][0] + (float)(x - picked_x), flow.inlet[connection_index].V[0][1], flow.inlet[connection_index].V[0][2]); + tmp_v2 = stim::vec3(flow.inlet[connection_index].V[1][0] + (float)(x - picked_x), flow.inlet[connection_index].V[1][1], flow.inlet[connection_index].V[1][2]); + if (tmp_v1[0] < flow.main_feeder[port_index][0] - length / 2) { + tmp_v1[0] = flow.main_feeder[port_index][0] - length / 2; + tmp_v2[0] = flow.main_feeder[port_index][0] - length / 2; + } + else if (tmp_v1[0] > flow.main_feeder[port_index][0] + length / 2) { + tmp_v1[0] = flow.main_feeder[port_index][0] + length / 2; + tmp_v2[0] = flow.main_feeder[port_index][0] + length / 2; + } + } + else { + tmp_v1 = stim::vec3(flow.outlet[connection_index].V[0][0] + (float)(x - picked_x), flow.outlet[connection_index].V[0][1], flow.outlet[connection_index].V[0][2]); + tmp_v2 = stim::vec3(flow.outlet[connection_index].V[1][0] + (float)(x - picked_x), flow.outlet[connection_index].V[1][1], flow.outlet[connection_index].V[1][2]); + if (tmp_v1[0] > flow.main_feeder[port_index][0] + length / 2) { + tmp_v1[0] = flow.main_feeder[port_index][0] + length / 2; + tmp_v2[0] = flow.main_feeder[port_index][0] + length / 2; + } + else if (tmp_v1[0] < flow.main_feeder[port_index][0] - length / 2) { + tmp_v1[0] = flow.main_feeder[port_index][0] - length / 2; + tmp_v2[0] = flow.main_feeder[port_index][0] - length / 2; + } + } + } + else + render_new_connection = false; + + mouse_x = x; + mouse_y = y; + + glutPostRedisplay(); // re-draw the visualization } // get click window coordinates void glut_mouse(int button, int state, int x, int y) { + mods = glutGetModifiers(); // get special keyboard input + mouse_x = x; mouse_y = y; + if (!mods) { + picked_connection = false; + render_new_connection = false; + } if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) LTbutton = true; else if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) LTbutton = false; - if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && simulation && !to_select_pressure) { - + if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !mods && simulation && !to_select_pressure) { GLdouble posX, posY, posZ; window_to_world(posX, posY, posZ); // get the world coordinates @@ -470,7 +570,7 @@ void glut_mouse(int button, int state, int x, int y) { to_select_pressure = true; } } - else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && simulation && to_select_pressure) { + else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !mods && simulation && to_select_pressure) { if (y > 2 * border_factor || y < vY - border_factor) { // within the pressure bar range to_select_pressure = false; float tmp_pressure = (float)(vY - y - border_factor) / ((float)vY - border_factor) * max_pressure; @@ -480,13 +580,141 @@ void glut_mouse(int button, int state, int x, int y) { flow.print_flow(); } } - else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && modified_bridge && change_fragment) { + else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !mods && modified_bridge && change_fragment) { if (y > 2 * border_factor || y < vY - border_factor) { // within the ratio bar range fragment_ratio = (float)(vY - y - border_factor) / ((float)vY - border_factor) * 1.0f; flow.modify_synthetic_connection(u, rou, hilbert_curve, height_threshold, fragment_ratio, default_radius); change_fragment = false; } } + // move connections along y-axis + else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && mods == GLUT_ACTIVE_SHIFT && !modified_bridge && !picked_connection) { + GLdouble posX, posY, posZ; + window_to_world(posX, posY, posZ); // get the world coordinates + + bool flag = flow.epsilon_edge((float)posX, (float)posY, (float)posZ, eps, connection_index, port_index); + if (flag) { + picked_connection = true; + picked_x = x; + picked_y = y; + if (!port_index) + if (flow.inlet[connection_index].V[2][1] > flow.main_feeder[port_index][1]) + coef = 1; + else + coef = -1; + else + if (flow.outlet[connection_index].V[2][1] > flow.main_feeder[port_index][1]) + coef = 1; + else + coef = -1; + } + else + picked_connection = false; + } + else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && mods == GLUT_ACTIVE_SHIFT && !modified_bridge && render_new_connection) { + float l = 0.0f; + std::vector > V; + unsigned i; + if (!port_index) { + i = flow.inlet[connection_index].V.size(); + if (tmp_v2[1] != flow.inlet[connection_index].V[i - 1][1]) { + V.resize(4); + V[0] = flow.inlet[connection_index].V[0]; + V[1] = tmp_v1; + V[2] = tmp_v2; + V[3] = flow.inlet[connection_index].V[i - 1]; + std::swap(flow.inlet[connection_index].V, V); + } + else { + V.resize(3); + V[0] = flow.inlet[connection_index].V[0]; + V[1] = tmp_v1; + V[2] = tmp_v2; + std::swap(flow.inlet[connection_index].V, V); + } + // calculate new length + for (unsigned i = 0; i < flow.inlet[connection_index].V.size() - 1; i++) { + l += (flow.inlet[connection_index].V[i + 1] - flow.inlet[connection_index].V[i]).len(); + } + flow.inlet[connection_index].l = l; + } + else { + i = flow.outlet[connection_index].V.size(); + if (tmp_v2[1] != flow.outlet[connection_index].V[i - 1][1]) { + V.resize(4); + V[0] = flow.outlet[connection_index].V[0]; + V[1] = tmp_v1; + V[2] = tmp_v2; + V[3] = flow.outlet[connection_index].V[i - 1]; + std::swap(flow.outlet[connection_index].V, V); + } + else { + V.resize(3); + V[0] = flow.outlet[connection_index].V[0]; + V[1] = tmp_v1; + V[2] = tmp_v2; + std::swap(flow.outlet[connection_index].V, V); + } + // calculate new length + for (unsigned i = 0; i < flow.outlet[connection_index].V.size() - 1; i++) { + l += (flow.outlet[connection_index].V[i + 1] - flow.outlet[connection_index].V[i]).len(); + } + flow.outlet[connection_index].l = l; + } + + redisplay = true; + render_new_connection = false; + picked_connection = false; + + flow.check_direct_connection(); + flow.backup(); // back up direct synthetic connections + } + // move connections along x-axis + else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && mods == GLUT_ACTIVE_CTRL && !modified_bridge && !picked_connection) { + GLdouble posX, posY, posZ; + window_to_world(posX, posY, posZ); // get the world coordinates + + bool flag = flow.epsilon_edge((float)posX, (float)posY, (float)posZ, eps, connection_index, port_index); + if (flag) { + picked_connection = true; + picked_x = x; + picked_y = y; + if (!port_index) + coef = 1; + else + coef = -1; + } + else + picked_connection = false; + } + else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && mods == GLUT_ACTIVE_CTRL && !modified_bridge && render_new_connection) { + float l = 0.0f; + if (!port_index) { + flow.inlet[connection_index].V[0] = tmp_v1; + flow.inlet[connection_index].V[1] = tmp_v2; + // calculate new length + for (unsigned i = 0; i < flow.inlet[connection_index].V.size() - 1; i++) { + l += (flow.inlet[connection_index].V[i + 1] - flow.inlet[connection_index].V[i]).len(); + } + flow.inlet[connection_index].l = l; + } + else { + flow.outlet[connection_index].V[0] = tmp_v1; + flow.outlet[connection_index].V[1] = tmp_v2; + // calculate new length + for (unsigned i = 0; i < flow.outlet[connection_index].V.size() - 1; i++) { + l += (flow.outlet[connection_index].V[i + 1] - flow.outlet[connection_index].V[i]).len(); + } + flow.outlet[connection_index].l = l; + } + + redisplay = true; + render_new_connection = false; + picked_connection = false; + + flow.check_direct_connection(); + flow.backup(); + } } // define camera move based on mouse wheel move -- libgit2 0.21.4