diff --git a/.gitignore b/.gitignore index 0d023b3..5a3680e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +Build/ DSC.xcodeproj/xcuserdata/asny.xcuserdatad/xcschemes/xcschememanagement.plist @@ -14,3 +15,5 @@ DSC.xcodeproj/project.xcworkspace/xcuserdata/asny.xcuserdatad/UserInterfaceState DSC.xcodeproj/xcuserdata/asny.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist DSC.xcodeproj/xcuserdata/asny.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist + +*userdata* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1da58c5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.6) +project(2D-DSC) + +set(CMAKE_CXX_STANDARD 14) + +if (APPLE) + # TODO for Mac +endif (APPLE) + +if (UNIX) + # TODO for UNix +endif (UNIX) +if(WIN32) + # TODO for Windows +endif() + + +aux_source_directory(./src SRC) + +include_directories(../GEL/src/GEL) + +link_directories(../GEL) + +add_library(2D-DSC SHARED ${SRC}) +target_link_libraries(2D-DSC GEL) \ No newline at end of file diff --git a/DSC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/DSC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/DSC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/DSC.xcodeproj/project.xcworkspace/xcuserdata/tuannt8.xcuserdatad/UserInterfaceState.xcuserstate b/DSC.xcodeproj/project.xcworkspace/xcuserdata/tuannt8.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..380ddb8 Binary files /dev/null and b/DSC.xcodeproj/project.xcworkspace/xcuserdata/tuannt8.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/DSC.xcodeproj/xcuserdata/tuannt8.xcuserdatad/xcschemes/DSC.xcscheme b/DSC.xcodeproj/xcuserdata/tuannt8.xcuserdatad/xcschemes/DSC.xcscheme new file mode 100644 index 0000000..a4363a7 --- /dev/null +++ b/DSC.xcodeproj/xcuserdata/tuannt8.xcuserdatad/xcschemes/DSC.xcscheme @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DSC.xcodeproj/xcuserdata/tuannt8.xcuserdatad/xcschemes/xcschememanagement.plist b/DSC.xcodeproj/xcuserdata/tuannt8.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..97c4917 --- /dev/null +++ b/DSC.xcodeproj/xcuserdata/tuannt8.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + DEMO.xcscheme + + orderHint + 3 + + DEMO.xcscheme_^#shared#^_ + + orderHint + 3 + + DSC.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 7A51F3D417D6399200A8F8F2 + + primary + + + + + diff --git a/src/DSC.cpp b/src/DSC.cpp index 30ccb7e..beddeb1 100644 --- a/src/DSC.cpp +++ b/src/DSC.cpp @@ -36,7 +36,7 @@ namespace DSC2D INTERFACE_COLOR = DARK_RED; CROSSING_COLOR = RED; - OUTSIDE_COLOR = BLACK; + OUTSIDE_COLOR = GRAY; DEFAULT_COLOR = DARK_BLUE; OUTSIDE_FACE_COLOR = INVISIBLE; DEFAULT_FACE_COLOR = BLUE; @@ -126,7 +126,7 @@ namespace DSC2D mesh->build(points.size()/3, &points[0], temp.size(), &temp[0], &faces[0]); } - void DeformableSimplicialComplex::validity_check() + void DeformableSimplicialComplex::validity_check() const { for (auto fi = faces_begin(); fi != faces_end(); fi++) { int i = 0; @@ -186,19 +186,20 @@ namespace DSC2D bool DeformableSimplicialComplex::move_vertex(node_key vid) { + vec2 pos = get_pos(vid); vec2 destination = get_destination(vid); real l = Util::length(destination - pos); - if (l < 1e-4 * AVG_LENGTH) + if (l < 1e-6 * AVG_LENGTH) { return true; } - real max_l = l*intersection_with_link(vid, destination) - 1e-4 * AVG_LENGTH; + real max_l = l*intersection_with_link(vid, destination) - 1e-6 * AVG_LENGTH; l = Util::max(Util::min(0.5*max_l, l), 0.); set_pos(vid, pos + l*Util::normalize(destination - pos)); - if(Util::length(destination - get_pos(vid)) < 1e-4 * AVG_LENGTH) + if(Util::length(destination - get_pos(vid)) < 1e-6 * AVG_LENGTH) { return true; } @@ -209,12 +210,12 @@ namespace DSC2D { bool work = true; int count = 0; - while(work && count < 10) + while(work && count < 50) { work = false; for (auto vi = vertices_begin(); vi != vertices_end(); vi++) { - if(is_movable(*vi)) + if(is_movable(*vi)&&is_interface(*vi)) { work = work | !move_vertex(*vi); } @@ -223,9 +224,11 @@ namespace DSC2D fix_complex(); count++; } - + resize_complex(); +// remove_needles(); + HMesh::IDRemap cleanup_map; cleanup_attributes(cleanup_map); @@ -291,6 +294,19 @@ namespace DSC2D return p; } + std::vector DeformableSimplicialComplex::get_design_variable_destinations() + { + std::vector p; + for (auto vi = vertices_begin(); vi != vertices_end(); vi++) + { + if(is_movable(*vi)) + { + p.push_back(get_destination(*vi)); + } + } + return p; + } + std::vector DeformableSimplicialComplex::get_interface_edge_positions() { std::vector p; @@ -305,6 +321,21 @@ namespace DSC2D } return p; } + + std::vector DeformableSimplicialComplex::get_interface_edge_destinations() + { + std::vector p; + for (auto eit = halfedges_begin(); eit != halfedges_end(); eit++) + { + if(is_interface(*eit)) + { + auto hew = walker(*eit); + p.push_back(get_destination(hew.vertex())); + p.push_back(get_destination(hew.opp().vertex())); + } + } + return p; + } vec2 DeformableSimplicialComplex::get_center() { @@ -326,6 +357,13 @@ namespace DSC2D return positions; } + std::vector DeformableSimplicialComplex::get_pos(edge_key eid) const + { + auto hew = walker(eid); + + return {get_pos(hew.vertex()), get_pos(hew.opp().vertex())}; + } + vec2 DeformableSimplicialComplex::get_destination(node_key vid) const { return vec2(destination[vid]); @@ -399,10 +437,10 @@ namespace DSC2D void DeformableSimplicialComplex::set_destination(const node_key& vid, const vec2& dest) { - if(is_movable(vid)) + // if(is_movable(vid)) { vec2 vec = dest - get_pos(vid); - clamp_vector(vid, vec); + // clamp_vector(vid, vec); destination[vid] = get_pos(vid) + vec; } } @@ -539,9 +577,10 @@ namespace DSC2D } - bool DeformableSimplicialComplex::split(edge_key eid) + bool DeformableSimplicialComplex::split(edge_key eid, node_key * n) { - if (!unsafe_editable(eid)) { + if (!unsafe_editable(eid)) + { return false; } @@ -569,6 +608,10 @@ namespace DSC2D init_attributes(newf2, get_label(f2)); update_locally(vid); + + if(n) + *n = vid; + return true; } @@ -589,7 +632,7 @@ namespace DSC2D return true; } - real DeformableSimplicialComplex::min_quality(const std::vector& eids, const vec2& pos_old, const vec2& pos_new) + real DeformableSimplicialComplex::min_quality(const std::vector& eids, const vec2& pos_old, const vec2& pos_new) const { real min_q = INFINITY; for (auto e : eids) @@ -605,7 +648,7 @@ namespace DSC2D return min_q; } - bool DeformableSimplicialComplex::is_collapsable(HMesh::Walker hew, bool safe) + bool DeformableSimplicialComplex::is_collapsable(HMesh::Walker hew, bool safe) const { if(safe) { @@ -770,13 +813,13 @@ namespace DSC2D return Util::length(get_destination(hew.vertex()) - get_destination(hew.opp().vertex())); } - real DeformableSimplicialComplex::min_edge_length(face_key fid) + real DeformableSimplicialComplex::min_edge_length(face_key fid) const { std::vector p = get_pos(fid); return Util::min(Util::min(Util::length(p[0] - p[1]), Util::length(p[1] - p[2])), Util::length(p[0] - p[2])); } - real DeformableSimplicialComplex::min_angle(face_key fid) + real DeformableSimplicialComplex::min_angle(face_key fid) const { std::vector p = get_pos(fid); return Util::min_angle(p[0], p[1], p[2]); @@ -1196,7 +1239,7 @@ namespace DSC2D } } - + bool operator<(const DeformableSimplicialComplex::PQElem& e0, const DeformableSimplicialComplex::PQElem& e1) { return e0.pri > e1.pri; @@ -1215,7 +1258,6 @@ namespace DSC2D if((energy<0) && (t < 10000)){ Q.push(PQElem(energy, h, t)); } - } void DeformableSimplicialComplex::add_one_ring_to_queue(HMesh::HalfEdgeAttributeVector& touched, std::priority_queue& Q, node_key v, const HMesh::EnergyFun& efun) @@ -1263,4 +1305,4 @@ namespace DSC2D priority_queue_optimization(energy_fun); } -} \ No newline at end of file +} diff --git a/src/DSC.h b/src/DSC.h index 0dbe807..33795bf 100644 --- a/src/DSC.h +++ b/src/DSC.h @@ -28,9 +28,10 @@ #include #endif +#define EPSILON 1e-9 namespace DSC2D { - + /** The base class representing a simplicial complex. @@ -84,6 +85,7 @@ namespace DSC2D { vec3 DEFAULT_FACE_COLOR; private: + public: HMesh::Manifold *mesh; DesignDomain *design_domain; @@ -131,7 +133,7 @@ namespace DSC2D { //************** ATTRIBUTE FUNCTIONS *************** protected: - + public: /** Clean up the attribute vectors (the lists that stores the attributes of each vertex, edge and face). Should be called after removing primitives. */ @@ -184,7 +186,7 @@ namespace DSC2D { /** Updates face, edge and vertex attributes. */ - void update_attributes(); + void update_attributes(); // It should be protected, but keep it public for the backforward compatibility. (Haojie). //************** GETTERS *************** @@ -198,6 +200,56 @@ namespace DSC2D { return AVG_LENGTH; } + real get_min_edge_length() const + { + return MIN_LENGTH; + } + + real get_deg_edge_length() const + { + return DEG_LENGTH; + } + + real get_max_edge_length() const + { + return MAX_LENGTH; + } + + real get_avg_area() const + { + return AVG_AREA; + } + + real get_min_area() const + { + return MIN_AREA; + } + + real get_deg_area() const + { + return DEG_AREA; + } + + real get_max_area() const + { + return MAX_AREA; + } + + real get_min_angle() const + { + return MIN_ANGLE; + } + + real get_deg_angle() const + { + return DEG_ANGLE; + } + + real get_cos_min_angle() const + { + return COS_MIN_ANGLE; + } + /** Returns the approximate center of the simplicial complex. */ @@ -248,6 +300,11 @@ namespace DSC2D { */ vec2 get_pos(node_key vid) const; + /** + Returns the positions of the vertices of the edge with ID eid. + */ + std::vector get_pos(edge_key eid) const; + /** Returns the positions of the vertices of the face with ID fid. */ @@ -345,6 +402,11 @@ namespace DSC2D { return mesh->vertices_end(); } + HMesh::IDIteratorPair vertices() const + { + return mesh->vertices(); + } + HMesh::HalfEdgeIDIterator halfedges_begin() const { return mesh->halfedges_begin(); @@ -355,6 +417,11 @@ namespace DSC2D { return mesh->halfedges_end(); } + HMesh::IDIteratorPair halfedges() const + { + return mesh->halfedges(); + } + HMesh::FaceIDIterator faces_begin() const { return mesh->faces_begin(); @@ -365,6 +432,12 @@ namespace DSC2D { return mesh->faces_end(); } + HMesh::IDIteratorPair faces() const + { + return mesh->faces(); + } + + HMesh::Walker walker(node_key vid) const { return mesh->walker(vid); @@ -517,7 +590,8 @@ namespace DSC2D { */ void deform(); - private: + protected: + public: /** Moves a the vertex with ID vid to its new position. Returns whether the vertex was succesfully moved to its new position. @@ -532,7 +606,7 @@ namespace DSC2D { /** Splits the edge eid by inserting a vertex at the center of the edge and splitting the two neighbouring faces of the edge. Returns whether it suceeds or not. */ - bool split(edge_key eid); + bool split(edge_key eid, node_key * n = nullptr); /** Collapses the edge with ID eid and updates attributes. If safe is true, the collapse will affect the shape of the interface minimally. Returns whether it suceeds or not. @@ -553,6 +627,7 @@ namespace DSC2D { //************** QUALITY CONTROL *************** protected: + public: /** Improves the quality of the simplicial complex by smoothing, removing needles and caps, maximize the minimum angle and removing degenerate faces. */ @@ -569,6 +644,7 @@ namespace DSC2D { void priority_queue_optimization(const HMesh::EnergyFun& efun); private: + public: /** Maximize minimum angles using greedy approach by flipping edges. */ @@ -630,32 +706,32 @@ namespace DSC2D { void thickening(); //************** UTIL *************** - private: + protected: /** Checks that the mesh is valid, i.e. that each face has three vertices and that the area of a face is positive (the face is not degenerate). */ - void validity_check(); + void validity_check() const; /** Returns the minimum angle of the face with ID fid. */ - real min_angle(face_key fid); + real min_angle(face_key fid) const; /** Returns the minimum edge length of the edges of the face with ID fid. */ - real min_edge_length(face_key fid); + real min_edge_length(face_key fid) const; /** * Returns the new minimum face quality (minimum angle) when moving a node from old_pos to new_pos. The edges in the link of the node should be passed in eids. */ - real min_quality(const std::vector& eids, const vec2& pos_old, const vec2& pos_new); + real min_quality(const std::vector& eids, const vec2& pos_old, const vec2& pos_new) const; /** Returns whether the half edge is possible to collapse. */ - bool is_collapsable(HMesh::Walker hew, bool safe); + bool is_collapsable(HMesh::Walker hew, bool safe) const; public: /** @@ -683,11 +759,15 @@ namespace DSC2D { */ std::vector get_design_variable_positions(); + std::vector get_design_variable_destinations(); + /** Returns the positions of the interface edges. */ std::vector get_interface_edge_positions(); + std::vector get_interface_edge_destinations(); + /** Returns the maximum distance a vertex is supposed to be moved (the distance between its new and old position). Should be called before move_vertices(). @@ -752,4 +832,4 @@ namespace DSC2D { }; -} \ No newline at end of file +}; diff --git a/src/design_domain.cpp b/src/design_domain.cpp index 7b0ddc9..aab6db4 100644 --- a/src/design_domain.cpp +++ b/src/design_domain.cpp @@ -56,6 +56,21 @@ namespace DSC2D { void DesignDomain::clamp_vector(const vec2& p, vec2& v) const { +// if (!is_inside(p)) +// { +// vec2 pc = p; +// clamp_position(pc); +// +// real distance_now = sqr_length(p - pc); +// real distance_future = sqr_length(p + v - pc); +// +// if (distance_future > distance_now) +// { +// v = vec2(0, 0); +// } +// return; +// } + if(!is_inside(p+v)) { vec2 c0, c1; @@ -64,8 +79,34 @@ namespace DSC2D { { c0 = corners[i]; c1 = corners[(i+1)%corners.size()]; + + // Haojie Added + real x = Util::cross(c0-p, c1-c0); + real y = Util::cross(v, c1-c0); + if(std::abs(y) < EPSILON) // v and the segment are parallel if true + { + if(std::abs(x) < EPSILON) // v and the segment are collinear if true + { + if ( dot(c0-p, c1-p) <= 0 ) + { + if( (p+v-c1).length() <= (p+v-c0).length()) + { + v = c1 - p; + } + else + { + v = c0 - p; + } + + return; + } + } + } + // Haojie finished the added code segement. + t = Util::intersection_ray_ray(p, v, c0, c1 - c0); - if(t >= 0. && t < 1.) + // if(t >= 0. && t < 1.) + if ( ( t>=0 && t < 1. ) || std::abs(t)< EPSILON ) { v = t*v; } @@ -78,12 +119,22 @@ namespace DSC2D { return Util::is_inside(p, corners); } + bool DesignDomain::on_boundary(const vec2& p) const + { + return Util::on_boundary(p, corners); + } + std::vector DesignDomain::get_corners() const { return corners; } - vec2 DesignDomain::get_center() + std::vector > DesignDomain::get_subdomain_corners() const + { + return subdomain_corners; + } + + vec2 DesignDomain::get_center() const { vec2 center(0.); for (int i = 0; i < corners.size(); i++) @@ -95,29 +146,62 @@ namespace DSC2D { real DesignDomain::get_volume() { +// if(volume < 0.) +// { +// volume = 0.; +// std::vector c(corners); +// vec2 c0, c1, c2; +// while(c.size() > 2) +// { +// int i = 0; +// do { +//#ifdef DEBUG +// assert(i < c.size()); +//#endif +// c0 = c[i]; +// c1 = c[(i+1)%c.size()]; +// c2 = c[(i+2)%c.size()]; +// i++; +// } while (Util::is_left_of(c0,c1,c2)); +// +// volume += std::abs(Util::signed_area(c0, c1, c2)); +// c.erase(c.begin() + (i%c.size())); +// } +// } + if(volume < 0.) { - volume = 0.; std::vector c(corners); - vec2 c0, c1, c2; - while(c.size() > 2) + c.push_back(corners[0]); + + double sum1 = 0; + double sum2 = 0; + + for (int i=0; i c(corners); + c.push_back(corners[0]); + + double perimeter = 0; + + for (int i=0; i corners; // Specified in a clockwise order + std::vector > subdomain_corners; real volume = -1.; + std::string name; + double mWidth; + double mHeight; public: - enum DESIGN_DOMAIN_TYPE {RECTANGLE, L, ESO}; + enum DESIGN_DOMAIN_TYPE {RECTANGLE, L, ESO, PORTAL}; /** Creates a design domain defined by the design domain type and size. It is possible to specify a boundary gap which translates the entire domain by the amount specified by the input parameter. */ - DesignDomain(DESIGN_DOMAIN_TYPE design, int SIZE_X, int SIZE_Y, real boundary) + + DesignDomain(DESIGN_DOMAIN_TYPE design, int SIZE_X, int SIZE_Y, real boundary1, real boundary2) { - switch (design) { + mWidth = SIZE_X; + mHeight = SIZE_Y; + switch (design) + { case RECTANGLE: + name = "RECTANGLE"; corners.push_back(vec2(0.,0.)); corners.push_back(vec2(0., SIZE_Y)); corners.push_back(vec2(SIZE_X, SIZE_Y)); corners.push_back(vec2(SIZE_X, 0.)); + subdomain_corners.push_back(corners); break; case L: + name = "L"; corners.push_back(vec2(0.,0.)); corners.push_back(vec2(0., SIZE_Y)); corners.push_back(vec2(0.4*SIZE_X, SIZE_Y)); corners.push_back(vec2(0.4*SIZE_X, 0.4*SIZE_Y)); corners.push_back(vec2(SIZE_X, 0.4*SIZE_Y)); corners.push_back(vec2(SIZE_X, 0.)); + subdomain_corners.push_back(corners); break; case ESO: + name = "ESO"; corners.push_back(vec2(0.,0.)); corners.push_back(vec2(0., 3.*SIZE_Y/7.)); corners.push_back(vec2(30.*SIZE_X/32., 3.*SIZE_Y/7.)); @@ -60,31 +73,309 @@ namespace DSC2D { corners.push_back(vec2(31.*SIZE_X/32., 3.*SIZE_Y/7.)); corners.push_back(vec2(SIZE_X, 3.*SIZE_Y/7.)); corners.push_back(vec2(SIZE_X, 0.)); + subdomain_corners.push_back(corners); + break; + case PORTAL: + name = "PORTAL"; + corners.push_back(vec2(0.,0.)); + corners.push_back(vec2(0., SIZE_Y)); + corners.push_back(vec2(SIZE_X, SIZE_Y)); + corners.push_back(vec2(SIZE_X, 0)); + corners.push_back(vec2(0.95*SIZE_X, 0)); + corners.push_back(vec2(0.5*SIZE_X, 0.65*SIZE_Y)); + corners.push_back(vec2(0.05*SIZE_X, 0)); + subdomain_corners.push_back({vec2(0.5*SIZE_X, 0.65*SIZE_Y), vec2(0.05*SIZE_X, 0), vec2(0.,0.), vec2(0., SIZE_Y), vec2(0.5*SIZE_X, SIZE_Y)}); + subdomain_corners.push_back({ vec2(0.5*SIZE_X, 0.65*SIZE_Y), vec2(0.5*SIZE_X, SIZE_Y), vec2(SIZE_X, SIZE_Y), vec2(SIZE_X, 0.), vec2(0.95*SIZE_X, 0) }); break; } for(auto &c : corners) { - c[0] += boundary; - c[1] += boundary; + c[0] += boundary1; + c[1] += boundary2; + } + + for(auto &subdomain : subdomain_corners) + { + for(auto &sub_corner : subdomain) + { + sub_corner[0] += boundary1; + sub_corner[1] += boundary2; + } + } + } + + DesignDomain(std::string design, int SIZE_X, int SIZE_Y, real boundary1, real boundary2) + { + mWidth = SIZE_X; + mHeight = SIZE_Y; + if (design == "RECTANGLE") + { + name = "RECTANGLE"; + corners.push_back(vec2(0.,0.)); + corners.push_back(vec2(0., SIZE_Y)); + corners.push_back(vec2(SIZE_X, SIZE_Y)); + corners.push_back(vec2(SIZE_X, 0.)); + subdomain_corners.push_back(corners); + } + else if(design == "L") + { + name = "L"; + corners.push_back(vec2(0.,0.)); + corners.push_back(vec2(0., SIZE_Y)); + corners.push_back(vec2(0.4*SIZE_X, SIZE_Y)); + corners.push_back(vec2(0.4*SIZE_X, 0.4*SIZE_Y)); + corners.push_back(vec2(SIZE_X, 0.4*SIZE_Y)); + corners.push_back(vec2(SIZE_X, 0.)); + subdomain_corners.push_back(corners); + } + else if(design == "ESO") + { + name = "ESO"; + corners.push_back(vec2(0.,0.)); + corners.push_back(vec2(0., 3.*SIZE_Y/7.)); + corners.push_back(vec2(30.*SIZE_X/32., 3.*SIZE_Y/7.)); + corners.push_back(vec2(30.*SIZE_X/32., SIZE_Y)); + corners.push_back(vec2(31.*SIZE_X/32., SIZE_Y)); + corners.push_back(vec2(31.*SIZE_X/32., 3.*SIZE_Y/7.)); + corners.push_back(vec2(SIZE_X, 3.*SIZE_Y/7.)); + corners.push_back(vec2(SIZE_X, 0.)); + subdomain_corners.push_back(corners); + } + else if(design == "PORTAL") + { + name = "PORTAL"; + corners.push_back(vec2(0.,0.)); + corners.push_back(vec2(0., SIZE_Y)); + corners.push_back(vec2(SIZE_X, SIZE_Y)); + corners.push_back(vec2(SIZE_X, 0)); + corners.push_back(vec2(0.95*SIZE_X, 0)); + corners.push_back(vec2(0.5*SIZE_X, 0.65*SIZE_Y)); + corners.push_back(vec2(0.05*SIZE_X, 0)); + subdomain_corners.push_back({vec2(0.5*SIZE_X, 0.65*SIZE_Y), vec2(0.05*SIZE_X, 0), vec2(0.,0.), vec2(0., SIZE_Y), vec2(0.5*SIZE_X, SIZE_Y)}); + subdomain_corners.push_back({ vec2(0.5*SIZE_X, 0.65*SIZE_Y), vec2(0.5*SIZE_X, SIZE_Y), vec2(SIZE_X, SIZE_Y), vec2(SIZE_X, 0.), vec2(0.95*SIZE_X, 0) }); + } + else + { + std::cerr << "No available domain type!" << std::endl; + std::exit(1); + } + + for(auto &c : corners) + { + c[0] += boundary1; + c[1] += boundary2; + } + + for(auto &subdomain : subdomain_corners) + { + for(auto &sub_corner : subdomain) + { + sub_corner[0] += boundary1; + sub_corner[1] += boundary2; + } + } + } + + DesignDomain(DESIGN_DOMAIN_TYPE design, int SIZE_X, int SIZE_Y, real boundary) : DesignDomain(design, SIZE_X, SIZE_Y, boundary, boundary) + { + + } + +// DesignDomain(DESIGN_DOMAIN_TYPE design, int SIZE_X, int SIZE_Y, real boundary) +// { +// mWidth = SIZE_X; +// mHeight = SIZE_Y; +// switch (design) +// { +// case RECTANGLE: +// name = "RECTANGLE"; +// corners.push_back(vec2(0.,0.)); +// corners.push_back(vec2(0., SIZE_Y)); +// corners.push_back(vec2(SIZE_X, SIZE_Y)); +// corners.push_back(vec2(SIZE_X, 0.)); +// subdomain_corners.push_back(corners); +// break; +// case L: +// name = "L"; +// corners.push_back(vec2(0.,0.)); +// corners.push_back(vec2(0., SIZE_Y)); +// corners.push_back(vec2(0.4*SIZE_X, SIZE_Y)); +// corners.push_back(vec2(0.4*SIZE_X, 0.4*SIZE_Y)); +// corners.push_back(vec2(SIZE_X, 0.4*SIZE_Y)); +// corners.push_back(vec2(SIZE_X, 0.)); +// subdomain_corners.push_back(corners); +// break; +// case ESO: +// name = "ESO"; +// corners.push_back(vec2(0.,0.)); +// corners.push_back(vec2(0., 3.*SIZE_Y/7.)); +// corners.push_back(vec2(30.*SIZE_X/32., 3.*SIZE_Y/7.)); +// corners.push_back(vec2(30.*SIZE_X/32., SIZE_Y)); +// corners.push_back(vec2(31.*SIZE_X/32., SIZE_Y)); +// corners.push_back(vec2(31.*SIZE_X/32., 3.*SIZE_Y/7.)); +// corners.push_back(vec2(SIZE_X, 3.*SIZE_Y/7.)); +// corners.push_back(vec2(SIZE_X, 0.)); +// subdomain_corners.push_back(corners); +// break; +// case PORTAL: +// name = "PORTAL"; +// corners.push_back(vec2(0.,0.)); +// corners.push_back(vec2(0., SIZE_Y)); +// corners.push_back(vec2(SIZE_X, SIZE_Y)); +// corners.push_back(vec2(SIZE_X, 0)); +// corners.push_back(vec2(0.95*SIZE_X, 0)); +// corners.push_back(vec2(0.5*SIZE_X, 0.65*SIZE_Y)); +// corners.push_back(vec2(0.05*SIZE_X, 0)); +// subdomain_corners.push_back({vec2(0.5*SIZE_X, 0.65*SIZE_Y), vec2(0.05*SIZE_X, 0), vec2(0.,0.), vec2(0., SIZE_Y), vec2(0.5*SIZE_X, SIZE_Y)}); +// subdomain_corners.push_back({ vec2(0.5*SIZE_X, 0.65*SIZE_Y), vec2(0.5*SIZE_X, SIZE_Y), vec2(SIZE_X, SIZE_Y), vec2(SIZE_X, 0.), vec2(0.95*SIZE_X, 0) }); +// break; +// } +// +// for(auto &c : corners) +// { +// c[0] += boundary; +// c[1] += boundary; +// } +// +// for(auto &subdomain : subdomain_corners) +// { +// for(auto &sub_corner : subdomain) +// { +// sub_corner[0] += boundary; +// sub_corner[1] += boundary; +// } +// } +// } + + DesignDomain(std::string design, int SIZE_X, int SIZE_Y, real boundary) : DesignDomain(design, SIZE_X, SIZE_Y, boundary, boundary) + { + + } +// DesignDomain(std::string design, int SIZE_X, int SIZE_Y, real boundary) +// { +// mWidth = SIZE_X; +// mHeight = SIZE_Y; +// if (design == "RECTANGLE") +// { +// name = "RECTANGLE"; +// corners.push_back(vec2(0.,0.)); +// corners.push_back(vec2(0., SIZE_Y)); +// corners.push_back(vec2(SIZE_X, SIZE_Y)); +// corners.push_back(vec2(SIZE_X, 0.)); +// subdomain_corners.push_back(corners); +// } +// else if(design == "L") +// { +// name = "L"; +// corners.push_back(vec2(0.,0.)); +// corners.push_back(vec2(0., SIZE_Y)); +// corners.push_back(vec2(0.4*SIZE_X, SIZE_Y)); +// corners.push_back(vec2(0.4*SIZE_X, 0.4*SIZE_Y)); +// corners.push_back(vec2(SIZE_X, 0.4*SIZE_Y)); +// corners.push_back(vec2(SIZE_X, 0.)); +// subdomain_corners.push_back(corners); +// } +// else if(design == "ESO") +// { +// name = "ESO"; +// corners.push_back(vec2(0.,0.)); +// corners.push_back(vec2(0., 3.*SIZE_Y/7.)); +// corners.push_back(vec2(30.*SIZE_X/32., 3.*SIZE_Y/7.)); +// corners.push_back(vec2(30.*SIZE_X/32., SIZE_Y)); +// corners.push_back(vec2(31.*SIZE_X/32., SIZE_Y)); +// corners.push_back(vec2(31.*SIZE_X/32., 3.*SIZE_Y/7.)); +// corners.push_back(vec2(SIZE_X, 3.*SIZE_Y/7.)); +// corners.push_back(vec2(SIZE_X, 0.)); +// subdomain_corners.push_back(corners); +// } +// else if(design == "PORTAL") +// { +// name = "PORTAL"; +// corners.push_back(vec2(0.,0.)); +// corners.push_back(vec2(0., SIZE_Y)); +// corners.push_back(vec2(SIZE_X, SIZE_Y)); +// corners.push_back(vec2(SIZE_X, 0)); +// corners.push_back(vec2(0.95*SIZE_X, 0)); +// corners.push_back(vec2(0.5*SIZE_X, 0.65*SIZE_Y)); +// corners.push_back(vec2(0.05*SIZE_X, 0)); +// subdomain_corners.push_back({vec2(0.5*SIZE_X, 0.65*SIZE_Y), vec2(0.05*SIZE_X, 0), vec2(0.,0.), vec2(0., SIZE_Y), vec2(0.5*SIZE_X, SIZE_Y)}); +// subdomain_corners.push_back({ vec2(0.5*SIZE_X, 0.65*SIZE_Y), vec2(0.5*SIZE_X, SIZE_Y), vec2(SIZE_X, SIZE_Y), vec2(SIZE_X, 0.), vec2(0.95*SIZE_X, 0) }); +// } +// else +// { +// std::cerr << "No available domain type!" << std::endl; +// std::exit(1); +// } +// +// for(auto &c : corners) +// { +// c[0] += boundary; +// c[1] += boundary; +// } +// +// for(auto &subdomain : subdomain_corners) +// { +// for(auto &sub_corner : subdomain) +// { +// sub_corner[0] += boundary; +// sub_corner[1] += boundary; +// } +// } +// } + + DesignDomain() + { + + } + + std::string get_name() const + { + return name; + } + + double get_width() const + { + return mWidth; + } + + double get_height() const + { + return mHeight; + } + + void set_corners(std::vector input_corners) + { + for (auto corner : input_corners ) + { + corners.push_back(corner); } } + void add_corner(vec2 corner) + { + corners.push_back(corner); + } + /** Returns the corners of the design domain. */ std::vector get_corners() const; + std::vector > get_subdomain_corners() const; + /** Returns an approximate center of the design domain. */ - vec2 get_center(); + vec2 get_center() const; /** Returns the total volume of the domain. */ real get_volume(); + real get_perimeter(); + /** Clamps the position pos to be within the domain. */ @@ -99,6 +390,11 @@ namespace DSC2D { Returns whether the position p is inside the domain. */ bool is_inside(const vec2& p) const; + + /** + Returns whether the position p is on the boundary. + */ + bool on_boundary(const vec2& p) const; }; } \ No newline at end of file diff --git a/src/draw.cpp b/src/draw.cpp new file mode 100644 index 0000000..4144109 --- /dev/null +++ b/src/draw.cpp @@ -0,0 +1,551 @@ +// +// Deformabel Simplicial Complex (DSC) method +// Copyright (C) 2013 Technical University of Denmark +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See licence.txt for a copy of the GNU General Public License. + +#include "draw.h" + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#endif + +using namespace DSC2D; + +void Painter::save_painting(int width, int height, std::string folder, int time_step) +{ + // std::cout << folder << std::endl; + std::ostringstream s; + if (folder.length() == 0) { + s << "scr"; + } + else { + s << folder << "/dsc"; + } + + if (time_step >= 0) + { + s << std::string(Util::concat4digits("_", time_step)); + } + s << "_dsc.png"; + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + int success = SOIL_save_screenshot(s.str().c_str(), SOIL_SAVE_TYPE_PNG, 0, 0, width, height); + if(!success) + { + std::cout << "ERROR: Failed to take screen shot: " << s.str().c_str() << std::endl; + return; + } + // std::cout << "Take screen shot: " << s.str().c_str() << std::endl; +} + +void Painter::save_painting(int width, int height, std::string folder, int dsc_time_step, int sub_time_step, std::string name) +{ + // std::cout << folder << std::endl; + std::ostringstream s; + if (folder.length() == 0) { + s << "scr"; + } + else { + s << folder << "/dsc"; + } + + s << std::string(Util::concat4digits("_", dsc_time_step)); + + if (sub_time_step >= 0) + { + s << std::string(Util::concat4digits(name, sub_time_step)); + } + s << ".png"; + glPixelStorei(GL_PACK_ALIGNMENT, 1); + int success = SOIL_save_screenshot(s.str().c_str(), SOIL_SAVE_TYPE_PNG, 0, 0, width, height); + if(!success) + { + std::cout << "ERROR: Failed to take screen shot: " << s.str().c_str() << std::endl; + return; + } + // std::cout << "Take screen shot: " << s.str().c_str() << std::endl; +} + +void Painter::save_painting(int width, int height, std::string folder, int dsc_time_step, int shape_opt_time_step, int sub_time_step, std::string name) +{ + // std::cout << folder << std::endl; + std::ostringstream s; + if (folder.length() == 0) { + s << "scr"; + } + else { + s << folder << "/dsc"; + } + + s << std::string(Util::concat4digits("_", dsc_time_step)); + + if (shape_opt_time_step >= 0) + { + s << std::string(Util::concat4digits("_shape_", shape_opt_time_step)); + } + + if (sub_time_step >= 0) + { + s << std::string(Util::concat4digits(name, sub_time_step)); + } + s << ".png"; + glPixelStorei(GL_PACK_ALIGNMENT, 1); + int success = SOIL_save_screenshot(s.str().c_str(), SOIL_SAVE_TYPE_PNG, 0, 0, width, height); + if(!success) + { + std::cout << "ERROR: Failed to take screen shot: " << s.str().c_str() << std::endl; + return; + } + // std::cout << "Take screen shot: " << s.str().c_str() << std::endl; +} + +void Painter::begin() +{ + glClearColor(BACKGROUND_COLOR[0], BACKGROUND_COLOR[1], BACKGROUND_COLOR[2],0); + glClear(GL_COLOR_BUFFER_BIT); +} + +void Painter::end() +{ + glFinish(); + glutSwapBuffers(); +} + + +void Painter::draw_complex(const DeformableSimplicialComplex& dsc) +{ + draw_domain(*dsc.get_design_domain()); + draw_faces(dsc); + draw_edges(dsc); + draw_vertices(dsc); +} + +void Painter::draw_destination_complex(const DeformableSimplicialComplex& dsc) +{ + draw_domain(*dsc.get_design_domain()); + draw_destination_faces(dsc); + draw_destination_edges(dsc); + draw_destination_vertices(dsc); +} + +void Painter::draw_domain(const DesignDomain& domain, vec3 color) +{ +// std::vector corners = domain.get_corners(); +// glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); +// vec2 p0, p1, p2; +// vec3 cor; +// int j = 0, i; +// glBegin(GL_TRIANGLES); +// while (corners.size() > 2) +// { +// i = (j+1)%corners.size(); +// p0 = corners[j%corners.size()]; +// p1 = corners[i]; +// p2 = corners[(j+2)%corners.size()]; +// if (!Util::is_left_of(p0, p1, p2)) +// { +// cor = vec3(p0[0], p0[1], 0.); +// glVertex3d(static_cast(cor[0]), static_cast(cor[1]), static_cast(cor[2])); +// cor = vec3(p1[0], p1[1], 0.); +// glVertex3d(static_cast(cor[0]), static_cast(cor[1]), static_cast(cor[2])); +// cor = vec3(p2[0], p2[1], 0.); +// glVertex3d(static_cast(cor[0]), static_cast(cor[1]), static_cast(cor[2])); +// corners.erase(corners.begin() + i); +// } +// else +// { +// j = i; +// } +// } +// glEnd(); + std::vector > subdomain_corners = domain.get_subdomain_corners(); + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + vec2 p0, p1, p2; + vec3 cor; + int j = 0, i; + glBegin(GL_TRIANGLES); + for (auto c = 0; c corners = subdomain_corners[c]; + while (corners.size() > 2) + { + i = (j+1)%corners.size(); + p0 = corners[j%corners.size()]; + p1 = corners[i]; + p2 = corners[(j+2)%corners.size()]; + if (!Util::is_left_of(p0, p1, p2)) + { + cor = vec3(p0[0], p0[1], 0.); + glVertex3d(static_cast(cor[0]), static_cast(cor[1]), static_cast(cor[2])); + cor = vec3(p1[0], p1[1], 0.); + glVertex3d(static_cast(cor[0]), static_cast(cor[1]), static_cast(cor[2])); + cor = vec3(p2[0], p2[1], 0.); + glVertex3d(static_cast(cor[0]), static_cast(cor[1]), static_cast(cor[2])); + corners.erase(corners.begin() + i); + } + else + { + j = i; + } + } + } + glEnd(); +} + +void Painter::draw_vertices(const DeformableSimplicialComplex& dsc) +{ + HMesh::VertexAttributeVector colors = dsc.get_vertex_colors(); + glPointSize(std::max(std::floor(POINT_SIZE*dsc.get_avg_edge_length()), 1.)); + glBegin(GL_POINTS); + vec3 p; + for(auto vi = dsc.vertices_begin(); vi != dsc.vertices_end(); ++vi) + { + if (colors[*vi] != INVISIBLE) + { + p = vec3(dsc.get_pos(*vi)[0], dsc.get_pos(*vi)[1], 0.); + glColor3d(static_cast(colors[*vi][0]), static_cast(colors[*vi][1]), static_cast(colors[*vi][2])); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(p[2])); + } + } + glEnd(); +} + +void Painter::draw_destination_vertices(const DeformableSimplicialComplex& dsc) +{ + HMesh::VertexAttributeVector colors = dsc.get_vertex_colors(); + glPointSize(std::max(std::floor(POINT_SIZE*dsc.get_avg_edge_length()), 1.)); + glBegin(GL_POINTS); + vec3 p; + for(auto vi = dsc.vertices_begin(); vi != dsc.vertices_end(); ++vi) + { + if (colors[*vi] != INVISIBLE) + { + p = vec3(dsc.get_destination(*vi)[0], dsc.get_destination(*vi)[1], 0.); + glColor3d(static_cast(colors[*vi][0]), static_cast(colors[*vi][1]), static_cast(colors[*vi][2])); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(p[2])); + } + } + glEnd(); +} + +void Painter::draw_interface(const DeformableSimplicialComplex& dsc, vec3 color) +{ + glPointSize(std::max(std::floor(POINT_SIZE*dsc.get_avg_edge_length()), 1.)); + glBegin(GL_POINTS); + vec3 p; + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + for(auto vi = dsc.vertices_begin(); vi != dsc.vertices_end(); ++vi) + { + if (dsc.is_movable(*vi)) { + vec3 temp(dsc.get_destination(*vi)[0], dsc.get_destination(*vi)[1], 0.); + glVertex3d(static_cast(temp[0]), static_cast(temp[1]), static_cast(temp[2])); + } + } + glEnd(); + glLineWidth(std::max(std::floor(LINE_WIDTH*dsc.get_avg_edge_length()), 1.)); + vec3 p1, p2; + glBegin(GL_LINES); + for(auto hei = dsc.halfedges_begin(); hei != dsc.halfedges_end(); ++hei) + { + auto hew = dsc.walker(*hei); + if (dsc.is_movable(hew.halfedge()) && (dsc.is_movable(hew.vertex()) || dsc.is_movable(hew.opp().vertex()))) + { + p1 = vec3(dsc.get_destination(hew.vertex())[0], dsc.get_destination(hew.vertex())[1], 0.); + p2 = vec3(dsc.get_destination(hew.opp().vertex())[0], dsc.get_destination(hew.opp().vertex())[1], 0.); + glVertex3d(static_cast(p1[0]), static_cast(p1[1]), static_cast(p1[2])); + glVertex3d(static_cast(p2[0]), static_cast(p2[1]), static_cast(p2[2])); + } + } + glEnd(); +} + +void Painter::draw_arrows(const DeformableSimplicialComplex& dsc, const HMesh::VertexAttributeVector &arrows, vec3 color, bool origin_movable) +{ + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + glLineWidth(std::max(std::floor(LINE_WIDTH*dsc.get_avg_edge_length()), 1.)); + vec3 arrow, a_hat, p; + for(auto vi = dsc.vertices_begin(); vi != dsc.vertices_end(); ++vi) + { + arrow = vec3(arrows[*vi][0], arrows[*vi][1], 0.f); + if(arrow.length() > EPSILON) + { + a_hat = vec3(-arrow[1], arrow[0], 0.f); + p = vec3(dsc.get_pos(*vi)[0], dsc.get_pos(*vi)[1], 0.); +#ifdef DEBUG + if (dsc.is_movable(*vi) && origin_movable) { + p = vec3(dsc.get_destination(*vi)[0], dsc.get_destination(*vi)[1], 0.); + } +#endif + glBegin(GL_LINES); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(p[2])); + glVertex3d(static_cast((p + 0.7*arrow)[0]), static_cast((p + 0.7*arrow)[1]), static_cast((p + 0.7*arrow)[2])); + glEnd(); + + glBegin(GL_POLYGON); + glVertex3d(static_cast((p + arrow)[0]), static_cast((p + arrow)[1]), static_cast((p + arrow)[2])); + glVertex3d(static_cast((p + 0.6*arrow + 0.13*a_hat)[0]), static_cast((p+ 0.6*arrow + 0.13*a_hat)[1]), static_cast((p+ 0.6*arrow + 0.13*a_hat)[2])); + glVertex3d(static_cast((p + 0.6*arrow - 0.13*a_hat)[0]), static_cast((p + 0.6*arrow - 0.13*a_hat)[1]), static_cast((p + 0.6*arrow - 0.13*a_hat)[2])); + glEnd(); + } + } +} + +void Painter::draw_edge_arrows(const DeformableSimplicialComplex& dsc, const HMesh::HalfEdgeAttributeVector &arrows, vec3 color) +{ + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + glLineWidth(std::max(std::floor(LINE_WIDTH*dsc.get_avg_edge_length()), 1.)); + vec3 arrow, a_hat, p; + for(auto eit = dsc.halfedges_begin(); eit != dsc.halfedges_end(); ++eit) + { + arrow = vec3(arrows[*eit][0], arrows[*eit][1], 0.f); + if(arrow.length() > EPSILON) + { + a_hat = vec3(-arrow[1], arrow[0], 0.f); + auto pt = Util::barycenter(dsc.get_pos(dsc.walker(*eit).vertex()), dsc.get_pos(dsc.walker(*eit).opp().vertex())); +#ifdef DEBUG + pt = Util::barycenter(dsc.get_destination(dsc.walker(*eit).vertex()), dsc.get_destination(dsc.walker(*eit).opp().vertex())); +#endif + p = vec3(pt[0], pt[1], 0.); + glBegin(GL_LINES); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(p[2])); + glVertex3d(static_cast((p + 0.7*arrow)[0]), static_cast((p + 0.7*arrow)[1]), static_cast((p + 0.7*arrow)[2])); + glEnd(); + + glBegin(GL_POLYGON); + glVertex3d(static_cast((p + arrow)[0]), static_cast((p + arrow)[1]), static_cast((p + arrow)[2])); + glVertex3d(static_cast((p + 0.6*arrow + 0.13*a_hat)[0]), static_cast((p+ 0.6*arrow + 0.13*a_hat)[1]), static_cast((p+ 0.6*arrow + 0.13*a_hat)[2])); + glVertex3d(static_cast((p + 0.6*arrow - 0.13*a_hat)[0]), static_cast((p + 0.6*arrow - 0.13*a_hat)[1]), static_cast((p + 0.6*arrow - 0.13*a_hat)[2])); + glEnd(); + } + } +} + + +void Painter::draw_lines(const DeformableSimplicialComplex& dsc, const HMesh::VertexAttributeVector &lines, vec3 color) +{ + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + glLineWidth(std::max(std::floor(LINE_WIDTH*dsc.get_avg_edge_length()), 1.)); + vec3 line, p; + for(auto vi = dsc.vertices_begin(); vi != dsc.vertices_end(); ++vi) + { + line = vec3(lines[*vi][0], lines[*vi][1], 0.f); + if(line.length() > EPSILON) + { + p = vec3(dsc.get_pos(*vi)[0], dsc.get_pos(*vi)[1], 0.); + + glBegin(GL_LINES); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(p[2])); + glVertex3d(static_cast((p + line)[0]), static_cast((p + line)[1]), static_cast((p + line)[2])); + glEnd(); + } + } +} + +void Painter::draw_edges(const DeformableSimplicialComplex& dsc) +{ + HMesh::HalfEdgeAttributeVector colors = dsc.get_edge_colors(); + glLineWidth(std::max(std::floor(LINE_WIDTH*dsc.get_avg_edge_length()), 1.)); + vec3 p1, p2; + glBegin(GL_LINES); + for(auto hei = dsc.halfedges_begin(); hei != dsc.halfedges_end(); ++hei) + { + if (colors[*hei] != INVISIBLE) + { + glColor3d(static_cast(colors[*hei][0]), static_cast(colors[*hei][1]), static_cast(colors[*hei][2])); + + auto hew = dsc.walker(*hei); + p1 = vec3(dsc.get_pos(hew.vertex())[0], dsc.get_pos(hew.vertex())[1], 0.); + p2 = vec3(dsc.get_pos(hew.opp().vertex())[0], dsc.get_pos(hew.opp().vertex())[1], 0.); + glVertex3d(static_cast(p1[0]), static_cast(p1[1]), static_cast(p1[2])); + glVertex3d(static_cast(p2[0]), static_cast(p2[1]), static_cast(p2[2])); + } + } + glEnd(); +} + +void Painter::draw_destination_edges(const DeformableSimplicialComplex& dsc) +{ + HMesh::HalfEdgeAttributeVector colors = dsc.get_edge_colors(); + glLineWidth(std::max(std::floor(LINE_WIDTH*dsc.get_avg_edge_length()), 1.)); + vec3 p1, p2; + glBegin(GL_LINES); + for(auto hei = dsc.halfedges_begin(); hei != dsc.halfedges_end(); ++hei) + { + if (colors[*hei] != INVISIBLE) + { + glColor3d(static_cast(colors[*hei][0]), static_cast(colors[*hei][1]), static_cast(colors[*hei][2])); + + auto hew = dsc.walker(*hei); + p1 = vec3(dsc.get_destination(hew.vertex())[0], dsc.get_destination(hew.vertex())[1], 0.); + p2 = vec3(dsc.get_destination(hew.opp().vertex())[0], dsc.get_destination(hew.opp().vertex())[1], 0.); + glVertex3d(static_cast(p1[0]), static_cast(p1[1]), static_cast(p1[2])); + glVertex3d(static_cast(p2[0]), static_cast(p2[1]), static_cast(p2[2])); + } + } + glEnd(); +} + +void Painter::draw_faces(const DeformableSimplicialComplex& dsc) +{ + HMesh::FaceAttributeVector colors = dsc.get_face_colors(); + draw_faces(dsc, colors); +} + +void Painter::draw_destination_faces(const DeformableSimplicialComplex& dsc) +{ + HMesh::FaceAttributeVector colors = dsc.get_face_colors(); + draw_destination_faces(dsc, colors); +} + +void Painter::draw_faces(const DeformableSimplicialComplex& dsc, const HMesh::FaceAttributeVector &colors) +{ + glBegin(GL_TRIANGLES); + for(auto fi = dsc.faces_begin(); fi != dsc.faces_end(); ++fi) + { + if(colors[*fi] != INVISIBLE) + { + glColor3d(static_cast(colors[*fi][0]), static_cast(colors[*fi][1]), static_cast(colors[*fi][2])); + for (auto hew = dsc.walker(*fi); !hew.full_circle(); hew = hew.circulate_face_cw()) + { + vec2 p = dsc.get_pos(hew.vertex()); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(0.)); + } + } + } + glEnd(); +} + +void Painter::draw_destination_faces(const DeformableSimplicialComplex& dsc, const HMesh::FaceAttributeVector &colors) +{ + glBegin(GL_TRIANGLES); + for(auto fi = dsc.faces_begin(); fi != dsc.faces_end(); ++fi) + { + if(colors[*fi] != INVISIBLE) + { + glColor3d(static_cast(colors[*fi][0]), static_cast(colors[*fi][1]), static_cast(colors[*fi][2])); + for (auto hew = dsc.walker(*fi); !hew.full_circle(); hew = hew.circulate_face_cw()) + { + vec2 p = dsc.get_destination(hew.vertex()); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(0.)); + } + } + } + glEnd(); +} + +void Painter::draw_faces(const DeformableSimplicialComplex& dsc, const HMesh::FaceAttributeVector &values) +{ + glBegin(GL_TRIANGLES); + for(auto fi = dsc.faces_begin(); fi != dsc.faces_end(); ++fi) + { + if(values[*fi] >= 0.) + { + for (auto hew = dsc.walker(*fi); !hew.full_circle(); hew = hew.circulate_face_cw()) + { +// real val = 0.; +// int i = 0; +// for (auto hew2 = dsc.walker(hew.vertex()); !hew2.full_circle(); hew2 = hew2.circulate_vertex_cw()) { +// if(values[hew2.face()] >= 0.) +// { +// val += values[hew2.face()]; +// i++; +// } +// } +// val = val / static_cast(i); + real val = values[*fi]; + vec3 color = Util::jet_color(val); + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + vec2 p = dsc.get_pos(hew.vertex()); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(0.)); + } + } + } + glEnd(); +} + +void Painter::draw_destination_faces(const DeformableSimplicialComplex& dsc, const HMesh::FaceAttributeVector &values) +{ + glBegin(GL_TRIANGLES); + for(auto fi = dsc.faces_begin(); fi != dsc.faces_end(); ++fi) + { + if(values[*fi] >= 0.) + { + for (auto hew = dsc.walker(*fi); !hew.full_circle(); hew = hew.circulate_face_cw()) + { + // real val = 0.; + // int i = 0; + // for (auto hew2 = dsc.walker(hew.vertex()); !hew2.full_circle(); hew2 = hew2.circulate_vertex_cw()) { + // if(values[hew2.face()] >= 0.) + // { + // val += values[hew2.face()]; + // i++; + // } + // } + // val = val / static_cast(i); + real val = values[*fi]; + vec3 color = Util::jet_color(val); + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + vec2 p = dsc.get_destination(hew.vertex()); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(0.)); + } + } + } + glEnd(); +} + +void Painter::draw_faces(const DeformableSimplicialComplex& dsc, const HMesh::VertexAttributeVector &values) +{ + glBegin(GL_TRIANGLES); + for(auto fi = dsc.faces_begin(); fi != dsc.faces_end(); ++fi) + { + auto verts = dsc.get_verts(*fi); + if(!dsc.is_outside(*fi)) + { + for (auto vert : verts) + { + vec3 color = Util::jet_color(values[vert]); + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + vec2 p = dsc.get_pos(vert); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(0.)); + } + } + } + glEnd(); +} + +void Painter::draw_destination_faces(const DeformableSimplicialComplex& dsc, const HMesh::VertexAttributeVector &values) +{ + glBegin(GL_TRIANGLES); + for(auto fi = dsc.faces_begin(); fi != dsc.faces_end(); ++fi) + { + auto verts = dsc.get_verts(*fi); + if(!dsc.is_outside(*fi)) + { + for (auto vert : verts) + { + vec3 color = Util::jet_color(values[vert]); + glColor3d(static_cast(color[0]), static_cast(color[1]), static_cast(color[2])); + vec2 p = dsc.get_destination(vert); + glVertex3d(static_cast(p[0]), static_cast(p[1]), static_cast(0.)); + } + } + } + glEnd(); +} + diff --git a/src/draw.h b/src/draw.h new file mode 100644 index 0000000..43b8017 --- /dev/null +++ b/src/draw.h @@ -0,0 +1,153 @@ +// +// Deformabel Simplicial Complex (DSC) method +// Copyright (C) 2013 Technical University of Denmark +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// See licence.txt for a copy of the GNU General Public License. + +#pragma once + +#include "DSC.h" +#include "velocity_function.h" + +const static double POINT_SIZE = 0.2; +const static double LINE_WIDTH = 0.1; + +const static DSC2D::vec3 BACKGROUND_COLOR = DSC2D::vec3(1.); +const static DSC2D::vec3 INVISIBLE = DSC2D::vec3(-1.); +const static DSC2D::vec3 DARK_RED = DSC2D::vec3(0.66,0.11,0.15); +const static DSC2D::vec3 RED = DSC2D::vec3(0.96,0.11,0.15); +const static DSC2D::vec3 DARK_BLUE = DSC2D::vec3(0.14,0.16,0.88); +const static DSC2D::vec3 BLUE = DSC2D::vec3(0.45,0.7,0.9); +const static DSC2D::vec3 GREEN = DSC2D::vec3(0.05,1.,0.15); +const static DSC2D::vec3 ORANGE = DSC2D::vec3(0.9,0.4,0.); +const static DSC2D::vec3 BLACK = DSC2D::vec3(0.); +const static DSC2D::vec3 DARK_GRAY = DSC2D::vec3(0.5); +const static DSC2D::vec3 GRAY = DSC2D::vec3(0.8); + +/** + A painter handles all draw functionality using OpenGL. + */ +class Painter { + + +public: + /** + Saves the current painting to the selected folder. + */ + static void save_painting(int width, int height, std::string folder = std::string(""), int time_step = -1); + + static void save_painting(int width, int height, std::string folder, int dsc_time_step, int sub_time_step, std::string name); + + static void save_painting(int width, int height, std::string folder, int dsc_time_step, int shape_step, int sub_time_step, std::string name); + + /** + Begins drawing. + */ + static void begin(); + + /** + Ends drawing. + */ + static void end(); + + /** + Draws the simplicial complex. + */ + static void draw_complex(const DSC2D::DeformableSimplicialComplex& complex); + + /** + Draws the simplicial complex. + */ + static void draw_destination_complex(const DSC2D::DeformableSimplicialComplex& complex); + + /** + Draws the domain. + */ + static void draw_domain(const DSC2D::DesignDomain& domain, DSC2D::vec3 color = GRAY); + + /** + Draws the vertices with the colors defined by the get_vertex_colors function in the simplicial complex. + */ + static void draw_vertices(const DSC2D::DeformableSimplicialComplex& complex); + + /** + Draws the vertices with the colors defined by the get_vertex_colors function in the simplicial complex. + */ + static void draw_destination_vertices(const DSC2D::DeformableSimplicialComplex& complex); + + /** + Draws the edges with the colors defined by the get_edge_colors function in the simplicial complex. + */ + static void draw_edges(const DSC2D::DeformableSimplicialComplex& complex); + + /** + Draws the edges with the colors defined by the get_edge_colors function in the simplicial complex. + */ + static void draw_destination_edges(const DSC2D::DeformableSimplicialComplex& complex); + + /** + Draws the faces with the colors defined by the get_face_colors function in the simplicial complex. + */ + static void draw_faces(const DSC2D::DeformableSimplicialComplex& complex); + + /** + Draws the faces with the colors defined by the get_face_colors function in the simplicial complex. + */ + static void draw_destination_faces(const DSC2D::DeformableSimplicialComplex& complex); + + /** + Draws the faces with the colors given as input. + */ + static void draw_faces(const DSC2D::DeformableSimplicialComplex& complex, const HMesh::FaceAttributeVector &colors); + + /** + Draws the faces with the colors given as input. + */ + static void draw_destination_faces(const DSC2D::DeformableSimplicialComplex& complex, const HMesh::FaceAttributeVector &colors); + + /** + Draws the faces using the 'jet' color scheme. + */ + static void draw_faces(const DSC2D::DeformableSimplicialComplex& complex, const HMesh::FaceAttributeVector &values); + + /** + Draws the faces using the 'jet' color scheme. + */ + static void draw_destination_faces(const DSC2D::DeformableSimplicialComplex& complex, const HMesh::FaceAttributeVector &values); + + /** + Draws the faces using the 'jet' color scheme. + */ + static void draw_faces(const DSC2D::DeformableSimplicialComplex& complex, const HMesh::VertexAttributeVector &values); + + /** + Draws the faces using the 'jet' color scheme. + */ + static void draw_destination_faces(const DSC2D::DeformableSimplicialComplex& complex, const HMesh::VertexAttributeVector &values); + + /** + Draws the interface with the color given as input. + */ + static void draw_interface(const DSC2D::DeformableSimplicialComplex& complex, DSC2D::vec3 color = ORANGE); + + /** + Draws the arrows given as input with the color given as input. + */ + static void draw_arrows(const DSC2D::DeformableSimplicialComplex& complex, const HMesh::VertexAttributeVector &arrows, DSC2D::vec3 color = ORANGE, bool origin_movable = true); + static void draw_edge_arrows(const DSC2D::DeformableSimplicialComplex& dsc, const HMesh::HalfEdgeAttributeVector &arrows, DSC2D::vec3 color = ORANGE); + + /** + Draws the lines given as input with the color given as input. + */ + static void draw_lines(const DSC2D::DeformableSimplicialComplex& complex, const HMesh::VertexAttributeVector &lines, DSC2D::vec3 color = GREEN); +}; diff --git a/src/object_generator.cpp b/src/object_generator.cpp index 13189b4..f92c71a 100644 --- a/src/object_generator.cpp +++ b/src/object_generator.cpp @@ -107,15 +107,46 @@ namespace DSC2D { } } + void ObjectGenerator::label_faces(DeformableSimplicialComplex& dsc, const std::vector& labels) + { + int face_ind = 0; + for (auto fi = dsc.faces_begin(); fi != dsc.faces_end(); fi++) + { + int label = labels[face_ind]; + + if (label == 1) + { + // std::cout << "label: " << label << std::endl; + dsc.update_attributes(*fi, 1); + } + face_ind++; + } + } + void ObjectGenerator::create_object(DeformableSimplicialComplex& dsc, const std::vector& corners, int label) { - dsc.init_attributes(); // Maybe not necessary?? - + // dsc.init_attributes(); // Maybe not necessary?? fit_mesh_to_object(dsc, corners); + dsc.init_attributes(); // it should be here, because fit_mesh_object change the pos. Haojie. label_faces(dsc, corners, label); dsc.update_attributes(); // Maybe not necessary?? dsc.fix_complex(); + dsc.init_attributes(); + dsc.update_attributes(); + } + + void ObjectGenerator::create_object_from_labels(DeformableSimplicialComplex& dsc, const std::vector& corners, const std::vector& labels) + { + // dsc.init_attributes(); // Maybe not necessary?? + fit_mesh_to_object(dsc, corners); + dsc.init_attributes(); // it should be here, because fit_mesh_object change the pos. Haojie. + label_faces(dsc, labels); + dsc.update_attributes(); // Maybe not necessary?? + + dsc.fix_complex(); + dsc.init_attributes(); + dsc.update_attributes(); } } \ No newline at end of file diff --git a/src/object_generator.h b/src/object_generator.h index f92a9d3..d8c408d 100644 --- a/src/object_generator.h +++ b/src/object_generator.h @@ -23,13 +23,17 @@ namespace DSC2D { class ObjectGenerator { - static void fit_mesh_to_object(DeformableSimplicialComplex& dsc, const std::vector& corners); - static void label_faces(DeformableSimplicialComplex& dsc, const std::vector& corners, int label); + public: + + static void label_faces(DeformableSimplicialComplex& dsc, const std::vector& labels); + + static void fit_mesh_to_object(DeformableSimplicialComplex& dsc, const std::vector& corners); + static void create_object(DeformableSimplicialComplex& dsc, const std::vector& corners, int label); - public: + static void create_object_from_labels(DeformableSimplicialComplex& dsc, const std::vector& corners, const std::vector& labels); static void create_blob(DeformableSimplicialComplex& dsc, const vec2& center, const real& radius, int label) { @@ -54,4 +58,4 @@ namespace DSC2D { }; -} \ No newline at end of file +} diff --git a/src/trializer.cpp b/src/trializer.cpp index b85082a..3d1be91 100644 --- a/src/trializer.cpp +++ b/src/trializer.cpp @@ -28,43 +28,51 @@ namespace DSC2D { std::vector x_half; x_full.push_back(0.); - for (real x=avg_edge_length; x #ifdef WIN32 -#include -#include +#include "CGLA/Vec2d.h" +#include "CGLA/Vec3d.h" #else #include -#include +#include + #include #endif +typedef CGLA::Vec2d vec2; +typedef CGLA::Vec3d vec3; +typedef CGLA::Vec2i vec2i; namespace DSC2D { @@ -165,6 +169,31 @@ namespace DSC2D return sqr_length(p - projection); } + /* + Returns the projection of point p to line segment vw + */ + inline vec2 project_point_to_line_segment(const vec2& v, const vec2& w, const vec2& p) + { + const real l2 = dot(v-w, v-w); // i.e. |w-v|^2 - avoid a sqrt + if (l2 == 0.) + { + return v; // v == w case + } + // Consider the line extending the segment, parameterized as v + t (w - v). + // We find projection of point p onto the line. + // It falls where t = [(p-v) . (w-v)] / |w-v|^2 + const real t = dot(p - v, w - v) / l2; + if (t < 0.0) + { + return v; // Beyond the 'v' end of the segment + } + else if (t > 1.0) + { + return w; // Beyond the 'w' end of the segment + } + return v + t * (w - v); // Projection falls on the segment + } + /** Returns whether you have to turn left when going from a to b to c. */ @@ -199,25 +228,65 @@ namespace DSC2D */ inline bool is_inside(const vec2& p, std::vector corners) { - vec2 c0, c1, c2; - while(corners.size() > 2) + + double x = p[0]; + double y = p[1]; + + int i, j = static_cast(corners.size())-1 ; + bool oddNodes=false; + double eps = 1e-8; + + for (i=0; i=y) || (corners[j][1]< y && corners[i][1]>=y) ) && (corners[i][0]<=x ||corners[j][0]<=x) ) + { + oddNodes^=(corners[i][0]+(y-corners[i][1])/(corners[j][1]-corners[i][1])*(corners[j][0]-corners[i][0]) 2) +// { +// int i = 0; +// do { +//#ifdef DEBUG +// assert(i < corners.size()); +//#endif +// c0 = corners[i]; +// c1 = corners[(i+1)%corners.size()]; +// c2 = corners[(i+2)%corners.size()]; +// i++; +// } while (is_left_of(c0,c1,c2)); +// +// if(!is_left_of(c0, c1, p) && !is_left_of(c1, c2, p) && !is_left_of(c2, c0, p)) +// { +// return true; +// } +// corners.erase(corners.begin() + (i%corners.size())); +// } +// return false; + } + + inline bool on_boundary(const vec2& p, std::vector corners) + { + int i, j = static_cast(corners.size())-1 ; + double eps = 1e-2; + + for (i=0; i +#include +#include namespace DSC2D { @@ -64,6 +67,11 @@ namespace DSC2D { return time_step; } + void set_max_time_steps(int max) + { + MAX_TIME_STEPS = max; + } + /** Returns the name of the velocity function. */ @@ -157,16 +165,18 @@ namespace DSC2D { */ virtual bool is_motion_finished(DeformableSimplicialComplex& dsc) { - if (time_step == MAX_TIME_STEPS) { + if (time_step >= MAX_TIME_STEPS) + { return true; } std::vector pos = dsc.get_design_variable_positions(); + double avg_length = dsc.get_avg_edge_length(); for (auto &p : pos) { bool match = false; for (int i = 0; i + 1 < pos_old.size(); i += 2) { - if (Util::min_dist_sqr(pos_old[i], pos_old[i+1], p) < ACCURACY*ACCURACY) + if (Util::min_dist_sqr(pos_old[i], pos_old[i+1], p) < avg_length*ACCURACY*avg_length*ACCURACY) { match = true; break; @@ -192,4 +202,4 @@ namespace DSC2D { }; -} \ No newline at end of file +}