Rev 150 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include <queue>
#include "HMesh/FaceCirculator.h"
#include "HMesh/VertexCirculator.h"
#include "caps_and_needles.h"
#include "Geometry/QEM.h"
using namespace std;
using namespace CGLA;
using namespace GEO;
using namespace HMesh;
namespace HMesh
{
namespace
{
float min_angle(const Vec3f& v0,const Vec3f& v1,const Vec3f& v2)
{
Vec3f a = normalize(v1-v0);
Vec3f b = normalize(v2-v1);
Vec3f c = normalize(v0-v2);
return min(dot(a,-c), min(dot(b,-a), dot(c,-b)));
}
float edge_error(HalfEdgeIter h,
const Vec3f& pa,
const Vec3f& pb)
{
QEM q;
if(h->face != NULL_FACE_ITER)
q += QEM(Vec3d(0), Vec3d(normal(h->face)));
if(h->opp->face != NULL_FACE_ITER)
q += QEM(Vec3d(0), Vec3d(normal(h->opp->face)));
return q.error(pb-pa);
}
float vertex_error(VertexIter va, const Vec3f& pb)
{
QEM q;
Vec3f pa = va->pos;
for(VertexCirculator vc(va); !vc.end(); ++vc)
{
FaceIter f = vc.get_face();
if(f != NULL_FACE_ITER)
{
Vec3f n = normal(f);
q += QEM(Vec3d(0), Vec3d(n));
}
}
return q.error(pb-pa);
}
}
void remove_caps_from_trimesh(Manifold& mani, float ang_thresh)
{
for(FaceIter fi=mani.faces_begin(); fi != mani.faces_end(); ++fi)
{
Vec3f p[3];
HalfEdgeIter he[3];
VertexIter vi[3];
int n=0;
for(FaceCirculator fc(fi); !fc.end(); ++fc,++n)
{
vi[n] = fc.get_vertex();
p[n] = fc.get_vertex()->pos;
he[n]= fc.get_halfedge();
}
assert(n=3);
bool is_collapsed = false;
Vec3f edges[3];
for(int i=0;i<3;++i)
{
edges[i] = p[(i+1)%3]-p[i];
float l = length(edges[i]);
if(l<1e-20)
is_collapsed = true;
else
edges[i] /= l;
}
if(is_collapsed) continue;
for(int i=0;i<3;++i)
{
float d = max(-1.0f,min(1.0f,dot(-edges[(i+2)%3],edges[i])));
float ang = acos(d);
if(ang > ang_thresh)
{
int iplus1 = (i+1)%3;
Vec3f edge_dir = edges[iplus1];
Vec3f pprj =
edge_dir * dot(edge_dir,p[i]-p[iplus1])+p[iplus1];
HalfEdgeIter h = he[iplus1];
Vec3f v0 = h->vert->pos;
Vec3f v1 = h->next->vert->pos;
Vec3f v2 = h->opp->vert->pos;
Vec3f v3 = h->opp->next->vert->pos;
float m1 = min(min_angle(v0,v1,v2), min_angle(v0,v2,v3));
float m2 = min(min_angle(v0,pprj,v3), min_angle(pprj,v2,v3));
if(m1 < m2)
{
if(edge_error(he[iplus1], pprj, vi[i]->pos) >
vertex_error(vi[i], pprj))
vi[i]->pos = pprj;
mani.flip(he[iplus1]);
break;
}
}
}
}
}
void remove_needles_from_trimesh(Manifold& mani,
float thresh)
{
bool did_work;
do
{
did_work = false;
for(VertexIter vi=mani.vertices_begin();
vi != mani.vertices_end(); ++vi)
{
if(is_boundary(vi)) continue;
for(VertexCirculator vc(vi);!vc.end();++vc)
{
if(is_boundary(vc.get_halfedge()->vert)) continue;
HalfEdgeIter he = vc.get_halfedge()->opp;
VertexIter n = vc.get_vertex();
float dist = length(he);
if((dist<thresh) && mani.collapse_precond(he))
{
if(vertex_error(vi,n->pos) <
vertex_error(n,vi->pos))
vi->pos = n->pos;
mani.collapse_halfedge(he);
did_work = true;
break;
}
}
}
}
while(did_work);
}
}