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
+}