mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-20 03:16:10 +00:00
Corrections of include paths to comply the new folder arrangement of the VCG library (a first set of the many filters; removing useless includes)
This commit is contained in:
parent
4a8d3a71df
commit
3a2303e66d
@ -22,7 +22,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "filter_plymc.h"
|
||||
#include <vcg/complex/trimesh/append.h>
|
||||
#include <vcg/complex/append.h>
|
||||
#include <wrap/io_trimesh/export_vmi.h>
|
||||
|
||||
#include "plymc.h"
|
||||
|
||||
@ -5,12 +5,12 @@ HEADERS += filter_plymc.h \
|
||||
voxel.h \
|
||||
plymc.h \
|
||||
simplemeshprovider.h \
|
||||
tri_edge_collapse_mc.h \
|
||||
$$VCGDIR/vcg/complex/local_optimization/tri_edge_collapse.h
|
||||
tri_edge_collapse_mc.h \
|
||||
$$VCGDIR/vcg/algorithms/local_optimization/tri_edge_collapse.h
|
||||
|
||||
|
||||
SOURCES += filter_plymc.cpp \
|
||||
../../../../vcglib/wrap/ply/plylib.cpp
|
||||
$$VCGDIR/wrap/ply/plylib.cpp
|
||||
|
||||
TARGET = filter_plymc
|
||||
QT += opengl
|
||||
|
||||
@ -30,28 +30,28 @@
|
||||
#include <vcg/simplex/vertex/base.h>
|
||||
#include <vcg/simplex/face/base.h>
|
||||
#include <vcg/complex/used_types.h>
|
||||
#include <vcg/complex/trimesh/base.h>
|
||||
#include <vcg/complex/complex.h>
|
||||
|
||||
#include <vcg/complex/trimesh/update/position.h>
|
||||
#include <vcg/complex/trimesh/update/normal.h>
|
||||
#include <vcg/complex/trimesh/update/quality.h>
|
||||
#include <vcg/complex/trimesh/update/edges.h>
|
||||
#include <vcg/complex/trimesh/update/topology.h>
|
||||
#include <vcg/complex/trimesh/update/flag.h>
|
||||
#include <vcg/complex/trimesh/update/bounding.h>
|
||||
#include <vcg/complex/algorithms/update/position.h>
|
||||
#include <vcg/complex/algorithms/update/normal.h>
|
||||
#include <vcg/complex/algorithms/update/quality.h>
|
||||
#include <vcg/complex/algorithms/update/edges.h>
|
||||
#include <vcg/complex/algorithms/update/topology.h>
|
||||
#include <vcg/complex/algorithms/update/flag.h>
|
||||
#include <vcg/complex/algorithms/update/bounding.h>
|
||||
#include <vcg/math/histogram.h>
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
#include <wrap/io_trimesh/export_ply.h>
|
||||
#include <wrap/ply/plystuff.h>
|
||||
|
||||
#include <vcg/complex/trimesh/create/marching_cubes.h>
|
||||
#include <vcg/complex/trimesh/create/extended_marching_cubes.h>
|
||||
#include <vcg/complex/algorithms/create/marching_cubes.h>
|
||||
#include <vcg/complex/algorithms/create/extended_marching_cubes.h>
|
||||
#include "trivial_walker.h"
|
||||
// local optimization
|
||||
#include <vcg/complex/local_optimization.h>
|
||||
#include <vcg/complex/local_optimization/tri_edge_collapse.h>
|
||||
#include <vcg/complex/local_optimization/tri_edge_collapse_quadric.h>
|
||||
#include <vcg/complex/algorithms/local_optimization.h>
|
||||
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse.h>
|
||||
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h>
|
||||
|
||||
#include <vcg/simplex/edge/base.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
@ -41,7 +41,7 @@ add samplefilter
|
||||
#include <time.h>
|
||||
|
||||
#include <common/interfaces.h>
|
||||
#include <vcg/complex/trimesh/create/platonic.h>
|
||||
#include <vcg/complex/algorithms/create/platonic.h>
|
||||
|
||||
#include "filter_poisson.h"
|
||||
#include "src/Geometry.h"
|
||||
|
||||
@ -34,12 +34,12 @@ $Log: samplefilter.cpp,v $
|
||||
|
||||
#include "filter_sampling.h"
|
||||
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/trimesh/point_sampling.h>
|
||||
#include <vcg/complex/trimesh/create/resampler.h>
|
||||
#include <vcg/complex/trimesh/clustering.h>
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
#include <vcg/complex/algorithms/point_sampling.h>
|
||||
#include <vcg/complex/algorithms/create/resampler.h>
|
||||
#include <vcg/complex/algorithms/clustering.h>
|
||||
#include <vcg/simplex/face/distance.h>
|
||||
#include <vcg/complex/trimesh/geodesic.h>
|
||||
#include <vcg/complex/algorithms/geodesic.h>
|
||||
#include <vcg/space/index/grid_static_ptr.h>
|
||||
#include "voronoi_clustering.h"
|
||||
|
||||
@ -54,7 +54,7 @@ using namespace std;
|
||||
For example, you can compute Hausdorff distance (that is a sampler) using various
|
||||
sampling strategies (montecarlo, stratified etc).
|
||||
|
||||
For further details see vcg/complex/trimesh/point_sampling.h header file.
|
||||
For further details see vcg/complex/algorithms/point_sampling.h header file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
include (../../shared.pri)
|
||||
|
||||
HEADERS += filter_sampling.h \
|
||||
$$VCGDIR/vcg/complex/trimesh/point_sampling.h
|
||||
$$VCGDIR/vcg/complex/algorithms/point_sampling.h
|
||||
SOURCES += filter_sampling.cpp
|
||||
TARGET = filter_sampling
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
#include <vcg/complex/trimesh/base.h>
|
||||
#include <vcg/complex/trimesh/update/topology.h>
|
||||
#include <vcg/complex/trimesh/update/edges.h>
|
||||
#include <vcg/complex/trimesh/update/bounding.h>
|
||||
#include <vcg/complex/trimesh/update/quality.h>
|
||||
#include <vcg/complex/trimesh/update/color.h>
|
||||
#include <vcg/complex/trimesh/update/flag.h>
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/complex.h>
|
||||
#include <vcg/complex/algorithms/update/topology.h>
|
||||
#include <vcg/complex/algorithms/update/edges.h>
|
||||
#include <vcg/complex/algorithms/update/bounding.h>
|
||||
#include <vcg/complex/algorithms/update/quality.h>
|
||||
#include <vcg/complex/algorithms/update/color.h>
|
||||
#include <vcg/complex/algorithms/update/flag.h>
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
#include <vcg/complex/intersection.h>
|
||||
#include <vcg/space/index/grid_static_ptr.h>
|
||||
#include <vcg/space/index/spatial_hashing.h>
|
||||
|
||||
@ -1,15 +1,6 @@
|
||||
#include <vcg/complex/trimesh/base.h>
|
||||
#include <vcg/complex/trimesh/update/topology.h>
|
||||
#include <vcg/complex/trimesh/update/edges.h>
|
||||
#include <vcg/complex/trimesh/update/bounding.h>
|
||||
#include <vcg/complex/trimesh/update/quality.h>
|
||||
#include <vcg/complex/trimesh/update/color.h>
|
||||
#include <vcg/complex/trimesh/update/flag.h>
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/intersection.h>
|
||||
#include <vcg/complex/algorithms/intersection.h>
|
||||
#include <vcg/space/index/grid_static_ptr.h>
|
||||
#include <vcg/space/index/spatial_hashing.h>
|
||||
#include <vcg/math/matrix33.h>
|
||||
|
||||
#include <vcg/space/index/grid_static_ptr.h> // vcg::GridStaticPtr
|
||||
#include <vcg/space/index/spatial_hashing.h> // vcg::SpatialHashTable
|
||||
@ -107,7 +98,7 @@ bool SdfPlugin::applyFilter(MeshDocument& md, RichParameterSet& pars, vcg::CallB
|
||||
float maxDist=m.bbox.Diag();
|
||||
// This is a small number to avoid self-intersection during ray
|
||||
// casting. It's a very common trick
|
||||
float epsilon = maxDist / 10000.0;
|
||||
float epsilon = maxDist / 1000.0;
|
||||
|
||||
//--- Ray casting
|
||||
vector<Ray3f> cone;
|
||||
@ -118,7 +109,7 @@ bool SdfPlugin::applyFilter(MeshDocument& md, RichParameterSet& pars, vcg::CallB
|
||||
for(int i=0; i<m.vert.size(); i++){
|
||||
CVertexO& v = m.vert[i];
|
||||
//--- Update progressbar
|
||||
cb( i/m.vert.size(), "Casting rays into volume...");
|
||||
cb( 100*i/m.vert.size(), "Casting rays into volume...");
|
||||
|
||||
//--- Generate the set of cones
|
||||
ray.Set( v.P(), -v.N() );
|
||||
@ -148,7 +139,7 @@ bool SdfPlugin::applyFilter(MeshDocument& md, RichParameterSet& pars, vcg::CallB
|
||||
//--- Compute average of samples, throwing away outliers
|
||||
float totVal = 0, totCnt = 0;
|
||||
for(unsigned int i=0; i<coneSdf.size(); i++)
|
||||
if( !math::IsNAN(coneSdf[i]) && coneSdf[i]>loperc && coneSdf[i]<hiperc ){
|
||||
if( !math::IsNAN(coneSdf[i]) && coneSdf[i]>=loperc && coneSdf[i]<=hiperc ){
|
||||
totVal += coneSdf[i];
|
||||
totCnt += 1;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
include (../../shared.pri)
|
||||
|
||||
HEADERS += $$VCGDIR/vcg/complex/trimesh/clean.h\
|
||||
HEADERS += $$VCGDIR/vcg/complex/algorithms/clean.h\
|
||||
meshselect.h
|
||||
SOURCES += meshselect.cpp
|
||||
|
||||
|
||||
@ -26,8 +26,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <vcg/space/colorspace.h>
|
||||
#include "meshselect.h"
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/trimesh/stat.h>
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
#include <vcg/complex/algorithms/stat.h>
|
||||
|
||||
using namespace vcg;
|
||||
|
||||
|
||||
@ -23,13 +23,12 @@
|
||||
|
||||
#include "filter_slice.h"
|
||||
//#include <stdlib.h>
|
||||
#include <vcg/complex/intersection.h>
|
||||
#include <vcg/complex/algorithms/intersection.h>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
#include "filter_slice_functors.h"
|
||||
#include <wrap/gl/glu_tesselator.h>
|
||||
#include <vcg/complex/trimesh/allocate.h>
|
||||
|
||||
#include "kdtree.h"
|
||||
|
||||
|
||||
@ -30,12 +30,8 @@
|
||||
#include <vcg/complex/edgemesh/base.h>
|
||||
|
||||
#include <vcg/complex/edgemesh/update/bounding.h>
|
||||
#include <vcg/complex/trimesh/update/bounding.h>
|
||||
#include <vcg/complex/trimesh/update/flag.h>
|
||||
#include <vcg/complex/trimesh/refine.h>
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/trimesh/append.h>
|
||||
#include <vcg/complex/trimesh/update/selection.h>
|
||||
#include <vcg/complex/algorithms/refine.h>
|
||||
#include <vcg/complex/append.h>
|
||||
#include <wrap/io_edgemesh/export_svg.h>
|
||||
|
||||
#include <vcg/space/plane3.h>
|
||||
|
||||
@ -1,198 +1,198 @@
|
||||
/****************************************************************************
|
||||
* MeshLab o o *
|
||||
* An extendible mesh processor o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005, 2009 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* 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 2 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef SLICE_KD_TREE
|
||||
#define SLICE_KD_TREE
|
||||
#include <vcg/space/point3.h>
|
||||
#include <vcg/complex/trimesh/update/bounding.h>
|
||||
#include "filter_slice_functors.h"
|
||||
#include "filter_slice.h"
|
||||
|
||||
template<typename MeshType>
|
||||
class KDTree
|
||||
{
|
||||
protected:
|
||||
KDTree<MeshType> *leftChild, *rightChild;
|
||||
MeshType *slice;
|
||||
MeshModel* mm;
|
||||
Point3f planeAxis;
|
||||
MeshDocument *m;
|
||||
int axisIndex;
|
||||
float eps;
|
||||
QString name;
|
||||
public:
|
||||
bool delfather;
|
||||
enum{X,Y,Z};
|
||||
KDTree(MeshDocument *_m, MeshModel* _mm, float _eps, int _axisIndex=X)
|
||||
{
|
||||
name="";
|
||||
m=_m;
|
||||
mm=_mm;
|
||||
eps=_eps;
|
||||
planeAxis=Point3f(0,0,0);
|
||||
leftChild=0;
|
||||
rightChild=0;
|
||||
slice=0;
|
||||
axisIndex=_axisIndex;
|
||||
assert(axisIndex>=0 && axisIndex<3);
|
||||
planeAxis[axisIndex]=1;
|
||||
delfather=false;
|
||||
}
|
||||
~KDTree(){}
|
||||
KDTree<MeshType>* L(){return leftChild;}
|
||||
KDTree<MeshType>* R(){return rightChild;}
|
||||
MeshType* S(){return slice;}
|
||||
void Slice(vcg::CallBackPos *cb)
|
||||
{
|
||||
Plane3f slicingPlane;
|
||||
vcg::tri::UpdateBounding<CMeshO>::Box(mm->cm);
|
||||
slicingPlane.Init(mm->cm.bbox.Center(),planeAxis);
|
||||
actual_slice(slicingPlane,cb);
|
||||
}
|
||||
|
||||
void actual_slice(Plane3f slicingPlane,vcg::CallBackPos *cb=0)
|
||||
{
|
||||
if (mm->cm.vn<=0)
|
||||
return;
|
||||
mm->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
if ( tri::Clean<CMeshO>::CountNonManifoldEdgeFF(mm->cm)>0 || tri::Clean<CMeshO>::CountNonManifoldVertexFF(mm->cm,false) != 0)
|
||||
return;
|
||||
|
||||
if (rightChild!=0 && leftChild!=0)
|
||||
{
|
||||
//find a plane
|
||||
Plane3f slicingPlane;
|
||||
vcg::Box3f leftbox=leftChild->mm->cm.bbox;
|
||||
vcg::Box3f rightbox=rightChild->mm->cm.bbox;
|
||||
leftbox.Translate(planeAxis*((leftbox.Dim()*.2)*planeAxis));
|
||||
rightbox.Translate(planeAxis*(-1)*((rightbox.Dim()*.2)*planeAxis));
|
||||
leftbox.Intersect(rightbox);
|
||||
slicingPlane.Init(leftbox.Center(),leftChild->planeAxis);
|
||||
|
||||
leftChild->actual_slice(slicingPlane,cb);
|
||||
rightChild->actual_slice(slicingPlane,cb);
|
||||
return;
|
||||
}
|
||||
//bool oriented;
|
||||
//bool orientable;
|
||||
//tolto per controllare le normali
|
||||
//tri::Clean<CMeshO>::IsOrientedMesh(mm->cm, oriented,orientable);
|
||||
//actual slicing
|
||||
|
||||
|
||||
//vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromNone(mm->cm);
|
||||
|
||||
SlicedEdge<CMeshO> slicededge(slicingPlane);
|
||||
SlicingFunction<CMeshO> slicingfunc(slicingPlane);
|
||||
//after the RefineE call, the mesh will be half vertices selected
|
||||
vcg::RefineE<CMeshO, SlicingFunction<CMeshO>, SlicedEdge<CMeshO> >
|
||||
(mm->cm, slicingfunc, slicededge, false, cb);
|
||||
//vcg::tri::UpdateTopology<MeshType>::FaceFace(mm->cm);
|
||||
vcg::tri::UpdateNormals<CMeshO>::PerVertexPerFace(mm->cm);
|
||||
//vcg::tri::Clean<CMeshO>::RemoveDuplicateVertex(mm->cm);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(mm->cm);
|
||||
|
||||
|
||||
|
||||
|
||||
QString layername;
|
||||
layername=name+"L.ply";
|
||||
MeshModel *slice1= m->addNewMesh("",qPrintable(layername));
|
||||
m->meshList.push_back(slice1); // mesh name
|
||||
slice1->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
vcg::tri::UpdateSelection<CMeshO>::VertexFromQualityRange(mm->cm,VERTEX_LEFT,VERTEX_LEFT);
|
||||
vcg::tri::UpdateSelection<CMeshO>::FaceFromVertexLoose(mm->cm);
|
||||
//if (hideSlices)
|
||||
//slice1->visible=false;
|
||||
//createSlice(mm->cm,slice1);
|
||||
tri::Append<CMeshO,CMeshO>::Mesh(slice1->cm, mm->cm, true);
|
||||
tri::UpdateTopology<CMeshO>::FaceFace(slice1->cm);
|
||||
tri::UpdateBounding<CMeshO>::Box(slice1->cm); // updates bounding box
|
||||
slice1->cm.Tr = (mm->cm).Tr; // copy transformation
|
||||
vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromNone(slice1->cm);
|
||||
layername=name+"_slice.ply";
|
||||
MeshModel* cap= m->addNewMesh("",qPrintable(layername));
|
||||
m->meshList.push_back(cap);
|
||||
cap->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
ExtraFilter_SlicePlugin::capHole(slice1,cap);
|
||||
|
||||
if (eps!=0)
|
||||
{
|
||||
layername=name+"_extr.ply";
|
||||
MeshModel* dup = m->addNewMesh("",qPrintable(layername));
|
||||
m->meshList.push_back(dup);
|
||||
dup->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
ExtraFilter_SlicePlugin::extrude(m,cap, dup, eps, planeAxis);
|
||||
}
|
||||
|
||||
tri::Append<CMeshO,CMeshO>::Mesh(slice1->cm, cap->cm);
|
||||
tri::Clean<CMeshO>::RemoveDuplicateVertex(slice1->cm);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(slice1->cm);
|
||||
vcg::tri::UpdateNormals<CMeshO>::PerVertexPerFace(slice1->cm);
|
||||
layername=name+"R.ply";
|
||||
MeshModel* slice2= m->addNewMesh("",qPrintable(layername));
|
||||
m->meshList.push_back(slice2);
|
||||
|
||||
slice2->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
vcg::tri::UpdateSelection<CMeshO>::VertexFromQualityRange(mm->cm,VERTEX_RIGHT,VERTEX_RIGHT);
|
||||
vcg::tri::UpdateSelection<CMeshO>::FaceFromVertexLoose(mm->cm);
|
||||
//createSlice(mesh,slice2);
|
||||
tri::Append<CMeshO,CMeshO>::Mesh(slice2->cm, mm->cm, true);
|
||||
tri::UpdateTopology<CMeshO>::FaceFace(slice2->cm);
|
||||
tri::UpdateBounding<CMeshO>::Box(slice2->cm); // updates bounding box
|
||||
slice2->cm.Tr = (mm->cm).Tr; // copy transformation
|
||||
tri::Clean<CMeshO>::FlipMesh(cap->cm);
|
||||
vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromNone(slice2->cm);
|
||||
tri::Append<CMeshO,CMeshO>::Mesh(slice2->cm, cap->cm);
|
||||
tri::Clean<CMeshO>::RemoveDuplicateVertex(slice2->cm);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(slice2->cm);
|
||||
vcg::tri::UpdateNormals<CMeshO>::PerVertexPerFace(slice2->cm);
|
||||
|
||||
leftChild=new KDTree<MeshType>(m,slice1,eps,(axisIndex+1)%3);
|
||||
leftChild->delfather=delfather;
|
||||
layername=name+"L";
|
||||
leftChild->name=layername.toStdString().c_str();
|
||||
rightChild=new KDTree<MeshType>(m,slice2,eps,(axisIndex+1)%3);
|
||||
rightChild->delfather=delfather;
|
||||
layername=name+"R";
|
||||
rightChild->name=layername.toStdString().c_str();
|
||||
|
||||
slice1->visible=false;
|
||||
slice1->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(slice1->cm);
|
||||
vcg::tri::UpdateBounding<CMeshO>::Box(slice1->cm);
|
||||
|
||||
slice2->visible=false;
|
||||
slice2->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(slice2->cm);
|
||||
vcg::tri::UpdateBounding<CMeshO>::Box(slice2->cm);
|
||||
|
||||
cap->visible=false;
|
||||
//if (delfather)
|
||||
//m->delMesh(mm);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
/****************************************************************************
|
||||
* MeshLab o o *
|
||||
* An extendible mesh processor o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005, 2009 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* 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 2 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef SLICE_KD_TREE
|
||||
#define SLICE_KD_TREE
|
||||
#include <vcg/space/point3.h>
|
||||
#include <vcg/complex/algorithms/update/bounding.h>
|
||||
#include "filter_slice_functors.h"
|
||||
#include "filter_slice.h"
|
||||
|
||||
template<typename MeshType>
|
||||
class KDTree
|
||||
{
|
||||
protected:
|
||||
KDTree<MeshType> *leftChild, *rightChild;
|
||||
MeshType *slice;
|
||||
MeshModel* mm;
|
||||
Point3f planeAxis;
|
||||
MeshDocument *m;
|
||||
int axisIndex;
|
||||
float eps;
|
||||
QString name;
|
||||
public:
|
||||
bool delfather;
|
||||
enum{X,Y,Z};
|
||||
KDTree(MeshDocument *_m, MeshModel* _mm, float _eps, int _axisIndex=X)
|
||||
{
|
||||
name="";
|
||||
m=_m;
|
||||
mm=_mm;
|
||||
eps=_eps;
|
||||
planeAxis=Point3f(0,0,0);
|
||||
leftChild=0;
|
||||
rightChild=0;
|
||||
slice=0;
|
||||
axisIndex=_axisIndex;
|
||||
assert(axisIndex>=0 && axisIndex<3);
|
||||
planeAxis[axisIndex]=1;
|
||||
delfather=false;
|
||||
}
|
||||
~KDTree(){}
|
||||
KDTree<MeshType>* L(){return leftChild;}
|
||||
KDTree<MeshType>* R(){return rightChild;}
|
||||
MeshType* S(){return slice;}
|
||||
void Slice(vcg::CallBackPos *cb)
|
||||
{
|
||||
Plane3f slicingPlane;
|
||||
vcg::tri::UpdateBounding<CMeshO>::Box(mm->cm);
|
||||
slicingPlane.Init(mm->cm.bbox.Center(),planeAxis);
|
||||
actual_slice(slicingPlane,cb);
|
||||
}
|
||||
|
||||
void actual_slice(Plane3f slicingPlane,vcg::CallBackPos *cb=0)
|
||||
{
|
||||
if (mm->cm.vn<=0)
|
||||
return;
|
||||
mm->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
if ( tri::Clean<CMeshO>::CountNonManifoldEdgeFF(mm->cm)>0 || tri::Clean<CMeshO>::CountNonManifoldVertexFF(mm->cm,false) != 0)
|
||||
return;
|
||||
|
||||
if (rightChild!=0 && leftChild!=0)
|
||||
{
|
||||
//find a plane
|
||||
Plane3f slicingPlane;
|
||||
vcg::Box3f leftbox=leftChild->mm->cm.bbox;
|
||||
vcg::Box3f rightbox=rightChild->mm->cm.bbox;
|
||||
leftbox.Translate(planeAxis*((leftbox.Dim()*.2)*planeAxis));
|
||||
rightbox.Translate(planeAxis*(-1)*((rightbox.Dim()*.2)*planeAxis));
|
||||
leftbox.Intersect(rightbox);
|
||||
slicingPlane.Init(leftbox.Center(),leftChild->planeAxis);
|
||||
|
||||
leftChild->actual_slice(slicingPlane,cb);
|
||||
rightChild->actual_slice(slicingPlane,cb);
|
||||
return;
|
||||
}
|
||||
//bool oriented;
|
||||
//bool orientable;
|
||||
//tolto per controllare le normali
|
||||
//tri::Clean<CMeshO>::IsOrientedMesh(mm->cm, oriented,orientable);
|
||||
//actual slicing
|
||||
|
||||
|
||||
//vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromNone(mm->cm);
|
||||
|
||||
SlicedEdge<CMeshO> slicededge(slicingPlane);
|
||||
SlicingFunction<CMeshO> slicingfunc(slicingPlane);
|
||||
//after the RefineE call, the mesh will be half vertices selected
|
||||
vcg::RefineE<CMeshO, SlicingFunction<CMeshO>, SlicedEdge<CMeshO> >
|
||||
(mm->cm, slicingfunc, slicededge, false, cb);
|
||||
//vcg::tri::UpdateTopology<MeshType>::FaceFace(mm->cm);
|
||||
vcg::tri::UpdateNormals<CMeshO>::PerVertexPerFace(mm->cm);
|
||||
//vcg::tri::Clean<CMeshO>::RemoveDuplicateVertex(mm->cm);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(mm->cm);
|
||||
|
||||
|
||||
|
||||
|
||||
QString layername;
|
||||
layername=name+"L.ply";
|
||||
MeshModel *slice1= m->addNewMesh("",qPrintable(layername));
|
||||
m->meshList.push_back(slice1); // mesh name
|
||||
slice1->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
vcg::tri::UpdateSelection<CMeshO>::VertexFromQualityRange(mm->cm,VERTEX_LEFT,VERTEX_LEFT);
|
||||
vcg::tri::UpdateSelection<CMeshO>::FaceFromVertexLoose(mm->cm);
|
||||
//if (hideSlices)
|
||||
//slice1->visible=false;
|
||||
//createSlice(mm->cm,slice1);
|
||||
tri::Append<CMeshO,CMeshO>::Mesh(slice1->cm, mm->cm, true);
|
||||
tri::UpdateTopology<CMeshO>::FaceFace(slice1->cm);
|
||||
tri::UpdateBounding<CMeshO>::Box(slice1->cm); // updates bounding box
|
||||
slice1->cm.Tr = (mm->cm).Tr; // copy transformation
|
||||
vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromNone(slice1->cm);
|
||||
layername=name+"_slice.ply";
|
||||
MeshModel* cap= m->addNewMesh("",qPrintable(layername));
|
||||
m->meshList.push_back(cap);
|
||||
cap->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
ExtraFilter_SlicePlugin::capHole(slice1,cap);
|
||||
|
||||
if (eps!=0)
|
||||
{
|
||||
layername=name+"_extr.ply";
|
||||
MeshModel* dup = m->addNewMesh("",qPrintable(layername));
|
||||
m->meshList.push_back(dup);
|
||||
dup->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
ExtraFilter_SlicePlugin::extrude(m,cap, dup, eps, planeAxis);
|
||||
}
|
||||
|
||||
tri::Append<CMeshO,CMeshO>::Mesh(slice1->cm, cap->cm);
|
||||
tri::Clean<CMeshO>::RemoveDuplicateVertex(slice1->cm);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(slice1->cm);
|
||||
vcg::tri::UpdateNormals<CMeshO>::PerVertexPerFace(slice1->cm);
|
||||
layername=name+"R.ply";
|
||||
MeshModel* slice2= m->addNewMesh("",qPrintable(layername));
|
||||
m->meshList.push_back(slice2);
|
||||
|
||||
slice2->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
vcg::tri::UpdateSelection<CMeshO>::VertexFromQualityRange(mm->cm,VERTEX_RIGHT,VERTEX_RIGHT);
|
||||
vcg::tri::UpdateSelection<CMeshO>::FaceFromVertexLoose(mm->cm);
|
||||
//createSlice(mesh,slice2);
|
||||
tri::Append<CMeshO,CMeshO>::Mesh(slice2->cm, mm->cm, true);
|
||||
tri::UpdateTopology<CMeshO>::FaceFace(slice2->cm);
|
||||
tri::UpdateBounding<CMeshO>::Box(slice2->cm); // updates bounding box
|
||||
slice2->cm.Tr = (mm->cm).Tr; // copy transformation
|
||||
tri::Clean<CMeshO>::FlipMesh(cap->cm);
|
||||
vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromNone(slice2->cm);
|
||||
tri::Append<CMeshO,CMeshO>::Mesh(slice2->cm, cap->cm);
|
||||
tri::Clean<CMeshO>::RemoveDuplicateVertex(slice2->cm);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(slice2->cm);
|
||||
vcg::tri::UpdateNormals<CMeshO>::PerVertexPerFace(slice2->cm);
|
||||
|
||||
leftChild=new KDTree<MeshType>(m,slice1,eps,(axisIndex+1)%3);
|
||||
leftChild->delfather=delfather;
|
||||
layername=name+"L";
|
||||
leftChild->name=layername.toStdString().c_str();
|
||||
rightChild=new KDTree<MeshType>(m,slice2,eps,(axisIndex+1)%3);
|
||||
rightChild->delfather=delfather;
|
||||
layername=name+"R";
|
||||
rightChild->name=layername.toStdString().c_str();
|
||||
|
||||
slice1->visible=false;
|
||||
slice1->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(slice1->cm);
|
||||
vcg::tri::UpdateBounding<CMeshO>::Box(slice1->cm);
|
||||
|
||||
slice2->visible=false;
|
||||
slice2->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
vcg::tri::UpdateTopology<CMeshO>::FaceFace(slice2->cm);
|
||||
vcg::tri::UpdateBounding<CMeshO>::Box(slice2->cm);
|
||||
|
||||
cap->visible=false;
|
||||
//if (delfather)
|
||||
//m->delMesh(mm);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -27,8 +27,8 @@
|
||||
#include <QObject>
|
||||
#include <QTime>
|
||||
|
||||
#include <vcg/complex/trimesh/attribute_seam.h>
|
||||
#include <vcg/complex/trimesh/point_sampling.h>
|
||||
#include <vcg/complex/algorithms/attribute_seam.h>
|
||||
#include <vcg/complex/algorithms/point_sampling.h>
|
||||
#include <vcg/space/triangle2.h>
|
||||
#include <common/interfaces.h>
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ $Log: samplefilter.cpp,v $
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <meshlab/meshmodel.h>
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
|
||||
#include "filter_texture.h"
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
#include <QtGui>
|
||||
#include <common/interfaces.h>
|
||||
#include <vcg/complex/trimesh/point_sampling.h>
|
||||
#include <vcg/complex/algorithms/point_sampling.h>
|
||||
#include <vcg/space/triangle2.h>
|
||||
|
||||
class VertexSampler
|
||||
|
||||
@ -24,12 +24,9 @@
|
||||
#include <QtGui>
|
||||
#include "filter_unsharp.h"
|
||||
|
||||
#include <vcg/complex/trimesh/update/quality.h>
|
||||
#include <vcg/complex/trimesh/update/color.h>
|
||||
#include <vcg/complex/trimesh/update/selection.h>
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/trimesh/smooth.h>
|
||||
#include <vcg/complex/trimesh/crease_cut.h>
|
||||
#include <vcg/complex/algorithms/clean.h>
|
||||
#include <vcg/complex/algorithms/smooth.h>
|
||||
#include <vcg/complex/algorithms/crease_cut.h>
|
||||
|
||||
|
||||
using namespace vcg;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
include (../../shared.pri)
|
||||
|
||||
HEADERS += filter_unsharp.h \
|
||||
$$VCGDIR/vcg/complex/trimesh/crease_cut.h
|
||||
$$VCGDIR/vcg/complex/algorithms/crease_cut.h
|
||||
|
||||
SOURCES += filter_unsharp.cpp
|
||||
|
||||
|
||||
@ -1,484 +1,484 @@
|
||||
#ifndef VCGLIB_REGION_GROWING
|
||||
#define VCGLIB_REGION_GROWING
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <vcg/complex/trimesh/allocate.h>
|
||||
|
||||
template <class FaceType>
|
||||
struct FaceError{
|
||||
FaceType * f;
|
||||
float val;
|
||||
FaceError(){};
|
||||
FaceError(FaceType * _f,double _val):f(_f),val(_val){}
|
||||
const bool operator <(const FaceError & o) const {return val < o.val;}
|
||||
};
|
||||
|
||||
|
||||
template<class MeshType>
|
||||
struct Region{
|
||||
Region():isd(false){}
|
||||
typedef Region RegionType;
|
||||
typedef typename MeshType MeshType;
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename MeshType::FaceType::CoordType CoordType;
|
||||
typedef typename MeshType::FaceType::ScalarType ScalarType;
|
||||
typedef typename std::vector<typename MeshType::FaceType*>::iterator FaceIterator;
|
||||
typedef typename std::list<Region*>::iterator AdjIterator;
|
||||
typedef FaceError<FaceType> FaceError;
|
||||
|
||||
// adjacent regions
|
||||
std::list<RegionType*> adj,nx_adj;
|
||||
|
||||
|
||||
// some flag
|
||||
bool isd;
|
||||
|
||||
// evaluate the gain if the triangle is added to the region
|
||||
ScalarType Evaluate( FaceType & f);
|
||||
|
||||
// update the approximation error of the region
|
||||
void UpdateError( );
|
||||
|
||||
// check if two regions are mergeable in one
|
||||
// i.e. if they have the same planes and coincide i non extreme
|
||||
ScalarType Mergeable( RegionType & tr);
|
||||
|
||||
// set the region as adjacent to this one
|
||||
void Connect( RegionType * tr);
|
||||
|
||||
// compute the faces which are on the border
|
||||
void ComputeOnBorder( std::vector<FaceType*> & onBorder);
|
||||
|
||||
// clean the list of adjacencies
|
||||
void Clean();
|
||||
|
||||
// refit the plane
|
||||
void Refit();
|
||||
|
||||
// keep the best % percentile
|
||||
void CutOff( FaceType*f);
|
||||
|
||||
// restart from the best fitting face
|
||||
void Restart();
|
||||
|
||||
void Decorate();
|
||||
|
||||
};
|
||||
|
||||
|
||||
template < class RegionType>
|
||||
class RegionGrower{
|
||||
public:
|
||||
RegionGrower():lastAdded(NULL),ave_error(-1),ave_var(-1),n_steps(0){}
|
||||
typedef typename RegionType RegionType;
|
||||
typedef typename RegionType::MeshType MeshType;
|
||||
typedef typename RegionType::FaceType FaceType;
|
||||
typedef typename FaceType::ScalarType ScalarType;
|
||||
typedef typename std::list<RegionType> ::iterator TriRegIterator;
|
||||
typedef typename std::list<RegionType*>::iterator AdjIterator;
|
||||
typedef typename RegionType::FaceError FaceError;
|
||||
|
||||
std::list<RegionType> regions;
|
||||
std::vector<RegionType*> workingset;
|
||||
int n_faces,target_max_regions;
|
||||
FaceType * lastAdded;
|
||||
ScalarType ave_error // average error (over single regions' error)
|
||||
,ave_var// average variance (over single regions' error)
|
||||
,changed // faces that have changed from previous step ([0..1))
|
||||
,err
|
||||
,target_error; // taget error
|
||||
|
||||
FaceType * worst;
|
||||
ScalarType worst_err ;
|
||||
MeshType * m;
|
||||
|
||||
typename MeshType:: template PerFaceAttributeHandle<int*> attr_r;
|
||||
typename MeshType:: template PerFaceAttributeHandle<int*> attr_r_old;
|
||||
|
||||
unsigned int n_steps;// number of steps done
|
||||
|
||||
struct CandiFace{
|
||||
FaceType * f;
|
||||
float val;
|
||||
RegionType * r;
|
||||
char inPlane; // a quale piano di r
|
||||
CandiFace(){};
|
||||
CandiFace(FaceType * _f,double _val,RegionType * _r):f(_f),val(_val),r(_r){}
|
||||
const bool operator <(const CandiFace & o) const {return val < o.val;}
|
||||
};
|
||||
|
||||
std::vector<CandiFace> facesheap;
|
||||
std::vector<FaceError > faceserr;
|
||||
|
||||
struct ErrorEval {
|
||||
|
||||
void Add(const float & v){
|
||||
if(!ns){
|
||||
if(v < samples[i_min]) i_min = 0; else {++i_min;
|
||||
if(v > samples[i_max]) i_max = 0;else ++i_max;
|
||||
}
|
||||
if(i_min == samples.size()) {i_min = 0; for(int i= 0; i < samples.size(); ++i) if(samples[i]<samples[i_min]) i_min = i; }
|
||||
if(i_max == samples.size()) {i_max = 0; for(int i= 0; i < samples.size(); ++i) if(samples[i]>samples[i_max]) i_max = i; }
|
||||
}
|
||||
samples.pop_back();samples.push_front(v);
|
||||
boxes.pop_back(); boxes.push_front(vcg::Point2f(samples[i_min],samples[i_max]));
|
||||
++ns ;
|
||||
}
|
||||
|
||||
float BoxOverlap(){
|
||||
float maxsize = std::max( boxes.back()[1]-boxes.back()[0], (*boxes.begin())[1]-(*boxes.begin())[0]);
|
||||
float overlap = std::max(0.f, std::min(boxes.back()[1],(*boxes.begin())[1])-std::max(boxes.back()[0],(*boxes.begin())[0]));
|
||||
assert(overlap <= maxsize);
|
||||
return (maxsize > 0.f)?overlap / maxsize:0.0;
|
||||
}
|
||||
float RelativeDecrease(){
|
||||
if (ns<2) return std::numeric_limits<float>::max();
|
||||
return (samples[0]<10e-22)?0.0:(samples[1]-samples[0])/samples[0];
|
||||
}
|
||||
|
||||
void Init(int n ){
|
||||
|
||||
samples.clear();
|
||||
boxes.clear();
|
||||
for(int i = 0 ; i < n; ++i) samples.push_front(std::numeric_limits<float>::max());
|
||||
for(int i = 0 ; i < n; ++i) boxes.push_front(vcg::Point2f(n,n-i));
|
||||
i_max = i_min = 0;
|
||||
ns = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
int i_min,i_max; // index of min and max element in the queue
|
||||
std::deque<float> samples;
|
||||
std::deque<vcg::Point2f> boxes;
|
||||
int ns;
|
||||
|
||||
};
|
||||
|
||||
ErrorEval erroreval;
|
||||
// init
|
||||
void Init(MeshType & mesh, int n_seeds,int max_regions, float max_err){
|
||||
erroreval.Init(10);
|
||||
m = &mesh;
|
||||
vcg::tri::Allocator<MeshType>::CompactFaceVector(*m);
|
||||
vcg::tri::UpdateTopology<MeshType>::FaceFace(*m);
|
||||
|
||||
float area = 0.f;
|
||||
for(typename MeshType::FaceIterator fi = m->face.begin(); fi != m->face.end(); ++fi)
|
||||
area += vcg::DoubleArea(*fi);
|
||||
area/=2.f;
|
||||
target_error = area*max_err*max_err;
|
||||
target_max_regions = max_regions;
|
||||
|
||||
// tte an attibute that will store the address in ocme for the vertex
|
||||
attr_r = vcg::tri::Allocator<MeshType>::template GetPerFaceAttribute<int*> (*m,"r");
|
||||
if(!vcg::tri::Allocator<MeshType>::IsValidHandle(*m,attr_r))
|
||||
attr_r = vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<int*> (*m,"r");
|
||||
|
||||
attr_r_old = vcg::tri::Allocator<MeshType>::template GetPerFaceAttribute<int*> (*m,"r_old");
|
||||
if(!vcg::tri::Allocator<MeshType>::IsValidHandle(*m,attr_r_old))
|
||||
attr_r_old = vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<int*> (*m,"r_old");
|
||||
|
||||
regions.clear();
|
||||
|
||||
for(int i = 0; i < m->face.size(); ++i){
|
||||
attr_r[i] = NULL;
|
||||
attr_r_old[i] = NULL;
|
||||
if( (i%(m->fn/n_seeds))==0)
|
||||
CreateRegion(&m->face[i]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// add a region
|
||||
void AddRegion(const RegionType & r){regions.push_back(r);}
|
||||
|
||||
// remove a region
|
||||
void DeleteRegion(const typename std::list<RegionType>::iterator & ri){std::remove(ri);}
|
||||
|
||||
// initialize a region
|
||||
void CreateRegion(FaceType * fi){
|
||||
AddRegion(RegionType());
|
||||
RegionType & tr =regions.back();
|
||||
AddFaceToRegion(tr,fi);
|
||||
tr.Refit();
|
||||
tr.color = vcg::Color4b::Scatter(2000,(int)regions.size());
|
||||
}
|
||||
void AddFaceToRegion( RegionType & r, FaceType * f){
|
||||
r.face.push_back(f);
|
||||
attr_r[*f] = (int*) &r;
|
||||
if(attr_r[*f]!=attr_r_old[*f]) ++r.changed;
|
||||
attr_r_old[*f] = attr_r[*f];
|
||||
++r.size;
|
||||
}
|
||||
|
||||
void Merge(RegionType & r0,RegionType & r1){
|
||||
assert(!r1.isd);
|
||||
typename RegionType::FaceIterator fi;
|
||||
AdjIterator ai;
|
||||
for(fi = r1.face.begin();fi != r1.face.end(); ++fi)
|
||||
AddFaceToRegion(r0,(*fi));
|
||||
for(ai= r1.adj.begin(); ai != r1.adj.end();++ai)
|
||||
if( !(*ai)->isd && (*ai)!=&r0)
|
||||
r0.nx_adj.push_back(*ai);
|
||||
|
||||
r1.face.clear();
|
||||
r1.isd = true;
|
||||
r0.Refit();
|
||||
}
|
||||
|
||||
|
||||
void PushHeap(std::vector<FaceType*> & candi, RegionType & r){
|
||||
typename std::vector<FaceType*>::iterator ci;
|
||||
for(ci = candi.begin(); ci != candi.end(); ++ci)
|
||||
{
|
||||
facesheap.push_back(CandiFace( *ci,-r.Evaluate(*(*ci)), &r));
|
||||
push_heap(facesheap.begin(),facesheap.end());
|
||||
}
|
||||
}
|
||||
|
||||
// the two regions are adjacent
|
||||
void Connect(RegionType * r1,RegionType * r2){
|
||||
assert(r1!=r2);
|
||||
r1->Connect(r2);
|
||||
r2->Connect(r1);
|
||||
}
|
||||
|
||||
// for each region take the candidates and fill in facesheap
|
||||
void Refill( ){
|
||||
facesheap.clear();
|
||||
|
||||
typename std::list<RegionType>::iterator ri;
|
||||
|
||||
std::vector<FaceType*> candi;
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri) if(!(*ri).isd)
|
||||
{
|
||||
candi.clear();
|
||||
Candidates((*ri),candi);
|
||||
PushHeap(candi,*ri);
|
||||
}
|
||||
std::make_heap(facesheap.begin(),facesheap.end());
|
||||
}
|
||||
|
||||
|
||||
void Candidates(RegionType & r, std::vector< typename RegionType::FaceType*> & c){
|
||||
typename RegionType::FaceIterator fi;
|
||||
|
||||
for(fi = r.face.begin(); fi!= r.face.end(); ++fi)
|
||||
for(int i = 0; i < 3; ++i)
|
||||
if( ((*fi)->FFp(i) != (*fi) ) &&
|
||||
(attr_r[(*fi)->FFp(i)] != (int*) &r) )
|
||||
c.push_back((*fi)->FFp(i));
|
||||
}
|
||||
|
||||
bool IsRelaxed(){
|
||||
ScalarType _ave_error=0;
|
||||
ScalarType _ave_var= 0;
|
||||
ScalarType _changed = 0.0;
|
||||
int nr=0;
|
||||
|
||||
typename std::list<RegionType>::iterator ri;
|
||||
worst=NULL;;
|
||||
worst_err = -1;
|
||||
qDebug("working set size: %d\n",workingset.size());
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri) if(!(*ri).isd){
|
||||
++nr;
|
||||
(*ri).UpdateError();
|
||||
_ave_error+=(*ri).approx_err;
|
||||
_ave_var+=(*ri).approx_var;
|
||||
_changed+=(*ri).changed;
|
||||
(*ri).changed=0;
|
||||
if((*ri).worst.val*(*ri).size > worst_err){
|
||||
worst = (*ri).worst.f;
|
||||
worst_err = (*ri).worst.val*(*ri).size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_ave_error/=nr;
|
||||
_ave_var/=nr;
|
||||
_changed/=n_faces;
|
||||
|
||||
erroreval.Add(_ave_error);
|
||||
qDebug("Err:%f ov: %f-------",_ave_error,erroreval.BoxOverlap());
|
||||
|
||||
|
||||
return (erroreval.BoxOverlap() > 0.5) || (erroreval.RelativeDecrease() < 0.1);
|
||||
}
|
||||
|
||||
void GrowStepOnce(){
|
||||
CandiFace cf;
|
||||
typename std::list<RegionType>::iterator ri;
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri) if(!(*ri).isd)
|
||||
(*ri).Clean();
|
||||
|
||||
if(!facesheap.empty()){
|
||||
|
||||
std::vector<FaceType*> toAdd;
|
||||
std::pop_heap(facesheap.begin(),facesheap.end());
|
||||
cf = facesheap.back();
|
||||
// qDebug("err:%f\n",cf.val);
|
||||
facesheap.pop_back();
|
||||
if (attr_r[*cf.f]==NULL){
|
||||
lastAdded = cf.f;
|
||||
AddFaceToRegion(*cf.r,cf.f); // adds to region
|
||||
for(int i=0; i < 3;++i) // put the adjacent in the set of faces to possibly add
|
||||
if( (attr_r[cf.f->FFp(i)] == NULL) )
|
||||
toAdd.push_back(cf.f->FFp(i));
|
||||
PushHeap(toAdd,*cf.r);
|
||||
}
|
||||
else
|
||||
{
|
||||
int * aa = attr_r[*cf.f] ;
|
||||
if ( attr_r[*cf.f] != (int*)(cf.r) )
|
||||
Connect((RegionType*)attr_r[*cf.f],(RegionType*)cf.r);
|
||||
}
|
||||
}
|
||||
int h = (int)facesheap.size();
|
||||
// qDebug("----> %d\n",h);
|
||||
}
|
||||
|
||||
void GrowStep(){
|
||||
CandiFace cf;
|
||||
typename std::list<RegionType>::iterator ri;
|
||||
|
||||
n_steps++;
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri) if(!(*ri).isd)
|
||||
(*ri).Clean();
|
||||
|
||||
while(!facesheap.empty() ){
|
||||
std::vector<FaceType*> toAdd;
|
||||
std::pop_heap(facesheap.begin(),facesheap.end());
|
||||
cf = facesheap.back();
|
||||
//printf("err:%f\n",cf.val);
|
||||
facesheap.pop_back();
|
||||
if (attr_r[*cf.f]==NULL){
|
||||
AddFaceToRegion( *cf.r,cf.f); // ads to region
|
||||
lastAdded = &*cf.f;
|
||||
for(int i=0; i < 3;++i) // put the adjacent in the set of faces to possibly add
|
||||
if( attr_r[ *cf.f->FFp(i)] == NULL )
|
||||
toAdd.push_back(cf.f->FFp(i));
|
||||
else
|
||||
if(attr_r[*cf.f->FFp(i)] != attr_r[*cf.f])
|
||||
Connect((RegionType*)attr_r[*cf.f->FFp(i)],(RegionType*)cf.r);
|
||||
|
||||
PushHeap(toAdd,*cf.r);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( attr_r[*cf.f] != (int*)(cf.r) )
|
||||
Connect((RegionType*)attr_r[*cf.f],(RegionType*)cf.r);
|
||||
}
|
||||
}
|
||||
int h = (int) facesheap.size();
|
||||
printf("----> %d\n",h);
|
||||
}
|
||||
|
||||
unsigned int MergeStep(){
|
||||
TriRegIterator tri;
|
||||
unsigned int merged = 0;
|
||||
typename RegionType::AdjIterator ai;
|
||||
|
||||
for(tri = regions.begin(); tri != regions.end(); ++tri)if(!(*tri).isd)
|
||||
for(ai = (*tri).adj.begin(); ai != (*tri).adj.end(); ++ai) if(!(*ai)->isd)
|
||||
if((*tri).Mergeable(*(*ai))){
|
||||
Merge((*tri),*(*ai));
|
||||
merged++;
|
||||
}
|
||||
|
||||
|
||||
for(tri = regions.begin(); tri != regions.end(); ++tri){
|
||||
for(ai = (*tri).nx_adj.begin(); ai != (*tri).nx_adj.end();++ai)
|
||||
if(!(*ai)->isd)
|
||||
(*tri).adj.push_back(*ai);
|
||||
(*tri).adj.sort();
|
||||
(*tri).adj.unique();
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
//void TeleportStep(){
|
||||
// TriRegIterator tri;
|
||||
// typename RegionType::AdjIterator ai;
|
||||
|
||||
// for(tri = regions.begin(); tri != regions.end(); ++tri)if(!(*tri).isd){
|
||||
// std::vector<FaceType*> & onBorder
|
||||
// ComputeOnBorder(onBorder);
|
||||
// if(onBorder.empty
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
bool Restart(){
|
||||
std::vector<FaceType*> candi;
|
||||
TriRegIterator ri;
|
||||
facesheap.clear();
|
||||
|
||||
if(IsRelaxed()){
|
||||
if( (worst_err <= target_error) || (regions.size() >= target_max_regions))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
erroreval.Init(10);
|
||||
FaceError wrs;
|
||||
wrs.f = worst;
|
||||
wrs.val = worst_err;
|
||||
printf("worst triangle error %f\n",worst_err);
|
||||
|
||||
CreateRegion(wrs.f);// CreateRegion changes wr->r
|
||||
|
||||
// reset state variables
|
||||
ave_error=-1;
|
||||
ave_var=-1;
|
||||
err=0.0;
|
||||
changed=0;
|
||||
}
|
||||
}
|
||||
|
||||
for(ri = regions.begin(); ri != regions.end(); )
|
||||
if((*ri).isd)
|
||||
ri = regions.erase(ri);
|
||||
else
|
||||
++ri;
|
||||
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri)
|
||||
{
|
||||
candi.clear();
|
||||
(*ri).Refit(); // fit a plane to the region
|
||||
Restart(*ri); // clear stuff in the region, move the seed to the best fitting to the plabne
|
||||
Candidates(*ri,candi); // take the (three) faces candidatees
|
||||
PushHeap(candi,(*ri)); // put the faces on to the heap
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Restart(RegionType &r){
|
||||
if(!r.face.empty()){
|
||||
r.size=0;
|
||||
float b_err = r.Evaluate(*(*r.face.begin())),err;
|
||||
FaceType* b_face =(*r.face.begin());
|
||||
typename RegionType::FaceIterator fi;
|
||||
|
||||
for( fi = r.face.begin(); fi != r.face.end(); ++fi)
|
||||
{
|
||||
err = r.Evaluate(**fi);
|
||||
if(err < b_err)
|
||||
{
|
||||
b_err = err;
|
||||
b_face = *fi;
|
||||
}
|
||||
}
|
||||
for( fi = r.face.begin(); fi != r.face.end(); ++fi) attr_r[(*fi)] = NULL;
|
||||
r.face.clear();
|
||||
r.adj.clear();
|
||||
AddFaceToRegion(r,b_face);
|
||||
r.Refit();
|
||||
}
|
||||
}
|
||||
|
||||
void MakeCharts(){
|
||||
#ifndef VCGLIB_REGION_GROWING
|
||||
#define VCGLIB_REGION_GROWING
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <vcg/complex/allocate.h>
|
||||
|
||||
template <class FaceType>
|
||||
struct FaceError{
|
||||
FaceType * f;
|
||||
float val;
|
||||
FaceError(){};
|
||||
FaceError(FaceType * _f,double _val):f(_f),val(_val){}
|
||||
const bool operator <(const FaceError & o) const {return val < o.val;}
|
||||
};
|
||||
|
||||
|
||||
template<class MeshType>
|
||||
struct Region{
|
||||
Region():isd(false){}
|
||||
typedef Region RegionType;
|
||||
typedef typename MeshType MeshType;
|
||||
typedef typename MeshType::FaceType FaceType;
|
||||
typedef typename MeshType::FaceType::CoordType CoordType;
|
||||
typedef typename MeshType::FaceType::ScalarType ScalarType;
|
||||
typedef typename std::vector<typename MeshType::FaceType*>::iterator FaceIterator;
|
||||
typedef typename std::list<Region*>::iterator AdjIterator;
|
||||
typedef FaceError<FaceType> FaceError;
|
||||
|
||||
// adjacent regions
|
||||
std::list<RegionType*> adj,nx_adj;
|
||||
|
||||
|
||||
// some flag
|
||||
bool isd;
|
||||
|
||||
// evaluate the gain if the triangle is added to the region
|
||||
ScalarType Evaluate( FaceType & f);
|
||||
|
||||
// update the approximation error of the region
|
||||
void UpdateError( );
|
||||
|
||||
// check if two regions are mergeable in one
|
||||
// i.e. if they have the same planes and coincide i non extreme
|
||||
ScalarType Mergeable( RegionType & tr);
|
||||
|
||||
// set the region as adjacent to this one
|
||||
void Connect( RegionType * tr);
|
||||
|
||||
// compute the faces which are on the border
|
||||
void ComputeOnBorder( std::vector<FaceType*> & onBorder);
|
||||
|
||||
// clean the list of adjacencies
|
||||
void Clean();
|
||||
|
||||
// refit the plane
|
||||
void Refit();
|
||||
|
||||
// keep the best % percentile
|
||||
void CutOff( FaceType*f);
|
||||
|
||||
// restart from the best fitting face
|
||||
void Restart();
|
||||
|
||||
void Decorate();
|
||||
|
||||
};
|
||||
|
||||
|
||||
template < class RegionType>
|
||||
class RegionGrower{
|
||||
public:
|
||||
RegionGrower():lastAdded(NULL),ave_error(-1),ave_var(-1),n_steps(0){}
|
||||
typedef typename RegionType RegionType;
|
||||
typedef typename RegionType::MeshType MeshType;
|
||||
typedef typename RegionType::FaceType FaceType;
|
||||
typedef typename FaceType::ScalarType ScalarType;
|
||||
typedef typename std::list<RegionType> ::iterator TriRegIterator;
|
||||
typedef typename std::list<RegionType*>::iterator AdjIterator;
|
||||
typedef typename RegionType::FaceError FaceError;
|
||||
|
||||
std::list<RegionType> regions;
|
||||
std::vector<RegionType*> workingset;
|
||||
int n_faces,target_max_regions;
|
||||
FaceType * lastAdded;
|
||||
ScalarType ave_error // average error (over single regions' error)
|
||||
,ave_var// average variance (over single regions' error)
|
||||
,changed // faces that have changed from previous step ([0..1))
|
||||
,err
|
||||
,target_error; // taget error
|
||||
|
||||
FaceType * worst;
|
||||
ScalarType worst_err ;
|
||||
MeshType * m;
|
||||
|
||||
typename MeshType:: template PerFaceAttributeHandle<int*> attr_r;
|
||||
typename MeshType:: template PerFaceAttributeHandle<int*> attr_r_old;
|
||||
|
||||
unsigned int n_steps;// number of steps done
|
||||
|
||||
struct CandiFace{
|
||||
FaceType * f;
|
||||
float val;
|
||||
RegionType * r;
|
||||
char inPlane; // a quale piano di r
|
||||
CandiFace(){};
|
||||
CandiFace(FaceType * _f,double _val,RegionType * _r):f(_f),val(_val),r(_r){}
|
||||
const bool operator <(const CandiFace & o) const {return val < o.val;}
|
||||
};
|
||||
|
||||
std::vector<CandiFace> facesheap;
|
||||
std::vector<FaceError > faceserr;
|
||||
|
||||
struct ErrorEval {
|
||||
|
||||
void Add(const float & v){
|
||||
if(!ns){
|
||||
if(v < samples[i_min]) i_min = 0; else {++i_min;
|
||||
if(v > samples[i_max]) i_max = 0;else ++i_max;
|
||||
}
|
||||
if(i_min == samples.size()) {i_min = 0; for(int i= 0; i < samples.size(); ++i) if(samples[i]<samples[i_min]) i_min = i; }
|
||||
if(i_max == samples.size()) {i_max = 0; for(int i= 0; i < samples.size(); ++i) if(samples[i]>samples[i_max]) i_max = i; }
|
||||
}
|
||||
samples.pop_back();samples.push_front(v);
|
||||
boxes.pop_back(); boxes.push_front(vcg::Point2f(samples[i_min],samples[i_max]));
|
||||
++ns ;
|
||||
}
|
||||
|
||||
float BoxOverlap(){
|
||||
float maxsize = std::max( boxes.back()[1]-boxes.back()[0], (*boxes.begin())[1]-(*boxes.begin())[0]);
|
||||
float overlap = std::max(0.f, std::min(boxes.back()[1],(*boxes.begin())[1])-std::max(boxes.back()[0],(*boxes.begin())[0]));
|
||||
assert(overlap <= maxsize);
|
||||
return (maxsize > 0.f)?overlap / maxsize:0.0;
|
||||
}
|
||||
float RelativeDecrease(){
|
||||
if (ns<2) return std::numeric_limits<float>::max();
|
||||
return (samples[0]<10e-22)?0.0:(samples[1]-samples[0])/samples[0];
|
||||
}
|
||||
|
||||
void Init(int n ){
|
||||
|
||||
samples.clear();
|
||||
boxes.clear();
|
||||
for(int i = 0 ; i < n; ++i) samples.push_front(std::numeric_limits<float>::max());
|
||||
for(int i = 0 ; i < n; ++i) boxes.push_front(vcg::Point2f(n,n-i));
|
||||
i_max = i_min = 0;
|
||||
ns = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
int i_min,i_max; // index of min and max element in the queue
|
||||
std::deque<float> samples;
|
||||
std::deque<vcg::Point2f> boxes;
|
||||
int ns;
|
||||
|
||||
};
|
||||
|
||||
ErrorEval erroreval;
|
||||
// init
|
||||
void Init(MeshType & mesh, int n_seeds,int max_regions, float max_err){
|
||||
erroreval.Init(10);
|
||||
m = &mesh;
|
||||
vcg::tri::Allocator<MeshType>::CompactFaceVector(*m);
|
||||
vcg::tri::UpdateTopology<MeshType>::FaceFace(*m);
|
||||
|
||||
float area = 0.f;
|
||||
for(typename MeshType::FaceIterator fi = m->face.begin(); fi != m->face.end(); ++fi)
|
||||
area += vcg::DoubleArea(*fi);
|
||||
area/=2.f;
|
||||
target_error = area*max_err*max_err;
|
||||
target_max_regions = max_regions;
|
||||
|
||||
// tte an attibute that will store the address in ocme for the vertex
|
||||
attr_r = vcg::tri::Allocator<MeshType>::template GetPerFaceAttribute<int*> (*m,"r");
|
||||
if(!vcg::tri::Allocator<MeshType>::IsValidHandle(*m,attr_r))
|
||||
attr_r = vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<int*> (*m,"r");
|
||||
|
||||
attr_r_old = vcg::tri::Allocator<MeshType>::template GetPerFaceAttribute<int*> (*m,"r_old");
|
||||
if(!vcg::tri::Allocator<MeshType>::IsValidHandle(*m,attr_r_old))
|
||||
attr_r_old = vcg::tri::Allocator<MeshType>::template AddPerFaceAttribute<int*> (*m,"r_old");
|
||||
|
||||
regions.clear();
|
||||
|
||||
for(int i = 0; i < m->face.size(); ++i){
|
||||
attr_r[i] = NULL;
|
||||
attr_r_old[i] = NULL;
|
||||
if( (i%(m->fn/n_seeds))==0)
|
||||
CreateRegion(&m->face[i]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// add a region
|
||||
void AddRegion(const RegionType & r){regions.push_back(r);}
|
||||
|
||||
// remove a region
|
||||
void DeleteRegion(const typename std::list<RegionType>::iterator & ri){std::remove(ri);}
|
||||
|
||||
// initialize a region
|
||||
void CreateRegion(FaceType * fi){
|
||||
AddRegion(RegionType());
|
||||
RegionType & tr =regions.back();
|
||||
AddFaceToRegion(tr,fi);
|
||||
tr.Refit();
|
||||
tr.color = vcg::Color4b::Scatter(2000,(int)regions.size());
|
||||
}
|
||||
void AddFaceToRegion( RegionType & r, FaceType * f){
|
||||
r.face.push_back(f);
|
||||
attr_r[*f] = (int*) &r;
|
||||
if(attr_r[*f]!=attr_r_old[*f]) ++r.changed;
|
||||
attr_r_old[*f] = attr_r[*f];
|
||||
++r.size;
|
||||
}
|
||||
|
||||
void Merge(RegionType & r0,RegionType & r1){
|
||||
assert(!r1.isd);
|
||||
typename RegionType::FaceIterator fi;
|
||||
AdjIterator ai;
|
||||
for(fi = r1.face.begin();fi != r1.face.end(); ++fi)
|
||||
AddFaceToRegion(r0,(*fi));
|
||||
for(ai= r1.adj.begin(); ai != r1.adj.end();++ai)
|
||||
if( !(*ai)->isd && (*ai)!=&r0)
|
||||
r0.nx_adj.push_back(*ai);
|
||||
|
||||
r1.face.clear();
|
||||
r1.isd = true;
|
||||
r0.Refit();
|
||||
}
|
||||
|
||||
|
||||
void PushHeap(std::vector<FaceType*> & candi, RegionType & r){
|
||||
typename std::vector<FaceType*>::iterator ci;
|
||||
for(ci = candi.begin(); ci != candi.end(); ++ci)
|
||||
{
|
||||
facesheap.push_back(CandiFace( *ci,-r.Evaluate(*(*ci)), &r));
|
||||
push_heap(facesheap.begin(),facesheap.end());
|
||||
}
|
||||
}
|
||||
|
||||
// the two regions are adjacent
|
||||
void Connect(RegionType * r1,RegionType * r2){
|
||||
assert(r1!=r2);
|
||||
r1->Connect(r2);
|
||||
r2->Connect(r1);
|
||||
}
|
||||
|
||||
// for each region take the candidates and fill in facesheap
|
||||
void Refill( ){
|
||||
facesheap.clear();
|
||||
|
||||
typename std::list<RegionType>::iterator ri;
|
||||
|
||||
std::vector<FaceType*> candi;
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri) if(!(*ri).isd)
|
||||
{
|
||||
candi.clear();
|
||||
Candidates((*ri),candi);
|
||||
PushHeap(candi,*ri);
|
||||
}
|
||||
std::make_heap(facesheap.begin(),facesheap.end());
|
||||
}
|
||||
|
||||
|
||||
void Candidates(RegionType & r, std::vector< typename RegionType::FaceType*> & c){
|
||||
typename RegionType::FaceIterator fi;
|
||||
|
||||
for(fi = r.face.begin(); fi!= r.face.end(); ++fi)
|
||||
for(int i = 0; i < 3; ++i)
|
||||
if( ((*fi)->FFp(i) != (*fi) ) &&
|
||||
(attr_r[(*fi)->FFp(i)] != (int*) &r) )
|
||||
c.push_back((*fi)->FFp(i));
|
||||
}
|
||||
|
||||
bool IsRelaxed(){
|
||||
ScalarType _ave_error=0;
|
||||
ScalarType _ave_var= 0;
|
||||
ScalarType _changed = 0.0;
|
||||
int nr=0;
|
||||
|
||||
typename std::list<RegionType>::iterator ri;
|
||||
worst=NULL;;
|
||||
worst_err = -1;
|
||||
qDebug("working set size: %d\n",workingset.size());
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri) if(!(*ri).isd){
|
||||
++nr;
|
||||
(*ri).UpdateError();
|
||||
_ave_error+=(*ri).approx_err;
|
||||
_ave_var+=(*ri).approx_var;
|
||||
_changed+=(*ri).changed;
|
||||
(*ri).changed=0;
|
||||
if((*ri).worst.val*(*ri).size > worst_err){
|
||||
worst = (*ri).worst.f;
|
||||
worst_err = (*ri).worst.val*(*ri).size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_ave_error/=nr;
|
||||
_ave_var/=nr;
|
||||
_changed/=n_faces;
|
||||
|
||||
erroreval.Add(_ave_error);
|
||||
qDebug("Err:%f ov: %f-------",_ave_error,erroreval.BoxOverlap());
|
||||
|
||||
|
||||
return (erroreval.BoxOverlap() > 0.5) || (erroreval.RelativeDecrease() < 0.1);
|
||||
}
|
||||
|
||||
void GrowStepOnce(){
|
||||
CandiFace cf;
|
||||
typename std::list<RegionType>::iterator ri;
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri) if(!(*ri).isd)
|
||||
(*ri).Clean();
|
||||
|
||||
if(!facesheap.empty()){
|
||||
|
||||
std::vector<FaceType*> toAdd;
|
||||
std::pop_heap(facesheap.begin(),facesheap.end());
|
||||
cf = facesheap.back();
|
||||
// qDebug("err:%f\n",cf.val);
|
||||
facesheap.pop_back();
|
||||
if (attr_r[*cf.f]==NULL){
|
||||
lastAdded = cf.f;
|
||||
AddFaceToRegion(*cf.r,cf.f); // adds to region
|
||||
for(int i=0; i < 3;++i) // put the adjacent in the set of faces to possibly add
|
||||
if( (attr_r[cf.f->FFp(i)] == NULL) )
|
||||
toAdd.push_back(cf.f->FFp(i));
|
||||
PushHeap(toAdd,*cf.r);
|
||||
}
|
||||
else
|
||||
{
|
||||
int * aa = attr_r[*cf.f] ;
|
||||
if ( attr_r[*cf.f] != (int*)(cf.r) )
|
||||
Connect((RegionType*)attr_r[*cf.f],(RegionType*)cf.r);
|
||||
}
|
||||
}
|
||||
int h = (int)facesheap.size();
|
||||
// qDebug("----> %d\n",h);
|
||||
}
|
||||
|
||||
void GrowStep(){
|
||||
CandiFace cf;
|
||||
typename std::list<RegionType>::iterator ri;
|
||||
|
||||
n_steps++;
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri) if(!(*ri).isd)
|
||||
(*ri).Clean();
|
||||
|
||||
while(!facesheap.empty() ){
|
||||
std::vector<FaceType*> toAdd;
|
||||
std::pop_heap(facesheap.begin(),facesheap.end());
|
||||
cf = facesheap.back();
|
||||
//printf("err:%f\n",cf.val);
|
||||
facesheap.pop_back();
|
||||
if (attr_r[*cf.f]==NULL){
|
||||
AddFaceToRegion( *cf.r,cf.f); // ads to region
|
||||
lastAdded = &*cf.f;
|
||||
for(int i=0; i < 3;++i) // put the adjacent in the set of faces to possibly add
|
||||
if( attr_r[ *cf.f->FFp(i)] == NULL )
|
||||
toAdd.push_back(cf.f->FFp(i));
|
||||
else
|
||||
if(attr_r[*cf.f->FFp(i)] != attr_r[*cf.f])
|
||||
Connect((RegionType*)attr_r[*cf.f->FFp(i)],(RegionType*)cf.r);
|
||||
|
||||
PushHeap(toAdd,*cf.r);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( attr_r[*cf.f] != (int*)(cf.r) )
|
||||
Connect((RegionType*)attr_r[*cf.f],(RegionType*)cf.r);
|
||||
}
|
||||
}
|
||||
int h = (int) facesheap.size();
|
||||
printf("----> %d\n",h);
|
||||
}
|
||||
|
||||
unsigned int MergeStep(){
|
||||
TriRegIterator tri;
|
||||
unsigned int merged = 0;
|
||||
typename RegionType::AdjIterator ai;
|
||||
|
||||
for(tri = regions.begin(); tri != regions.end(); ++tri)if(!(*tri).isd)
|
||||
for(ai = (*tri).adj.begin(); ai != (*tri).adj.end(); ++ai) if(!(*ai)->isd)
|
||||
if((*tri).Mergeable(*(*ai))){
|
||||
Merge((*tri),*(*ai));
|
||||
merged++;
|
||||
}
|
||||
|
||||
|
||||
for(tri = regions.begin(); tri != regions.end(); ++tri){
|
||||
for(ai = (*tri).nx_adj.begin(); ai != (*tri).nx_adj.end();++ai)
|
||||
if(!(*ai)->isd)
|
||||
(*tri).adj.push_back(*ai);
|
||||
(*tri).adj.sort();
|
||||
(*tri).adj.unique();
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
//void TeleportStep(){
|
||||
// TriRegIterator tri;
|
||||
// typename RegionType::AdjIterator ai;
|
||||
|
||||
// for(tri = regions.begin(); tri != regions.end(); ++tri)if(!(*tri).isd){
|
||||
// std::vector<FaceType*> & onBorder
|
||||
// ComputeOnBorder(onBorder);
|
||||
// if(onBorder.empty
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
bool Restart(){
|
||||
std::vector<FaceType*> candi;
|
||||
TriRegIterator ri;
|
||||
facesheap.clear();
|
||||
|
||||
if(IsRelaxed()){
|
||||
if( (worst_err <= target_error) || (regions.size() >= target_max_regions))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
erroreval.Init(10);
|
||||
FaceError wrs;
|
||||
wrs.f = worst;
|
||||
wrs.val = worst_err;
|
||||
printf("worst triangle error %f\n",worst_err);
|
||||
|
||||
CreateRegion(wrs.f);// CreateRegion changes wr->r
|
||||
|
||||
// reset state variables
|
||||
ave_error=-1;
|
||||
ave_var=-1;
|
||||
err=0.0;
|
||||
changed=0;
|
||||
}
|
||||
}
|
||||
|
||||
for(ri = regions.begin(); ri != regions.end(); )
|
||||
if((*ri).isd)
|
||||
ri = regions.erase(ri);
|
||||
else
|
||||
++ri;
|
||||
|
||||
for(ri = regions.begin(); ri != regions.end(); ++ri)
|
||||
{
|
||||
candi.clear();
|
||||
(*ri).Refit(); // fit a plane to the region
|
||||
Restart(*ri); // clear stuff in the region, move the seed to the best fitting to the plabne
|
||||
Candidates(*ri,candi); // take the (three) faces candidatees
|
||||
PushHeap(candi,(*ri)); // put the faces on to the heap
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Restart(RegionType &r){
|
||||
if(!r.face.empty()){
|
||||
r.size=0;
|
||||
float b_err = r.Evaluate(*(*r.face.begin())),err;
|
||||
FaceType* b_face =(*r.face.begin());
|
||||
typename RegionType::FaceIterator fi;
|
||||
|
||||
for( fi = r.face.begin(); fi != r.face.end(); ++fi)
|
||||
{
|
||||
err = r.Evaluate(**fi);
|
||||
if(err < b_err)
|
||||
{
|
||||
b_err = err;
|
||||
b_face = *fi;
|
||||
}
|
||||
}
|
||||
for( fi = r.face.begin(); fi != r.face.end(); ++fi) attr_r[(*fi)] = NULL;
|
||||
r.face.clear();
|
||||
r.adj.clear();
|
||||
AddFaceToRegion(r,b_face);
|
||||
r.Refit();
|
||||
}
|
||||
}
|
||||
|
||||
void MakeCharts(){
|
||||
this->Refill();
|
||||
while(this->Restart()){
|
||||
//do{
|
||||
@ -487,7 +487,7 @@ void GrowStepOnce(){
|
||||
}
|
||||
//while(this->MergeStep());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -35,12 +35,7 @@ $Log: samplefilter.cpp,v $
|
||||
#include "region_growing.h"
|
||||
#include "planar_region.h"
|
||||
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
#include <vcg/complex/trimesh/allocate.h>
|
||||
#include <vcg/complex/trimesh/update/position.h>
|
||||
#include <vcg/complex/trimesh/update/normal.h>
|
||||
#include <vcg/complex/trimesh/update/bounding.h>
|
||||
#include<vcg/complex/trimesh/append.h>
|
||||
#include<vcg/complex/append.h>
|
||||
|
||||
|
||||
using namespace vcg;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,470 +1,470 @@
|
||||
/****************************************************************************
|
||||
* MeshLab o o *
|
||||
* A versatile mesh processing toolbox o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* 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 2 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
/****************************************************************************
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef FILTERZIPPERING_H
|
||||
#define FILTERZIPPERING_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <common/interfaces.h>
|
||||
#include <vcg/space/distance3.h>
|
||||
#include <vcg/complex/trimesh/closest.h>
|
||||
#include <vcg/space/index/grid_static_ptr.h>
|
||||
|
||||
#define SAMPLES_PER_EDGE 5 //modificare, length/epsilon
|
||||
|
||||
// Polyline (set of consecutive segments)
|
||||
struct polyline {
|
||||
std::vector< vcg::Segment3<CMeshO::ScalarType> > edges; //polyline edges
|
||||
std::vector< std::pair<int, int> > verts;
|
||||
};
|
||||
|
||||
//Auxiliar info for triangulation
|
||||
struct aux_info {
|
||||
std::vector< polyline > conn; //Close components (to be triangulated)
|
||||
std::vector< polyline > trash; //Close components (to be deleted)
|
||||
std::vector< polyline > border; //Segment intersecting components
|
||||
float eps; //epsilon
|
||||
//Add segment c to border
|
||||
virtual bool AddToBorder( vcg::Segment3<CMeshO::ScalarType> c, std::pair<int, int> v ) {
|
||||
/****Insert new segment****/
|
||||
//Search for segment S having S.P0() == c.P1 or S.P1 == c.P0()
|
||||
if ( v.first == 4013 && v.second == 4015 )
|
||||
int stop = 3;
|
||||
if ( v.first == v.second ) return false;
|
||||
if ( c.Length() < eps ) {
|
||||
c.P0() = c.P1();
|
||||
v.first = v.second;
|
||||
//if segment is too short (it's basically a point) check if it's one of the vertices
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) {
|
||||
for ( size_t j = 0; j < trash[i].edges.size(); j ++ ) { //Only one trash component
|
||||
if ( vcg::Distance<float>( trash[i].edges[j].P0(), c.P0() ) < eps ) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( v.first == 4013 && v.second == 4013 )
|
||||
int stop = 3;
|
||||
//check if c doesn't lie on existing edges
|
||||
//if it does, split edge
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) {
|
||||
for ( size_t j = 0; j < trash[i].edges.size(); j ++ ) { //Only one trash component
|
||||
vcg::Segment3<CMeshO::ScalarType> a, b;
|
||||
a = trash[i].edges[j]; b = c;
|
||||
float tx0 = (float) (b.P0().X() - a.P0().X())/(a.P1().X() - a.P0().X());
|
||||
float ty0 = (float) (b.P0().Y() - a.P0().Y())/(a.P1().Y() - a.P0().Y());
|
||||
float tz0 = (float) (b.P0().Z() - a.P0().Z())/(a.P1().Z() - a.P0().Z());
|
||||
if ( (fabs(tx0 - ty0) < eps ) && (fabs(ty0 - tz0) < eps) ) {
|
||||
float tx1 = (float) (b.P1().X() - a.P0().X())/(a.P1().X() - a.P0().X());
|
||||
float ty1 = (float) (b.P1().Y() - a.P0().Y())/(a.P1().Y() - a.P0().Y());
|
||||
float tz1 = (float) (b.P1().Z() - a.P0().Z())/(a.P1().Z() - a.P0().Z());
|
||||
if ( (fabs(tx1 - ty1) < eps) && (fabs(ty1 - tz1) < eps) ) {
|
||||
if ( (tx0 < 0.0f + eps) && (tx1 > 1.0f - eps) ) return false; //external
|
||||
if ( (tx1 < 0.0f + eps) && (tx0 > 1.0f - eps) ) return false; //external
|
||||
if ( (tx0 >= 0.0f + eps) && (tx0 <= 1.0f - eps) && (tx1 >= 0.0f + eps) && (tx1 <= 1.0f - eps) ) {
|
||||
//double split
|
||||
if ( tx0 > tx1 ) { c.Flip(); v = std::make_pair( v.second, v.first ); }
|
||||
//insert new edges
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 1, vcg::Segment3<CMeshO::ScalarType>( trash[i].edges[j].P0(), c.P0() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 1, std::make_pair( trash[i].verts[j].first, v.first ) );
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 2, c );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 2, v );
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 3, vcg::Segment3<CMeshO::ScalarType>( c.P1(), trash[i].edges[j].P1() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 3, std::make_pair( v.second, trash[i].verts[j].second ) );
|
||||
//erase old one
|
||||
trash[i].edges.erase( trash[i].edges.begin() + j );
|
||||
trash[i].verts.erase( trash[i].verts.begin() + j );
|
||||
return true;
|
||||
}
|
||||
if ( (tx0 >= 0.0f + eps) && (tx0 <= 1.0f - eps) ) {
|
||||
//single split in P0
|
||||
//insert new edges
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 1, vcg::Segment3<CMeshO::ScalarType>( trash[i].edges[j].P0(), c.P0() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 1, std::make_pair( trash[i].verts[j].first, v.first ) );
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 2, vcg::Segment3<CMeshO::ScalarType>( c.P0(), trash[i].edges[j].P1() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 2, std::make_pair( v.first, trash[i].verts[j].second ) );
|
||||
//erase old one
|
||||
trash[i].edges.erase( trash[i].edges.begin() + j );
|
||||
trash[i].verts.erase( trash[i].verts.begin() + j );
|
||||
return true;
|
||||
}
|
||||
if ( (tx1 >= 0.0f + eps) && (tx1 <= 1.0f - eps) ) {
|
||||
//single split in P1
|
||||
//insert new edges
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 1, vcg::Segment3<CMeshO::ScalarType>( trash[i].edges[j].P0(), c.P1() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 1, std::make_pair( trash[i].verts[j].first, v.second ) );
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 2, vcg::Segment3<CMeshO::ScalarType>( c.P1(), trash[i].edges[j].P1() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 2, std::make_pair( v.second, trash[i].verts[j].second ) );
|
||||
//erase old one
|
||||
trash[i].edges.erase( trash[i].edges.begin() + j );
|
||||
trash[i].verts.erase( trash[i].verts.begin() + j );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for ( unsigned int j = 0; j < border.size(); j ++ ) {
|
||||
for ( size_t i = 0; i < border[j].verts.size() && !found; i ++ ) {
|
||||
if ( border[j].verts[i].first == v.second ) { found = true; border[j].edges.insert( border[j].edges.begin() + i, c ); border[j].verts.insert( border[j].verts.begin() + i, v ); } //insert before i-th element
|
||||
else
|
||||
if ( border[j].verts[i].second == v.first ) { found = true; border[j].edges.insert( border[j].edges.begin() + i + 1, c ); border[j].verts.insert( border[j].verts.begin() + i + 1, v ); } //insert after i-th element
|
||||
}
|
||||
}
|
||||
if (!found) { //Create a new polyline ad add it to the border list
|
||||
polyline nwpoly; nwpoly.edges.push_back( c ); nwpoly.verts.push_back( v ); border.push_back( nwpoly );
|
||||
} else {
|
||||
//Merge consecutive polylines into a single one
|
||||
for ( unsigned int j = 0; j < border.size(); j ++ )
|
||||
for ( unsigned int i = j+1; i < border.size(); i ++ ) {
|
||||
if ( border[j].verts.front().first == border[i].verts.back().second ) {
|
||||
border[j].edges.insert( border[j].edges.begin(), border[i].edges.begin(), border[i].edges.end() );
|
||||
border[j].verts.insert( border[j].verts.begin(), border[i].verts.begin(), border[i].verts.end() );
|
||||
border.erase(border.begin() + i);
|
||||
}
|
||||
else if ( border[j].verts.back().second == border[i].verts.front().first ) {
|
||||
border[j].edges.insert( border[j].edges.end(), border[i].edges.begin(), border[i].edges.end() );
|
||||
border[j].verts.insert( border[j].verts.end(), border[i].verts.begin(), border[i].verts.end() );
|
||||
border.erase(border.begin() + i);
|
||||
}
|
||||
}
|
||||
}//end if (!found)
|
||||
|
||||
for ( size_t k = 0; k < border.size(); k ++) {
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) {
|
||||
for ( size_t j = 0; j < trash[i].verts.size(); j ++ ) { //Only one trash component
|
||||
if ( trash[i].verts[j].first == border[k].verts.back().second ) {
|
||||
trash[i].edges[j].P0() = border[k].edges.back().P1();
|
||||
//trash[i].edges.erase( trash[i].edges.begin() + j ); trash[i].verts.erase( trash[i].verts.begin() + j )
|
||||
} else
|
||||
if ( trash[i].verts[j].first == border[k].verts.front().first ) {
|
||||
trash[i].edges[j].P0() = border[k].edges.front().P0();
|
||||
//trash[i].edges.erase( trash[i].edges.begin() + j ); trash[i].verts.erase( trash[i].verts.begin() + j )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}//end AddToBorder
|
||||
|
||||
// Add c.component
|
||||
virtual void AddCComponent( polyline c ) {
|
||||
conn.push_back(c);
|
||||
}
|
||||
// Add t.component
|
||||
virtual void AddTComponent( polyline t ) {
|
||||
trash.push_back(t);
|
||||
}
|
||||
|
||||
//Set eps
|
||||
virtual void SetEps( float e ) {
|
||||
eps = e;
|
||||
}
|
||||
|
||||
// Set initial t.component
|
||||
virtual void Init( CMeshO::FaceType f, int a, int b, int c ) {
|
||||
if (!trash.empty()) return;
|
||||
polyline tri; tri.edges.push_back( vcg::Segment3<CMeshO::ScalarType>(f.P(0), f.P(1)) );
|
||||
tri.edges.push_back( vcg::Segment3<CMeshO::ScalarType>(f.P(1), f.P(2)) );
|
||||
tri.edges.push_back( vcg::Segment3<CMeshO::ScalarType>(f.P(2), f.P(0)) );
|
||||
tri.verts.push_back( std::make_pair(a, b) );
|
||||
tri.verts.push_back( std::make_pair(b, c) );
|
||||
tri.verts.push_back( std::make_pair(c, a) );
|
||||
AddTComponent( tri );
|
||||
}
|
||||
|
||||
// Remove c.component
|
||||
virtual void RemoveCComponent( int i ) {
|
||||
conn.erase( conn.begin() + i );
|
||||
}
|
||||
|
||||
// Remove t.component
|
||||
virtual void RemoveTComponent( int i ) {
|
||||
trash.erase( trash.begin() + i );
|
||||
}
|
||||
|
||||
// Number of c.component
|
||||
virtual int nCComponent( ) {
|
||||
return conn.size();
|
||||
}
|
||||
|
||||
// Number of t.component
|
||||
virtual size_t nTComponent( ) {
|
||||
return trash.size();
|
||||
}
|
||||
|
||||
// Add vertex in original triangle
|
||||
virtual bool addVertex( CMeshO::VertexPointer v, int v_index ) {
|
||||
int cnt = 0; int split = -1;
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) { //one component only
|
||||
|
||||
for ( size_t j = 0; j < trash[i].verts.size(); j ++ ) { //search for closest edge
|
||||
if ( trash[i].verts[j].first == v_index ) return false;
|
||||
}
|
||||
|
||||
for ( size_t j = 0; j < trash[i].edges.size(); j ++ ) { //search for closest edge
|
||||
//if ( vcg::SquaredDistance<float>( trash[i].edges[j], v->P() ) <= eps ) {
|
||||
float dist;
|
||||
vcg::Point3f clos;
|
||||
vcg::SegmentPointSquaredDistance<float>(trash[i].edges[j], v->P(),clos,dist);
|
||||
if (dist <= eps ) {
|
||||
cnt++; split = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cnt) return false;
|
||||
|
||||
if ( cnt == 1 ) { //one edge only -> split the edge
|
||||
vcg::Segment3<CMeshO::ScalarType> splitting_edge = trash[0].edges[split];
|
||||
std::pair<int, int> splitting_edge_v = trash[0].verts[split];
|
||||
|
||||
trash[0].edges.erase(trash[0].edges.begin()+split); //remove edge
|
||||
trash[0].verts.erase(trash[0].verts.begin()+split);
|
||||
//replace edge using two new edges
|
||||
trash[0].edges.insert(trash[0].edges.begin()+split, vcg::Segment3<CMeshO::ScalarType>( splitting_edge.P0(), v->P() ) );
|
||||
trash[0].edges.insert(trash[0].edges.begin()+split+1, vcg::Segment3<CMeshO::ScalarType>( v->P(), splitting_edge.P1() ) );
|
||||
trash[0].verts.insert(trash[0].verts.begin()+split, std::make_pair( splitting_edge_v.first, v_index ) );
|
||||
trash[0].verts.insert(trash[0].verts.begin()+split+1, std::make_pair( v_index, splitting_edge_v.second ) );
|
||||
}
|
||||
|
||||
if ( cnt == 2 ) { // search for closest vertex and copy vertex coords
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) { //one component only
|
||||
for ( size_t j = 0; j < trash[i].edges.size(); j ++ ) { //search for closest edge
|
||||
if ( vcg::Distance<float>( trash[i].edges[j].P0(), v->P() ) <= eps ) {
|
||||
v->P() = trash[i].edges[j].P0();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};//end struct
|
||||
|
||||
class compareFaceQuality {
|
||||
public:
|
||||
compareFaceQuality() { };
|
||||
|
||||
bool operator () (const std::pair<CMeshO::FacePointer,char> f1, const std::pair<CMeshO::FacePointer,char> f2) {
|
||||
//quality f1 < quality f2 return true
|
||||
return ( f1.first->Q() > f2.first->Q() );
|
||||
}
|
||||
};
|
||||
|
||||
class FilterZippering : public QObject, public MeshFilterInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MeshFilterInterface)
|
||||
|
||||
typedef vcg::GridStaticPtr<CMeshO::FaceType, CMeshO::ScalarType > MeshFaceGrid;
|
||||
typedef vcg::GridStaticPtr<CMeshO::VertexType, CMeshO::ScalarType > MeshVertGrid;
|
||||
|
||||
public:
|
||||
//Different operations in different plugins
|
||||
enum { FP_REDUNDANCY,
|
||||
FP_ZIPPERING };
|
||||
|
||||
FilterZippering();
|
||||
|
||||
virtual QString filterName(FilterIDType filter) const;
|
||||
virtual QString filterInfo(FilterIDType filter) const;
|
||||
virtual void initParameterSet(QAction *,MeshDocument &/*m*/, RichParameterSet & /*parent*/);
|
||||
int getRequirements(QAction *action);
|
||||
virtual bool applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & /*parent*/, vcg::CallBackPos * cb) ;
|
||||
FilterClass getClass(QAction *a);
|
||||
virtual int postCondition( QAction */*a*/ ) const { return MeshModel::MM_FACEFACETOPO|MeshModel::MM_VERTNORMAL; }
|
||||
|
||||
|
||||
|
||||
private:
|
||||
template <class ScalarType>
|
||||
ScalarType SquaredDistance( vcg::Segment3<ScalarType> &s, vcg::Point3<ScalarType> &p);
|
||||
|
||||
template <class ScalarType>
|
||||
vcg::Point3<ScalarType> ClosestPoint( vcg::Segment3<ScalarType> &s, vcg::Point3<ScalarType> &p);
|
||||
|
||||
bool checkRedundancy( CMeshO::FacePointer f, //face
|
||||
MeshModel *a, //mesh A
|
||||
MeshFaceGrid &grid, //grid A
|
||||
CMeshO::ScalarType max_dist ); //Max search distance
|
||||
bool simpleCheckRedundancy( CMeshO::FacePointer f, //face
|
||||
MeshModel *a, //mesh A
|
||||
MeshFaceGrid &grid, //grid A
|
||||
CMeshO::ScalarType max_dist,//Max search distance
|
||||
bool test );
|
||||
bool isBorderVert( CMeshO::FacePointer f, int i);
|
||||
bool isOnBorder( CMeshO::CoordType point, CMeshO::FacePointer f );
|
||||
bool isOnEdge( CMeshO::CoordType point, CMeshO::FacePointer f );
|
||||
bool isAdjacent( CMeshO::FacePointer f1, CMeshO::FacePointer f2 );
|
||||
int sharesVertex( CMeshO::FacePointer f1, CMeshO::FacePointer f2 );
|
||||
void handleBorder( aux_info &info, //Auxiliar information for triangulatio
|
||||
vcg::Point3<CMeshO::ScalarType> N, //face normal (useful for proiection)
|
||||
std::vector<CMeshO::CoordType> &coords, //output coords
|
||||
std::vector<int> &output ); //output v. pointers
|
||||
polyline cutComponent( polyline comp, //Component to be cut
|
||||
polyline border, //border
|
||||
vcg::Matrix44<CMeshO::ScalarType> rot_mat ); //Rotation matrix
|
||||
int searchComponent( aux_info &info, //Auxiliar info
|
||||
vcg::Point3<CMeshO::ScalarType> P0, //Start border point
|
||||
vcg::Point3<CMeshO::ScalarType> P1, //End border point
|
||||
bool &conn );
|
||||
bool findIntersection( CMeshO::FacePointer currentF, //face
|
||||
vcg::Segment3<float> edge, //edge
|
||||
int last_split, //last splitted edge
|
||||
int &splitted_edge, //currently splitted edge
|
||||
vcg::Point3<CMeshO::ScalarType> &hit ); //approximate intersection point
|
||||
|
||||
|
||||
|
||||
//init unsorted queue
|
||||
bool Init_q( std::vector< std::pair<CMeshO::FacePointer,char> >& queue, //the queue
|
||||
MeshModel* a, //mesh A
|
||||
MeshModel* b, //mesh B
|
||||
bool fullProcess ); //fullProcess flag
|
||||
//init priority queue (overload)
|
||||
bool Init_pq( std::priority_queue< std::pair<CMeshO::FacePointer,char>, std::vector< std::pair<CMeshO::FacePointer,char> >, compareFaceQuality >& queue, //the queue
|
||||
MeshModel* a, //mesh A
|
||||
MeshModel* b, //mesh B
|
||||
bool fullProcess );
|
||||
//select redundant face (normal method, unsorted queue)
|
||||
int selectRedundant( std::vector< std::pair<CMeshO::FacePointer,char> >& queue, //queue
|
||||
MeshModel* a, //mesh A
|
||||
MeshModel* b, //mesh B
|
||||
float epsilon ); //max search distance
|
||||
//select redundant face (normal method, priority queue)
|
||||
int selectRedundant_pq( std::priority_queue< std::pair<CMeshO::FacePointer,char>, std::vector< std::pair<CMeshO::FacePointer,char> >, compareFaceQuality >& queue, //the queue
|
||||
MeshModel* a, //mesh A
|
||||
MeshModel* b, //mesh B
|
||||
float epsilon ); //max search distance
|
||||
//refine border of a mesh, splitting faces having two border edges
|
||||
int refineBorder( MeshModel* m );
|
||||
//project face of B on the surface of A
|
||||
void projectFace( CMeshO::FacePointer f, //pointer to the face that will be projected
|
||||
MeshModel* a, //mesh A
|
||||
MeshFaceGrid grid_a, //grid on A
|
||||
float max_dist, //max dist search
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector< CMeshO::FacePointer >& tbt_faces, //vector to-be-triangulated faces
|
||||
std::vector< CMeshO::FacePointer >& tbr_faces, //vector to-be-removed faces
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 01: vertices of border edge project on the same face
|
||||
void handleBorderEdgeSF ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 02: vertices of border edge project on adjacent faces
|
||||
void handleBorderEdgeAF ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 03: vertices of border edge project on non-adjacent faces
|
||||
void handleBorderEdgeNF ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 04: both vertices of current_edge project on another border edge
|
||||
//return true if the whole current_edge project on border edge
|
||||
bool handleBorderEdgeBB ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
MeshFaceGrid grid_a, //grid on A (needed for sampling)
|
||||
float max_dist, //max search dist (needed for sampling)
|
||||
vcg::Point3<CMeshO::ScalarType> closestStart, //closest point on startF
|
||||
vcg::Point3<CMeshO::ScalarType> closestEnd, //closest point on endF
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
|
||||
//case 04: both vertices of current_edge project on another border edge
|
||||
//return true if the whole current_edge project on border edge
|
||||
bool handleBorderEdgeBB ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
MeshFaceGrid grid_a, //grid on A (needed for sampling)
|
||||
float max_dist, //max search dist (needed for sampling)
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 05: one of the vertices doesn't project on the surface of the mesh
|
||||
void handleBorderEdgeOB ( std::pair< int, int >& current_edge, //current border edge
|
||||
int direction, //splitting direction (1 from start to end, 0 from end to start)
|
||||
MeshModel* a, //mesh A
|
||||
MeshFaceGrid grid_a, //grid on A (needed for sampling)
|
||||
float max_dist, //max search dist (needed for sampling)
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< CMeshO::FacePointer >& tbt_faces, //stack containing pointers to face that wille be retriangulated
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
int preProcess ( std::vector< std::pair<CMeshO::FacePointer,char> >& queue, //queue
|
||||
MeshModel* a,
|
||||
MeshModel* b,
|
||||
MeshFaceGrid grid_a, //grid on A
|
||||
MeshFaceGrid grid_b, //grid on A
|
||||
float max_dist ); //max dist search
|
||||
|
||||
int preProcess_pq ( std::priority_queue< std::pair<CMeshO::FacePointer,char>, std::vector< std::pair<CMeshO::FacePointer,char> >, compareFaceQuality >& queue, //the queue
|
||||
MeshModel* a,
|
||||
MeshModel* b,
|
||||
MeshFaceGrid grid_a, //grid on A
|
||||
MeshFaceGrid grid_b, //grid on A
|
||||
float max_dist ); //max dist search
|
||||
|
||||
|
||||
float eps;
|
||||
|
||||
int dbg_cnt;
|
||||
};
|
||||
|
||||
#endif
|
||||
/****************************************************************************
|
||||
* MeshLab o o *
|
||||
* A versatile mesh processing toolbox o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* 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 2 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
/****************************************************************************
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef FILTERZIPPERING_H
|
||||
#define FILTERZIPPERING_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <common/interfaces.h>
|
||||
#include <vcg/space/distance3.h>
|
||||
#include <vcg/complex/algorithms/closest.h>
|
||||
#include <vcg/space/index/grid_static_ptr.h>
|
||||
|
||||
#define SAMPLES_PER_EDGE 5 //modificare, length/epsilon
|
||||
|
||||
// Polyline (set of consecutive segments)
|
||||
struct polyline {
|
||||
std::vector< vcg::Segment3<CMeshO::ScalarType> > edges; //polyline edges
|
||||
std::vector< std::pair<int, int> > verts;
|
||||
};
|
||||
|
||||
//Auxiliar info for triangulation
|
||||
struct aux_info {
|
||||
std::vector< polyline > conn; //Close components (to be triangulated)
|
||||
std::vector< polyline > trash; //Close components (to be deleted)
|
||||
std::vector< polyline > border; //Segment intersecting components
|
||||
float eps; //epsilon
|
||||
//Add segment c to border
|
||||
virtual bool AddToBorder( vcg::Segment3<CMeshO::ScalarType> c, std::pair<int, int> v ) {
|
||||
/****Insert new segment****/
|
||||
//Search for segment S having S.P0() == c.P1 or S.P1 == c.P0()
|
||||
if ( v.first == 4013 && v.second == 4015 )
|
||||
int stop = 3;
|
||||
if ( v.first == v.second ) return false;
|
||||
if ( c.Length() < eps ) {
|
||||
c.P0() = c.P1();
|
||||
v.first = v.second;
|
||||
//if segment is too short (it's basically a point) check if it's one of the vertices
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) {
|
||||
for ( size_t j = 0; j < trash[i].edges.size(); j ++ ) { //Only one trash component
|
||||
if ( vcg::Distance<float>( trash[i].edges[j].P0(), c.P0() ) < eps ) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( v.first == 4013 && v.second == 4013 )
|
||||
int stop = 3;
|
||||
//check if c doesn't lie on existing edges
|
||||
//if it does, split edge
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) {
|
||||
for ( size_t j = 0; j < trash[i].edges.size(); j ++ ) { //Only one trash component
|
||||
vcg::Segment3<CMeshO::ScalarType> a, b;
|
||||
a = trash[i].edges[j]; b = c;
|
||||
float tx0 = (float) (b.P0().X() - a.P0().X())/(a.P1().X() - a.P0().X());
|
||||
float ty0 = (float) (b.P0().Y() - a.P0().Y())/(a.P1().Y() - a.P0().Y());
|
||||
float tz0 = (float) (b.P0().Z() - a.P0().Z())/(a.P1().Z() - a.P0().Z());
|
||||
if ( (fabs(tx0 - ty0) < eps ) && (fabs(ty0 - tz0) < eps) ) {
|
||||
float tx1 = (float) (b.P1().X() - a.P0().X())/(a.P1().X() - a.P0().X());
|
||||
float ty1 = (float) (b.P1().Y() - a.P0().Y())/(a.P1().Y() - a.P0().Y());
|
||||
float tz1 = (float) (b.P1().Z() - a.P0().Z())/(a.P1().Z() - a.P0().Z());
|
||||
if ( (fabs(tx1 - ty1) < eps) && (fabs(ty1 - tz1) < eps) ) {
|
||||
if ( (tx0 < 0.0f + eps) && (tx1 > 1.0f - eps) ) return false; //external
|
||||
if ( (tx1 < 0.0f + eps) && (tx0 > 1.0f - eps) ) return false; //external
|
||||
if ( (tx0 >= 0.0f + eps) && (tx0 <= 1.0f - eps) && (tx1 >= 0.0f + eps) && (tx1 <= 1.0f - eps) ) {
|
||||
//double split
|
||||
if ( tx0 > tx1 ) { c.Flip(); v = std::make_pair( v.second, v.first ); }
|
||||
//insert new edges
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 1, vcg::Segment3<CMeshO::ScalarType>( trash[i].edges[j].P0(), c.P0() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 1, std::make_pair( trash[i].verts[j].first, v.first ) );
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 2, c );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 2, v );
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 3, vcg::Segment3<CMeshO::ScalarType>( c.P1(), trash[i].edges[j].P1() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 3, std::make_pair( v.second, trash[i].verts[j].second ) );
|
||||
//erase old one
|
||||
trash[i].edges.erase( trash[i].edges.begin() + j );
|
||||
trash[i].verts.erase( trash[i].verts.begin() + j );
|
||||
return true;
|
||||
}
|
||||
if ( (tx0 >= 0.0f + eps) && (tx0 <= 1.0f - eps) ) {
|
||||
//single split in P0
|
||||
//insert new edges
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 1, vcg::Segment3<CMeshO::ScalarType>( trash[i].edges[j].P0(), c.P0() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 1, std::make_pair( trash[i].verts[j].first, v.first ) );
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 2, vcg::Segment3<CMeshO::ScalarType>( c.P0(), trash[i].edges[j].P1() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 2, std::make_pair( v.first, trash[i].verts[j].second ) );
|
||||
//erase old one
|
||||
trash[i].edges.erase( trash[i].edges.begin() + j );
|
||||
trash[i].verts.erase( trash[i].verts.begin() + j );
|
||||
return true;
|
||||
}
|
||||
if ( (tx1 >= 0.0f + eps) && (tx1 <= 1.0f - eps) ) {
|
||||
//single split in P1
|
||||
//insert new edges
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 1, vcg::Segment3<CMeshO::ScalarType>( trash[i].edges[j].P0(), c.P1() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 1, std::make_pair( trash[i].verts[j].first, v.second ) );
|
||||
trash[i].edges.insert( trash[i].edges.begin() + j + 2, vcg::Segment3<CMeshO::ScalarType>( c.P1(), trash[i].edges[j].P1() ) );
|
||||
trash[i].verts.insert( trash[i].verts.begin() + j + 2, std::make_pair( v.second, trash[i].verts[j].second ) );
|
||||
//erase old one
|
||||
trash[i].edges.erase( trash[i].edges.begin() + j );
|
||||
trash[i].verts.erase( trash[i].verts.begin() + j );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for ( unsigned int j = 0; j < border.size(); j ++ ) {
|
||||
for ( size_t i = 0; i < border[j].verts.size() && !found; i ++ ) {
|
||||
if ( border[j].verts[i].first == v.second ) { found = true; border[j].edges.insert( border[j].edges.begin() + i, c ); border[j].verts.insert( border[j].verts.begin() + i, v ); } //insert before i-th element
|
||||
else
|
||||
if ( border[j].verts[i].second == v.first ) { found = true; border[j].edges.insert( border[j].edges.begin() + i + 1, c ); border[j].verts.insert( border[j].verts.begin() + i + 1, v ); } //insert after i-th element
|
||||
}
|
||||
}
|
||||
if (!found) { //Create a new polyline ad add it to the border list
|
||||
polyline nwpoly; nwpoly.edges.push_back( c ); nwpoly.verts.push_back( v ); border.push_back( nwpoly );
|
||||
} else {
|
||||
//Merge consecutive polylines into a single one
|
||||
for ( unsigned int j = 0; j < border.size(); j ++ )
|
||||
for ( unsigned int i = j+1; i < border.size(); i ++ ) {
|
||||
if ( border[j].verts.front().first == border[i].verts.back().second ) {
|
||||
border[j].edges.insert( border[j].edges.begin(), border[i].edges.begin(), border[i].edges.end() );
|
||||
border[j].verts.insert( border[j].verts.begin(), border[i].verts.begin(), border[i].verts.end() );
|
||||
border.erase(border.begin() + i);
|
||||
}
|
||||
else if ( border[j].verts.back().second == border[i].verts.front().first ) {
|
||||
border[j].edges.insert( border[j].edges.end(), border[i].edges.begin(), border[i].edges.end() );
|
||||
border[j].verts.insert( border[j].verts.end(), border[i].verts.begin(), border[i].verts.end() );
|
||||
border.erase(border.begin() + i);
|
||||
}
|
||||
}
|
||||
}//end if (!found)
|
||||
|
||||
for ( size_t k = 0; k < border.size(); k ++) {
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) {
|
||||
for ( size_t j = 0; j < trash[i].verts.size(); j ++ ) { //Only one trash component
|
||||
if ( trash[i].verts[j].first == border[k].verts.back().second ) {
|
||||
trash[i].edges[j].P0() = border[k].edges.back().P1();
|
||||
//trash[i].edges.erase( trash[i].edges.begin() + j ); trash[i].verts.erase( trash[i].verts.begin() + j )
|
||||
} else
|
||||
if ( trash[i].verts[j].first == border[k].verts.front().first ) {
|
||||
trash[i].edges[j].P0() = border[k].edges.front().P0();
|
||||
//trash[i].edges.erase( trash[i].edges.begin() + j ); trash[i].verts.erase( trash[i].verts.begin() + j )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}//end AddToBorder
|
||||
|
||||
// Add c.component
|
||||
virtual void AddCComponent( polyline c ) {
|
||||
conn.push_back(c);
|
||||
}
|
||||
// Add t.component
|
||||
virtual void AddTComponent( polyline t ) {
|
||||
trash.push_back(t);
|
||||
}
|
||||
|
||||
//Set eps
|
||||
virtual void SetEps( float e ) {
|
||||
eps = e;
|
||||
}
|
||||
|
||||
// Set initial t.component
|
||||
virtual void Init( CMeshO::FaceType f, int a, int b, int c ) {
|
||||
if (!trash.empty()) return;
|
||||
polyline tri; tri.edges.push_back( vcg::Segment3<CMeshO::ScalarType>(f.P(0), f.P(1)) );
|
||||
tri.edges.push_back( vcg::Segment3<CMeshO::ScalarType>(f.P(1), f.P(2)) );
|
||||
tri.edges.push_back( vcg::Segment3<CMeshO::ScalarType>(f.P(2), f.P(0)) );
|
||||
tri.verts.push_back( std::make_pair(a, b) );
|
||||
tri.verts.push_back( std::make_pair(b, c) );
|
||||
tri.verts.push_back( std::make_pair(c, a) );
|
||||
AddTComponent( tri );
|
||||
}
|
||||
|
||||
// Remove c.component
|
||||
virtual void RemoveCComponent( int i ) {
|
||||
conn.erase( conn.begin() + i );
|
||||
}
|
||||
|
||||
// Remove t.component
|
||||
virtual void RemoveTComponent( int i ) {
|
||||
trash.erase( trash.begin() + i );
|
||||
}
|
||||
|
||||
// Number of c.component
|
||||
virtual int nCComponent( ) {
|
||||
return conn.size();
|
||||
}
|
||||
|
||||
// Number of t.component
|
||||
virtual size_t nTComponent( ) {
|
||||
return trash.size();
|
||||
}
|
||||
|
||||
// Add vertex in original triangle
|
||||
virtual bool addVertex( CMeshO::VertexPointer v, int v_index ) {
|
||||
int cnt = 0; int split = -1;
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) { //one component only
|
||||
|
||||
for ( size_t j = 0; j < trash[i].verts.size(); j ++ ) { //search for closest edge
|
||||
if ( trash[i].verts[j].first == v_index ) return false;
|
||||
}
|
||||
|
||||
for ( size_t j = 0; j < trash[i].edges.size(); j ++ ) { //search for closest edge
|
||||
//if ( vcg::SquaredDistance<float>( trash[i].edges[j], v->P() ) <= eps ) {
|
||||
float dist;
|
||||
vcg::Point3f clos;
|
||||
vcg::SegmentPointSquaredDistance<float>(trash[i].edges[j], v->P(),clos,dist);
|
||||
if (dist <= eps ) {
|
||||
cnt++; split = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cnt) return false;
|
||||
|
||||
if ( cnt == 1 ) { //one edge only -> split the edge
|
||||
vcg::Segment3<CMeshO::ScalarType> splitting_edge = trash[0].edges[split];
|
||||
std::pair<int, int> splitting_edge_v = trash[0].verts[split];
|
||||
|
||||
trash[0].edges.erase(trash[0].edges.begin()+split); //remove edge
|
||||
trash[0].verts.erase(trash[0].verts.begin()+split);
|
||||
//replace edge using two new edges
|
||||
trash[0].edges.insert(trash[0].edges.begin()+split, vcg::Segment3<CMeshO::ScalarType>( splitting_edge.P0(), v->P() ) );
|
||||
trash[0].edges.insert(trash[0].edges.begin()+split+1, vcg::Segment3<CMeshO::ScalarType>( v->P(), splitting_edge.P1() ) );
|
||||
trash[0].verts.insert(trash[0].verts.begin()+split, std::make_pair( splitting_edge_v.first, v_index ) );
|
||||
trash[0].verts.insert(trash[0].verts.begin()+split+1, std::make_pair( v_index, splitting_edge_v.second ) );
|
||||
}
|
||||
|
||||
if ( cnt == 2 ) { // search for closest vertex and copy vertex coords
|
||||
for ( size_t i = 0; i < trash.size(); i ++ ) { //one component only
|
||||
for ( size_t j = 0; j < trash[i].edges.size(); j ++ ) { //search for closest edge
|
||||
if ( vcg::Distance<float>( trash[i].edges[j].P0(), v->P() ) <= eps ) {
|
||||
v->P() = trash[i].edges[j].P0();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};//end struct
|
||||
|
||||
class compareFaceQuality {
|
||||
public:
|
||||
compareFaceQuality() { };
|
||||
|
||||
bool operator () (const std::pair<CMeshO::FacePointer,char> f1, const std::pair<CMeshO::FacePointer,char> f2) {
|
||||
//quality f1 < quality f2 return true
|
||||
return ( f1.first->Q() > f2.first->Q() );
|
||||
}
|
||||
};
|
||||
|
||||
class FilterZippering : public QObject, public MeshFilterInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MeshFilterInterface)
|
||||
|
||||
typedef vcg::GridStaticPtr<CMeshO::FaceType, CMeshO::ScalarType > MeshFaceGrid;
|
||||
typedef vcg::GridStaticPtr<CMeshO::VertexType, CMeshO::ScalarType > MeshVertGrid;
|
||||
|
||||
public:
|
||||
//Different operations in different plugins
|
||||
enum { FP_REDUNDANCY,
|
||||
FP_ZIPPERING };
|
||||
|
||||
FilterZippering();
|
||||
|
||||
virtual QString filterName(FilterIDType filter) const;
|
||||
virtual QString filterInfo(FilterIDType filter) const;
|
||||
virtual void initParameterSet(QAction *,MeshDocument &/*m*/, RichParameterSet & /*parent*/);
|
||||
int getRequirements(QAction *action);
|
||||
virtual bool applyFilter(QAction *filter, MeshDocument &md, RichParameterSet & /*parent*/, vcg::CallBackPos * cb) ;
|
||||
FilterClass getClass(QAction *a);
|
||||
virtual int postCondition( QAction */*a*/ ) const { return MeshModel::MM_FACEFACETOPO|MeshModel::MM_VERTNORMAL; }
|
||||
|
||||
|
||||
|
||||
private:
|
||||
template <class ScalarType>
|
||||
ScalarType SquaredDistance( vcg::Segment3<ScalarType> &s, vcg::Point3<ScalarType> &p);
|
||||
|
||||
template <class ScalarType>
|
||||
vcg::Point3<ScalarType> ClosestPoint( vcg::Segment3<ScalarType> &s, vcg::Point3<ScalarType> &p);
|
||||
|
||||
bool checkRedundancy( CMeshO::FacePointer f, //face
|
||||
MeshModel *a, //mesh A
|
||||
MeshFaceGrid &grid, //grid A
|
||||
CMeshO::ScalarType max_dist ); //Max search distance
|
||||
bool simpleCheckRedundancy( CMeshO::FacePointer f, //face
|
||||
MeshModel *a, //mesh A
|
||||
MeshFaceGrid &grid, //grid A
|
||||
CMeshO::ScalarType max_dist,//Max search distance
|
||||
bool test );
|
||||
bool isBorderVert( CMeshO::FacePointer f, int i);
|
||||
bool isOnBorder( CMeshO::CoordType point, CMeshO::FacePointer f );
|
||||
bool isOnEdge( CMeshO::CoordType point, CMeshO::FacePointer f );
|
||||
bool isAdjacent( CMeshO::FacePointer f1, CMeshO::FacePointer f2 );
|
||||
int sharesVertex( CMeshO::FacePointer f1, CMeshO::FacePointer f2 );
|
||||
void handleBorder( aux_info &info, //Auxiliar information for triangulatio
|
||||
vcg::Point3<CMeshO::ScalarType> N, //face normal (useful for proiection)
|
||||
std::vector<CMeshO::CoordType> &coords, //output coords
|
||||
std::vector<int> &output ); //output v. pointers
|
||||
polyline cutComponent( polyline comp, //Component to be cut
|
||||
polyline border, //border
|
||||
vcg::Matrix44<CMeshO::ScalarType> rot_mat ); //Rotation matrix
|
||||
int searchComponent( aux_info &info, //Auxiliar info
|
||||
vcg::Point3<CMeshO::ScalarType> P0, //Start border point
|
||||
vcg::Point3<CMeshO::ScalarType> P1, //End border point
|
||||
bool &conn );
|
||||
bool findIntersection( CMeshO::FacePointer currentF, //face
|
||||
vcg::Segment3<float> edge, //edge
|
||||
int last_split, //last splitted edge
|
||||
int &splitted_edge, //currently splitted edge
|
||||
vcg::Point3<CMeshO::ScalarType> &hit ); //approximate intersection point
|
||||
|
||||
|
||||
|
||||
//init unsorted queue
|
||||
bool Init_q( std::vector< std::pair<CMeshO::FacePointer,char> >& queue, //the queue
|
||||
MeshModel* a, //mesh A
|
||||
MeshModel* b, //mesh B
|
||||
bool fullProcess ); //fullProcess flag
|
||||
//init priority queue (overload)
|
||||
bool Init_pq( std::priority_queue< std::pair<CMeshO::FacePointer,char>, std::vector< std::pair<CMeshO::FacePointer,char> >, compareFaceQuality >& queue, //the queue
|
||||
MeshModel* a, //mesh A
|
||||
MeshModel* b, //mesh B
|
||||
bool fullProcess );
|
||||
//select redundant face (normal method, unsorted queue)
|
||||
int selectRedundant( std::vector< std::pair<CMeshO::FacePointer,char> >& queue, //queue
|
||||
MeshModel* a, //mesh A
|
||||
MeshModel* b, //mesh B
|
||||
float epsilon ); //max search distance
|
||||
//select redundant face (normal method, priority queue)
|
||||
int selectRedundant_pq( std::priority_queue< std::pair<CMeshO::FacePointer,char>, std::vector< std::pair<CMeshO::FacePointer,char> >, compareFaceQuality >& queue, //the queue
|
||||
MeshModel* a, //mesh A
|
||||
MeshModel* b, //mesh B
|
||||
float epsilon ); //max search distance
|
||||
//refine border of a mesh, splitting faces having two border edges
|
||||
int refineBorder( MeshModel* m );
|
||||
//project face of B on the surface of A
|
||||
void projectFace( CMeshO::FacePointer f, //pointer to the face that will be projected
|
||||
MeshModel* a, //mesh A
|
||||
MeshFaceGrid grid_a, //grid on A
|
||||
float max_dist, //max dist search
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector< CMeshO::FacePointer >& tbt_faces, //vector to-be-triangulated faces
|
||||
std::vector< CMeshO::FacePointer >& tbr_faces, //vector to-be-removed faces
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 01: vertices of border edge project on the same face
|
||||
void handleBorderEdgeSF ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 02: vertices of border edge project on adjacent faces
|
||||
void handleBorderEdgeAF ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 03: vertices of border edge project on non-adjacent faces
|
||||
void handleBorderEdgeNF ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 04: both vertices of current_edge project on another border edge
|
||||
//return true if the whole current_edge project on border edge
|
||||
bool handleBorderEdgeBB ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
MeshFaceGrid grid_a, //grid on A (needed for sampling)
|
||||
float max_dist, //max search dist (needed for sampling)
|
||||
vcg::Point3<CMeshO::ScalarType> closestStart, //closest point on startF
|
||||
vcg::Point3<CMeshO::ScalarType> closestEnd, //closest point on endF
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
|
||||
//case 04: both vertices of current_edge project on another border edge
|
||||
//return true if the whole current_edge project on border edge
|
||||
bool handleBorderEdgeBB ( std::pair< int, int >& current_edge, //current border edge
|
||||
MeshModel* a, //mesh A
|
||||
MeshFaceGrid grid_a, //grid on A (needed for sampling)
|
||||
float max_dist, //max search dist (needed for sampling)
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
//case 05: one of the vertices doesn't project on the surface of the mesh
|
||||
void handleBorderEdgeOB ( std::pair< int, int >& current_edge, //current border edge
|
||||
int direction, //splitting direction (1 from start to end, 0 from end to start)
|
||||
MeshModel* a, //mesh A
|
||||
MeshFaceGrid grid_a, //grid on A (needed for sampling)
|
||||
float max_dist, //max search dist (needed for sampling)
|
||||
CMeshO::FacePointer startF, //face where first vertex lies
|
||||
CMeshO::FacePointer endF, //face where second vertex lies
|
||||
CMeshO::FacePointer splittingF, //splitting face
|
||||
std::map< CMeshO::FacePointer, aux_info >& map_info, //map with auxiliar information
|
||||
std::vector < std::pair< int, int > >& stack, //stack containing border edges
|
||||
std::vector< CMeshO::FacePointer >& tbt_faces, //stack containing pointers to face that wille be retriangulated
|
||||
std::vector< int >& verts ); //vector of indices
|
||||
|
||||
int preProcess ( std::vector< std::pair<CMeshO::FacePointer,char> >& queue, //queue
|
||||
MeshModel* a,
|
||||
MeshModel* b,
|
||||
MeshFaceGrid grid_a, //grid on A
|
||||
MeshFaceGrid grid_b, //grid on A
|
||||
float max_dist ); //max dist search
|
||||
|
||||
int preProcess_pq ( std::priority_queue< std::pair<CMeshO::FacePointer,char>, std::vector< std::pair<CMeshO::FacePointer,char> >, compareFaceQuality >& queue, //the queue
|
||||
MeshModel* a,
|
||||
MeshModel* b,
|
||||
MeshFaceGrid grid_a, //grid on A
|
||||
MeshFaceGrid grid_b, //grid on A
|
||||
float max_dist ); //max dist search
|
||||
|
||||
|
||||
float eps;
|
||||
|
||||
int dbg_cnt;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user