mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-16 01:24:36 +00:00
applyFilter rewritten from scratch.
Added a method (refineNeededEdges) to refine, if needed, the edges which will be eroded in the next phase (inspired to the RefineE vcg function). Added a support method and 2 support classes for the refineNeededEdges method.
This commit is contained in:
parent
0ea7a257af
commit
59f73d683f
@ -24,13 +24,13 @@
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <iostream> // DEBUG
|
||||
|
||||
//#include <vcg/complex/trimesh/update/selection.h> // DEBUG
|
||||
#include <vcg/complex/trimesh/allocate.h>
|
||||
//#include <iostream> // DEBUG
|
||||
|
||||
#include "filter_aging.h"
|
||||
|
||||
#include <vcg/complex/trimesh/allocate.h>
|
||||
#include <vcg/complex/trimesh/update/normal.h>
|
||||
|
||||
|
||||
// Constructor
|
||||
GeometryAgingPlugin::GeometryAgingPlugin()
|
||||
@ -88,7 +88,8 @@ void GeometryAgingPlugin::initParameterSet(QAction *action, MeshModel &m, Filter
|
||||
{
|
||||
switch(ID(action)) {
|
||||
case FP_ERODE:
|
||||
params.addFloat("AngleThreshold", 60.0, "Angle Threshold", "The minimum angle between two adjacent faces to consider the edge they are sharing.");
|
||||
params.addAbsPerc("AngleThreshold", 60.0, 10.0, 170.0, "Angle Threshold", "The minimum angle between two adjacent faces to consider the edge they are sharing.");
|
||||
params.addAbsPerc("EdgeLenThreshold", m.cm.bbox.Diag()*0.01, 0.0, m.cm.bbox.Diag(),"Edge Len Threshold", "The minimum length of an edge. Usefull to avoid the creation of too many small faces.");
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@ -99,165 +100,17 @@ void GeometryAgingPlugin::initParameterSet(QAction *action, MeshModel &m, Filter
|
||||
// The Real Core Function doing the actual mesh processing
|
||||
bool GeometryAgingPlugin::applyFilter(QAction *filter, MeshModel &m, FilterParameterSet ¶ms, vcg::CallBackPos *cb)
|
||||
{
|
||||
CMeshO::FaceIterator fi;
|
||||
int borderNum = 0;
|
||||
int chips = 0;
|
||||
float angleThreshold = params.getFloat("AngleThreshold");
|
||||
bool hasSel = hasSelected(m);
|
||||
typedef std::pair<CMeshO::FacePointer, int> sedge; // selected edge
|
||||
map<sedge, vector<EroderPoint>* > edge2Eroder;
|
||||
float angleThreshold;
|
||||
float edgeLenTreshold;
|
||||
|
||||
// first loop to clear V bits
|
||||
for(fi=m.cm.face.begin(); fi!=m.cm.face.end(); ++fi)
|
||||
(*fi).ClearV();
|
||||
//tri::UpdateSelection<CMeshO>::ClearFace(m.cm); // DEBUG
|
||||
|
||||
// I'm looking for edges whose incident faces normals make an angle of at least
|
||||
// 60 degrees (or other threshold value chosen by the user).
|
||||
// I'm also interested in border edges.
|
||||
for(fi=m.cm.face.begin(); fi!=m.cm.face.end(); ++fi) {
|
||||
// Typical usage of the callback for showing a nice progress bar in the bottom.
|
||||
// First parameter is a 0..100 number indicating percentage of completion, the second is an info string.
|
||||
//cb(100*vcount/model.cm.vert.size(), "Exploring the mesh...");
|
||||
|
||||
if(!(*fi).IsD()) {
|
||||
if(hasSel && !(*fi).IsS()) continue; // some faces of the mesh are selected but not the current one
|
||||
for(int j=0; j<3; j++) {
|
||||
if((*fi).FFp(j)->IsV()) continue; // face already visited
|
||||
if(hasSel && !(*fi).FFp(j)->IsS()) continue; // some faces of the mesh are selected, the current one too, but not its j-th neighbour
|
||||
if(/*(*fi).FFp(j) == &(*fi)*/(*fi).IsB(j)) { // found border edge
|
||||
borderNum++;
|
||||
edge2Eroder[sedge(&(*fi), j)] = generateEdgeEroder(true, vcg::Distance((*fi).P0(j), (*fi).P1(j)));
|
||||
// (*fi).SetS(); // DEBUG
|
||||
// (*fi).FFp(j)->SetS(); // DEBUG
|
||||
}
|
||||
else { // this is not a border edge
|
||||
// the angle between the two face normals in degrees
|
||||
// TODO: check non 2-manifold cases, it's all ok? or there are problems?
|
||||
double ffangle = vcg::Angle((*fi).N(), (*fi).FFp(j)->N())*180/M_PI;
|
||||
|
||||
// the 2 points not shared between the 2 faces
|
||||
CVertexO *f1p = (*fi).V2(j);
|
||||
CVertexO *f2p = (*fi).FFp(j)->V2((*fi).FFi(j));
|
||||
|
||||
Point3<CVertexO::ScalarType> y, median;
|
||||
|
||||
y = (*fi).N().Normalize() ^ (*fi).FFp(j)->N().Normalize();
|
||||
median = y ^ (Point3<CVertexO::ScalarType>(f1p->P() - f2p->P()));
|
||||
|
||||
/* There are always 2 cases wich produce the same angle value:
|
||||
___|_ ____
|
||||
| | |
|
||||
-| |-
|
||||
|
||||
In the first case the edge lies in a concave area of the mesh
|
||||
while in the second case it lies in a convex area.
|
||||
I need a way to know wich is the current case.
|
||||
This is done comparing ffangle with the angle between the
|
||||
normal to the current face and the median vector.
|
||||
*/
|
||||
if(ffangle-angleThreshold >= -0.001 && vcg::Angle((*fi).N(), median)*180/M_PI < ffangle) {
|
||||
chips++;
|
||||
// (*fi).SetS(); // DEBUG
|
||||
// (*fi).FFp(j)->SetS(); // DEBUG
|
||||
}
|
||||
}
|
||||
}
|
||||
(*fi).SetV();
|
||||
}
|
||||
switch(ID(filter)) {
|
||||
case FP_ERODE:
|
||||
angleThreshold = params.getAbsPerc("AngleThreshold");
|
||||
edgeLenTreshold = params.getAbsPerc("EdgeLenThreshold");
|
||||
return refineNeededEdges(m.cm, FractPoint(), EdgePred(angleThreshold, edgeLenTreshold), hasSelected(m), cb);
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// erode border edges
|
||||
/*if(borderNum > 0) {
|
||||
CMeshO::VertexIterator lastv = tri::Allocator<CMeshO>::AddVertices(m.cm, borderNum);
|
||||
CMeshO::FaceIterator lastf = tri::Allocator<CMeshO>::AddFaces(m.cm, borderNum);
|
||||
for(map<sedge, vector<EroderPoint>* >::iterator it = edge2Eroder.begin(); it != edge2Eroder.end(); ++it) {
|
||||
if((*it).first.first->IsB((*it).first.second)) { // border face
|
||||
CMeshO::FacePointer f = (*it).first.first;
|
||||
int z = (*it).first.second;
|
||||
vector<EroderPoint>* e = (*it).second;
|
||||
vector<CMeshO::VertexPointer> vv;
|
||||
vector<CMeshO::FacePointer> fv;
|
||||
vector<CMeshO::FaceType::TexCoordType> wtt;
|
||||
|
||||
for(unsigned int j=0; j<3; j++)
|
||||
vv.push_back(f->V((z+j)%3));
|
||||
|
||||
for(unsigned int i=0; i<e->size(); i++) {
|
||||
(*lastv).P() = f->V(z)->P() * (1.0f - e->at(i).yrel) + f->V1(z)->P() * e->at(i).yrel;
|
||||
if(CMeshO::HasPerVertexNormal())
|
||||
(*lastv).N()= (f->V(z)->N() * (1.0f - e->at(i).yrel) + f->V1(z)->N() * e->at(i).yrel).Normalize();
|
||||
if(CMeshO::HasPerVertexColor())
|
||||
(*lastv).C().lerp(f->V(z)->C(), f->V1(z)->C(), e->at(i).yrel);
|
||||
vv.push_back(&*lastv);
|
||||
++lastv;
|
||||
}
|
||||
|
||||
fv.push_back(f);
|
||||
for(unsigned int i=0; i<vv.size()-3; i++) {
|
||||
fv.push_back(&*lastf);
|
||||
++lastf;
|
||||
}
|
||||
|
||||
if(tri::HasPerWedgeTexCoord(m.cm)) {
|
||||
for(unsigned int i=0; i<3; i++)
|
||||
wtt.push_back(f->WT(i));
|
||||
CMeshO::FaceType::TexCoordType t0 = f->WT(z);
|
||||
CMeshO::FaceType::TexCoordType t1 = f->WT((z+1)%3);
|
||||
assert(t0.n() == t1.n());
|
||||
for(unsigned int i=0; i<e->size(); i++) {
|
||||
CMeshO::FaceType::TexCoordType tmp;
|
||||
tmp.n() = t0.n();
|
||||
tmp.t() = (t0.t() * (1.0f - e->at(i).yrel) + t1.t() * e->at(i).yrel);
|
||||
wtt.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
int orgflag = f->UberFlags();
|
||||
for(unsigned int i=0; i<fv.size(); i++) {
|
||||
fv.at(i)->V(0) = vv.at((i>0?2+i:i));
|
||||
fv.at(i)->V(1) = vv.at((i<fv.size()-1?3+i:1));
|
||||
fv.at(i)->V(2) = vv.at(2);
|
||||
if(tri::HasPerWedgeTexCoord(m.cm)) {
|
||||
fv.at(i)->WT(0) = wtt.at((i>0?2+i:i));
|
||||
fv.at(i)->WT(1) = wtt.at((i<fv.size()-1?3+i:1));
|
||||
fv.at(i)->WT(2) = wtt.at(2);
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int i=0; i<fv.size(); i++) {
|
||||
if(orgflag & (CMeshO::FaceType::BORDER0 << z))
|
||||
fv.at(i)->SetB(0);
|
||||
else
|
||||
fv.at(i)->ClearB(0);
|
||||
fv.at(i)->ClearB(1);
|
||||
fv.at(i)->ClearB(2);
|
||||
}
|
||||
if(orgflag & (CMeshO::FaceType::BORDER0 << z+1))
|
||||
fv.at(fv.size()-1)->SetB(1);
|
||||
else
|
||||
fv.at(fv.size()-1)->ClearB(1);
|
||||
if(orgflag & (CMeshO::FaceType::BORDER0 << z+2))
|
||||
fv.at(0)->SetB(2);
|
||||
else
|
||||
fv.at(0)->ClearB(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(m.cm);*/
|
||||
//vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromFF(m.cm);
|
||||
|
||||
// clear V bits again
|
||||
for(fi=m.cm.face.begin(); fi!=m.cm.face.end(); ++fi)
|
||||
(*fi).ClearV();
|
||||
|
||||
// Log function dump textual info in the lower part of the MeshLab screen
|
||||
Log(0,"Found %i border edges and %i internal edges to erode.", borderNum, chips); // DEBUG
|
||||
|
||||
for(map<sedge, vector<EroderPoint>* >::iterator it = edge2Eroder.begin(); it != edge2Eroder.end(); ++it)
|
||||
delete it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -273,14 +126,14 @@ bool GeometryAgingPlugin::hasSelected(MeshModel &m)
|
||||
|
||||
|
||||
// randomly creates a vector of eroderPoints and returns a pointer to it
|
||||
vector<GeometryAgingPlugin::EroderPoint>* GeometryAgingPlugin::generateEdgeEroder(bool border, float len)
|
||||
vector<GeometryAgingPlugin::EroderPoint>* GeometryAgingPlugin::generateEdgeEroder(CMeshO::FacePointer f, int z)
|
||||
{
|
||||
vector<EroderPoint>* e = new vector<EroderPoint>();
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
//std::cout << "len: " << len << std::endl; // DEBUG
|
||||
if(border)
|
||||
if(f->IsB(z))
|
||||
e->push_back(GeometryAgingPlugin::EroderPoint(0.5, 0.0));
|
||||
/*else
|
||||
e->push_back(GeometryAgingPlugin::EroderPoint(0.5, 0.0, 0.0));*/
|
||||
@ -289,4 +142,220 @@ vector<GeometryAgingPlugin::EroderPoint>* GeometryAgingPlugin::generateEdgeErode
|
||||
}
|
||||
|
||||
|
||||
// refines the edges which will be eroded in the next phase
|
||||
bool GeometryAgingPlugin::refineNeededEdges(CMeshO &m, FractPoint frpoi, EdgePred ep, bool hasSelected, CallBackPos *cb)
|
||||
{
|
||||
int j, newVertNum = 0, newFaceNum = 0;
|
||||
typedef std::pair<CMeshO::VertexPointer, CMeshO::VertexPointer> vvpair;
|
||||
typedef std::pair<vvpair, int> vvi;
|
||||
map<vvi, CMeshO::VertexPointer> edge2Vert;
|
||||
|
||||
// First Loop: we analyze the mesh to compute the number of the new faces and new vertices
|
||||
CMeshO::FaceIterator fi;
|
||||
int step = 0, percStep = m.fn / 33;
|
||||
if(percStep == 0) percStep = 1;
|
||||
for(fi=m.face.begin(),j=0; fi!=m.face.end(); ++fi)
|
||||
if(!(*fi).IsD())
|
||||
{
|
||||
if(cb && (++step%percStep) == 0)
|
||||
(*cb)(step/percStep, "Eroding...");
|
||||
for(j=0; j<3; j++) {
|
||||
if(ep(&(*fi), j) && (!hasSelected || ((*fi).IsS() && (*fi).FFp(j)->IsS()))) {
|
||||
int numf = ep.numFacesToAdd(&(*fi), j);
|
||||
if(numf <= 0) continue;
|
||||
newFaceNum += numf;
|
||||
if(((*fi).V(j) < (*fi).V1(j)) || (*fi).IsB(j))
|
||||
newVertNum += numf;
|
||||
}
|
||||
}
|
||||
} // end face loop
|
||||
|
||||
if(newVertNum==0) { // temporary error message
|
||||
errorMessage = QString("Found 0 edges to erode. Change filter parameters and try again.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CMeshO::VertexIterator lastv = tri::Allocator<CMeshO>::AddVertices(m, newVertNum);
|
||||
|
||||
// Second Loop: initialization of the edge-vertexes map
|
||||
// and the position of new vertexes
|
||||
for(fi=m.face.begin(); fi!=m.face.end(); ++fi)
|
||||
if(!(*fi).IsD())
|
||||
{
|
||||
if(cb && (++step%percStep) == 0)
|
||||
(*cb)(step/percStep, "Eroding...");
|
||||
for(j=0; j<3; j++)
|
||||
if(ep(&(*fi), j) && (!hasSelected || ((*fi).IsS() && (*fi).FFp(j)->IsS())))
|
||||
if((*fi).V(j) < (*fi).V1(j) || (*fi).IsB(j)) {
|
||||
int numf = ep.numFacesToAdd(&(*fi), j) + 1;
|
||||
for(int p=1; p<numf; p++) {
|
||||
frpoi((*lastv), face::Pos<CMeshO::FaceType>(&*fi,j), (float)p/numf);
|
||||
edge2Vert[vvi(vvpair((*fi).V(j), (*fi).V1(j)), p)] = &*lastv;
|
||||
++lastv;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(lastv == m.vert.end());
|
||||
|
||||
CMeshO::FaceIterator lastf = tri::Allocator<CMeshO>::AddFaces(m, newFaceNum);
|
||||
CMeshO::FaceIterator oldendf = lastf;
|
||||
|
||||
/*
|
||||
v0
|
||||
|
||||
|
||||
f0
|
||||
|
||||
mp01 mp02
|
||||
|
||||
f3
|
||||
f1 f2
|
||||
|
||||
v1 mp12 v2
|
||||
|
||||
*/
|
||||
|
||||
vector<CMeshO::VertexPointer> vv; // total face vertexes
|
||||
// 0..2 original face vertexes
|
||||
// 3... newly created vertexes
|
||||
vector<CMeshO::FacePointer> nf; // total faces (the original one and the newly created)
|
||||
vector<CMeshO::FaceType::TexCoordType> wtt; // per wedge texture coordinates
|
||||
|
||||
for(fi=m.face.begin(); fi!=oldendf; ++fi)
|
||||
if(!(*fi).IsD())
|
||||
{
|
||||
if(cb && (++step%percStep) == 0)
|
||||
(*cb)(step/percStep, "Eroding...");
|
||||
vv.clear();
|
||||
nf.clear();
|
||||
wtt.clear();
|
||||
vv.push_back((*fi).V(0));
|
||||
vv.push_back((*fi).V(1));
|
||||
vv.push_back((*fi).V(2));
|
||||
int n[3];
|
||||
for(j=0; j<3; j++) {
|
||||
if(ep(&(*fi), j) && (!hasSelected || ((*fi).IsS() && (*fi).FFp(j)->IsS()))) {
|
||||
n[j] = ep.numFacesToAdd(&(*fi), j);
|
||||
if((*fi).V(j) < (*fi).V1(j) || (*fi).IsB(j))
|
||||
for(int p=1; p<n[j]+1; p++)
|
||||
vv.push_back(edge2Vert[vvi(vvpair((*fi).V(j), (*fi).V1(j)), p)]);
|
||||
else
|
||||
for(int p=1; p<n[j]+1; p++)
|
||||
vv.push_back(edge2Vert[vvi(vvpair((*fi).V1(j), (*fi).V(j)), p)]);
|
||||
}
|
||||
else
|
||||
n[j] = 0;
|
||||
}
|
||||
|
||||
nf.push_back(&*fi);
|
||||
int i;
|
||||
for(i=1; i<=n[0]+n[1]+n[2]; i++) {
|
||||
nf.push_back(&*lastf);
|
||||
lastf++;
|
||||
if(hasSelected || (*fi).IsS())
|
||||
(*nf[i]).SetS();
|
||||
}
|
||||
|
||||
if(tri::HasPerWedgeTexCoord(m)) {
|
||||
for(i=0; i<3; ++i)
|
||||
wtt.push_back((*fi).WT(i));
|
||||
for(j=1; j<=n[0]; j++)
|
||||
wtt.push_back(frpoi.WedgeInterp((*fi).WT(0), (*fi).WT(1), j/(n[0]+1)));
|
||||
for(j=1; j<=n[1]; j++)
|
||||
wtt.push_back(frpoi.WedgeInterp((*fi).WT(1), (*fi).WT(2), j/(n[1]+1)));
|
||||
for(j=1; j<=n[2]; j++)
|
||||
wtt.push_back(frpoi.WedgeInterp((*fi).WT(2), (*fi).WT(0), j/(n[2]+1)));
|
||||
}
|
||||
|
||||
int orgflag = (*fi).UberFlags();
|
||||
for(j=0; j<3; j++)
|
||||
splitFaceEdge(m, nf, vv, wtt, n, j, orgflag);
|
||||
}
|
||||
|
||||
assert(lastf == m.face.end());
|
||||
assert(!m.vert.empty());
|
||||
for(fi=m.face.begin(); fi!=m.face.end(); ++fi)
|
||||
if(!(*fi).IsD()){
|
||||
assert((*fi).V(0) >= &*m.vert.begin() && (*fi).V(0) <= &m.vert.back());
|
||||
assert((*fi).V(1) >= &*m.vert.begin() && (*fi).V(1) <= &m.vert.back());
|
||||
assert((*fi).V(2) >= &*m.vert.begin() && (*fi).V(2) <= &m.vert.back());
|
||||
}
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(m);
|
||||
vcg::tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(m);
|
||||
|
||||
Log(0,"Created %i new vertexes and %i new faces.", newVertNum, newFaceNum); // DEBUG
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// splits the current edge (z) of the current face creating numf[z] new faces.
|
||||
// actually the face edges are already splitted: the new vertexes (contained in vector vv) are
|
||||
// already in their final position but the area need to be retriangulated
|
||||
// (vector f contains the pointers to all the faces needed to retriangulate the old face)
|
||||
void GeometryAgingPlugin::splitFaceEdge(CMeshO &m, vector<CMeshO::FacePointer> &f, vector<CMeshO::VertexPointer> &vv, vector<CMeshO::FaceType::TexCoordType> &wtt, int numf[3], int z, int orgflag)
|
||||
{
|
||||
if(numf[z] <= 0) return;
|
||||
|
||||
int idx = 3; // index of the first vertex of the curr face (the second will be idx+1)
|
||||
int idx3; // index of the third vertex of the curr face
|
||||
int oldf = 0; // face to split index
|
||||
int newf = 1; // first new face index
|
||||
int vf0 = (z+1)%3; // index of the vertex to move in face 0 (original face to split)
|
||||
|
||||
if(z == 0)
|
||||
idx3 = 2;
|
||||
else if(z == 1) {
|
||||
if(numf[0] > 0) {
|
||||
idx3 = 2 + numf[0];
|
||||
oldf += numf[0];
|
||||
newf += numf[0];
|
||||
}
|
||||
else
|
||||
idx3 = 0;
|
||||
}
|
||||
else {
|
||||
if(numf[0] > 0) {
|
||||
idx3 = 3;
|
||||
newf += numf[0] + numf[1];
|
||||
}
|
||||
else if(numf[1] > 0) {
|
||||
idx3 = 2 + numf[1];
|
||||
oldf += numf[1];
|
||||
newf += numf[1];
|
||||
vf0 = z;
|
||||
}
|
||||
else
|
||||
idx3 = 1;
|
||||
}
|
||||
|
||||
int i;
|
||||
for(i=0; i<z; i++) idx += numf[i];
|
||||
|
||||
f.at(oldf)->V(vf0) = vv.at(idx);
|
||||
if(tri::HasPerWedgeTexCoord(m))
|
||||
f.at(oldf)->WT((z+1)%3) = wtt.at(idx);
|
||||
if(idx > 2)
|
||||
f.at(oldf)->ClearB((z+1)%3);
|
||||
|
||||
for(i=0; i<numf[z]; i++, idx++, newf++) {
|
||||
f.at(newf)->V(0) = vv.at(idx);
|
||||
f.at(newf)->V(1) = vv.at((i==(numf[z]-1)?(z+1)%3:idx+1));
|
||||
f.at(newf)->V(2) = vv.at(idx3);
|
||||
if(tri::HasPerWedgeTexCoord(m)) {
|
||||
f.at(newf)->WT(0) = wtt.at(idx);
|
||||
f.at(newf)->WT(1) = wtt.at((i==(numf[z]-1)?(z+1)%3:idx+1));
|
||||
f.at(newf)->WT(2) = wtt.at(idx3);
|
||||
}
|
||||
for(int j=0; j<3; j++) assert(f.at(newf)->V(j) != 0);
|
||||
if(orgflag & (CMeshO::FaceType::BORDER0 << z))
|
||||
f.at(newf)->SetB(0);
|
||||
else
|
||||
f.at(newf)->ClearB(0);
|
||||
f.at(newf)->ClearB(1);
|
||||
f.at(newf)->ClearB(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Q_EXPORT_PLUGIN(GeometryAgingPlugin)
|
||||
|
||||
@ -22,14 +22,93 @@
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef GEOMETRYAGINGPLUGIN_H
|
||||
#define GEOMETRYAGINGPLUGIN_H
|
||||
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <meshlab/meshmodel.h>
|
||||
#include <meshlab/interfaces.h>
|
||||
//#include <vcg/complex/trimesh/refine.h>
|
||||
|
||||
|
||||
struct FractPoint : public std::unary_function<face::Pos<CMeshO::FaceType>, CMeshO::CoordType>
|
||||
{
|
||||
void operator()(CMeshO::VertexType &nv, face::Pos<CMeshO::FaceType> ep, float relpos = 0.5f) {
|
||||
nv.P() = ep.f->V(ep.z)->P() * (1.0f - relpos) + ep.f->V1(ep.z)->P() * relpos;
|
||||
if(CMeshO::HasPerVertexNormal())
|
||||
nv.N() = (ep.f->V(ep.z)->N() * (1.0f - relpos) + ep.f->V1(ep.z)->N() * relpos).Normalize();
|
||||
if(CMeshO::HasPerVertexColor())
|
||||
nv.C().lerp(ep.f->V(ep.z)->C(), ep.f->V1(ep.z)->C(), relpos);
|
||||
}
|
||||
|
||||
Color4<CMeshO::ScalarType> WedgeInterp(Color4<CMeshO::ScalarType> &c0, Color4<CMeshO::ScalarType> &c1, float relpos = 0.5f)
|
||||
{
|
||||
Color4<CMeshO::ScalarType> cc;
|
||||
cc.lerp(c0, c1, relpos);
|
||||
return cc;
|
||||
}
|
||||
|
||||
template<class FL_TYPE>
|
||||
TexCoord2<FL_TYPE, 1> WedgeInterp(TexCoord2<FL_TYPE, 1> &t0, TexCoord2<FL_TYPE, 1> &t1, float relpos = 0.5f)
|
||||
{
|
||||
TexCoord2<FL_TYPE, 1> tmp;
|
||||
assert(t0.n() == t1.n());
|
||||
tmp.n() = t0.n();
|
||||
tmp.t() = t0.t() * (1.0f - relpos) + t1.t() * relpos;
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class EdgePred
|
||||
{
|
||||
public:
|
||||
EdgePred(float angleTh, float edgeLenTh) {
|
||||
this->angleTh = angleTh;
|
||||
this->edgeLenTh = edgeLenTh;
|
||||
}
|
||||
|
||||
bool operator()(CMeshO::FacePointer f, int idx) {
|
||||
if(f->IsB(idx)) return true;
|
||||
|
||||
// the angle between the two face normals in degrees
|
||||
// TODO: check non 2-manifold cases, it's all ok? or there are problems?
|
||||
/*double ffangle = vcg::Angle(f->N(), f->FFp(idx)->N()) * 180 / M_PI;
|
||||
|
||||
// the 2 points not shared between the 2 faces
|
||||
CVertexO *f1p = f->V2(idx);
|
||||
CVertexO *f2p = f->FFp(idx)->V2(f->FFi(idx));
|
||||
|
||||
Point3<CVertexO::ScalarType> y, median;
|
||||
|
||||
y = f->N().Normalize() ^ f->FFp(idx)->N().Normalize();
|
||||
median = y ^ (Point3<CVertexO::ScalarType>(f1p->P() - f2p->P()));
|
||||
*/
|
||||
/* There are always 2 cases wich produce the same angle value:
|
||||
___|_ ____
|
||||
| | |
|
||||
-| |-
|
||||
|
||||
In the first case the edge lies in a concave area of the mesh
|
||||
while in the second case it lies in a convex area.
|
||||
We need a way to know wich is the current case.
|
||||
This is done comparing ffangle with the angle between the
|
||||
normal to the current face and the median vector.
|
||||
*/
|
||||
//return (ffangle-angleThreshold >= -0.001 && vcg::Angle(f->N(), median) * 180 / M_PI < ffangle);
|
||||
return false;
|
||||
}
|
||||
|
||||
int numFacesToAdd(CMeshO::FacePointer f, int idx) {
|
||||
return (int)(Distance(f->V(idx)->P(), f->V1(idx)->P()) / edgeLenTh) - 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
float angleTh;
|
||||
float edgeLenTh;
|
||||
};
|
||||
|
||||
|
||||
class GeometryAgingPlugin : public QObject, public MeshFilterInterface
|
||||
@ -62,9 +141,10 @@ class GeometryAgingPlugin : public QObject, public MeshFilterInterface
|
||||
virtual bool applyFilter(QAction *filter, MeshModel &m, FilterParameterSet ¶ms, vcg::CallBackPos *cb);
|
||||
|
||||
protected:
|
||||
virtual bool hasSelected(MeshModel &m);
|
||||
vector<EroderPoint>* generateEdgeEroder(bool border, float len);
|
||||
|
||||
bool hasSelected(MeshModel &m);
|
||||
vector<EroderPoint>* generateEdgeEroder(CMeshO::FacePointer f, int z);
|
||||
bool refineNeededEdges(CMeshO &m, FractPoint mid, EdgePred ep, bool hasSelected, CallBackPos *cb);
|
||||
void splitFaceEdge(CMeshO &m, vector<CMeshO::FacePointer> &f, vector<CMeshO::VertexPointer> &vv, vector<CMeshO::FaceType::TexCoordType> &wtt, int numf[3], int z, int orgflag);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user