From ee850a6aba7d1be81f3902e5a8cafcf6d2e9de4e Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Sat, 27 Dec 2008 10:03:09 +0000 Subject: [PATCH] Almost finished filter "Cross section parallel planes". --- .../filter_slice/filter_slice.cpp | 628 ++++++++++++------ .../filter_slice/filter_slice.h | 11 +- .../filter_slice/filter_slice_functors.h | 19 +- 3 files changed, 425 insertions(+), 233 deletions(-) diff --git a/src/meshlabplugins/filter_slice/filter_slice.cpp b/src/meshlabplugins/filter_slice/filter_slice.cpp index b8d8018ff..32f938d6d 100644 --- a/src/meshlabplugins/filter_slice/filter_slice.cpp +++ b/src/meshlabplugins/filter_slice/filter_slice.cpp @@ -1,32 +1,32 @@ -/**************************************************************************** -* 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. * -* * -****************************************************************************/ - -#include "filter_slice.h" +/**************************************************************************** +* 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. * +* * +****************************************************************************/ + +#include "filter_slice.h" //#include -#include -#include +#include +#include #include -#include +#include #include #include #include @@ -36,159 +36,236 @@ #include "filter_slice_functors.h" #include -#include +#include #include -using namespace std; -using namespace vcg; - -// Constructor usually performs only two simple tasks of filling the two lists -// - typeList: with all the possible id of the filtering actions -// - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly - -ExtraFilter_SlicePlugin::ExtraFilter_SlicePlugin () -{ - typeList << FP_PLANE; - - foreach(FilterIDType tt , types()) - actionList << new QAction(filterName(tt), this); -} - -// ST() must return the very short string describing each filtering action -// (this string is used also to define the menu entry) -const QString ExtraFilter_SlicePlugin::filterName(FilterIDType filterId) -{ - switch(filterId) { - case FP_PLANE : return QString("Cross section plane"); - default : assert(0); - } - return QString("error!"); -} - -// Info() must return the longer string describing each filtering action -// (this string is used in the About plugin dialog) -const QString ExtraFilter_SlicePlugin::filterInfo(FilterIDType filterId) -{ - switch(filterId) { - case FP_PLANE : return QString("Export one or more cross sections of the current mesh relative to one of the XY, YZ or ZX axes in svg format. By default, the cross-section goes through the middle of the object (Cross plane offset == 0)."); - - default : assert(0); - } - return QString("error!"); -} - -// This function define the needed parameters for each filter. Return true if the filter has some parameters -// it is called every time, so you can set the default value of parameters according to the mesh -// For each parmeter you need to define, -// - the name of the parameter, -// - the string shown in the dialog -// - the default value -// - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -//void ExtraSamplePlugin::initParameterSet(QAction *action,MeshModel &m, FilterParameterSet & parlst) -void ExtraFilter_SlicePlugin::initParameterSet(QAction *filter, MeshModel &m, FilterParameterSet &parlst) +using namespace std; +using namespace vcg; + +// Constructor usually performs only two simple tasks of filling the two lists +// - typeList: with all the possible id of the filtering actions +// - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly + +ExtraFilter_SlicePlugin::ExtraFilter_SlicePlugin () { - vcg::tri::UpdateBounding::Box(m.cm); - switch(ID(filter)) - { - case FP_PLANE : - { - QStringList metrics; - metrics.push_back("XY Axis"); - metrics.push_back("YZ Axis"); - metrics.push_back("ZX Axis"); - parlst.addEnum ("planeAxis", 0, metrics, tr("Axis"), tr("The Slicing plane will be done perpendicular to the axis")); + typeList << FP_PARALLEL_PLANES; +// <::Box(m.cm); + parlst.addEnum ("planeAxis", 0, QStringList()<<"YZ Axis"<<"XZ Axis"<<"XY Axis", tr("Axis"), tr("The Slicing plane will be done perpendicular to the axis")); + switch(ID(filter)) + { + case FP_PARALLEL_PLANES : + { parlst.addFloat ("planeOffset", 0.0, "Cross plane offset", "Specify an offset of the cross-plane. The offset corresponds to the distance between the center of the object and the point where the plan crosses it. By default (Cross plane offset == 0), the plane crosses the center of the object, so the offset can be positive or negetive"); - // Origin=0, BBox min=1, BBox center=2 - parlst.addEnum ("relativeTo",0,QStringList()<<"Bounding box Center"<<"Bounding box min"<<"Origin","plane reference","Specify the reference from which the planes are shifted"); - //parlst.addBool ("absOffset",false,"Absolute offset", "if true the above offset is absolute is relative to the origin of the coordinate system, if false the offset is relative to the center of the bbox."); - parlst.addAbsPerc("planeDist", 0.0,0,m.cm.bbox.Diag(), "Distance between planes", "Step value between each plane for automatically generating cross-sections. Should be used with the bool selection above."); - parlst.addInt ("planeNum", 1, "Number of Planes", "Step value between each plane for automatically generating cross-sections. Should be used with the bool selection above."); - parlst.addString ("filename", "Slice", "filename","Name of the svg files and of the folder contaning them, it is automatically created in the Sample folder of the Meshlab tree"); - parlst.addBool ("singleFile", true, "Single SVG","Automatically generate a series of cross-sections along the whole length of the object and store each plane in a separate SVG file. The distance between each plane is given by the step value below"); - } - break; - default : assert(0); - } -} - -// The Real Core Function doing the actual mesh processing. -// Move Vertex of a random quantity -bool ExtraFilter_SlicePlugin::applyFilter(QAction *filter, MeshDocument &m, FilterParameterSet &parlst, vcg::CallBackPos *cb) -{ - if (!tri::Clean::IsTwoManifoldFace(m.mm()->cm) || (tri::Clean::CountNonManifoldVertexFF(m.mm()->cm,false) != 0)) - { - Log(0,"Mesh is not two manifold, cannot apply filter"); - return false; + // BBox min=0, BBox center=1, Origin=2 + parlst.addEnum ("relativeTo",0,QStringList()<<"Bounding box min"<<"Bounding box Center"<<"Origin","plane reference","Specify the reference from which the planes are shifted"); + //parlst.addBool ("absOffset",false,"Absolute offset", "if true the above offset is absolute is relative to the origin of the coordinate system, if false the offset is relative to the center of the bbox."); + //parlst.addAbsPerc("planeDist", 0.0,0,m.cm.bbox.Diag(), "Distance between planes", "Step value between each plane for automatically generating cross-sections. Should be used with the bool selection above."); + parlst.addEnum ("units",0,QStringList()<<"cm"<<"in","Units","units in which the objects is measured"); + parlst.addFloat ("length",29,"Length","Length of the object referred to the units specified above"); + parlst.addFloat ("eps",0,"Medium thickness","Thickness of the medium where the pieces will be cut away"); + parlst.addInt ("planeNum", 1, "Number of Planes", "Step value between each plane for automatically generating cross-sections. Should be used with the bool selection above."); + + QStringList nn=QString(m.fileName.c_str()).split("/"); + + QString name=nn.last().left(nn.last().lastIndexOf(".")); + if (name=="") + name="Slice"; + parlst.addString ("filename", name, "filename","Name of the svg files and of the folder contaning them, it is automatically created in the Sample folder of the Meshlab tree"); + parlst.addBool ("singleFile", true, "Single SVG","Automatically generate a series of cross-sections along the whole length of the object and store each plane in a separate SVG file. The distance between each plane is given by the step value below"); + parlst.addBool ("hideBase",true,"Hide Original Mesh","Hide the Original Mesh"); + parlst.addBool ("hideSlices",true,"Hide Slices","Hide the Generated Slices"); + parlst.addBool ("hidePlanes",false,"Hide Planes","Hide the Generated Slicing Planes"); + } + break; + case FP_RECURSIVE_SLICE: + parlst.addFloat("eps",.2,"epsilon","epsilon"); + break; + default : assert(0); } - else - Log(0,"Mesh is two manifold"); - - switch(ID(filter)) - { - case FP_PLANE : - { - Point3f planeAxis(0,0,0); - int axisIndex = parlst.getEnum("planeAxis"); - assert(axisIndex >=0 && axisIndex <3); - planeAxis[axisIndex] = 1.0f; - float planeDist = parlst.getAbsPerc("planeDist"); - float planeOffset = parlst.getFloat("planeOffset"); - int planeNum = parlst.getInt("planeNum"); - //bool absOffset = parlst.getBool("absOffset"); - int reference=parlst.getEnum("relativeTo"); - Point3f planeCenter; - Plane3f slicingPlane; - pr.numCol=max((int)sqrt(planeNum),2); - pr.numRow=max(planeNum/pr.numCol,2); - pr.sizeCm=Point2f(4,4); - pr.projDir = planeAxis; - pr.projCenter = m.mm()->cm.bbox.Center(); +} + +// The Real Core Function doing the actual mesh processing. +// Move Vertex of a random quantity +bool ExtraFilter_SlicePlugin::applyFilter(QAction *filter, MeshDocument &m, FilterParameterSet &parlst, vcg::CallBackPos *cb) +{ + Point3f planeAxis(0,0,0); + int axisIndex = parlst.getEnum("planeAxis"); + assert(axisIndex >=0 && axisIndex <3); + planeAxis[axisIndex] = 1.0f; + + switch(ID(filter)) + { + case FP_PARALLEL_PLANES : + { + //float planeDist = parlst.getAbsPerc("planeDist"); + float planeDist=0; + float planeOffset = parlst.getFloat("planeOffset"); + int planeNum = parlst.getInt("planeNum"); + int units=parlst.getEnum("units"); + float length=parlst.getFloat("length"); + float eps=parlst.getFloat("eps"); + eps=m.mm()->cm.bbox.Diag()*(eps/length); + //bool absOffset = parlst.getBool("absOffset"); + int reference=parlst.getEnum("relativeTo"); + Point3f planeCenter; + Plane3f slicingPlane; + pr.numCol=max((int)sqrt(planeNum*1.0f),2); + pr.numRow=max(planeNum/pr.numCol,2); + //da rivedere per le misure + pr.sizeCm=Point2f(4,4); + pr.projDir = planeAxis; + pr.projCenter = m.mm()->cm.bbox.Center(); pr.scale = 2.0/m.mm()->cm.bbox.Diag(); - pr.lineWidthPt=200; + pr.lineWidthPt=200; + + bool hideBase=parlst.getBool("hideBase"); + bool hideSlices=parlst.getBool("hideSlices"); + bool hidePlanes=parlst.getBool("hidePlanes"); vector ev; - m.mm()->visible=false; - for(int i=0;ivisible=false; + Box3f bbox=m.mm()->cm.bbox; + MeshModel* base=m.mm(); + MeshModel* orig=m.mm(); + for(int i=0;i::IsTwoManifoldFace(base->cm) || (tri::Clean::CountNonManifoldVertexFF(base->cm,false) != 0)) + { + Log(0,"Mesh is not two manifold, cannot apply filter"); + return false; + } + + QString s; + s.sprintf("calculating slice %d",i+1); + cb((i+1)*100.0f/planeNum,s.toStdString().c_str()); switch(reference) { - case 2: planeCenter = planeAxis*planeOffset; //origin + case 2: + planeCenter = planeAxis*planeOffset; //origin break; - case 1: planeCenter = m.mm()->cm.bbox.min+planeAxis*planeOffset*(m.mm()->cm.bbox.Diag()/2.0); //bbox min + case 0: + planeCenter = bbox.min+planeAxis*planeOffset*(bbox.Diag()/2.0); //bbox min + if (planeNum!=1) + planeDist=(bbox.Dim()*planeAxis)/(planeNum-1); break; - case 0: planeCenter = m.mm()->cm.bbox.Center()+ planeAxis*planeOffset*(m.mm()->cm.bbox.Diag()/2.0); //bbox min + case 1: + planeCenter = bbox.Center()+ planeAxis*planeOffset*(bbox.Diag()/2.0); //bbox center + if (planeNum!=1) + planeDist=(bbox.Dim()*planeAxis)/(2*(planeNum-1)); break; } - - planeCenter+=planeAxis*planeDist*i; + + planeCenter+=planeAxis*planeDist*i; slicingPlane.Init(planeCenter,planeAxis); //clear the selection flags + vcg::tri::UpdateFlags::FaceBorderFromNone(base->cm); SlicedEdge slicededge(slicingPlane); SlicingFunction slicingfunc(slicingPlane); //after the RefineE call, the mesh will be half vertices selected vcg::RefineE, SlicedEdge > - (m.mm()->cm, slicingfunc, slicededge, false, cb); - vcg::tri::UpdateNormals::PerVertexPerFace(m.mm()->cm); + (base->cm, slicingfunc, slicededge, false, cb); + vcg::tri::UpdateNormals::PerVertexPerFace(base->cm); - vcg::tri::UpdateSelection::VertexFromQualityRange(m.mm()->cm,VERTEX_LEFT,VERTEX_LEFT); - vcg::tri::UpdateSelection::FaceFromVertexLoose(m.mm()->cm); - createSlice(m); - capHole(m); + MeshModel *slice1= new MeshModel(); + m.meshList.push_back(slice1); + QString layername; + layername.sprintf("slice_%d-%d.ply",i,i+1); + slice1->fileName = layername.toStdString().c_str(); // mesh name + slice1->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); + vcg::tri::UpdateSelection::VertexFromQualityRange(base->cm,VERTEX_LEFT,VERTEX_LEFT); + vcg::tri::UpdateSelection::FaceFromVertexLoose(base->cm); + if (hideSlices) + slice1->visible=false; - vcg::tri::UpdateSelection::VertexFromQualityRange(m.mm()->cm,VERTEX_RIGHT,VERTEX_RIGHT); - vcg::tri::UpdateSelection::FaceFromVertexLoose(m.mm()->cm); - createSlice(m); - capHole(m); + createSlice(base,slice1); + vcg::tri::UpdateFlags::FaceBorderFromNone(slice1->cm); + //m.setCurrentMesh(m.meshList.size()-1); - /* - this is for generating the svd slices - - MyEdgeMesh *edgeMesh = new MyEdgeMesh(); - vcg::Intersection(m.mm()->cm, slicingPlane , *edgeMesh); + MeshModel* cap= new MeshModel(); + m.meshList.push_back(cap); + layername.sprintf("plane_%d.ply",i+1); + cap->fileName = layername.toStdString().c_str(); // mesh name + cap->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); + capHole(slice1,cap); + if (eps!=0) + { + MeshModel* dup= new MeshModel(); + m.meshList.push_back(dup); + layername.sprintf("plane_%d_extruded.ply",i+1); + dup->fileName = layername.toStdString().c_str(); // mesh name + dup->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); + extrude(cap, dup, eps, planeAxis); + } + if (hidePlanes) + cap->visible=false; + tri::Append::Mesh(slice1->cm, cap->cm); + tri::Clean::RemoveDuplicateVertex(slice1->cm); + vcg::tri::UpdateTopology::FaceFace(slice1->cm); + vcg::tri::UpdateNormals::PerVertexPerFace(slice1->cm); + MeshModel* slice2= new MeshModel(); + m.meshList.push_back(slice2); + layername.sprintf("slice_%d-%d.ply",i+1,i+2); + slice2->fileName = layername.toStdString().c_str(); // mesh name + slice2->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); + vcg::tri::UpdateSelection::VertexFromQualityRange(base->cm,VERTEX_RIGHT,VERTEX_RIGHT); + vcg::tri::UpdateSelection::FaceFromVertexLoose(base->cm); + createSlice(base,slice2); + vcg::tri::UpdateFlags::FaceBorderFromNone(slice2->cm); + tri::Append::Mesh(slice2->cm, cap->cm); + tri::Clean::RemoveDuplicateVertex(slice2->cm); + vcg::tri::UpdateTopology::FaceFace(slice2->cm); + vcg::tri::UpdateNormals::PerVertexPerFace(slice2->cm); + if (hideSlices) + slice2->visible=false; + if (i!=0) + m.delMesh(base); + base=slice2; + //this is used to generate svd slices + MyEdgeMesh *edgeMesh = new MyEdgeMesh(); + vcg::Intersection(orig->cm, slicingPlane , *edgeMesh); vcg::edg::UpdateBounding::Box(*edgeMesh); - ev.push_back(edgeMesh); - */ } QString fname=parlst.getString("filename"); @@ -197,80 +274,197 @@ bool ExtraFilter_SlicePlugin::applyFilter(QAction *filter, MeshDocument &m, Filt if (!fname.endsWith(".svg")) fname+=".svg"; vcg::edg::io::ExporterSVG::Save(ev, fname.toStdString().c_str(), pr); + } + break; + case FP_RECURSIVE_SLICE: + { - - } - break; - } - return true; -} - -const MeshFilterInterface::FilterClass ExtraFilter_SlicePlugin::getClass(QAction *filter) -{ - switch(ID(filter)) - { - case FP_PLANE : return MeshFilterInterface::Generic; - default: assert(0); - } - return MeshFilterInterface::Generic; -} - -bool ExtraFilter_SlicePlugin::autoDialog(QAction *action) -{ - switch(ID(action)) - { - case FP_PLANE: return true; - default: return false; - } -} -void ExtraFilter_SlicePlugin::createSlice(MeshDocument& m) + } + break; + } + return true; +} + +void ExtraFilter_SlicePlugin::extrude(MeshModel* orig, MeshModel* dest, float eps, Point3f planeAxis) { - MeshModel *mm= new MeshModel(); - m.meshList.push_back(mm); - MeshModel *destMesh = m.meshList.back(); // destination = last - MeshModel *currentMesh = m.mm(); // source = current - tri::Append::Mesh(destMesh->cm, m.mm()->cm, true); - destMesh->fileName = "newmesh.ply"; // mesh name + tri::Append::Mesh(dest->cm, orig->cm); + tri::UpdateTopology::FaceFace(dest->cm); + //create the clone, move it eps/2 on the left and invert its normals + for (int i=0;icm.vert.size();i++) + dest->cm.vert[i].P()-=planeAxis*eps/2; + tri::Clean::FlipMesh(dest->cm); + vcg::tri::UpdateTopology::FaceFace(dest->cm); + vcg::tri::UpdateNormals::PerVertexPerFace(dest->cm); + //find the border outlines + std::vector< std::vector > outlines; + std::vector outline; + vcg::tri::UpdateFlags::VertexClearV(dest->cm); + vcg::tri::UpdateFlags::FaceBorderFromNone(dest->cm); + int nv=0; + for(int i=0;icm.face.size();i++) + { + for (int j=0;j<3;j++) + if (!dest->cm.face[i].IsV() && dest->cm.face[i].IsB(j)) + { + CFaceO* startB=&(dest->cm.face[i]); + vcg::face::Pos p(startB,j); + do + { + p.V()->SetV(); + outline.push_back(p.V()->P()); + p.NextB(); + nv++; + } + while(!p.V()->IsV()); + outlines.push_back(outline); + outline.clear(); + } + } + if (nv<2) return; + //I have at least 3 vertexes + MeshModel* tempMesh= new MeshModel(); + tri::Append::Mesh(tempMesh->cm, orig->cm); + for (int i=0;icm.vert.size();i++) + tempMesh->cm.vert[i].P()+=planeAxis*eps/2; + //create the clone and move it eps/2 on the right + tri::Append::Mesh(dest->cm, tempMesh->cm); + delete tempMesh; + //create the new mesh and the triangulation between the clones + tempMesh= new MeshModel(); + CMeshO::VertexIterator vi=vcg::tri::Allocator::AddVertices(tempMesh->cm,2*nv); + + //I have at least 6 vertexes + for (int i=0;iP()=outlines[i][0]; + CVertexO* v0=(&*vi); ++vi; + (&*vi)->P()=outlines[i][0]+planeAxis*eps; + CVertexO* v1=(&*vi); ++vi; + CVertexO* vs0=v0; //we need the start point + CVertexO* vs1=v1; //to close the loop + Log(0,"%d",outlines[i].size()); + for(int j=1;jP()=outlines[i][j]; + CVertexO* v2=(&*vi); ++vi; + (&*vi)->P()=outlines[i][j]+planeAxis*eps; + CVertexO* v3=(&*vi); ++vi; + CMeshO::FaceIterator fi=vcg::tri::Allocator::AddFaces(tempMesh->cm,2); + + (&*fi)->V(2)=v0; + (&*fi)->V(1)=v1; + (&*fi)->V(0)=v2; + ++fi; + (&*fi)->V(0)=v1; + (&*fi)->V(1)=v2; + (&*fi)->V(2)=v3; + + v0=v2; + v1=v3; + if (j==outlines[i].size()-1) + { + CMeshO::FaceIterator fi=vcg::tri::Allocator::AddFaces(tempMesh->cm,2); + (&*fi)->V(2)=v0; + (&*fi)->V(1)=v1; + (&*fi)->V(0)=vs0; + ++fi; + (&*fi)->V(0)=v1; + (&*fi)->V(1)=vs0; + (&*fi)->V(2)=vs1; + } + } + } + + tri::Append::Mesh(dest->cm, tempMesh->cm); + tri::Clean::RemoveDuplicateVertex(dest->cm); + tri::UpdateTopology::FaceFace(dest->cm); + tri::UpdateNormals::PerVertexPerFace(dest->cm); + + delete tempMesh; + +} +const MeshFilterInterface::FilterClass ExtraFilter_SlicePlugin::getClass(QAction *filter) +{ + switch(ID(filter)) + { + case FP_PARALLEL_PLANES : + case FP_RECURSIVE_SLICE : + return MeshFilterInterface::Generic; + default: assert(0); + } + return MeshFilterInterface::Generic; +} + +bool ExtraFilter_SlicePlugin::autoDialog(QAction *action) +{ + switch(ID(action)) + { + case FP_RECURSIVE_SLICE: + case FP_PARALLEL_PLANES: return true; + default: return false; + } +} + +void ExtraFilter_SlicePlugin::createSlice(MeshModel* currentMesh, MeshModel* destMesh) +{ + tri::Append::Mesh(destMesh->cm, currentMesh->cm, true); + tri::UpdateTopology::FaceFace(destMesh->cm); tri::UpdateBounding::Box(destMesh->cm); // updates bounding box destMesh->cm.Tr = currentMesh->cm.Tr; // copy transformation } -void ExtraFilter_SlicePlugin::capHole(MeshDocument& m) +void ExtraFilter_SlicePlugin::capHole(MeshModel* currentMesh, MeshModel* destMesh) { - std::vector outline; - for(int i=0;icm.vert.size();i++) - if (m.mm()->cm.vert[i].Q()==VERTEX_SLICE) - outline.push_back(m.mm()->cm.vert[i].P()); - - // tesselation input: each outline represents a polygon contour std::vector< std::vector > outlines; - outlines.push_back(outline); - Log(0,"%d points",outline.size()); - // tesselation output (triangles indices) - std::vector indices; - - // compute triangles indices - glu_tesselator::tesselate(outlines, indices); - - // unroll input contours points - std::vector points; - - glu_tesselator::unroll(outlines, points); - - CMeshO::FaceIterator fi=tri::Allocator::AddFaces(m.mm()->cm,indices.size()); - Log(0,"%d new faces",indices.size()); - // create triangles - for (size_t i=0; i outline; + vcg::tri::UpdateFlags::VertexClearV(currentMesh->cm); + vcg::tri::UpdateFlags::FaceBorderFromNone(currentMesh->cm); + int nv=0; + for(int i=0;icm.face.size();i++) { - (*&fi)->V0(0)->P()=points[ indices[i+0] ]; - (*&fi)->V1(0)->P()=points[ indices[i+1] ]; - (*&fi)->V2(0)->P()=points[ indices[i+2] ]; + for (int j=0;j<3;j++) + if (!currentMesh->cm.face[i].IsV() && currentMesh->cm.face[i].IsB(j)) + { + CFaceO* startB=&(currentMesh->cm.face[i]); + vcg::face::Pos p(startB,j); + do + { + p.V()->SetV(); + outline.push_back(p.V()->P()); + p.NextB(); + nv++; + } + while(!p.V()->IsV()); + outlines.push_back(outline); + outline.clear(); + } + } + if (nv<2) return; + CMeshO::VertexIterator vi=vcg::tri::Allocator::AddVertices(destMesh->cm,nv); + for (int i=0;iP()=outlines[i][j]; } - vcg::tri::UpdateTopology::FaceFace(m.mm()->cm); + std::vector indices; + glu_tesselator::tesselate(outlines, indices); + Log(0,"%d new faces",indices.size()); + std::vector points; + glu_tesselator::unroll(outlines, points); + CMeshO::FaceIterator fi=tri::Allocator::AddFaces(destMesh->cm,nv-2); + for (size_t i=0; iV(0)=&destMesh->cm.vert[ indices[i+0] ]; + (*&fi)->V(1)=&destMesh->cm.vert[ indices[i+1] ]; + (*&fi)->V(2)=&destMesh->cm.vert[ indices[i+2] ]; + } + tri::Clean::RemoveDuplicateVertex(destMesh->cm); + vcg::tri::UpdateTopology::FaceFace(destMesh->cm); + vcg::tri::UpdateBounding::Box(destMesh->cm); } - -Q_EXPORT_PLUGIN(ExtraFilter_SlicePlugin) + +Q_EXPORT_PLUGIN(ExtraFilter_SlicePlugin) diff --git a/src/meshlabplugins/filter_slice/filter_slice.h b/src/meshlabplugins/filter_slice/filter_slice.h index e50746547..62666c4cf 100644 --- a/src/meshlabplugins/filter_slice/filter_slice.h +++ b/src/meshlabplugins/filter_slice/filter_slice.h @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include @@ -65,7 +65,7 @@ class ExtraFilter_SlicePlugin : public QObject, public MeshFilterInterface Q_INTERFACES(MeshFilterInterface) public: - enum { FP_PLANE }; + enum { FP_PARALLEL_PLANES, FP_RECURSIVE_SLICE }; ExtraFilter_SlicePlugin(); ~ExtraFilter_SlicePlugin(){}; @@ -76,11 +76,12 @@ public: virtual void initParameterSet(QAction *,MeshModel &/*m*/, FilterParameterSet & /*parent*/); virtual bool applyFilter(QAction *filter, MeshDocument &m, FilterParameterSet & /*parent*/, vcg::CallBackPos * cb) ; virtual bool applyFilter(QAction * /* filter */, MeshModel &, FilterParameterSet & /*parent*/, vcg::CallBackPos *) { assert(0); return false;} ; - virtual const int getRequirements(QAction *){return MeshModel::MM_FACEFACETOPO;} + virtual const int getRequirements(QAction *){return MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER;} private: SVGProperties pr; - void createSlice(MeshDocument& orig); - void capHole(MeshDocument& orig); + void createSlice(MeshModel* orig,MeshModel* dest); + void capHole(MeshModel* orig, MeshModel* dest); + void extrude(MeshModel* orig, MeshModel* dest, float eps, vcg::Point3f planeAxis); }; #endif diff --git a/src/meshlabplugins/filter_slice/filter_slice_functors.h b/src/meshlabplugins/filter_slice/filter_slice_functors.h index aa9200159..c4afebb33 100644 --- a/src/meshlabplugins/filter_slice/filter_slice_functors.h +++ b/src/meshlabplugins/filter_slice/filter_slice_functors.h @@ -15,21 +15,18 @@ public: { p=_p; } - bool operator()(face::Pos ep) { Point3f pp; - Segment3f seg(ep.f->V(ep.z)->P(),ep.f->V1(ep.z)->P()); - if(Distance(ep.f->V0(ep.z)->P(),p)<0) - ep.f->V0(ep.z)->Q()=VERTEX_LEFT; - else - ep.f->V0(ep.z)->Q()=VERTEX_RIGHT; - if(Distance(ep.f->V1(ep.z)->P(),p)<0) - ep.f->V1(ep.z)->Q()=VERTEX_LEFT; - else - ep.f->V1(ep.z)->Q()=VERTEX_RIGHT; - return Intersection(p,seg,pp); + if(Distance(ep.V()->P(),p)<0) ep.V()->Q()=VERTEX_LEFT; + else ep.V()->Q()=VERTEX_RIGHT; + + if(Distance(ep.VFlip()->P(),p)<0) ep.VFlip()->Q()=VERTEX_LEFT; + else ep.VFlip()->Q()=VERTEX_RIGHT; + + return ep.V()->Q() != ep.VFlip()->Q(); } + protected: Plane3f p; };