From 3965101582068eff0495d2c167bba89423bd2be0 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Mon, 4 Apr 2011 06:11:19 +0000 Subject: [PATCH] Corrections of include paths to comply the new folder arrangement of the VCG library (another set of the many filters; cleaning up and removing useless includes) --- src/fgt/edit_hole/fgtHole.h | 1089 +++-- src/fgt/edit_hole/holeSetManager.h | 1078 ++--- src/fgt/edit_quality/qualitymapperdialog.cpp | 8 - src/fgt/edit_quality/qualitymapperdialog.h | 2 +- src/fgt/edit_texture/edittexture.cpp | 2 +- src/fgt/edit_texture/textureeditor.h | 2 +- src/fgt/edit_topo/edit_topo.cpp | 3686 ++++++++--------- src/fgt/edit_topo/edit_topomeshbuilder.h | 1030 ++--- src/fgt/edit_topo/filter_topo/filter_topo.cpp | 268 +- src/fgt/edit_virtual_scan/vs/sampler.h | 390 +- .../edit_virtual_scan/vs/simple_renderer.h | 420 +- src/fgt/editpaint/editpaint.cpp | 10 - src/fgt/filter_aging/filter_aging.cpp | 12 +- src/fgt/filter_aging/filter_aging.h | 5 +- 14 files changed, 3984 insertions(+), 4018 deletions(-) diff --git a/src/fgt/edit_hole/fgtHole.h b/src/fgt/edit_hole/fgtHole.h index 05880ee13..30befd03d 100644 --- a/src/fgt/edit_hole/fgtHole.h +++ b/src/fgt/edit_hole/fgtHole.h @@ -1,545 +1,544 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* 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 HOLE_H -#define HOLE_H - -#include -#include -#include -#include -#include -#include "vcg/simplex/face/pos.h" -#include "vcg/space/point3.h" -#include "vcg/complex/trimesh/hole.h" -#include "vcg/complex/trimesh/allocate.h" -#include -#include -#include "vcg/space/color4.h" -#include "holeSetManager.h" - -/** An hole type, extends vcg::tri::Hole::Info adding more information - * as filling, selection, filing autocompenetration and non manifoldness. - * This class also allow to fill (and restore) an hole using different criteria. - * - * FgtHole uses meshe's additional data to mark interesting face, so surfing - * the hole faces is driven by face-face ajacency and mark meaning. - * Additional data are accesible for an hole by parentManager (HoleSetManager) - * which links hole to a mesh. - * Characteristic faces for an hole are marked as: - * - HoleBorderFace: face which initially (before filling) have 1 or 2 border edge. - * - HolePatchFace: faces added to fill the hole - * - PatchCompFace: patch faces which are selfintersected with mesh. - * - BridgeFace: faces added to edit hole (unify 2 holes, subdivide an hole, partitioning a - * non-manifold hole in more manifold ones) - * - BridgeFace + HolePatchFace: this combo is used to individuate faces added to subdivide - * a non manifold hole and also close a non manifold hole, ie an hole made up from only 3 edge - * - * --------+-------+----+-----| --------+-------+----+------| - * hole /\ hole /\ hole | hole /\ f0 /\ f1| hole | f0: BridgeFace + PatchFace - * A / \ A / \ A | A / \ / \ | B | f1: BridgeFace - * / \ / \ | / \ / \ | | - * ______/ \/ \______| ______/ \/ \|______| - */ -template -class FgtHole : public vcg::tri::Hole::Info -{ -public: - -private: - enum State - { - NONE = 0x0000, - SELECTED = 0x0001, - FILLED = 0x0002, - ACCEPTED = 0x0004, - COMPENET = 0x0008, - NONMANIF = 0x0010, - BRIDGED = 0x0020 - }; - -public: - enum FillerMode - { - Trivial, MinimumWeight, SelfIntersection - }; - - typedef typename MESH::FaceType FaceType; - typedef typename MESH::FacePointer FacePointer; - typedef typename std::vector FacePointerVector; - typedef typename MESH::VertexType VertexType; - typedef typename MESH::ScalarType ScalarType; - typedef typename vcg::face::Pos PosType; - typedef typename std::vector< PosType > PosVector; - typedef typename vcg::tri::Hole vcgHole; - typedef typename vcgHole::Info HoleInfo; - typedef typename std::vector< FgtHole > HoleVector; - typedef typename HoleVector::iterator HoleIterator; - typedef typename vcg::tri::TrivialEar TrivialEar; - typedef typename vcg::tri::MinimumWeightEar MinimumWeightEar; - typedef typename vcg::tri::SelfIntersectionEar SelfIntersectionEar; - - FgtHole(HoleInfo &hi, QString holeName, HoleSetManager *parent) : - HoleInfo(hi.p, hi.size, hi.bb) - { - parentManager = parent; - name = holeName; - _state = ACCEPTED; - perimeter = HoleInfo::Perimeter(); - findNonManifoldness(); - }; - - FgtHole(PosType startPos, QString holeName, HoleSetManager *parent) - { - assert(startPos.IsBorder()); - parentManager = parent; - name = holeName; - _state = ACCEPTED; - this->p = startPos; - updateInfo(); - }; - - ~FgtHole() {}; - - inline int Size() const { return this->size; }; - inline ScalarType Perimeter() const { return this->perimeter; }; - inline bool IsFilled() const { return (_state & FILLED) != 0; }; - inline bool IsSelected() const { return (_state & SELECTED) != 0; }; - inline bool IsCompenetrating() const { return IsFilled() && (_state & COMPENET) != 0; }; - inline bool IsAccepted() const { return !IsFilled() || ( (_state & ACCEPTED) != 0); }; - inline bool IsNonManifold() const { return (_state & NONMANIF) != 0; }; - inline bool IsBridged() const { return (_state & BRIDGED) != 0;; }; - inline void SetBridged(bool val) - { - if(val) _state |= BRIDGED; - else _state &= (~BRIDGED); - }; - - void SetSelect(bool val) - { - bool oldVal = IsSelected(); - if(val) _state |= SELECTED; - else _state &= (~SELECTED); - if(oldVal != val) - { - if(val) parentManager->nSelected++; - else parentManager->nSelected--; - } - }; - - void SetAccepted(bool val) - { - bool oldVal = IsAccepted(); - if(val) _state |= ACCEPTED; - else _state &= (~ACCEPTED); - if(oldVal != val) - { - if(val) parentManager->nAccepted++; - else parentManager->nAccepted--; - } - }; - - inline void SetStartPos(PosType initP) - { - assert(!IsFilled()); - this->p = initP; - assert(this->p.IsBorder()); - updateInfo(); - }; - - void Draw() const - { - typename PosVector::const_iterator it = borderPos.begin(); - glBegin(GL_LINE_LOOP); - for( ; it != borderPos.end(); it++) - glVertex( it->v->P() ); - glEnd(); - }; - - void DrawCompenetratingFace(GLenum glmode) const - { - assert(IsCompenetrating()); - - typename std::vector::const_iterator it; - - glBegin(glmode); - for( it=patches.begin(); it != patches.end(); it++) - if( parentManager->IsCompFace(*it) ) - { - glVertex( (*it)->V(0)->P() ); - glVertex( (*it)->V(1)->P() ); - glVertex( (*it)->V(2)->P() ); - } - - glEnd(); - } - - /* Reset flags used by this plugin (holeBorder and patch) to unmark this hole and its patch. - */ - void ResetFlag() - { - std::vector bridgesFaces; - if( IsFilled() ) - { - typename std::vector::iterator it; - - while(patches.size()>0) - { - FacePointer f = patches.back(); - patches.pop_back(); - parentManager->ClearPatchAttr(f); - parentManager->ClearCompAttr(f); - - for(int i=0; i<3; i++) - { - FacePointer adjF = f->FFp(i); - parentManager->ClearHoleBorderAttr(adjF); - } - } - } - else - { - // we can walk the border to find hole's faces added by bridges - PosType curPos = this->p; - do{ - parentManager->ClearHoleBorderAttr(curPos.f); - curPos.NextB(); - }while( curPos != this->p ); - } - }; - - - /* Restore hole, remove patch faces applied to mesh to fill this hole. */ - void RestoreHole() - { - assert( IsFilled() ); - _state &= (~FILLED); - - typename std::vector::iterator it; - for(it = patches.begin(); it!=patches.end(); it++) - { - // PathcHoleFlag+BridgeFaceFlag is special case - if(parentManager->IsBridgeFace(*it)) continue; - - assert(parentManager->IsPatchFace(*it)); - for(int e=0; e<3; e++) - { - if(!IsBorder(**it, e)) - { - FacePointer adjF = (*it)->FFp(e); - if(!parentManager->IsPatchFace(adjF)) - { - int adjEI = (*it)->FFi(e); - adjF->FFp( adjEI ) = adjF; - adjF->FFi( adjEI ) = adjEI; - assert(IsBorder(*adjF, adjEI)); - } - } - } - if(!(**it).IsD()) - vcg::tri::Allocator::DeleteFace(*parentManager->mesh, **it); - } - patches.clear(); - }; - - void Fill(FillerMode mode, MESH &mesh, std::vector &local_facePointer) - { - assert(!IsFilled()); - assert(this->p.IsBorder()); - int patchBit = FaceType::NewBitFlag(); - switch(mode) - { - case FgtHole::Trivial: - vcgHole::template FillHoleEar< TrivialEar >(mesh, *this, patchBit, local_facePointer); - break; - case FgtHole::MinimumWeight: - vcgHole::template FillHoleEar< MinimumWeightEar >(mesh, *this, patchBit, local_facePointer); - break; - case FgtHole::SelfIntersection: - std::vector vfp = local_facePointer; - SelfIntersectionEar::AdjacencyRing().clear(); - PosType ip = this->p; - do - { - PosType inp = ip; - do - { - inp.FlipE(); - inp.FlipF(); - SelfIntersectionEar::AdjacencyRing().push_back(inp.f); - } while(!inp.IsBorder()); - ip.NextB(); - }while(ip != this->p); - - typename std::vector::iterator fpi = SelfIntersectionEar::AdjacencyRing().begin(); - for( ; fpi != SelfIntersectionEar::AdjacencyRing().end(); ++fpi) - vfp.push_back( &*fpi ); - - vcgHole::template FillHoleEar< SelfIntersectionEar >(mesh, *this, patchBit, vfp); - SelfIntersectionEar::AdjacencyRing().clear(); - break; - } - - // hole filling leaves V flag to border vertex... resetting! - typename PosVector::const_iterator it = borderPos.begin(); - for( ;it!=borderPos.end(); it++) - it->v->ClearV(); - - parentManager->faceAttr->UpdateSize(); - - _state |= FILLED; - _state |= ACCEPTED; - _state &= (~COMPENET); - updatePatchState(patchBit); - FaceType::DeleteBitFlag(patchBit); - }; - - /* Check if face is a border face of this hole */ - bool HaveBorderFace(FacePointer bFace) const - { - assert(parentManager->IsHoleBorderFace(bFace)); - typename PosVector::const_iterator it; - for(it=borderPos.begin(); it!= borderPos.end(); it++) - if( bFace == it->f ) - return true; - return false; - } - - /* Check if pFace is a patch face of this hole */ - bool HavePatchFace(FacePointer pFace) const - { - assert( parentManager->IsPatchFace(pFace) ); - if( !IsFilled() ) - return false; - - typename std::vector::const_iterator it; - for(it = patches.begin(); it!=patches.end(); it++) - if(pFace == *it) - return true; - return false; - }; - - /* walk over hole border, watching each adiacent faces to its vertex - * looking for bridge faces. - */ - void UpdateBridgingStatus() - { - assert(!IsFilled()); - PosType curPos = this->p; - do{ - do{ - if( parentManager->IsBridgeFace(curPos.f) ) - { - SetBridged(true); - return; - } - curPos.FlipE(); - curPos.FlipF(); - }while(!curPos.IsBorder()); - curPos.FlipV(); - }while(curPos != this->p); - SetBridged(false); - }; - - // concats its face reference to a vector - void AddFaceReference(std::vector &facesReferences) - { - facesReferences.push_back(&this->p.f); - - typename PosVector::iterator pit; - for(pit=borderPos.begin(); pit != borderPos.end(); pit++) - facesReferences.push_back( &pit->f ); - - typename std::vector::iterator fit; - for(fit=patches.begin(); fit!=patches.end(); fit++) - facesReferences.push_back(&*fit); - }; - -private: - - /* Walking the hole computing vcgHole::Info data and other info */ - void updateInfo() - { - assert(!IsFilled()); - borderPos.clear(); - _state &= (~NONMANIF); - this->bb.SetNull(); - this->size = 0; - - PosType curPos = this->p; - do{ - assert(!curPos.f->IsD()); - borderPos.push_back(curPos); - parentManager->SetHoleBorderAttr(curPos.f); - this->bb.Add(curPos.v->cP()); - ++this->size; - if(curPos.v->IsV()) - _state |= NONMANIF; - else - curPos.v->SetV(); - curPos.NextB(); - assert(curPos.IsBorder()); - }while( curPos != this->p ); - - curPos = this->p; - do{ - curPos.v->ClearV(); - curPos.NextB(); - }while( curPos != this->p ); - - perimeter = HoleInfo::Perimeter(); - }; - - /* Walking the hole storing vertexes and finding non manifold one */ - void findNonManifoldness() - { - assert(!IsFilled()); - _state &= (~NONMANIF); - PosType curPos = this->p; - do{ - borderPos.push_back(curPos); - if(curPos.v->IsV()) - _state |= NONMANIF; - else - curPos.v->SetV(); - curPos.NextB(); - }while( curPos != this->p ); - - curPos = this->p; - do{ - curPos.v->ClearV(); - curPos.NextB(); - }while( curPos != this->p ); - }; - - /* set patch flag and auto-compenetration flag when needed */ - void updatePatchState(int patchFlag) - { - assert( IsFilled() ); - _state &= (~COMPENET); - vcg::GridStaticPtr gM; - gM.Set(parentManager->mesh->face.begin(),parentManager->mesh->face.end()); - - std::vector inBox; - vcg::Box3< ScalarType> bbox; - getPatchFaces(patchFlag); - typename FacePointerVector::iterator pi = patches.begin(); - for( ; pi!=patches.end(); ++pi) - { - FacePointer f = *pi; - if(TestFaceMeshCompenetration(*parentManager->mesh, gM, f)) - { - _state |= COMPENET; - parentManager->SetCompAttr(f); - } - (*pi)->ClearUserBit(patchFlag); - parentManager->SetPatchAttr(*pi); - } - }; - - - /* First patch face is the adjacent one to initial Pos ("p" field of Hole::Info) - * Other patch face are found looking adjacent face on each vertex of known patch faces. - * NB: looking adjacent faces to vertexes it can find patches also for non manifold hole. - */ - void getPatchFaces(int patchFlag) - { - assert( IsFilled() ); - patches.clear(); - std::vector stack; - PosType pos = this->p; - pos.FlipF(); - assert(pos.f->IsUserBit(patchFlag)); - pos.f->SetV(); - stack.push_back(pos.f); - while(stack.size()>0) - { - FacePointer f = stack.back(); - stack.pop_back(); - patches.push_back(f); - - // visit faces adjacent to f's vertexes - for(int v=0; v<3; v++) - { - pos = PosType(f, v); - do{ - pos.FlipF(); - pos.FlipE(); - if(pos.f->IsUserBit(patchFlag) && !pos.f->IsV()) - { - pos.f->SetV(); - stack.push_back(pos.f); - } - }while(pos.f != f); - } - } - - typename std::vector::iterator it; - for(it=patches.begin(); it!=patches.end(); ++it) - (*it)->ClearV(); - }; - - /********* Static functions **********/ -public: - - static bool TestFaceMeshCompenetration(MESH &mesh, vcg::GridStaticPtr &gM, - const FacePointer f) - { - std::vector inBox; - vcg::Box3< ScalarType> bbox; - - f->GetBBox(bbox); - vcg::tri::GetInBoxFace(mesh, gM, bbox,inBox); - - typename std::vector::iterator fib; - for(fib=inBox.begin();fib!=inBox.end();++fib) - { - if (f != *fib) - { - if(vcg::tri::Clean::TestIntersection( *fib, f )) - return true; - } - } - return false; - }; - - -public: - static int &HoleId(){static int _holeId=0; return _holeId;}; - static void ResetHoleId() { HoleId()=0; }; - static int GetHoleId() { return ++HoleId(); }; - QString name; - -public: - HoleSetManager* parentManager; - std::vector patches; - -private: - int _state; - ScalarType perimeter; - - std::vector borderPos; - -}; - -#endif +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* 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 HOLE_H +#define HOLE_H + +#include +#include +#include +#include +#include +#include "vcg/simplex/face/pos.h" +#include "vcg/space/point3.h" +#include "vcg/complex/algorithms/hole.h" +#include +#include +#include "vcg/space/color4.h" +#include "holeSetManager.h" + +/** An hole type, extends vcg::tri::Hole::Info adding more information + * as filling, selection, filing autocompenetration and non manifoldness. + * This class also allow to fill (and restore) an hole using different criteria. + * + * FgtHole uses meshe's additional data to mark interesting face, so surfing + * the hole faces is driven by face-face ajacency and mark meaning. + * Additional data are accesible for an hole by parentManager (HoleSetManager) + * which links hole to a mesh. + * Characteristic faces for an hole are marked as: + * - HoleBorderFace: face which initially (before filling) have 1 or 2 border edge. + * - HolePatchFace: faces added to fill the hole + * - PatchCompFace: patch faces which are selfintersected with mesh. + * - BridgeFace: faces added to edit hole (unify 2 holes, subdivide an hole, partitioning a + * non-manifold hole in more manifold ones) + * - BridgeFace + HolePatchFace: this combo is used to individuate faces added to subdivide + * a non manifold hole and also close a non manifold hole, ie an hole made up from only 3 edge + * + * --------+-------+----+-----| --------+-------+----+------| + * hole /\ hole /\ hole | hole /\ f0 /\ f1| hole | f0: BridgeFace + PatchFace + * A / \ A / \ A | A / \ / \ | B | f1: BridgeFace + * / \ / \ | / \ / \ | | + * ______/ \/ \______| ______/ \/ \|______| + */ +template +class FgtHole : public vcg::tri::Hole::Info +{ +public: + +private: + enum State + { + NONE = 0x0000, + SELECTED = 0x0001, + FILLED = 0x0002, + ACCEPTED = 0x0004, + COMPENET = 0x0008, + NONMANIF = 0x0010, + BRIDGED = 0x0020 + }; + +public: + enum FillerMode + { + Trivial, MinimumWeight, SelfIntersection + }; + + typedef typename MESH::FaceType FaceType; + typedef typename MESH::FacePointer FacePointer; + typedef typename std::vector FacePointerVector; + typedef typename MESH::VertexType VertexType; + typedef typename MESH::ScalarType ScalarType; + typedef typename vcg::face::Pos PosType; + typedef typename std::vector< PosType > PosVector; + typedef typename vcg::tri::Hole vcgHole; + typedef typename vcgHole::Info HoleInfo; + typedef typename std::vector< FgtHole > HoleVector; + typedef typename HoleVector::iterator HoleIterator; + typedef typename vcg::tri::TrivialEar TrivialEar; + typedef typename vcg::tri::MinimumWeightEar MinimumWeightEar; + typedef typename vcg::tri::SelfIntersectionEar SelfIntersectionEar; + + FgtHole(HoleInfo &hi, QString holeName, HoleSetManager *parent) : + HoleInfo(hi.p, hi.size, hi.bb) + { + parentManager = parent; + name = holeName; + _state = ACCEPTED; + perimeter = HoleInfo::Perimeter(); + findNonManifoldness(); + }; + + FgtHole(PosType startPos, QString holeName, HoleSetManager *parent) + { + assert(startPos.IsBorder()); + parentManager = parent; + name = holeName; + _state = ACCEPTED; + this->p = startPos; + updateInfo(); + }; + + ~FgtHole() {}; + + inline int Size() const { return this->size; }; + inline ScalarType Perimeter() const { return this->perimeter; }; + inline bool IsFilled() const { return (_state & FILLED) != 0; }; + inline bool IsSelected() const { return (_state & SELECTED) != 0; }; + inline bool IsCompenetrating() const { return IsFilled() && (_state & COMPENET) != 0; }; + inline bool IsAccepted() const { return !IsFilled() || ( (_state & ACCEPTED) != 0); }; + inline bool IsNonManifold() const { return (_state & NONMANIF) != 0; }; + inline bool IsBridged() const { return (_state & BRIDGED) != 0;; }; + inline void SetBridged(bool val) + { + if(val) _state |= BRIDGED; + else _state &= (~BRIDGED); + }; + + void SetSelect(bool val) + { + bool oldVal = IsSelected(); + if(val) _state |= SELECTED; + else _state &= (~SELECTED); + if(oldVal != val) + { + if(val) parentManager->nSelected++; + else parentManager->nSelected--; + } + }; + + void SetAccepted(bool val) + { + bool oldVal = IsAccepted(); + if(val) _state |= ACCEPTED; + else _state &= (~ACCEPTED); + if(oldVal != val) + { + if(val) parentManager->nAccepted++; + else parentManager->nAccepted--; + } + }; + + inline void SetStartPos(PosType initP) + { + assert(!IsFilled()); + this->p = initP; + assert(this->p.IsBorder()); + updateInfo(); + }; + + void Draw() const + { + typename PosVector::const_iterator it = borderPos.begin(); + glBegin(GL_LINE_LOOP); + for( ; it != borderPos.end(); it++) + glVertex( it->v->P() ); + glEnd(); + }; + + void DrawCompenetratingFace(GLenum glmode) const + { + assert(IsCompenetrating()); + + typename std::vector::const_iterator it; + + glBegin(glmode); + for( it=patches.begin(); it != patches.end(); it++) + if( parentManager->IsCompFace(*it) ) + { + glVertex( (*it)->V(0)->P() ); + glVertex( (*it)->V(1)->P() ); + glVertex( (*it)->V(2)->P() ); + } + + glEnd(); + } + + /* Reset flags used by this plugin (holeBorder and patch) to unmark this hole and its patch. + */ + void ResetFlag() + { + std::vector bridgesFaces; + if( IsFilled() ) + { + typename std::vector::iterator it; + + while(patches.size()>0) + { + FacePointer f = patches.back(); + patches.pop_back(); + parentManager->ClearPatchAttr(f); + parentManager->ClearCompAttr(f); + + for(int i=0; i<3; i++) + { + FacePointer adjF = f->FFp(i); + parentManager->ClearHoleBorderAttr(adjF); + } + } + } + else + { + // we can walk the border to find hole's faces added by bridges + PosType curPos = this->p; + do{ + parentManager->ClearHoleBorderAttr(curPos.f); + curPos.NextB(); + }while( curPos != this->p ); + } + }; + + + /* Restore hole, remove patch faces applied to mesh to fill this hole. */ + void RestoreHole() + { + assert( IsFilled() ); + _state &= (~FILLED); + + typename std::vector::iterator it; + for(it = patches.begin(); it!=patches.end(); it++) + { + // PathcHoleFlag+BridgeFaceFlag is special case + if(parentManager->IsBridgeFace(*it)) continue; + + assert(parentManager->IsPatchFace(*it)); + for(int e=0; e<3; e++) + { + if(!IsBorder(**it, e)) + { + FacePointer adjF = (*it)->FFp(e); + if(!parentManager->IsPatchFace(adjF)) + { + int adjEI = (*it)->FFi(e); + adjF->FFp( adjEI ) = adjF; + adjF->FFi( adjEI ) = adjEI; + assert(IsBorder(*adjF, adjEI)); + } + } + } + if(!(**it).IsD()) + vcg::tri::Allocator::DeleteFace(*parentManager->mesh, **it); + } + patches.clear(); + }; + + void Fill(FillerMode mode, MESH &mesh, std::vector &local_facePointer) + { + assert(!IsFilled()); + assert(this->p.IsBorder()); + int patchBit = FaceType::NewBitFlag(); + switch(mode) + { + case FgtHole::Trivial: + vcgHole::template FillHoleEar< TrivialEar >(mesh, *this, patchBit, local_facePointer); + break; + case FgtHole::MinimumWeight: + vcgHole::template FillHoleEar< MinimumWeightEar >(mesh, *this, patchBit, local_facePointer); + break; + case FgtHole::SelfIntersection: + std::vector vfp = local_facePointer; + SelfIntersectionEar::AdjacencyRing().clear(); + PosType ip = this->p; + do + { + PosType inp = ip; + do + { + inp.FlipE(); + inp.FlipF(); + SelfIntersectionEar::AdjacencyRing().push_back(inp.f); + } while(!inp.IsBorder()); + ip.NextB(); + }while(ip != this->p); + + typename std::vector::iterator fpi = SelfIntersectionEar::AdjacencyRing().begin(); + for( ; fpi != SelfIntersectionEar::AdjacencyRing().end(); ++fpi) + vfp.push_back( &*fpi ); + + vcgHole::template FillHoleEar< SelfIntersectionEar >(mesh, *this, patchBit, vfp); + SelfIntersectionEar::AdjacencyRing().clear(); + break; + } + + // hole filling leaves V flag to border vertex... resetting! + typename PosVector::const_iterator it = borderPos.begin(); + for( ;it!=borderPos.end(); it++) + it->v->ClearV(); + + parentManager->faceAttr->UpdateSize(); + + _state |= FILLED; + _state |= ACCEPTED; + _state &= (~COMPENET); + updatePatchState(patchBit); + FaceType::DeleteBitFlag(patchBit); + }; + + /* Check if face is a border face of this hole */ + bool HaveBorderFace(FacePointer bFace) const + { + assert(parentManager->IsHoleBorderFace(bFace)); + typename PosVector::const_iterator it; + for(it=borderPos.begin(); it!= borderPos.end(); it++) + if( bFace == it->f ) + return true; + return false; + } + + /* Check if pFace is a patch face of this hole */ + bool HavePatchFace(FacePointer pFace) const + { + assert( parentManager->IsPatchFace(pFace) ); + if( !IsFilled() ) + return false; + + typename std::vector::const_iterator it; + for(it = patches.begin(); it!=patches.end(); it++) + if(pFace == *it) + return true; + return false; + }; + + /* walk over hole border, watching each adiacent faces to its vertex + * looking for bridge faces. + */ + void UpdateBridgingStatus() + { + assert(!IsFilled()); + PosType curPos = this->p; + do{ + do{ + if( parentManager->IsBridgeFace(curPos.f) ) + { + SetBridged(true); + return; + } + curPos.FlipE(); + curPos.FlipF(); + }while(!curPos.IsBorder()); + curPos.FlipV(); + }while(curPos != this->p); + SetBridged(false); + }; + + // concats its face reference to a vector + void AddFaceReference(std::vector &facesReferences) + { + facesReferences.push_back(&this->p.f); + + typename PosVector::iterator pit; + for(pit=borderPos.begin(); pit != borderPos.end(); pit++) + facesReferences.push_back( &pit->f ); + + typename std::vector::iterator fit; + for(fit=patches.begin(); fit!=patches.end(); fit++) + facesReferences.push_back(&*fit); + }; + +private: + + /* Walking the hole computing vcgHole::Info data and other info */ + void updateInfo() + { + assert(!IsFilled()); + borderPos.clear(); + _state &= (~NONMANIF); + this->bb.SetNull(); + this->size = 0; + + PosType curPos = this->p; + do{ + assert(!curPos.f->IsD()); + borderPos.push_back(curPos); + parentManager->SetHoleBorderAttr(curPos.f); + this->bb.Add(curPos.v->cP()); + ++this->size; + if(curPos.v->IsV()) + _state |= NONMANIF; + else + curPos.v->SetV(); + curPos.NextB(); + assert(curPos.IsBorder()); + }while( curPos != this->p ); + + curPos = this->p; + do{ + curPos.v->ClearV(); + curPos.NextB(); + }while( curPos != this->p ); + + perimeter = HoleInfo::Perimeter(); + }; + + /* Walking the hole storing vertexes and finding non manifold one */ + void findNonManifoldness() + { + assert(!IsFilled()); + _state &= (~NONMANIF); + PosType curPos = this->p; + do{ + borderPos.push_back(curPos); + if(curPos.v->IsV()) + _state |= NONMANIF; + else + curPos.v->SetV(); + curPos.NextB(); + }while( curPos != this->p ); + + curPos = this->p; + do{ + curPos.v->ClearV(); + curPos.NextB(); + }while( curPos != this->p ); + }; + + /* set patch flag and auto-compenetration flag when needed */ + void updatePatchState(int patchFlag) + { + assert( IsFilled() ); + _state &= (~COMPENET); + vcg::GridStaticPtr gM; + gM.Set(parentManager->mesh->face.begin(),parentManager->mesh->face.end()); + + std::vector inBox; + vcg::Box3< ScalarType> bbox; + getPatchFaces(patchFlag); + typename FacePointerVector::iterator pi = patches.begin(); + for( ; pi!=patches.end(); ++pi) + { + FacePointer f = *pi; + if(TestFaceMeshCompenetration(*parentManager->mesh, gM, f)) + { + _state |= COMPENET; + parentManager->SetCompAttr(f); + } + (*pi)->ClearUserBit(patchFlag); + parentManager->SetPatchAttr(*pi); + } + }; + + + /* First patch face is the adjacent one to initial Pos ("p" field of Hole::Info) + * Other patch face are found looking adjacent face on each vertex of known patch faces. + * NB: looking adjacent faces to vertexes it can find patches also for non manifold hole. + */ + void getPatchFaces(int patchFlag) + { + assert( IsFilled() ); + patches.clear(); + std::vector stack; + PosType pos = this->p; + pos.FlipF(); + assert(pos.f->IsUserBit(patchFlag)); + pos.f->SetV(); + stack.push_back(pos.f); + while(stack.size()>0) + { + FacePointer f = stack.back(); + stack.pop_back(); + patches.push_back(f); + + // visit faces adjacent to f's vertexes + for(int v=0; v<3; v++) + { + pos = PosType(f, v); + do{ + pos.FlipF(); + pos.FlipE(); + if(pos.f->IsUserBit(patchFlag) && !pos.f->IsV()) + { + pos.f->SetV(); + stack.push_back(pos.f); + } + }while(pos.f != f); + } + } + + typename std::vector::iterator it; + for(it=patches.begin(); it!=patches.end(); ++it) + (*it)->ClearV(); + }; + + /********* Static functions **********/ +public: + + static bool TestFaceMeshCompenetration(MESH &mesh, vcg::GridStaticPtr &gM, + const FacePointer f) + { + std::vector inBox; + vcg::Box3< ScalarType> bbox; + + f->GetBBox(bbox); + vcg::tri::GetInBoxFace(mesh, gM, bbox,inBox); + + typename std::vector::iterator fib; + for(fib=inBox.begin();fib!=inBox.end();++fib) + { + if (f != *fib) + { + if(vcg::tri::Clean::TestIntersection( *fib, f )) + return true; + } + } + return false; + }; + + +public: + static int &HoleId(){static int _holeId=0; return _holeId;}; + static void ResetHoleId() { HoleId()=0; }; + static int GetHoleId() { return ++HoleId(); }; + QString name; + +public: + HoleSetManager* parentManager; + std::vector patches; + +private: + int _state; + ScalarType perimeter; + + std::vector borderPos; + +}; + +#endif diff --git a/src/fgt/edit_hole/holeSetManager.h b/src/fgt/edit_hole/holeSetManager.h index 0c1a3a288..ccb2d668f 100644 --- a/src/fgt/edit_hole/holeSetManager.h +++ b/src/fgt/edit_hole/holeSetManager.h @@ -1,539 +1,539 @@ -/**************************************************************************** -* VCGLib o o * -* Visual and Computer Graphics Library o o * -* _ O _ * -* Copyright(C) 2004 \/)\/ * -* 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 HOLESETMANAGER_H -#define HOLESETMANAGER_H - -#include "fgtHole.h" -#include "fgtBridge.h" -#include "vcg/complex/trimesh/hole.h" -#include - - -/* HoleSetManager class rappresent an entity which manages the holes and bridges - * founded into the same MESH. - * It allows to invoke some functionality for each (may be the selected ones) - * holes as filling and bridging. - * His presence is necessary because it connect holes to a mesh with the - * additional data used by holes to mark its "characteristic" faces. - */ -template -class HoleSetManager -{ - enum FaceAttribute - { - NONE = 0x0000, - BORDER = 0x0001, - PATCH = 0x0002, - COMPENET = 0x0004, - BRIDGE = 0x0020 - }; - - typedef FgtHole< MESH > HoleType; - typedef typename std::vector< HoleType > HoleVector; - typedef typename HoleVector::iterator HoleIterator; - typedef typename std::vector< FgtBridgeBase* > BridgeVector; - typedef typename BridgeVector::iterator BridgeIterator; - typedef typename MESH::FaceType FaceType; - typedef typename MESH::FacePointer FacePointer; - typedef typename MESH::FaceContainer FaceContainer; - typedef typename vcg::tri::Hole vcgHole; - typedef typename vcgHole::Info HoleInfo; - typedef typename vcg::face::Pos PosType; - typedef typename std::vector< PosType > PosVector; - typedef typename vcg::SimpleTempData SimpleData; - typedef typename HoleType::FillerMode FillerMode; - -public: - - HoleSetManager() - { - autoBridgeCB = 0; - }; - - void Init(MESH* m) - { - nAccepted = nSelected = 0; - mesh = m; - faceAttr = new SimpleData (m->face, NONE); - getMeshHoles(); - }; - - void Clear() - { - typename HoleVector::iterator it; - for(it=holes.begin(); it!=holes.end(); it++) - it->ResetFlag(); - - holes.clear(); - }; - - /***************** PerFace additional data ********************/ - - inline bool IsHoleBorderFace(FacePointer f) const { return ( (*faceAttr)[f] & BORDER) != 0; }; - inline bool IsPatchFace(FacePointer f) const { return ((*faceAttr)[f] & PATCH) != 0; }; - inline bool IsCompFace(FacePointer f) const { return ((*faceAttr)[f] & COMPENET) != 0; }; - inline bool IsBridgeFace(FacePointer f) const { return ((*faceAttr)[f] & BRIDGE) != 0; }; - - inline void SetHoleBorderAttr(FacePointer f) { (*faceAttr)[f] |= BORDER; }; - inline void ClearHoleBorderAttr(FacePointer f) { (*faceAttr)[f] &= (~BORDER); }; - - inline void SetPatchAttr(FacePointer f) { (*faceAttr)[f] |= PATCH; }; - inline void ClearPatchAttr(FacePointer f) { (*faceAttr)[f] &= (~PATCH); } - - inline void SetCompAttr(FacePointer f) { (*faceAttr)[f] |= COMPENET; }; - inline void ClearCompAttr(FacePointer f) { (*faceAttr)[f] &= (~COMPENET); }; - - inline void SetBridgeAttr(FacePointer f){ (*faceAttr)[f] |= BRIDGE; }; - inline void ClearBridgeAttr(FacePointer f){ (*faceAttr)[f] &= (~BRIDGE); }; - - /**************** Statistical info *****************/ - inline int SelectionCount() const { return nSelected; }; - inline int HolesCount() const { return holes.size(); }; - inline int AcceptedCount() const { return nAccepted; }; - - /**************** Holes editing ********************/ - - bool Fill(FillerMode mode) - { - if(nSelected==0) - return false; - - std::vector local_facePointer; - AddFaceReference(local_facePointer); - - HoleIterator hit = holes.begin(); - for( ; hit != holes.end(); hit++ ) - if( hit->IsSelected() ) - { - hit->Fill(mode, *mesh, local_facePointer); - - // there are new face reference to update in next filling - typename std::vector::iterator fit; - for(fit=hit->patches.begin(); fit!=hit->patches.end(); fit++) - local_facePointer.push_back(&*fit); - } - - nAccepted=nSelected; - return true; - }; - - /* For accepted holes: patch faces and its adjacent bridge faces become - * faces of this mesh. - * - reset additional data for its faces - * - remove hole from list - * - accept bridge adjacent to hole - * - * For not accepted holes: patch faces are removed from mesh - * - remove hole patch and restore border - */ - void ConfirmFilling(bool accept) - { - typename std::vector bridgeF; - typename std::vector::iterator fpit; - - HoleIterator it = holes.begin(); - while( it != holes.end() ) - { - if( it->IsFilled() ) - { - - if( ( it->IsSelected() && !it->IsAccepted() ) || !accept) - { - it->RestoreHole(); - } - else if( it->IsSelected() && it->IsAccepted() ) - { - if(it->IsBridged()) - { - for(fpit = it->patches.begin(); fpit != it->patches.end(); fpit++) - { - if( IsBridgeFace( *fpit ) ) - bridgeF.push_back( *fpit ); - - for(int i=0; i<3; i++) - { - if( IsBridgeFace( (*fpit)->FFp(i) ) ) - bridgeF.push_back( (*fpit)->FFp(i) ); - } - } - } - it->ResetFlag(); - it = holes.erase(it++); - continue; - } - } - else it++; - } - - for(fpit = bridgeF.begin(); fpit != bridgeF.end(); fpit++) - { - BridgeIterator bit = bridges.begin(); - while( bit != bridges.end() ) - { - PosType a = (*bit)->GetAbutmentA(); - PosType b = (*bit)->GetAbutmentB(); - - if( *fpit == a.f->FFp(a.z) || *fpit == b.f->FFp(b.z) ) - { - (*bit)->ResetFlag(); - delete *bit; - bit = bridges.erase(bit++); - } - else - bit++; - } - } - - // update bridging status for holes remaining. - // some hole marked as "bridged" can be adjacent to bridge which is accepted - // because it is adjacent to hole filled and accepted, so they arent "bridged" now. - for( it= holes.begin(); it != holes.end(); it++) - { - assert(!it->IsFilled()); - if( it->IsBridged() ) - it->UpdateBridgingStatus(); - } - - countSelected(); - }; - - /* Bridges became face of this mesh - */ - inline void ConfirmBridges() - { - BridgeIterator bit = bridges.begin(); - for( ; bit != bridges.end(); bit++ ) - { - (*bit)->ResetFlag(); - delete *bit; - } - bridges.clear(); - - typename HoleVector::iterator hit = holes.begin(); - for( ; hit!=holes.end(); hit++ ) - hit->SetBridged(false); - }; - - /* Bridges are removed from bridges vector and mesh is restored, - * bridge faces are removed from mesh. - */ - inline void DiscardBridges() - { - removeBridges(); - countSelected(); - }; - - void CloseNonManifoldHoles() - { - FgtNMBridge::CloseNonManifoldVertex(this); - }; - - void AutoSelfBridging(double distCoeff, std::vector *facesRef) - { - FgtBridge::AutoSelfBridging(this, distCoeff, facesRef); - countSelected(); - }; - - void AutoMultiBridging(std::vector *facesRef) - { - FgtBridge::AutoMultiBridging(this, facesRef); - countSelected(); - }; - - /** Return index of hole adjacent to picked face into holes vector. - * Also return the iterator on correct position in holes list. - */ - int FindHoleFromFace(FacePointer pFace, HoleIterator &it) - { - int index = 0; - HoleIterator hit = holes.begin(); - - // it know if bFace is adjacent to patchFace - if(IsPatchFace(pFace)) - { - for( ; hit != holes.end(); ++hit) - { - if(hit->HavePatchFace(pFace)) - { - it = hit; - return index; - } - index++; - } - } - else if(IsHoleBorderFace(pFace)) - { - for( ; hit != holes.end(); ++hit) - { - if(hit->HaveBorderFace(pFace)) - { - it = hit; - return index; - } - index++; - } - } - - it = holes.end(); // invalid iterator - return -1; - }; - - /** Return boolean indicatind if the picking have select a border face which can be used - * as abutment for a bridge. If true it also return BridgeAbutment allowing to know - * border edge and its relative hole. - */ - bool FindBridgeAbutmentFromPick( FacePointer bFace, int pickedX, int pickedY, - BridgeAbutment &pickedResult) - { - if( vcg::face::BorderCount(*bFace) == 0 ) - return false; - - HoleIterator hit; - if( FindHoleFromFace(bFace, hit) < 0 ) - { - pickedResult.SetNull(); - return false; - } - - pickedResult.h = &*hit; - pickedResult.f = bFace; - if( vcg::face::BorderCount(*bFace) == 1 ) - { - // it choose the only one border edge - for(int i=0; i<3; i++) - if(vcg::face::IsBorder(*bFace, i)) - pickedResult.z = i; - } - else - { - // looking for the closest border edge to pick point - PosType retPos = getClosestPos(bFace, pickedX, pickedY); - pickedResult.f = retPos.f; - pickedResult.z = retPos.z; - } - - return true; - }; - - - /* Appends all its face reference to a vector, all face reference of its hole type - * and its bridge. - */ - void AddFaceReference(std::vector &facesReferences) - { - typename HoleVector::iterator hit = holes.begin(); - for( ; hit!=holes.end(); hit++) - hit->AddFaceReference(facesReferences); - - BridgeIterator bit = bridges.begin(); - for( ; bit != bridges.end(); bit++ ) - (*bit)->AddFaceReference(facesReferences); - } - - -private: - - /* Inspect a mesh to find its holes. */ - void getMeshHoles() - { - holes.clear(); - std::vector vhi; - - //prendo la lista di info(sugli hole) tutte le facce anche le non selezionate - FaceType::NewBitFlag(); - int borderFlag = vcgHole::GetInfo(*mesh, false, vhi); - - HoleType::ResetHoleId(); - typename std::vector::iterator itH = vhi.begin(); - for( ; itH != vhi.end(); itH++) - { - holes.push_back(HoleType(*itH, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), this)); - - // reset flag and setting of - PosType curPos = itH->p; - do{ - curPos.f->ClearUserBit(borderFlag); - SetHoleBorderAttr(curPos.f); - curPos.NextB(); - assert(curPos.IsBorder()); - }while( curPos != itH->p ); - } - - FaceType::DeleteBitFlag(borderFlag); - }; - - /* Return border half-edge of the same face which is nearest to point(x, y) of glArea. - */ - static PosType getClosestPos(FaceType* face, int x, int y) - { - double mvmatrix[16], projmatrix[16]; - GLint viewport[4]; - double rx, ry, rz; - vcg::Point2d vertex[3]; - vcg::Point2d point((double)x, (double)y); - - glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix); - glGetDoublev (GL_PROJECTION_MATRIX, projmatrix); - glGetIntegerv(GL_VIEWPORT, viewport); - - for(int i=0; i<3; i++) - { - gluProject(face->V(i)->P()[0],face->V(i)->P()[1],face->V(i)->P()[2],mvmatrix,projmatrix,viewport,&rx,&ry,&rz); - vertex[i] = vcg::Point2d(rx,ry); - } - - double dist = DBL_MAX; - int nearest = 0; - for(int i=0; i<3; i++) - { - if(!vcg::face::IsBorder(*face, i)) - continue; - - vcg::Line2d el(vertex[i], vertex[(i+1)%3]-vertex[i]); - double tmp = vcg::Distance(el, point); - - if(dist > tmp) - { - dist = tmp; - nearest = i; - } - } - return PosType(face, nearest, face->V(nearest) ); - }; - - /* Remove all bridges updating holes vector and its selection - */ - void removeBridges() - { - assert( holes.size()>0 ); - // contains all half-edge located over non-bridge face and over edge shared with bridge face. - // these half-edges will become border edge when bridge faces are removed. - PosVector adjBorderPos; - - PosType pos; - BridgeIterator bit = bridges.begin(); - for( ; bit != bridges.end(); bit++ ) - { - adjBorderPos.push_back( (*bit)->GetAbutmentA() ); - adjBorderPos.push_back( (*bit)->GetAbutmentB() ); - } - - // remove holes adjacent to bridge - HoleIterator hit = holes.begin(); - while(hit != holes.end() ) - { - if( hit->IsBridged() ) - { - if( hit->IsSelected() ) - { - PosType curPos = hit->p; - do - { - curPos.f->SetS(); - curPos.NextB(); - }while( curPos != hit->p ); - } - hit = holes.erase(hit++); - } - else - hit++; - } - - for( bit = bridges.begin(); bit != bridges.end(); bit++ ) - { - (*bit)->DeleteFromMesh(); - delete *bit; - } - bridges.clear(); - - // update hole list inserting holes touched by bridge - // use adjBorderPos element as start pos to walk over the border, if walking doesn't - // visit some adjBorderPos element means this belongo to other hole. - PosType initPos, curPos; - typename PosVector::iterator it; - for( it=adjBorderPos.begin(); it!=adjBorderPos.end(); it++) - { - // bridge abutment can be placed over face of another bridge... - // this abutments must be ignored - if(it->f->IsD()) - continue; - - assert( it->IsBorder() ); - bool sel=it->f->IsS(); - it->f->ClearS(); - - if(it->f->IsV() || it->f->IsD()) - continue; - - curPos = initPos = *it; - do{ - curPos.f->SetV(); - sel = sel || curPos.f->IsS(); - curPos.f->ClearS(); - curPos.NextB(); - assert(curPos.IsBorder()); - }while(curPos != initPos); - - FgtHole newHole(initPos, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), this); - newHole.SetSelect(sel); - holes.push_back( newHole ); - } - - // resetto flag visited sulle facce degli hole interessati - for(it=adjBorderPos.begin(); it!=adjBorderPos.end(); it++) - { - if(!it->f->IsV()) - continue; - curPos = initPos = *it; - do{ - curPos.f->ClearV(); - curPos.NextB(); - assert(curPos.IsBorder()); - }while(curPos != initPos); - } - }; - - // update statistical info - void countSelected() - { - nSelected = 0; - HoleIterator hit = holes.begin(); - for( ; hit!=holes.end(); hit++) - if(hit->IsSelected()) - nSelected++; - }; - - -public: - int nSelected; - int nAccepted; - MESH* mesh; - HoleVector holes; - BridgeVector bridges; - SimpleData* faceAttr; - - AutoBridgingCallback* autoBridgeCB; -}; - -#endif +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* 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 HOLESETMANAGER_H +#define HOLESETMANAGER_H + +#include "fgtHole.h" +#include "fgtBridge.h" +#include "vcg/complex/algorithms/hole.h" +#include + + +/* HoleSetManager class rappresent an entity which manages the holes and bridges + * founded into the same MESH. + * It allows to invoke some functionality for each (may be the selected ones) + * holes as filling and bridging. + * His presence is necessary because it connect holes to a mesh with the + * additional data used by holes to mark its "characteristic" faces. + */ +template +class HoleSetManager +{ + enum FaceAttribute + { + NONE = 0x0000, + BORDER = 0x0001, + PATCH = 0x0002, + COMPENET = 0x0004, + BRIDGE = 0x0020 + }; + + typedef FgtHole< MESH > HoleType; + typedef typename std::vector< HoleType > HoleVector; + typedef typename HoleVector::iterator HoleIterator; + typedef typename std::vector< FgtBridgeBase* > BridgeVector; + typedef typename BridgeVector::iterator BridgeIterator; + typedef typename MESH::FaceType FaceType; + typedef typename MESH::FacePointer FacePointer; + typedef typename MESH::FaceContainer FaceContainer; + typedef typename vcg::tri::Hole vcgHole; + typedef typename vcgHole::Info HoleInfo; + typedef typename vcg::face::Pos PosType; + typedef typename std::vector< PosType > PosVector; + typedef typename vcg::SimpleTempData SimpleData; + typedef typename HoleType::FillerMode FillerMode; + +public: + + HoleSetManager() + { + autoBridgeCB = 0; + }; + + void Init(MESH* m) + { + nAccepted = nSelected = 0; + mesh = m; + faceAttr = new SimpleData (m->face, NONE); + getMeshHoles(); + }; + + void Clear() + { + typename HoleVector::iterator it; + for(it=holes.begin(); it!=holes.end(); it++) + it->ResetFlag(); + + holes.clear(); + }; + + /***************** PerFace additional data ********************/ + + inline bool IsHoleBorderFace(FacePointer f) const { return ( (*faceAttr)[f] & BORDER) != 0; }; + inline bool IsPatchFace(FacePointer f) const { return ((*faceAttr)[f] & PATCH) != 0; }; + inline bool IsCompFace(FacePointer f) const { return ((*faceAttr)[f] & COMPENET) != 0; }; + inline bool IsBridgeFace(FacePointer f) const { return ((*faceAttr)[f] & BRIDGE) != 0; }; + + inline void SetHoleBorderAttr(FacePointer f) { (*faceAttr)[f] |= BORDER; }; + inline void ClearHoleBorderAttr(FacePointer f) { (*faceAttr)[f] &= (~BORDER); }; + + inline void SetPatchAttr(FacePointer f) { (*faceAttr)[f] |= PATCH; }; + inline void ClearPatchAttr(FacePointer f) { (*faceAttr)[f] &= (~PATCH); } + + inline void SetCompAttr(FacePointer f) { (*faceAttr)[f] |= COMPENET; }; + inline void ClearCompAttr(FacePointer f) { (*faceAttr)[f] &= (~COMPENET); }; + + inline void SetBridgeAttr(FacePointer f){ (*faceAttr)[f] |= BRIDGE; }; + inline void ClearBridgeAttr(FacePointer f){ (*faceAttr)[f] &= (~BRIDGE); }; + + /**************** Statistical info *****************/ + inline int SelectionCount() const { return nSelected; }; + inline int HolesCount() const { return holes.size(); }; + inline int AcceptedCount() const { return nAccepted; }; + + /**************** Holes editing ********************/ + + bool Fill(FillerMode mode) + { + if(nSelected==0) + return false; + + std::vector local_facePointer; + AddFaceReference(local_facePointer); + + HoleIterator hit = holes.begin(); + for( ; hit != holes.end(); hit++ ) + if( hit->IsSelected() ) + { + hit->Fill(mode, *mesh, local_facePointer); + + // there are new face reference to update in next filling + typename std::vector::iterator fit; + for(fit=hit->patches.begin(); fit!=hit->patches.end(); fit++) + local_facePointer.push_back(&*fit); + } + + nAccepted=nSelected; + return true; + }; + + /* For accepted holes: patch faces and its adjacent bridge faces become + * faces of this mesh. + * - reset additional data for its faces + * - remove hole from list + * - accept bridge adjacent to hole + * + * For not accepted holes: patch faces are removed from mesh + * - remove hole patch and restore border + */ + void ConfirmFilling(bool accept) + { + typename std::vector bridgeF; + typename std::vector::iterator fpit; + + HoleIterator it = holes.begin(); + while( it != holes.end() ) + { + if( it->IsFilled() ) + { + + if( ( it->IsSelected() && !it->IsAccepted() ) || !accept) + { + it->RestoreHole(); + } + else if( it->IsSelected() && it->IsAccepted() ) + { + if(it->IsBridged()) + { + for(fpit = it->patches.begin(); fpit != it->patches.end(); fpit++) + { + if( IsBridgeFace( *fpit ) ) + bridgeF.push_back( *fpit ); + + for(int i=0; i<3; i++) + { + if( IsBridgeFace( (*fpit)->FFp(i) ) ) + bridgeF.push_back( (*fpit)->FFp(i) ); + } + } + } + it->ResetFlag(); + it = holes.erase(it++); + continue; + } + } + else it++; + } + + for(fpit = bridgeF.begin(); fpit != bridgeF.end(); fpit++) + { + BridgeIterator bit = bridges.begin(); + while( bit != bridges.end() ) + { + PosType a = (*bit)->GetAbutmentA(); + PosType b = (*bit)->GetAbutmentB(); + + if( *fpit == a.f->FFp(a.z) || *fpit == b.f->FFp(b.z) ) + { + (*bit)->ResetFlag(); + delete *bit; + bit = bridges.erase(bit++); + } + else + bit++; + } + } + + // update bridging status for holes remaining. + // some hole marked as "bridged" can be adjacent to bridge which is accepted + // because it is adjacent to hole filled and accepted, so they arent "bridged" now. + for( it= holes.begin(); it != holes.end(); it++) + { + assert(!it->IsFilled()); + if( it->IsBridged() ) + it->UpdateBridgingStatus(); + } + + countSelected(); + }; + + /* Bridges became face of this mesh + */ + inline void ConfirmBridges() + { + BridgeIterator bit = bridges.begin(); + for( ; bit != bridges.end(); bit++ ) + { + (*bit)->ResetFlag(); + delete *bit; + } + bridges.clear(); + + typename HoleVector::iterator hit = holes.begin(); + for( ; hit!=holes.end(); hit++ ) + hit->SetBridged(false); + }; + + /* Bridges are removed from bridges vector and mesh is restored, + * bridge faces are removed from mesh. + */ + inline void DiscardBridges() + { + removeBridges(); + countSelected(); + }; + + void CloseNonManifoldHoles() + { + FgtNMBridge::CloseNonManifoldVertex(this); + }; + + void AutoSelfBridging(double distCoeff, std::vector *facesRef) + { + FgtBridge::AutoSelfBridging(this, distCoeff, facesRef); + countSelected(); + }; + + void AutoMultiBridging(std::vector *facesRef) + { + FgtBridge::AutoMultiBridging(this, facesRef); + countSelected(); + }; + + /** Return index of hole adjacent to picked face into holes vector. + * Also return the iterator on correct position in holes list. + */ + int FindHoleFromFace(FacePointer pFace, HoleIterator &it) + { + int index = 0; + HoleIterator hit = holes.begin(); + + // it know if bFace is adjacent to patchFace + if(IsPatchFace(pFace)) + { + for( ; hit != holes.end(); ++hit) + { + if(hit->HavePatchFace(pFace)) + { + it = hit; + return index; + } + index++; + } + } + else if(IsHoleBorderFace(pFace)) + { + for( ; hit != holes.end(); ++hit) + { + if(hit->HaveBorderFace(pFace)) + { + it = hit; + return index; + } + index++; + } + } + + it = holes.end(); // invalid iterator + return -1; + }; + + /** Return boolean indicatind if the picking have select a border face which can be used + * as abutment for a bridge. If true it also return BridgeAbutment allowing to know + * border edge and its relative hole. + */ + bool FindBridgeAbutmentFromPick( FacePointer bFace, int pickedX, int pickedY, + BridgeAbutment &pickedResult) + { + if( vcg::face::BorderCount(*bFace) == 0 ) + return false; + + HoleIterator hit; + if( FindHoleFromFace(bFace, hit) < 0 ) + { + pickedResult.SetNull(); + return false; + } + + pickedResult.h = &*hit; + pickedResult.f = bFace; + if( vcg::face::BorderCount(*bFace) == 1 ) + { + // it choose the only one border edge + for(int i=0; i<3; i++) + if(vcg::face::IsBorder(*bFace, i)) + pickedResult.z = i; + } + else + { + // looking for the closest border edge to pick point + PosType retPos = getClosestPos(bFace, pickedX, pickedY); + pickedResult.f = retPos.f; + pickedResult.z = retPos.z; + } + + return true; + }; + + + /* Appends all its face reference to a vector, all face reference of its hole type + * and its bridge. + */ + void AddFaceReference(std::vector &facesReferences) + { + typename HoleVector::iterator hit = holes.begin(); + for( ; hit!=holes.end(); hit++) + hit->AddFaceReference(facesReferences); + + BridgeIterator bit = bridges.begin(); + for( ; bit != bridges.end(); bit++ ) + (*bit)->AddFaceReference(facesReferences); + } + + +private: + + /* Inspect a mesh to find its holes. */ + void getMeshHoles() + { + holes.clear(); + std::vector vhi; + + //prendo la lista di info(sugli hole) tutte le facce anche le non selezionate + FaceType::NewBitFlag(); + int borderFlag = vcgHole::GetInfo(*mesh, false, vhi); + + HoleType::ResetHoleId(); + typename std::vector::iterator itH = vhi.begin(); + for( ; itH != vhi.end(); itH++) + { + holes.push_back(HoleType(*itH, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), this)); + + // reset flag and setting of + PosType curPos = itH->p; + do{ + curPos.f->ClearUserBit(borderFlag); + SetHoleBorderAttr(curPos.f); + curPos.NextB(); + assert(curPos.IsBorder()); + }while( curPos != itH->p ); + } + + FaceType::DeleteBitFlag(borderFlag); + }; + + /* Return border half-edge of the same face which is nearest to point(x, y) of glArea. + */ + static PosType getClosestPos(FaceType* face, int x, int y) + { + double mvmatrix[16], projmatrix[16]; + GLint viewport[4]; + double rx, ry, rz; + vcg::Point2d vertex[3]; + vcg::Point2d point((double)x, (double)y); + + glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix); + glGetDoublev (GL_PROJECTION_MATRIX, projmatrix); + glGetIntegerv(GL_VIEWPORT, viewport); + + for(int i=0; i<3; i++) + { + gluProject(face->V(i)->P()[0],face->V(i)->P()[1],face->V(i)->P()[2],mvmatrix,projmatrix,viewport,&rx,&ry,&rz); + vertex[i] = vcg::Point2d(rx,ry); + } + + double dist = DBL_MAX; + int nearest = 0; + for(int i=0; i<3; i++) + { + if(!vcg::face::IsBorder(*face, i)) + continue; + + vcg::Line2d el(vertex[i], vertex[(i+1)%3]-vertex[i]); + double tmp = vcg::Distance(el, point); + + if(dist > tmp) + { + dist = tmp; + nearest = i; + } + } + return PosType(face, nearest, face->V(nearest) ); + }; + + /* Remove all bridges updating holes vector and its selection + */ + void removeBridges() + { + assert( holes.size()>0 ); + // contains all half-edge located over non-bridge face and over edge shared with bridge face. + // these half-edges will become border edge when bridge faces are removed. + PosVector adjBorderPos; + + PosType pos; + BridgeIterator bit = bridges.begin(); + for( ; bit != bridges.end(); bit++ ) + { + adjBorderPos.push_back( (*bit)->GetAbutmentA() ); + adjBorderPos.push_back( (*bit)->GetAbutmentB() ); + } + + // remove holes adjacent to bridge + HoleIterator hit = holes.begin(); + while(hit != holes.end() ) + { + if( hit->IsBridged() ) + { + if( hit->IsSelected() ) + { + PosType curPos = hit->p; + do + { + curPos.f->SetS(); + curPos.NextB(); + }while( curPos != hit->p ); + } + hit = holes.erase(hit++); + } + else + hit++; + } + + for( bit = bridges.begin(); bit != bridges.end(); bit++ ) + { + (*bit)->DeleteFromMesh(); + delete *bit; + } + bridges.clear(); + + // update hole list inserting holes touched by bridge + // use adjBorderPos element as start pos to walk over the border, if walking doesn't + // visit some adjBorderPos element means this belongo to other hole. + PosType initPos, curPos; + typename PosVector::iterator it; + for( it=adjBorderPos.begin(); it!=adjBorderPos.end(); it++) + { + // bridge abutment can be placed over face of another bridge... + // this abutments must be ignored + if(it->f->IsD()) + continue; + + assert( it->IsBorder() ); + bool sel=it->f->IsS(); + it->f->ClearS(); + + if(it->f->IsV() || it->f->IsD()) + continue; + + curPos = initPos = *it; + do{ + curPos.f->SetV(); + sel = sel || curPos.f->IsS(); + curPos.f->ClearS(); + curPos.NextB(); + assert(curPos.IsBorder()); + }while(curPos != initPos); + + FgtHole newHole(initPos, QString("Hole_%1").arg(HoleType::GetHoleId(),3,10,QChar('0')), this); + newHole.SetSelect(sel); + holes.push_back( newHole ); + } + + // resetto flag visited sulle facce degli hole interessati + for(it=adjBorderPos.begin(); it!=adjBorderPos.end(); it++) + { + if(!it->f->IsV()) + continue; + curPos = initPos = *it; + do{ + curPos.f->ClearV(); + curPos.NextB(); + assert(curPos.IsBorder()); + }while(curPos != initPos); + } + }; + + // update statistical info + void countSelected() + { + nSelected = 0; + HoleIterator hit = holes.begin(); + for( ; hit!=holes.end(); hit++) + if(hit->IsSelected()) + nSelected++; + }; + + +public: + int nSelected; + int nAccepted; + MESH* mesh; + HoleVector holes; + BridgeVector bridges; + SimpleData* faceAttr; + + AutoBridgingCallback* autoBridgeCB; +}; + +#endif diff --git a/src/fgt/edit_quality/qualitymapperdialog.cpp b/src/fgt/edit_quality/qualitymapperdialog.cpp index ca77685a8..f85501af1 100644 --- a/src/fgt/edit_quality/qualitymapperdialog.cpp +++ b/src/fgt/edit_quality/qualitymapperdialog.cpp @@ -19,12 +19,6 @@ * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * -****************************************************************************/ -/**************************************************************************** -History -Revision 1.0 2008/02/20 Alessandro Maione, Federico Bellucci -FIRST RELEASE - ****************************************************************************/ #include "qualitymapperdialog.h" @@ -32,8 +26,6 @@ FIRST RELEASE #include #include -#include - using namespace vcg; //returns true if relative x of h1 is < then x of h2. diff --git a/src/fgt/edit_quality/qualitymapperdialog.h b/src/fgt/edit_quality/qualitymapperdialog.h index 33b3ec56f..aba252e0d 100644 --- a/src/fgt/edit_quality/qualitymapperdialog.h +++ b/src/fgt/edit_quality/qualitymapperdialog.h @@ -34,7 +34,7 @@ FIRST RELEASE #include #include #include -#include // for ComputePerVertexQualityMinMax +#include // for ComputePerVertexQualityMinMax #include #include "ui_qualitymapperdialog.h" #include "common/transferfunction.h" diff --git a/src/fgt/edit_texture/edittexture.cpp b/src/fgt/edit_texture/edittexture.cpp index 7abb7fbf6..637c6a8c5 100644 --- a/src/fgt/edit_texture/edittexture.cpp +++ b/src/fgt/edit_texture/edittexture.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include using namespace vcg; diff --git a/src/fgt/edit_texture/textureeditor.h b/src/fgt/edit_texture/textureeditor.h index 23dd0ed62..ce4594e0a 100644 --- a/src/fgt/edit_texture/textureeditor.h +++ b/src/fgt/edit_texture/textureeditor.h @@ -30,7 +30,7 @@ #include "ui_textureeditor.h" #include "renderarea.h" #include // da rimuovere una volta spostato smooth -#include +#include #define MARGIN 5 #define MAXW 1400 diff --git a/src/fgt/edit_topo/edit_topo.cpp b/src/fgt/edit_topo/edit_topo.cpp index 162acf1d8..2f0117cfc 100644 --- a/src/fgt/edit_topo/edit_topo.cpp +++ b/src/fgt/edit_topo/edit_topo.cpp @@ -1,1846 +1,1840 @@ -/**************************************************************************** - * MeshLab o o * - * A versatile mesh processing toolbox o o * - * _ O _ * - * Copyright(C) 2008 \/)\/ * - * 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. * - * * - ****************************************************************************/ -/**************************************************************************** - History -$Log: edit_topo.cpp,v $ -****************************************************************************/ -#include "edit_topo.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -using namespace vcg; -// -// --- "Edit plugin" specific methods --- -// - - - -// -// Edit plugin constructor -// -edit_topo::edit_topo() -{ - edit_topodialogobj=0; - reDraw = false; - click = false; - first_model_generated=false; - - nameVtxCount = 0; - stack.clear(); - Estack.clear(); - - drag_click=false; - drag_stack.clear(); - - lastPoint.V = Point3f(0,0,0); - lastPoint.vName = "--"; - - connectStart.V = Point3f(0,0,0); - connectStart.vName = "--"; - connectEnd.V = Point3f(0,0,0); - connectEnd.vName = "--"; -} - -// -// Edit plugin destructor -// -edit_topo::~edit_topo() -{ - stack.clear(); - Estack.clear(); - Fstack.clear(); - - - if (edit_topodialogobj != 0) - { - delete edit_topodialogobj; - edit_topodialogobj = 0; - } - -} - -const QString edit_topo::Info() -{ - return tr("Allow to re-top a model"); -} - -/************************************************************************************/ -// -// -- Edit topology Methods: -// Those methods are used by the plugin to edit -// the new topology defined by the user -// -// All of the methods here are directly used to build -// the base topology mesh as defined by the user -// - -// -// Adds a vertex to the new topo vertices list -// The new vertex will be selected from one of the existing mesh -// -void edit_topo::editAddVertex(MeshModel &m) -{ - CVertexO * temp_vert=0; - if (getVertexAtMouse(m, temp_vert)) - { - if(temp_vert->P() != lastPoint.V) - { - Vtx temp; - temp.V = temp_vert->P(); - temp.vName = QString("V%1").arg(nameVtxCount++); - - bool contained = false; - for(int i=0; iupdateVtxTable(stack); - } - else nameVtxCount--; - } - } -} - -// -// Adds a vertex to the new topo vertices list -// The new vertex is freely selected over the existing mesh -// -void edit_topo::editAddVertexFree() -{ - Point3f temp_vert; - if (Pick(mousePos.x(), mouseRealY, temp_vert)) - { - if(temp_vert != lastPoint.V) - { - Vtx temp; - temp.V = temp_vert; - temp.vName = QString("V%1").arg(nameVtxCount++); - - bool contained = false; - for(int i=0; iupdateVtxTable(stack); - } - else nameVtxCount--; - } - } -} - -// -// Removes a vertex from the new topo vertices list -// The operation will affect also Edges and Faces lists -// -void edit_topo::editDeleteVertex() -{ - Vtx vtx; - if(getVisibleVertexNearestToMouse(stack, vtx)) - { - // Remove vertex from Vert list - for(int i=0; iupdateVtxTable(stack); - } - - int EtoDel = 0; - int FtoDel = 0; - - // And delete all the edges and faces where this vertex is present - for(int e=0; eupdateEdgTable(Estack); - del = true; - }} - - for(int i=0; iupdateFceTable(Fstack); - del = true; - }} - if(stack.count()==0) - nameVtxCount = 0; - } -} - -// -// Connects two vertices and creates a new edge -// The operation will also create a new face in the faces list -// if the selected edge is connected to other two edges -// -void edit_topo::editConnectVertex() -{ - if(connectStart.V==Point3f(0,0,0)) - { - Vtx vtx; - // First click - if(getVisibleVertexNearestToMouse(stack, vtx)) - { - connectStart.V = vtx.V; - connectStart.vName = vtx.vName; - } - } - else - { - Vtx vtx; - // Second click (insert the edge in the Ed. list) - if(getVisibleVertexNearestToMouse(stack, vtx)) - if(vtx.V != connectStart.V) - { - connectEnd.V = vtx.V; - connectEnd.vName = vtx.vName; - Edg added; - added.v[0] = connectStart; - added.v[1] = connectEnd; - - if(!Estack.contains(added)) - { - Estack.push_back(added); - edit_topodialogobj->updateEdgTable(Estack); - - QList endStack; - QList staStack; - Edg _3rd; - - //--> Check if the "just now" selected edge is connected to others. Then, create a new face - for(int i=0; i vNames; - for(int n=0; n<3; n++) - for(int m=0; m<2; m++) - if(!vNames.contains(toAdd.e[n].v[m].vName)) - vNames.push_back(toAdd.e[n].v[m].vName); - edit_topodialogobj->updateFceTable(Fstack); - } - } - } - } - - connectStart.V = Point3f(0,0,0); - connectStart.vName = "00"; - } - connectEnd.V = Point3f(0,0,0); - connectEnd.vName = "00"; - } - } -} - - -// -// Selects or deselects the face selected by the user -// -void edit_topo::editSelectFace() -{ - Fce nearest; - bool got = false; - double tx,ty,tz; - int at = 0; - for(int f=0; f allv; - for(int e=0; e<3; e++) - for(int v=0; v<2; v++) - if(!allv.contains(fc.e[e].v[v])) - allv.push_back(fc.e[e].v[v]); - - gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p0 = QPointF(tx, ty); - gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p1 = QPointF(tx, ty); - gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p2 = QPointF(tx, ty); - - QPoint p = QPoint(mousePos.x(), mouseRealY); - - if(pointInTriangle(p, p0, p1, p2)) - { - nearest = fc; - got = true; - at = f; - } - } - if(got) - { - Fstack.removeAt(at); - nearest.selected=!nearest.selected; - Fstack.push_back(nearest); - } -} - -// -// Removes an edge from the edge's list -// The operation will also remove each face using that -// edge (if present), but will not remove any vertex -// -void edit_topo::editDeconnectEdge() -{ - Edg minE; - // Remove the edge from his stack, and also from the faces stack - if(getVisibleEdgeNearestToMouse(Estack, minE)) - { - for(int at=0; atupdateVtxTable(stack); - edit_topodialogobj->updateFceTable(Fstack); - edit_topodialogobj->updateEdgTable(Estack); - } -} - - -// -// Manage the drag&drop process used to move a vertex to a new -// position as selected with mouse -// The method will delete old vertex and insert a new vertex, -// and also adjourn each edge/face that is using it -// -void edit_topo::editDragAndDropVertex() -{ - drag_stack.clear(); - if(!drag_click) - { - // First click: select vertex - drag_click = true; - - Vtx vtx; - if(getVisibleVertexNearestToMouse(stack, vtx)) - { - drag_vtx = vtx; - - for(int f=0; fupdateVtxTable(stack); - edit_topodialogobj->updateFceTable(Fstack); - edit_topodialogobj->updateEdgTable(Estack); - - /* Uncomment this if you want the mesh to be auto-recreated - if(first_model_generated) - on_mesh_create();*/ - } - } -} - - -// -// Split an edge on its mid point -// The process will remove the original edge and add two new -// faces. This will also add a new vertex and create (eventually) -// two new faces. -// -void edit_topo::editEdgeSplit() -{ - Edg minE; - if(getVisibleEdgeNearestToMouse(Estack, minE)) - { - Vtx newVtx; - Point3f new3f; - - double tx,ty,tz; - gluProject(minE.v[0].V.X(),minE.v[0].V.Y(),minE.v[0].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p0 = QPointF(tx, ty); - gluProject(minE.v[1].V.X(),minE.v[1].V.Y(),minE.v[1].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p1 = QPointF(tx, ty); - - QPointF Qmid = (p1 + p0)/2; - - if(Pick(Qmid.x(), Qmid.y(), new3f)) - { - newVtx.V = new3f; - newVtx.vName = QString("V%1").arg(nameVtxCount++); - - int fCount = 0; - for(int f=0; f allv; - for(int e=0; e<3; e++) - for(int v=0; v<2; v++) - if(!allv.contains(fc.e[e].v[v])) - allv.push_back(fc.e[e].v[v]); - - Vtx oldVtx; - for(int i=0; i<3; i++) - if((allv.at(i)!=oldV1)&&(allv.at(i)!=oldV2)) - oldVtx=allv.at(i); - - newEdgMid.v[0]=oldVtx; - newEdgMid.v[1]=newVtx; - - Estack.push_back(newEdgMid); - Fstack.removeAt(f); - Fstack.push_back(newF1); - Fstack.push_back(newF2); - - found = true; - } - } - } - - Edg newEdg1 = minE; - Edg newEdg2 = minE; - - newEdg1.v[0] = newVtx; - newEdg2.v[1] = newVtx; - - for(int e=0; eupdateVtxTable(stack); - edit_topodialogobj->updateFceTable(Fstack); - edit_topodialogobj->updateEdgTable(Estack); - } - } -} - -// -// Collapse an edge over its mid point -// This will also remove faces using the old edge -// -void edit_topo::editEdgeCollapse() -{ - Edg toColl; - if(getVisibleEdgeNearestToMouse(Estack, toColl)) - { - Vtx oldVtx1 = toColl.v[0]; - Vtx oldVtx2 = toColl.v[1]; - - Vtx newVtx; - Point3f new3f; - - double tx,ty,tz; - gluProject(oldVtx1.V.X(),oldVtx1.V.Y(),oldVtx1.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p0 = QPointF(tx, ty); - gluProject(oldVtx2.V.X(),oldVtx2.V.Y(),oldVtx2.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p1 = QPointF(tx, ty); - - QPointF Qmid = (p1 + p0)/2; - - if(Pick(Qmid.x(), Qmid.y(), new3f)) - { - newVtx.V = new3f; - newVtx.vName = QString("V%1").arg(nameVtxCount++); - - // Remove faces containing the coll edge - int times = 0; - for(int f=0; fupdateVtxTable(stack); - edit_topodialogobj->updateFceTable(Fstack); - edit_topodialogobj->updateEdgTable(Estack); - } - } -} - - - - -/************************************************************************************/ -// -// -- Decoration Plugin methods -// Those methods are used by the plugin to draw decorations -// on each plugin's user states -// -// Each method declared here is used only in decorations functions, -// so, each method here will be called by the Decorate() func - - -// -// Standard decoration mode -// Draws points and edges as defined by the user. -// And, also, vertices labels -// -void edit_topo::editDecoStandard(MeshModel &m) -{ - if(stack.count()!=0) - drawPoint(m, 3.0f, Color4b::Red, stack); - - if(stack.count()!=0) - drawLabel(stack); - - if(Estack.count()!=0) - { - for(int i=0; i allv; - for(int e=0; e<3; e++) - for(int v=0; v<2; v++) - if(!allv.contains(fc.e[e].v[v])) - allv.push_back(fc.e[e].v[v]); - - QVector v = allv.toVector(); - - for(int i=0; i<3; i++) - if(v[i] == drag_vtx) - v[i].V = pmouse; - - drawLine(Color4b::Yellow, Color4b::Yellow, v[0].V, v[1].V); - drawLine(Color4b::Yellow, Color4b::Yellow, v[1].V, v[2].V); - drawLine(Color4b::Yellow, Color4b::Yellow, v[2].V, v[0].V); - } - } - } - else - { - Vtx vtx; - if(getVisibleVertexNearestToMouse(stack, vtx)) - drawPoint(m, 4.0f, Color4b::Yellow, vtx.V); - - } -} - -// -// Face selection decoration mode -// Draws each face (no vertices, no labels) in blue, -// and the face nearest to the mouse in yellow (and, so, -// face will be selectable) -// -// This method will also draw the "auto" elaborated vertices -// as defined by the edit topo algorithm -// -void edit_topo::editDecoFaceSelect(MeshModel &m) -{ - // Draw auto-generated new mesh vertices - if(out.count()!=0) - { - for(int i=0; i allv; - for(int e=0; e<3; e++) - for(int v=0; v<2; v++) - if(!allv.contains(f.e[e].v[v])) - allv.push_back(f.e[e].v[v]); - - if(f.selected) - { - drawLine(Color4b::Blue, Color4b::Black, allv.at(0).V, allv.at(1).V); - drawLine(Color4b::Blue, Color4b::Black, allv.at(1).V, allv.at(2).V); - drawLine(Color4b::Blue, Color4b::Black, allv.at(2).V, allv.at(0).V); - - Point3f mid = (allv.at(0).V + allv.at(1).V + allv.at(2).V) / 3; - if(isVertexVisible(allv.at(0).V)&&isVertexVisible(allv.at(1).V)&&isVertexVisible(allv.at(2).V)) - drawPoint(m, 5.0f, Color4b::Green, mid); - } - else - { - drawLine(Color4b::DarkRed, Color4b::Black, allv.at(0).V, allv.at(1).V); - drawLine(Color4b::DarkRed, Color4b::Black, allv.at(1).V, allv.at(2).V); - drawLine(Color4b::DarkRed, Color4b::Black, allv.at(2).V, allv.at(0).V); - } - } - - double tx,ty,tz; - for(int f=0; f allv; - for(int e=0; e<3; e++) - for(int v=0; v<2; v++) - if(!allv.contains(fc.e[e].v[v])) - allv.push_back(fc.e[e].v[v]); - - gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p0 = QPointF(tx, ty); - gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p1 = QPointF(tx, ty); - gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p2 = QPointF(tx, ty); - - QPoint p = QPoint(mousePos.x(), mouseRealY); - - if(pointInTriangle(p, p0, p1, p2)) - { - nearest = fc; - got = true; - } - } - if(got) - { - QList allv; - for(int e=0; e<3; e++) - for(int v=0; v<2; v++) - if(!allv.contains(nearest.e[e].v[v])) - allv.push_back(nearest.e[e].v[v]); - - drawLine(Color4b::Yellow, Color4b::Red, allv.at(0).V, allv.at(1).V); - drawLine(Color4b::Yellow, Color4b::Red, allv.at(1).V, allv.at(2).V); - drawLine(Color4b::Yellow, Color4b::Red, allv.at(2).V, allv.at(0).V); - } - } -} - -// -// Vertex selection decoration -// Draws in yellow the selectable vertex (the selectable vertex is the nearest to the mouse) -// -void edit_topo::editDecoVertexSelect(MeshModel &m) -{ - Point3f p = Point3f(0,0,0); - - glPushMatrix(); - glMultMatrix(m.cm.Tr); - - CVertexO * temp_vert=0; - if (getVertexAtMouse(m, temp_vert)) - { - cursorPoint = temp_vert->P(); - drawPoint(m, 4.0f, Color4b::Yellow, cursorPoint); - } -} - -// -// Vertex deletion decoration -// Draws in yellow the deletable vertex (the deletable vertex is the nearest to the mouse) -// -void edit_topo::editDecoDeleteVertexSelect(MeshModel &m) -{ - Vtx vtx; - if(getVisibleVertexNearestToMouse(stack, vtx)) - drawPoint(m, 4.0f, Color4b::Green, vtx.V); -} - -// -// Edge deletion decoration -// Draws in yellow the deletable edge -// -void edit_topo::editDecoDeleteVertexConnect(MeshModel &m) -{ - if(connectStart.V==Point3f(0,0,0) && connectEnd.V==Point3f(0,0,0)) - { - Vtx vtx; - if(getVisibleVertexNearestToMouse(stack, vtx)) - drawPoint(m, 4.0f, Color4b::Green, vtx.V); - } - - if(connectStart.V!=Point3f(0,0,0) && connectEnd.V==Point3f(0,0,0)) - { - drawPoint(m, 4.0f, Color4b::LightBlue, connectStart.V); - - Vtx vtx; - if(getVisibleVertexNearestToMouse(stack, vtx)) - { - drawPoint(m, 4.0f, Color4b::Green, vtx.V); - drawLine(Color4b::Blue, Color4b::Green, connectStart.V, vtx.V); - } - } -} - -// -// Edge deletion decoration -// -void edit_topo::editDecoDeleteVertexDeconnect(MeshModel &) -{ - Edg minE; - if(getVisibleEdgeNearestToMouse(Estack, minE)) - drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V); -} - -// -// Split selection decoration -// Draws in yellow the splittable edge -// -void edit_topo::editDecoSplit(MeshModel &) -{ - Edg minE; - if(getVisibleEdgeNearestToMouse(Estack, minE)) - drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V); -} - -// -// Collapse selection decoration -// Draws in yellow the collapse able edge -// -void edit_topo::editDecoCollapse(MeshModel &) -{ - Edg minE; - if(getVisibleEdgeNearestToMouse(Estack, minE)) - drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V); -} - -// -// Main decoration method -// -void edit_topo::Decorate(MeshModel &m, GLArea *) -{ - updateMatrixes(); - // onClick - if(click) - { - click=false; - - //--- - // Existing vertex selection mode (yellow pointer) - //--- - if(edit_topodialogobj->utensil==U_VTX_SEL) - editAddVertex(m); - - //--- - // Free vertex selection (no pointer) - //--- - if(edit_topodialogobj->utensil==U_VTX_SEL_FREE) - editAddVertexFree(); - - //--- - // Remove selected vertex mode (Yellow pointer) - //--- - if(edit_topodialogobj->utensil==U_VTX_DEL) - editDeleteVertex(); - - //--- - // Edge mode (vertex connection) - //--- - if(edit_topodialogobj->utensil==U_VTX_CONNECT) - editConnectVertex(); - - //--- - // Face Select/Deselect - //--- - if(edit_topodialogobj->utensil==U_FCE_SEL) - editSelectFace(); - - //--- - // edge deselection mode - //--- - if(edit_topodialogobj->utensil==U_VTX_DE_CONNECT) - editDeconnectEdge(); - - //--- - // Vertex moove mode - //--- - if(edit_topodialogobj->utensil==U_DND) - editDragAndDropVertex(); - - //--- - // edge split mode - //--- - if(edit_topodialogobj->utensil==U_EDG_SPLIT) - editEdgeSplit(); - - //--- - // edge collapse mode - //--- - if(edit_topodialogobj->utensil==U_EDG_COLLAPSE) - editEdgeCollapse(); - }// end if click - - - /*** Decorations ***/ - - - //--- - // Even if there's something selected: show edges - //--- - if((edit_topodialogobj->utensil==U_VTX_CONNECT)||(edit_topodialogobj->utensil==U_VTX_DE_CONNECT) - ||(edit_topodialogobj->utensil==U_DND)||(edit_topodialogobj->utensil==U_EDG_SPLIT) - ||(edit_topodialogobj->utensil==U_EDG_COLLAPSE)) - editDecoStandard(m); - - //--- - // First step: show only vertices - //--- - if((edit_topodialogobj->utensil==U_VTX_SEL_FREE)||(edit_topodialogobj->utensil==U_VTX_DEL) - ||(edit_topodialogobj->utensil==U_VTX_SEL)) - editDecoOnlyVertex(m); - - //--- - // Drag and drop vertices mode - //--- - if(edit_topodialogobj->utensil==U_DND) - editDecoDragAndDropVertex(m); - - //--- - // Face selection mode - //--- - if(edit_topodialogobj->utensil==U_FCE_SEL) - editDecoFaceSelect(m); - - //--- - // Yellow pointer (vertex selection) - //--- - if(edit_topodialogobj->utensil==U_VTX_SEL) - editDecoVertexSelect(m); - - //--- - // Vertex de-selection (Yellow pointeR) - //--- - if((edit_topodialogobj->utensil==U_VTX_DEL)&&(stack.count()!=0)) - editDecoDeleteVertexSelect(m); - - //--- - // edge mode (vtx connection) - //--- - if(edit_topodialogobj->utensil==U_VTX_CONNECT) - editDecoDeleteVertexConnect(m); - - //--- - // edge deselection mode - //--- - if(edit_topodialogobj->utensil==U_VTX_DE_CONNECT) - editDecoDeleteVertexDeconnect(m); - - //--- - // edge split mode - //--- - if(edit_topodialogobj->utensil==U_EDG_SPLIT) - editDecoSplit(m); - - //--- - // edge collapse mode - //--- - if(edit_topodialogobj->utensil==U_EDG_COLLAPSE) - editDecoCollapse(m); -} - -// -// Plugin init -// -bool edit_topo::StartEdit(MeshModel &m, GLArea *gla) -{ - parentGla = gla; - gla->setCursor(QCursor(QPixmap(":/images/cursor_paint.png"),1,1)); - - // Init uniform grid - float dist = m.cm.bbox.Diag(); - - // Init data masks - m.updateDataMask(MeshModel::MM_FACEMARK); - tri::UpdateNormals::PerFaceNormalized(m.cm); - tri::UpdateFlags::FaceProjection(m.cm); - - // Init retopology model builder object - rm.init(&m, dist); - - // Init miminum visible distance param (used only for labels rendering) - _md = 0.03; - - // Init ui - if (edit_topodialogobj == 0) - { - edit_topodialogobj = new edit_topodialog(gla->window()); - dock = new QDockWidget(gla->window()); - dock->setAllowedAreas(Qt::NoDockWidgetArea); - dock->setWidget(edit_topodialogobj); - QPoint p = gla->window()->mapToGlobal(QPoint(0,0)); - dock->setGeometry(-5+p.x()+gla->window()->width()-edit_topodialogobj->width(),p.y(),edit_topodialogobj->width(),edit_topodialogobj->height()); - dock->setFloating(true); - } - dock->setVisible(true); - dock->layout()->update(); - - gla->update(); - gla->setMouseTracking(true); - - // Connect slots - connect(edit_topodialogobj, SIGNAL( mesh_create() ), - this, SLOT( on_mesh_create() ) ); - - connect(edit_topodialogobj, SIGNAL( update_request() ), - this, SLOT( on_update_request() ) ); - return true; -} - -// -// End edit -// -void edit_topo::EndEdit(MeshModel &, GLArea *) -{ - stack.clear(); - Estack.clear(); - Fstack.clear(); - - reDraw = false; - click = false; - first_model_generated=false; - - nameVtxCount = 0; - - drag_click=false; - drag_stack.clear(); - - lastPoint.V = Point3f(0,0,0); - lastPoint.vName = "--"; - - connectStart.V = Point3f(0,0,0); - connectStart.vName = "--"; - connectEnd.V = Point3f(0,0,0); - connectEnd.vName = "--"; - - if (edit_topodialogobj != 0) - { - delete edit_topodialogobj; - delete dock; - edit_topodialogobj = 0; - dock = 0; - } -} - - -/************************************************************************************/ -// -// --- Slot implementation methods --- -// Those two methods are invoked by the gui -// - -// -// "Create new mesh" click -// This method calls the retopology algoritm, and creates -// the new mesh using the user defined new topology -// -void edit_topo::on_mesh_create() -{ - out.clear(); - - if(first_model_generated) - parentGla->meshDoc->meshList.pop_back(); - - - MeshModel *mm= parentGla->meshDoc->addNewMesh(""); - //parentGla->meshDoc->meshList.push_back(mm); - first_model_generated = true; - - - MeshModel *m = parentGla->meshDoc->meshList.back(); // destination = new mesh - MeshModel *currentMesh = parentGla->meshDoc->mm(); // source = current mesh - - // if debug value is true, the algorithm will respond with all the - // auto generated vertices. - // The isDEBUG value is forced by the "Draw auto-filled vertices" gui checkbox - if(edit_topodialogobj->isDEBUG()) - { - rm.Lout.clear(); - int iter = edit_topodialogobj->getIterations(); - float dist = edit_topodialogobj->dist()/100; - - // Retopology algorithm call - rm.createRefinedMesh(*m, /* *currentMesh,*/ dist, iter, Fstack, stack, edit_topodialogobj, true); - out = rm.Lout; - } - else - { - int iter = edit_topodialogobj->getIterations(); - float dist = edit_topodialogobj->dist()/100; - - // Retopology algorithm call - rm.createRefinedMesh(*m, /* *currentMesh, */ dist, iter, Fstack, stack, edit_topodialogobj, false); - } - - m->cm.Tr = currentMesh->cm.Tr; - parentGla->update(); -} - - -// -// General update requested by some gui functions -// -void edit_topo::on_update_request() -{ - parentGla->update(); -} - - - - - -/************************************************************************************/ -// -// --- Plugin events methods --- -// -void edit_topo::mousePressEvent(QMouseEvent * event, MeshModel &m, GLArea * gla) -{ - mousePos=event->pos(); - click=false; - gla->update(); -} - -void edit_topo::mouseMoveEvent(QMouseEvent * event, MeshModel &m, GLArea * gla) -{ - mousePos=event->pos(); - mouseRealY = gla->curSiz.height() - mousePos.y(); - reDraw=true; - gla->update(); -} - -void edit_topo::mouseReleaseEvent(QMouseEvent * event, MeshModel &, GLArea * gla) -{ - if(event->button() == Qt::LeftButton) - { - click=true; - reDraw=true; - } - else if(event->button() == Qt::RightButton) - { - connectStart.V=Point3f(0,0,0); - - drag_stack.clear(); - drag_click = false; - } - gla->update(); - mousePos=event->pos(); -} - - -/************************************************************************************/ -// -// --- New topology mesh methods --- -// Those methods are used by the edit plugin -// to elaborate topology related operations -// - - -// -// Get nearest 2d point of the given array -// Returns: array index -int edit_topo::getNearest(QPointF center, QPointF *points,int num) { - int nearestInd=0; - float dist=fabsf(center.x()-points[0].x())*fabsf(center.x()-points[0].x())+fabsf(center.y()-points[0].y())*fabsf(center.y()-points[0].y()); - for (int lauf=1; lauf::PickNearestFace(mid.x(), mid.y(), m.cm, val,2,2)); -} - -// -// Get existing nearest 3d vertex on the given mesh model -// Returns: true if found, and vertexpointer value -bool edit_topo::getVertexAtMouse(MeshModel &m,CMeshO::VertexPointer& value) -{ - CFaceO * temp=0; - - QPoint mid=QPoint(mousePos.x(), mouseRealY); - double tx,ty,tz; - if (getFaceAtMouse(m,temp)) - { - QPointF point[3]; - for (int lauf=0; lauf<3; lauf++) - { - gluProject(temp->V(lauf)->P()[0],temp->V(lauf)->P()[1],temp->V(lauf)->P()[2],mvmatrix,projmatrix,viewport,&tx,&ty,&tz); - point[lauf]=QPointF(tx,ty); - } - value=temp->V(getNearest(mid,point,3)); - return true; - } - return false; -} - - -// -// Check if the given vertex is visible on the current user view -// This method is used for rendering vertices labels, and -// rendering edges/faces -// Returns: true if visible -bool edit_topo::isVertexVisible(Point3f v) -{ - float pix; - double tx,ty,tz; - - gluProject(v.X(),v.Y(),v.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - glReadPixels(tx,ty,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&pix); - - float ff = fabs(tz - pix); - - return ((ff < 0.003)); -} - -// -// Get visible vertex nearest to mouse position (from a given vertices list) -// Returns: true if visible -bool edit_topo::getVisibleVertexNearestToMouse(QList list, Vtx &out) -{ - bool found = false; - double minDist = 100000; - int minIdx = -1; - Point3f t; - - QList visib; - - for(int i=0; i dx) ? 0.41*dx+0.941246*dy : 0.41*dy+0.941246*dx; - - double dist = sqrt((double)(math::Sqr(qp.x() - mPos.x()) + math::Sqr(qp.y() - mPos.y()))); - - if(dist listE, Edg &ret) -{ - Fce nearest; - bool got = false; - double tx,ty,tz; - int at = 0; - for(int f=0; f allv; - for(int e=0; e<3; e++) - for(int v=0; v<2; v++) - if(!allv.contains(fc.e[e].v[v])) - allv.push_back(fc.e[e].v[v]); - - gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p0 = QPointF(tx, ty); - gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p1 = QPointF(tx, ty); - gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p2 = QPointF(tx, ty); - - QPoint p = QPoint(mousePos.x(), mouseRealY); - - if(pointInTriangle(p, p0, p1, p2)) - { - nearest = fc; - got = true; - at = f; - } - } - - if(got) - { - Edg minE; - float bestD = -1; - bool found = false; - double tx,ty,tz; - - for(int i=0; i<3; i++) - { - Edg e = nearest.e[i]; - gluProject(e.v[0].V.X(),e.v[0].V.Y(),e.v[0].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p0 = QPointF(tx, ty); - gluProject(e.v[1].V.X(),e.v[1].V.Y(),e.v[1].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - QPointF p1 = QPointF(tx, ty); - - float dist = distancePointSegment(QPointF(mousePos.x(),mouseRealY), p1, p0); - if((dist < bestD)||(bestD==-1)) - { - bestD = dist; - minE = e; - found = true; - } - } - - ret = minE; - return found; - } - return false; -} - -// -// Checks if the given point is in the given triangle -// -bool edit_topo::pointInTriangle(const QPointF &p, const QPointF &a, const QPointF &b, const QPointF &c) -{ - float fab=(p.y()-a.y())*(b.x()-a.x()) - (p.x()-a.x())*(b.y()-a.y()); - float fbc=(p.y()-c.y())*(a.x()-c.x()) - (p.x()-c.x())*(a.y()-c.y()); - float fca=(p.y()-b.y())*(c.x()-b.x()) - (p.x()-b.x())*(c.y()-b.y()); - - return (fab*fbc>0 && fbc*fca>0); -} - -// -// 2d distance p-seg -// -float edit_topo::distancePointSegment(QPointF p, QPointF segmentP1,QPointF segmentP2) -{ - float x0, y0, x1, x2, y1, y2, m, q; - - x1 = segmentP1.x(); - y1 = segmentP1.y(); - - x2 = segmentP2.x(); - y2 = segmentP2.y(); - - m = (y2-y1)/(x2-x1); - q = y1 - m*x1; - - x0 = p.x(); - y0 = p.y(); - - return fabs((y0 - m*x0 -q) / (sqrt(1 + m*m))); -} - -// -// 2d distance p-p -// -float edit_topo::distancePointPoint(QPointF P1, QPointF P2) -{ - return sqrt(pow((P1.x()-P2.x()),2)+pow((P1.y()-P2.y()),2)); -} - -/************************************************************************************/ -// -// --- Plugin rendering methods --- -// Those methods are used by the plugin to draw labels -// vertices, edges, faces, ... in opengl - -// -// Draws user selected vertices labels -// -void edit_topo::drawLabel(QList list) -{ - - QVector v = list.toVector(); - int pCount = list.count(); - - for(int i=0; idrawLabels())) - { - double tx,ty,tz; - gluProject(v.V.X(),v.V.Y(),v.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); - int x,y; - x = tx+5; - y=(parentGla->curSiz.height() - 5 - ty); - - // new style - QString text = v.vName; - QFont font; - font.setFamily("Helvetica"); - font.setPixelSize(10); - QFontMetrics fm(font); - QRect brec=fm.boundingRect(text); - glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT ); - glDisable(GL_LIGHTING); - glDisable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - gluOrtho2D(0,parentGla->width(),parentGla->height(),0); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glColor4f(0,0,0,0.6f); - glBegin(GL_QUADS); - glVertex2f(x+brec.left(),y+brec.bottom()); - glVertex2f(x+brec.right(),y+brec.bottom()); - glVertex2f(x+brec.right(),y+brec.top()); - glVertex2f(x+brec.left(),y+brec.top()); - glEnd(); - int offset=2; - glColor4f(0,0,0,0.3f); - glBegin(GL_QUADS); - glVertex2f(x+brec.left()-offset,y+brec.bottom()+offset); - glVertex2f(x+brec.right()+offset,y+brec.bottom()+offset); - glVertex2f(x+brec.right()+offset,y+brec.top()-offset); - glVertex2f(x+brec.left()-offset,y+brec.top()-offset); - glEnd(); - glColor3f(1,1,1); - parentGla->renderText(x,y, text,QFont()); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glPopAttrib(); - } -} - -// -// Draws a point -// -void edit_topo::drawPoint(MeshModel &m, float pSize, Color4b colorFront, Point3f p) -{ - glPushMatrix(); - glMultMatrix(m.cm.Tr); - glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LINE_BIT | GL_DEPTH_BUFFER_BIT); - glDepthFunc(GL_ALWAYS); - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - glDisable(GL_LIGHTING); - - glColor(colorFront); - - glPointSize(pSize); - - glBegin(GL_POINTS); - glVertex(p); - glVertex(p); - glEnd(); -/* - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glColor(colorBack); - - glPointSize(0.3); - - glBegin(GL_POINT); - glVertex(cursorPoint); - glVertex(cursorPoint); - glEnd(); -*/ - glPopAttrib(); - glPopMatrix(); -} - -// -// Draws all vertices -// -void edit_topo::drawPoint(MeshModel &m, float pSize, Color4b colorFront, QList list) -{ - glPushMatrix(); - glMultMatrix(m.cm.Tr); - glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LINE_BIT | GL_DEPTH_BUFFER_BIT); - glLineWidth(2.0f); - glDepthFunc(GL_ALWAYS); - glDisable(GL_DEPTH_TEST); - glDepthMask(GL_FALSE); - - glDisable(GL_LIGHTING); - glColor(colorFront); - - glPointSize(pSize); - - QVector v = list.toVector(); - int pCount = list.count(); - - glBegin(GL_POINTS); - for(int i=0; i vectSub(int part, Point3f p1, Point3f p2) -{ - if(part==2) - { - QVector toRet(3); - toRet[0]=p1; - toRet[1]=(p1+p2)/2; - toRet[2]=p2; - return toRet; - } - else - { - QVector L; - QVector R; - - int np=(int)(part/2); - - L = vectSub(np, p1, (p1+p2)/2); - R = vectSub(np, (p1+p2)/2, p2); - - QVector toRet; - for(int i=0; i trattP; - int part = 32; - float dist = (p1-p2).Norm(); - if(dist>10) part*=2; - if(dist>50) part*=2; - if(dist>100) part*=2; - if(dist>400) part*=2; - - Point3f pp1, pp2; - trattP = vectSub(part, p1, p2); - - for(int i=0; i<(trattP.size()-1); i+=2) - { - pp1 = trattP[i]; - pp2 = trattP[i+1]; - - glDisable(GL_DEPTH_TEST); - - glLineWidth(0.5f); - glPointSize(0.3f); - glBegin(GL_LINES); - glVertex(pp1); - glVertex(pp2); - glEnd(); - glBegin(GL_POINTS); - glVertex(pp1); - glVertex(pp2); - glEnd(); - } - glPopAttrib(); - } - else if(edit_topodialogobj->drawEdges()) - { - glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT); - glDisable(GL_LIGHTING); - glDisable(GL_TEXTURE_2D); - glDepthMask(false); - glLineWidth(1.5f); - glPointSize(0.4f); - - // Fill the intermed. points to draw a dotted line - QVector trattP; - int part = 8; - float dist = (p1-p2).Norm(); - if(dist>10) part*=2; - if(dist>50) part*=2; - if(dist>100) part*=2; - if(dist>400) part*=2; - - Point3f pp1, pp2; - trattP = vectSub(part, p1, p2); - - glColor(colorBack); - glDisable(GL_DEPTH_TEST); - - for(int i=0; i<(trattP.size()-1); i+=2) - { - pp1 = trattP[i]; - pp2 = trattP[i+1]; - - glBegin(GL_LINES); - glVertex(pp1); - glVertex(pp2); - glEnd(); - glBegin(GL_POINTS); - glVertex(pp1); - glVertex(pp2); - glEnd(); - } - glPopAttrib(); - } -} - -// -// Draws a triangle -// -void edit_topo::drawFace(CMeshO::FacePointer fp) -{ - glPointSize(3.0f); - - glBegin(GL_POINTS); //GL_LINE_LOOP); - glVertex(fp->P(0)); - glVertex(fp->P(1)); - glVertex(fp->P(2)); - glEnd(); -} +/**************************************************************************** + * MeshLab o o * + * A versatile mesh processing toolbox o o * + * _ O _ * + * Copyright(C) 2008 \/)\/ * + * 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. * + * * + ****************************************************************************/ +/**************************************************************************** + History +$Log: edit_topo.cpp,v $ +****************************************************************************/ +#include "edit_topo.h" + +#include +#include +#include + +using namespace std; +using namespace vcg; +// +// --- "Edit plugin" specific methods --- +// + + + +// +// Edit plugin constructor +// +edit_topo::edit_topo() +{ + edit_topodialogobj=0; + reDraw = false; + click = false; + first_model_generated=false; + + nameVtxCount = 0; + stack.clear(); + Estack.clear(); + + drag_click=false; + drag_stack.clear(); + + lastPoint.V = Point3f(0,0,0); + lastPoint.vName = "--"; + + connectStart.V = Point3f(0,0,0); + connectStart.vName = "--"; + connectEnd.V = Point3f(0,0,0); + connectEnd.vName = "--"; +} + +// +// Edit plugin destructor +// +edit_topo::~edit_topo() +{ + stack.clear(); + Estack.clear(); + Fstack.clear(); + + + if (edit_topodialogobj != 0) + { + delete edit_topodialogobj; + edit_topodialogobj = 0; + } + +} + +const QString edit_topo::Info() +{ + return tr("Allow to re-top a model"); +} + +/************************************************************************************/ +// +// -- Edit topology Methods: +// Those methods are used by the plugin to edit +// the new topology defined by the user +// +// All of the methods here are directly used to build +// the base topology mesh as defined by the user +// + +// +// Adds a vertex to the new topo vertices list +// The new vertex will be selected from one of the existing mesh +// +void edit_topo::editAddVertex(MeshModel &m) +{ + CVertexO * temp_vert=0; + if (getVertexAtMouse(m, temp_vert)) + { + if(temp_vert->P() != lastPoint.V) + { + Vtx temp; + temp.V = temp_vert->P(); + temp.vName = QString("V%1").arg(nameVtxCount++); + + bool contained = false; + for(int i=0; iupdateVtxTable(stack); + } + else nameVtxCount--; + } + } +} + +// +// Adds a vertex to the new topo vertices list +// The new vertex is freely selected over the existing mesh +// +void edit_topo::editAddVertexFree() +{ + Point3f temp_vert; + if (Pick(mousePos.x(), mouseRealY, temp_vert)) + { + if(temp_vert != lastPoint.V) + { + Vtx temp; + temp.V = temp_vert; + temp.vName = QString("V%1").arg(nameVtxCount++); + + bool contained = false; + for(int i=0; iupdateVtxTable(stack); + } + else nameVtxCount--; + } + } +} + +// +// Removes a vertex from the new topo vertices list +// The operation will affect also Edges and Faces lists +// +void edit_topo::editDeleteVertex() +{ + Vtx vtx; + if(getVisibleVertexNearestToMouse(stack, vtx)) + { + // Remove vertex from Vert list + for(int i=0; iupdateVtxTable(stack); + } + + int EtoDel = 0; + int FtoDel = 0; + + // And delete all the edges and faces where this vertex is present + for(int e=0; eupdateEdgTable(Estack); + del = true; + }} + + for(int i=0; iupdateFceTable(Fstack); + del = true; + }} + if(stack.count()==0) + nameVtxCount = 0; + } +} + +// +// Connects two vertices and creates a new edge +// The operation will also create a new face in the faces list +// if the selected edge is connected to other two edges +// +void edit_topo::editConnectVertex() +{ + if(connectStart.V==Point3f(0,0,0)) + { + Vtx vtx; + // First click + if(getVisibleVertexNearestToMouse(stack, vtx)) + { + connectStart.V = vtx.V; + connectStart.vName = vtx.vName; + } + } + else + { + Vtx vtx; + // Second click (insert the edge in the Ed. list) + if(getVisibleVertexNearestToMouse(stack, vtx)) + if(vtx.V != connectStart.V) + { + connectEnd.V = vtx.V; + connectEnd.vName = vtx.vName; + Edg added; + added.v[0] = connectStart; + added.v[1] = connectEnd; + + if(!Estack.contains(added)) + { + Estack.push_back(added); + edit_topodialogobj->updateEdgTable(Estack); + + QList endStack; + QList staStack; + Edg _3rd; + + //--> Check if the "just now" selected edge is connected to others. Then, create a new face + for(int i=0; i vNames; + for(int n=0; n<3; n++) + for(int m=0; m<2; m++) + if(!vNames.contains(toAdd.e[n].v[m].vName)) + vNames.push_back(toAdd.e[n].v[m].vName); + edit_topodialogobj->updateFceTable(Fstack); + } + } + } + } + + connectStart.V = Point3f(0,0,0); + connectStart.vName = "00"; + } + connectEnd.V = Point3f(0,0,0); + connectEnd.vName = "00"; + } + } +} + + +// +// Selects or deselects the face selected by the user +// +void edit_topo::editSelectFace() +{ + Fce nearest; + bool got = false; + double tx,ty,tz; + int at = 0; + for(int f=0; f allv; + for(int e=0; e<3; e++) + for(int v=0; v<2; v++) + if(!allv.contains(fc.e[e].v[v])) + allv.push_back(fc.e[e].v[v]); + + gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p0 = QPointF(tx, ty); + gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p1 = QPointF(tx, ty); + gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p2 = QPointF(tx, ty); + + QPoint p = QPoint(mousePos.x(), mouseRealY); + + if(pointInTriangle(p, p0, p1, p2)) + { + nearest = fc; + got = true; + at = f; + } + } + if(got) + { + Fstack.removeAt(at); + nearest.selected=!nearest.selected; + Fstack.push_back(nearest); + } +} + +// +// Removes an edge from the edge's list +// The operation will also remove each face using that +// edge (if present), but will not remove any vertex +// +void edit_topo::editDeconnectEdge() +{ + Edg minE; + // Remove the edge from his stack, and also from the faces stack + if(getVisibleEdgeNearestToMouse(Estack, minE)) + { + for(int at=0; atupdateVtxTable(stack); + edit_topodialogobj->updateFceTable(Fstack); + edit_topodialogobj->updateEdgTable(Estack); + } +} + + +// +// Manage the drag&drop process used to move a vertex to a new +// position as selected with mouse +// The method will delete old vertex and insert a new vertex, +// and also adjourn each edge/face that is using it +// +void edit_topo::editDragAndDropVertex() +{ + drag_stack.clear(); + if(!drag_click) + { + // First click: select vertex + drag_click = true; + + Vtx vtx; + if(getVisibleVertexNearestToMouse(stack, vtx)) + { + drag_vtx = vtx; + + for(int f=0; fupdateVtxTable(stack); + edit_topodialogobj->updateFceTable(Fstack); + edit_topodialogobj->updateEdgTable(Estack); + + /* Uncomment this if you want the mesh to be auto-recreated + if(first_model_generated) + on_mesh_create();*/ + } + } +} + + +// +// Split an edge on its mid point +// The process will remove the original edge and add two new +// faces. This will also add a new vertex and create (eventually) +// two new faces. +// +void edit_topo::editEdgeSplit() +{ + Edg minE; + if(getVisibleEdgeNearestToMouse(Estack, minE)) + { + Vtx newVtx; + Point3f new3f; + + double tx,ty,tz; + gluProject(minE.v[0].V.X(),minE.v[0].V.Y(),minE.v[0].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p0 = QPointF(tx, ty); + gluProject(minE.v[1].V.X(),minE.v[1].V.Y(),minE.v[1].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p1 = QPointF(tx, ty); + + QPointF Qmid = (p1 + p0)/2; + + if(Pick(Qmid.x(), Qmid.y(), new3f)) + { + newVtx.V = new3f; + newVtx.vName = QString("V%1").arg(nameVtxCount++); + + int fCount = 0; + for(int f=0; f allv; + for(int e=0; e<3; e++) + for(int v=0; v<2; v++) + if(!allv.contains(fc.e[e].v[v])) + allv.push_back(fc.e[e].v[v]); + + Vtx oldVtx; + for(int i=0; i<3; i++) + if((allv.at(i)!=oldV1)&&(allv.at(i)!=oldV2)) + oldVtx=allv.at(i); + + newEdgMid.v[0]=oldVtx; + newEdgMid.v[1]=newVtx; + + Estack.push_back(newEdgMid); + Fstack.removeAt(f); + Fstack.push_back(newF1); + Fstack.push_back(newF2); + + found = true; + } + } + } + + Edg newEdg1 = minE; + Edg newEdg2 = minE; + + newEdg1.v[0] = newVtx; + newEdg2.v[1] = newVtx; + + for(int e=0; eupdateVtxTable(stack); + edit_topodialogobj->updateFceTable(Fstack); + edit_topodialogobj->updateEdgTable(Estack); + } + } +} + +// +// Collapse an edge over its mid point +// This will also remove faces using the old edge +// +void edit_topo::editEdgeCollapse() +{ + Edg toColl; + if(getVisibleEdgeNearestToMouse(Estack, toColl)) + { + Vtx oldVtx1 = toColl.v[0]; + Vtx oldVtx2 = toColl.v[1]; + + Vtx newVtx; + Point3f new3f; + + double tx,ty,tz; + gluProject(oldVtx1.V.X(),oldVtx1.V.Y(),oldVtx1.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p0 = QPointF(tx, ty); + gluProject(oldVtx2.V.X(),oldVtx2.V.Y(),oldVtx2.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p1 = QPointF(tx, ty); + + QPointF Qmid = (p1 + p0)/2; + + if(Pick(Qmid.x(), Qmid.y(), new3f)) + { + newVtx.V = new3f; + newVtx.vName = QString("V%1").arg(nameVtxCount++); + + // Remove faces containing the coll edge + int times = 0; + for(int f=0; fupdateVtxTable(stack); + edit_topodialogobj->updateFceTable(Fstack); + edit_topodialogobj->updateEdgTable(Estack); + } + } +} + + + + +/************************************************************************************/ +// +// -- Decoration Plugin methods +// Those methods are used by the plugin to draw decorations +// on each plugin's user states +// +// Each method declared here is used only in decorations functions, +// so, each method here will be called by the Decorate() func + + +// +// Standard decoration mode +// Draws points and edges as defined by the user. +// And, also, vertices labels +// +void edit_topo::editDecoStandard(MeshModel &m) +{ + if(stack.count()!=0) + drawPoint(m, 3.0f, Color4b::Red, stack); + + if(stack.count()!=0) + drawLabel(stack); + + if(Estack.count()!=0) + { + for(int i=0; i allv; + for(int e=0; e<3; e++) + for(int v=0; v<2; v++) + if(!allv.contains(fc.e[e].v[v])) + allv.push_back(fc.e[e].v[v]); + + QVector v = allv.toVector(); + + for(int i=0; i<3; i++) + if(v[i] == drag_vtx) + v[i].V = pmouse; + + drawLine(Color4b::Yellow, Color4b::Yellow, v[0].V, v[1].V); + drawLine(Color4b::Yellow, Color4b::Yellow, v[1].V, v[2].V); + drawLine(Color4b::Yellow, Color4b::Yellow, v[2].V, v[0].V); + } + } + } + else + { + Vtx vtx; + if(getVisibleVertexNearestToMouse(stack, vtx)) + drawPoint(m, 4.0f, Color4b::Yellow, vtx.V); + + } +} + +// +// Face selection decoration mode +// Draws each face (no vertices, no labels) in blue, +// and the face nearest to the mouse in yellow (and, so, +// face will be selectable) +// +// This method will also draw the "auto" elaborated vertices +// as defined by the edit topo algorithm +// +void edit_topo::editDecoFaceSelect(MeshModel &m) +{ + // Draw auto-generated new mesh vertices + if(out.count()!=0) + { + for(int i=0; i allv; + for(int e=0; e<3; e++) + for(int v=0; v<2; v++) + if(!allv.contains(f.e[e].v[v])) + allv.push_back(f.e[e].v[v]); + + if(f.selected) + { + drawLine(Color4b::Blue, Color4b::Black, allv.at(0).V, allv.at(1).V); + drawLine(Color4b::Blue, Color4b::Black, allv.at(1).V, allv.at(2).V); + drawLine(Color4b::Blue, Color4b::Black, allv.at(2).V, allv.at(0).V); + + Point3f mid = (allv.at(0).V + allv.at(1).V + allv.at(2).V) / 3; + if(isVertexVisible(allv.at(0).V)&&isVertexVisible(allv.at(1).V)&&isVertexVisible(allv.at(2).V)) + drawPoint(m, 5.0f, Color4b::Green, mid); + } + else + { + drawLine(Color4b::DarkRed, Color4b::Black, allv.at(0).V, allv.at(1).V); + drawLine(Color4b::DarkRed, Color4b::Black, allv.at(1).V, allv.at(2).V); + drawLine(Color4b::DarkRed, Color4b::Black, allv.at(2).V, allv.at(0).V); + } + } + + double tx,ty,tz; + for(int f=0; f allv; + for(int e=0; e<3; e++) + for(int v=0; v<2; v++) + if(!allv.contains(fc.e[e].v[v])) + allv.push_back(fc.e[e].v[v]); + + gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p0 = QPointF(tx, ty); + gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p1 = QPointF(tx, ty); + gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p2 = QPointF(tx, ty); + + QPoint p = QPoint(mousePos.x(), mouseRealY); + + if(pointInTriangle(p, p0, p1, p2)) + { + nearest = fc; + got = true; + } + } + if(got) + { + QList allv; + for(int e=0; e<3; e++) + for(int v=0; v<2; v++) + if(!allv.contains(nearest.e[e].v[v])) + allv.push_back(nearest.e[e].v[v]); + + drawLine(Color4b::Yellow, Color4b::Red, allv.at(0).V, allv.at(1).V); + drawLine(Color4b::Yellow, Color4b::Red, allv.at(1).V, allv.at(2).V); + drawLine(Color4b::Yellow, Color4b::Red, allv.at(2).V, allv.at(0).V); + } + } +} + +// +// Vertex selection decoration +// Draws in yellow the selectable vertex (the selectable vertex is the nearest to the mouse) +// +void edit_topo::editDecoVertexSelect(MeshModel &m) +{ + Point3f p = Point3f(0,0,0); + + glPushMatrix(); + glMultMatrix(m.cm.Tr); + + CVertexO * temp_vert=0; + if (getVertexAtMouse(m, temp_vert)) + { + cursorPoint = temp_vert->P(); + drawPoint(m, 4.0f, Color4b::Yellow, cursorPoint); + } +} + +// +// Vertex deletion decoration +// Draws in yellow the deletable vertex (the deletable vertex is the nearest to the mouse) +// +void edit_topo::editDecoDeleteVertexSelect(MeshModel &m) +{ + Vtx vtx; + if(getVisibleVertexNearestToMouse(stack, vtx)) + drawPoint(m, 4.0f, Color4b::Green, vtx.V); +} + +// +// Edge deletion decoration +// Draws in yellow the deletable edge +// +void edit_topo::editDecoDeleteVertexConnect(MeshModel &m) +{ + if(connectStart.V==Point3f(0,0,0) && connectEnd.V==Point3f(0,0,0)) + { + Vtx vtx; + if(getVisibleVertexNearestToMouse(stack, vtx)) + drawPoint(m, 4.0f, Color4b::Green, vtx.V); + } + + if(connectStart.V!=Point3f(0,0,0) && connectEnd.V==Point3f(0,0,0)) + { + drawPoint(m, 4.0f, Color4b::LightBlue, connectStart.V); + + Vtx vtx; + if(getVisibleVertexNearestToMouse(stack, vtx)) + { + drawPoint(m, 4.0f, Color4b::Green, vtx.V); + drawLine(Color4b::Blue, Color4b::Green, connectStart.V, vtx.V); + } + } +} + +// +// Edge deletion decoration +// +void edit_topo::editDecoDeleteVertexDeconnect(MeshModel &) +{ + Edg minE; + if(getVisibleEdgeNearestToMouse(Estack, minE)) + drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V); +} + +// +// Split selection decoration +// Draws in yellow the splittable edge +// +void edit_topo::editDecoSplit(MeshModel &) +{ + Edg minE; + if(getVisibleEdgeNearestToMouse(Estack, minE)) + drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V); +} + +// +// Collapse selection decoration +// Draws in yellow the collapse able edge +// +void edit_topo::editDecoCollapse(MeshModel &) +{ + Edg minE; + if(getVisibleEdgeNearestToMouse(Estack, minE)) + drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V); +} + +// +// Main decoration method +// +void edit_topo::Decorate(MeshModel &m, GLArea *) +{ + updateMatrixes(); + // onClick + if(click) + { + click=false; + + //--- + // Existing vertex selection mode (yellow pointer) + //--- + if(edit_topodialogobj->utensil==U_VTX_SEL) + editAddVertex(m); + + //--- + // Free vertex selection (no pointer) + //--- + if(edit_topodialogobj->utensil==U_VTX_SEL_FREE) + editAddVertexFree(); + + //--- + // Remove selected vertex mode (Yellow pointer) + //--- + if(edit_topodialogobj->utensil==U_VTX_DEL) + editDeleteVertex(); + + //--- + // Edge mode (vertex connection) + //--- + if(edit_topodialogobj->utensil==U_VTX_CONNECT) + editConnectVertex(); + + //--- + // Face Select/Deselect + //--- + if(edit_topodialogobj->utensil==U_FCE_SEL) + editSelectFace(); + + //--- + // edge deselection mode + //--- + if(edit_topodialogobj->utensil==U_VTX_DE_CONNECT) + editDeconnectEdge(); + + //--- + // Vertex moove mode + //--- + if(edit_topodialogobj->utensil==U_DND) + editDragAndDropVertex(); + + //--- + // edge split mode + //--- + if(edit_topodialogobj->utensil==U_EDG_SPLIT) + editEdgeSplit(); + + //--- + // edge collapse mode + //--- + if(edit_topodialogobj->utensil==U_EDG_COLLAPSE) + editEdgeCollapse(); + }// end if click + + + /*** Decorations ***/ + + + //--- + // Even if there's something selected: show edges + //--- + if((edit_topodialogobj->utensil==U_VTX_CONNECT)||(edit_topodialogobj->utensil==U_VTX_DE_CONNECT) + ||(edit_topodialogobj->utensil==U_DND)||(edit_topodialogobj->utensil==U_EDG_SPLIT) + ||(edit_topodialogobj->utensil==U_EDG_COLLAPSE)) + editDecoStandard(m); + + //--- + // First step: show only vertices + //--- + if((edit_topodialogobj->utensil==U_VTX_SEL_FREE)||(edit_topodialogobj->utensil==U_VTX_DEL) + ||(edit_topodialogobj->utensil==U_VTX_SEL)) + editDecoOnlyVertex(m); + + //--- + // Drag and drop vertices mode + //--- + if(edit_topodialogobj->utensil==U_DND) + editDecoDragAndDropVertex(m); + + //--- + // Face selection mode + //--- + if(edit_topodialogobj->utensil==U_FCE_SEL) + editDecoFaceSelect(m); + + //--- + // Yellow pointer (vertex selection) + //--- + if(edit_topodialogobj->utensil==U_VTX_SEL) + editDecoVertexSelect(m); + + //--- + // Vertex de-selection (Yellow pointeR) + //--- + if((edit_topodialogobj->utensil==U_VTX_DEL)&&(stack.count()!=0)) + editDecoDeleteVertexSelect(m); + + //--- + // edge mode (vtx connection) + //--- + if(edit_topodialogobj->utensil==U_VTX_CONNECT) + editDecoDeleteVertexConnect(m); + + //--- + // edge deselection mode + //--- + if(edit_topodialogobj->utensil==U_VTX_DE_CONNECT) + editDecoDeleteVertexDeconnect(m); + + //--- + // edge split mode + //--- + if(edit_topodialogobj->utensil==U_EDG_SPLIT) + editDecoSplit(m); + + //--- + // edge collapse mode + //--- + if(edit_topodialogobj->utensil==U_EDG_COLLAPSE) + editDecoCollapse(m); +} + +// +// Plugin init +// +bool edit_topo::StartEdit(MeshModel &m, GLArea *gla) +{ + parentGla = gla; + gla->setCursor(QCursor(QPixmap(":/images/cursor_paint.png"),1,1)); + + // Init uniform grid + float dist = m.cm.bbox.Diag(); + + // Init data masks + m.updateDataMask(MeshModel::MM_FACEMARK); + tri::UpdateNormals::PerFaceNormalized(m.cm); + tri::UpdateFlags::FaceProjection(m.cm); + + // Init retopology model builder object + rm.init(&m, dist); + + // Init miminum visible distance param (used only for labels rendering) + _md = 0.03; + + // Init ui + if (edit_topodialogobj == 0) + { + edit_topodialogobj = new edit_topodialog(gla->window()); + dock = new QDockWidget(gla->window()); + dock->setAllowedAreas(Qt::NoDockWidgetArea); + dock->setWidget(edit_topodialogobj); + QPoint p = gla->window()->mapToGlobal(QPoint(0,0)); + dock->setGeometry(-5+p.x()+gla->window()->width()-edit_topodialogobj->width(),p.y(),edit_topodialogobj->width(),edit_topodialogobj->height()); + dock->setFloating(true); + } + dock->setVisible(true); + dock->layout()->update(); + + gla->update(); + gla->setMouseTracking(true); + + // Connect slots + connect(edit_topodialogobj, SIGNAL( mesh_create() ), + this, SLOT( on_mesh_create() ) ); + + connect(edit_topodialogobj, SIGNAL( update_request() ), + this, SLOT( on_update_request() ) ); + return true; +} + +// +// End edit +// +void edit_topo::EndEdit(MeshModel &, GLArea *) +{ + stack.clear(); + Estack.clear(); + Fstack.clear(); + + reDraw = false; + click = false; + first_model_generated=false; + + nameVtxCount = 0; + + drag_click=false; + drag_stack.clear(); + + lastPoint.V = Point3f(0,0,0); + lastPoint.vName = "--"; + + connectStart.V = Point3f(0,0,0); + connectStart.vName = "--"; + connectEnd.V = Point3f(0,0,0); + connectEnd.vName = "--"; + + if (edit_topodialogobj != 0) + { + delete edit_topodialogobj; + delete dock; + edit_topodialogobj = 0; + dock = 0; + } +} + + +/************************************************************************************/ +// +// --- Slot implementation methods --- +// Those two methods are invoked by the gui +// + +// +// "Create new mesh" click +// This method calls the retopology algoritm, and creates +// the new mesh using the user defined new topology +// +void edit_topo::on_mesh_create() +{ + out.clear(); + + if(first_model_generated) + parentGla->meshDoc->meshList.pop_back(); + + + MeshModel *mm= parentGla->meshDoc->addNewMesh(""); + //parentGla->meshDoc->meshList.push_back(mm); + first_model_generated = true; + + + MeshModel *m = parentGla->meshDoc->meshList.back(); // destination = new mesh + MeshModel *currentMesh = parentGla->meshDoc->mm(); // source = current mesh + + // if debug value is true, the algorithm will respond with all the + // auto generated vertices. + // The isDEBUG value is forced by the "Draw auto-filled vertices" gui checkbox + if(edit_topodialogobj->isDEBUG()) + { + rm.Lout.clear(); + int iter = edit_topodialogobj->getIterations(); + float dist = edit_topodialogobj->dist()/100; + + // Retopology algorithm call + rm.createRefinedMesh(*m, /* *currentMesh,*/ dist, iter, Fstack, stack, edit_topodialogobj, true); + out = rm.Lout; + } + else + { + int iter = edit_topodialogobj->getIterations(); + float dist = edit_topodialogobj->dist()/100; + + // Retopology algorithm call + rm.createRefinedMesh(*m, /* *currentMesh, */ dist, iter, Fstack, stack, edit_topodialogobj, false); + } + + m->cm.Tr = currentMesh->cm.Tr; + parentGla->update(); +} + + +// +// General update requested by some gui functions +// +void edit_topo::on_update_request() +{ + parentGla->update(); +} + + + + + +/************************************************************************************/ +// +// --- Plugin events methods --- +// +void edit_topo::mousePressEvent(QMouseEvent * event, MeshModel &m, GLArea * gla) +{ + mousePos=event->pos(); + click=false; + gla->update(); +} + +void edit_topo::mouseMoveEvent(QMouseEvent * event, MeshModel &m, GLArea * gla) +{ + mousePos=event->pos(); + mouseRealY = gla->curSiz.height() - mousePos.y(); + reDraw=true; + gla->update(); +} + +void edit_topo::mouseReleaseEvent(QMouseEvent * event, MeshModel &, GLArea * gla) +{ + if(event->button() == Qt::LeftButton) + { + click=true; + reDraw=true; + } + else if(event->button() == Qt::RightButton) + { + connectStart.V=Point3f(0,0,0); + + drag_stack.clear(); + drag_click = false; + } + gla->update(); + mousePos=event->pos(); +} + + +/************************************************************************************/ +// +// --- New topology mesh methods --- +// Those methods are used by the edit plugin +// to elaborate topology related operations +// + + +// +// Get nearest 2d point of the given array +// Returns: array index +int edit_topo::getNearest(QPointF center, QPointF *points,int num) { + int nearestInd=0; + float dist=fabsf(center.x()-points[0].x())*fabsf(center.x()-points[0].x())+fabsf(center.y()-points[0].y())*fabsf(center.y()-points[0].y()); + for (int lauf=1; lauf::PickNearestFace(mid.x(), mid.y(), m.cm, val,2,2)); +} + +// +// Get existing nearest 3d vertex on the given mesh model +// Returns: true if found, and vertexpointer value +bool edit_topo::getVertexAtMouse(MeshModel &m,CMeshO::VertexPointer& value) +{ + CFaceO * temp=0; + + QPoint mid=QPoint(mousePos.x(), mouseRealY); + double tx,ty,tz; + if (getFaceAtMouse(m,temp)) + { + QPointF point[3]; + for (int lauf=0; lauf<3; lauf++) + { + gluProject(temp->V(lauf)->P()[0],temp->V(lauf)->P()[1],temp->V(lauf)->P()[2],mvmatrix,projmatrix,viewport,&tx,&ty,&tz); + point[lauf]=QPointF(tx,ty); + } + value=temp->V(getNearest(mid,point,3)); + return true; + } + return false; +} + + +// +// Check if the given vertex is visible on the current user view +// This method is used for rendering vertices labels, and +// rendering edges/faces +// Returns: true if visible +bool edit_topo::isVertexVisible(Point3f v) +{ + float pix; + double tx,ty,tz; + + gluProject(v.X(),v.Y(),v.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + glReadPixels(tx,ty,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&pix); + + float ff = fabs(tz - pix); + + return ((ff < 0.003)); +} + +// +// Get visible vertex nearest to mouse position (from a given vertices list) +// Returns: true if visible +bool edit_topo::getVisibleVertexNearestToMouse(QList list, Vtx &out) +{ + bool found = false; + double minDist = 100000; + int minIdx = -1; + Point3f t; + + QList visib; + + for(int i=0; i dx) ? 0.41*dx+0.941246*dy : 0.41*dy+0.941246*dx; + + double dist = sqrt((double)(math::Sqr(qp.x() - mPos.x()) + math::Sqr(qp.y() - mPos.y()))); + + if(dist listE, Edg &ret) +{ + Fce nearest; + bool got = false; + double tx,ty,tz; + int at = 0; + for(int f=0; f allv; + for(int e=0; e<3; e++) + for(int v=0; v<2; v++) + if(!allv.contains(fc.e[e].v[v])) + allv.push_back(fc.e[e].v[v]); + + gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p0 = QPointF(tx, ty); + gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p1 = QPointF(tx, ty); + gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p2 = QPointF(tx, ty); + + QPoint p = QPoint(mousePos.x(), mouseRealY); + + if(pointInTriangle(p, p0, p1, p2)) + { + nearest = fc; + got = true; + at = f; + } + } + + if(got) + { + Edg minE; + float bestD = -1; + bool found = false; + double tx,ty,tz; + + for(int i=0; i<3; i++) + { + Edg e = nearest.e[i]; + gluProject(e.v[0].V.X(),e.v[0].V.Y(),e.v[0].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p0 = QPointF(tx, ty); + gluProject(e.v[1].V.X(),e.v[1].V.Y(),e.v[1].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + QPointF p1 = QPointF(tx, ty); + + float dist = distancePointSegment(QPointF(mousePos.x(),mouseRealY), p1, p0); + if((dist < bestD)||(bestD==-1)) + { + bestD = dist; + minE = e; + found = true; + } + } + + ret = minE; + return found; + } + return false; +} + +// +// Checks if the given point is in the given triangle +// +bool edit_topo::pointInTriangle(const QPointF &p, const QPointF &a, const QPointF &b, const QPointF &c) +{ + float fab=(p.y()-a.y())*(b.x()-a.x()) - (p.x()-a.x())*(b.y()-a.y()); + float fbc=(p.y()-c.y())*(a.x()-c.x()) - (p.x()-c.x())*(a.y()-c.y()); + float fca=(p.y()-b.y())*(c.x()-b.x()) - (p.x()-b.x())*(c.y()-b.y()); + + return (fab*fbc>0 && fbc*fca>0); +} + +// +// 2d distance p-seg +// +float edit_topo::distancePointSegment(QPointF p, QPointF segmentP1,QPointF segmentP2) +{ + float x0, y0, x1, x2, y1, y2, m, q; + + x1 = segmentP1.x(); + y1 = segmentP1.y(); + + x2 = segmentP2.x(); + y2 = segmentP2.y(); + + m = (y2-y1)/(x2-x1); + q = y1 - m*x1; + + x0 = p.x(); + y0 = p.y(); + + return fabs((y0 - m*x0 -q) / (sqrt(1 + m*m))); +} + +// +// 2d distance p-p +// +float edit_topo::distancePointPoint(QPointF P1, QPointF P2) +{ + return sqrt(pow((P1.x()-P2.x()),2)+pow((P1.y()-P2.y()),2)); +} + +/************************************************************************************/ +// +// --- Plugin rendering methods --- +// Those methods are used by the plugin to draw labels +// vertices, edges, faces, ... in opengl + +// +// Draws user selected vertices labels +// +void edit_topo::drawLabel(QList list) +{ + + QVector v = list.toVector(); + int pCount = list.count(); + + for(int i=0; idrawLabels())) + { + double tx,ty,tz; + gluProject(v.V.X(),v.V.Y(),v.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz); + int x,y; + x = tx+5; + y=(parentGla->curSiz.height() - 5 - ty); + + // new style + QString text = v.vName; + QFont font; + font.setFamily("Helvetica"); + font.setPixelSize(10); + QFontMetrics fm(font); + QRect brec=fm.boundingRect(text); + glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT ); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(0,parentGla->width(),parentGla->height(),0); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glColor4f(0,0,0,0.6f); + glBegin(GL_QUADS); + glVertex2f(x+brec.left(),y+brec.bottom()); + glVertex2f(x+brec.right(),y+brec.bottom()); + glVertex2f(x+brec.right(),y+brec.top()); + glVertex2f(x+brec.left(),y+brec.top()); + glEnd(); + int offset=2; + glColor4f(0,0,0,0.3f); + glBegin(GL_QUADS); + glVertex2f(x+brec.left()-offset,y+brec.bottom()+offset); + glVertex2f(x+brec.right()+offset,y+brec.bottom()+offset); + glVertex2f(x+brec.right()+offset,y+brec.top()-offset); + glVertex2f(x+brec.left()-offset,y+brec.top()-offset); + glEnd(); + glColor3f(1,1,1); + parentGla->renderText(x,y, text,QFont()); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); + } +} + +// +// Draws a point +// +void edit_topo::drawPoint(MeshModel &m, float pSize, Color4b colorFront, Point3f p) +{ + glPushMatrix(); + glMultMatrix(m.cm.Tr); + glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LINE_BIT | GL_DEPTH_BUFFER_BIT); + glDepthFunc(GL_ALWAYS); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glDisable(GL_LIGHTING); + + glColor(colorFront); + + glPointSize(pSize); + + glBegin(GL_POINTS); + glVertex(p); + glVertex(p); + glEnd(); +/* + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + glColor(colorBack); + + glPointSize(0.3); + + glBegin(GL_POINT); + glVertex(cursorPoint); + glVertex(cursorPoint); + glEnd(); +*/ + glPopAttrib(); + glPopMatrix(); +} + +// +// Draws all vertices +// +void edit_topo::drawPoint(MeshModel &m, float pSize, Color4b colorFront, QList list) +{ + glPushMatrix(); + glMultMatrix(m.cm.Tr); + glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LINE_BIT | GL_DEPTH_BUFFER_BIT); + glLineWidth(2.0f); + glDepthFunc(GL_ALWAYS); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glDisable(GL_LIGHTING); + glColor(colorFront); + + glPointSize(pSize); + + QVector v = list.toVector(); + int pCount = list.count(); + + glBegin(GL_POINTS); + for(int i=0; i vectSub(int part, Point3f p1, Point3f p2) +{ + if(part==2) + { + QVector toRet(3); + toRet[0]=p1; + toRet[1]=(p1+p2)/2; + toRet[2]=p2; + return toRet; + } + else + { + QVector L; + QVector R; + + int np=(int)(part/2); + + L = vectSub(np, p1, (p1+p2)/2); + R = vectSub(np, (p1+p2)/2, p2); + + QVector toRet; + for(int i=0; i trattP; + int part = 32; + float dist = (p1-p2).Norm(); + if(dist>10) part*=2; + if(dist>50) part*=2; + if(dist>100) part*=2; + if(dist>400) part*=2; + + Point3f pp1, pp2; + trattP = vectSub(part, p1, p2); + + for(int i=0; i<(trattP.size()-1); i+=2) + { + pp1 = trattP[i]; + pp2 = trattP[i+1]; + + glDisable(GL_DEPTH_TEST); + + glLineWidth(0.5f); + glPointSize(0.3f); + glBegin(GL_LINES); + glVertex(pp1); + glVertex(pp2); + glEnd(); + glBegin(GL_POINTS); + glVertex(pp1); + glVertex(pp2); + glEnd(); + } + glPopAttrib(); + } + else if(edit_topodialogobj->drawEdges()) + { + glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + glDepthMask(false); + glLineWidth(1.5f); + glPointSize(0.4f); + + // Fill the intermed. points to draw a dotted line + QVector trattP; + int part = 8; + float dist = (p1-p2).Norm(); + if(dist>10) part*=2; + if(dist>50) part*=2; + if(dist>100) part*=2; + if(dist>400) part*=2; + + Point3f pp1, pp2; + trattP = vectSub(part, p1, p2); + + glColor(colorBack); + glDisable(GL_DEPTH_TEST); + + for(int i=0; i<(trattP.size()-1); i+=2) + { + pp1 = trattP[i]; + pp2 = trattP[i+1]; + + glBegin(GL_LINES); + glVertex(pp1); + glVertex(pp2); + glEnd(); + glBegin(GL_POINTS); + glVertex(pp1); + glVertex(pp2); + glEnd(); + } + glPopAttrib(); + } +} + +// +// Draws a triangle +// +void edit_topo::drawFace(CMeshO::FacePointer fp) +{ + glPointSize(3.0f); + + glBegin(GL_POINTS); //GL_LINE_LOOP); + glVertex(fp->P(0)); + glVertex(fp->P(1)); + glVertex(fp->P(2)); + glEnd(); +} diff --git a/src/fgt/edit_topo/edit_topomeshbuilder.h b/src/fgt/edit_topo/edit_topomeshbuilder.h index fe265d313..10ac53f4b 100644 --- a/src/fgt/edit_topo/edit_topomeshbuilder.h +++ b/src/fgt/edit_topo/edit_topomeshbuilder.h @@ -1,515 +1,515 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2008 \/)\/ * -* 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 edit_topomeshbuilder_H -#define edit_topomeshbuilder_H - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "edit_topodialog.h" - - - - -//************************************************************** -// template class NearestMidPoint -// This class is used by the retopology algorithm -// to obtain the closest point to each "ideal" new -// mesh vertex -// -// The operator () is called by the standard vcg "Refine<,>" -// method to obtain the new vertices coordinates -// -// Because of the great reuse of that operator, this class -// needs to be initialized with the original "source" model. -// This can be done by calling the "init" method -// -template -class NearestMidPoint : public std::unary_function, typename MESH_TYPE::CoordType> -{ - typedef GridStaticPtr MetroMeshGrid; - -public: - // if DEBUG value is true, the class will fill - // the LoutMid QList with ALL the "failed" vertices. - // So, LoutMid will contain all vertices that have not - // been found by the UnifGrid.GetClosest() function - bool DEBUG; - QList * LoutMid; - - // Uniform grid, init by the "init()" method - MetroMeshGrid unifGrid; - - // Marker - typedef tri::FaceTmark MarkerFace; - MarkerFace markerFunctor; - - // All of the data structures used by the retopology algo have - // to be initialized *before* the function call. - // - // This is necessary in order to reduce comput time - void init(MESH_TYPE *_m, float dist) - { - m=_m; - if(m) - { - // Set up uniform grid - unifGrid.Set(m->face.begin(),m->face.end()); - markerFunctor.SetMesh(m); - dist_upper_bound = dist; - } - } - - // Standard operator called by Refine<> - // - // If you want to change the way new vertices are generated - // you have to modify the "VertexTypr nv" output coords - void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep) - { - Point3f closestPt, normf, bestq, ip; - - float dist = dist_upper_bound; - vcg::face::PointDistanceBaseFunctor PDistFunct; - - // startPt is the point from where the "GetClosest" query will start - const typename MESH_TYPE::CoordType &startPt= (ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0; - CMeshO::FaceType *nearestF=0; - - // in "dist" will be returned the closest point distance from startPt - dist=dist_upper_bound; - - Point3f p1 = ep.f->V(ep.z)->P(); - Point3f p2 = ep.f->V1(ep.z)->P(); - float incDist = sqrt(math::Sqr(p1.X()-p2.X())+math::Sqr(p1.Y()-p2.Y())+math::Sqr(p1.Z()-p2.Z())); - - // distPerc is the % distance used to evaluate the maximum query distance - incDist = incDist * distPerc; - - // dist_ upper_bound is the maximum query distance, evaluated - // with a % factor given by the user - dist_upper_bound = incDist; - - // Query the uniform grid and get the original mesh's point nearest to startPt - nearestF = unifGrid.GetClosest(PDistFunct, - markerFunctor, - startPt, - dist_upper_bound, - dist, - closestPt); - - // Output distance has not changed: no closest point found. - // The original "ideal" point will be used, and then will be - // smoothed with laplacian smooth algorithm - if(dist == dist_upper_bound) - { - nv.P()= startPt; - nv.N()= ((ep.f->V(ep.z)->N() + ep.f->V(ep.z)->N())/2).normalized(); - nv.C().lerp(ep.f->V(ep.z)->C(),ep.f->V1(ep.z)->C(),.5f); - nv.Q() = ((ep.f->V(ep.z)->Q()+ep.f->V1(ep.z)->Q())) / 2.0; - - // Mark it as selected to smooth it - nv.SetS(); - - qDebug("Unable to find closest point. Marked for smoothing"); - - // If debug mode is on, the point will be drawn in meshlab - if(DEBUG) LoutMid->push_back(startPt); - } - // distance has changed: got the closest point - else - { - nv.P()= closestPt; - - Point3f interp; - // Try to interpolate vertex colors and normals - if(InterpolationParameters(*nearestF,(*nearestF).cN(), closestPt, interp[0], interp[1], interp[2])) - { - interp[2]=1.0-interp[1]-interp[0]; - - nv.P()= closestPt; - nv.N()= ((nearestF->V(0)->N() + nearestF->V(1)->N() + nearestF->V(2)->N())/3).normalized(); - nv.C().lerp(nearestF->V(0)->C(),nearestF->V(1)->C(),nearestF->V(2)->C(),interp); - nv.Q() = nearestF->V(0)->Q()*interp[0] + nearestF->V(1)->Q()*interp[1] + nearestF->V(2)->Q()*interp[2]; - - nv.ClearS(); - } - } - } - - // Color interpolation called by Refine<,> - Color4 WedgeInterp(Color4 &c0, Color4 &c1) - { - Color4 cc; - return cc.lerp(c0,c1,0.5f); - } - - // Color interpolation called by Refine<,> - template - TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) - { - TexCoord2 tmp; - assert(t0.n()== t1.n()); - tmp.n()=t0.n(); - tmp.t()=(t0.t()+t1.t())/2.0; - return tmp; - } - - float dist_upper_bound; // maximum upper distance (See below "distPerc") - float distPerc; // distance for getClosest() is evalutated as a % of the edge's length (float from 0.01 to 0.99) - -private: - // Internal mesh model - CMeshO *m; -}; - - - - - - - - - - - -//************************************************************** -// class RetopMeshBuilder -// This class contains the retopology algorithm, -// and is used for "edit" and "filter" plugin modes -// -class RetopMeshBuilder -{ -public: - // Mid point sampler object, used by "Refine" in the retopo process - NearestMidPoint * midSampler; - - // This list will be filled (in debug mode) with all the "not found" closest vertices - QList Lout; - - RetopMeshBuilder() {}; - - // init mid point sampler object - void init(MeshModel *_mm, double dist) - { - _mm->updateDataMask(MeshModel::MM_FACEMARK); - midSampler = new NearestMidPoint(); - midSampler->init(&_mm->cm, dist); - } - - // - // Creates the retopology mesh in edit mode (edit_topo plugin) - // - void createRefinedMesh(MeshModel &outMesh, /*MeshModel &in,*/ float dist, int iterations, QList Fstack, QList stack, edit_topodialog *dialog, bool DEBUG) - { - dialog->setBarMax(iterations); - dialog->setStatusLabel("Init topo"); - - midSampler->DEBUG = DEBUG; - midSampler->distPerc = dist; - midSampler->LoutMid = &Lout; - - // Create a "flat" mesh from the user defined topology defined - // in faces stack "Fstack" and vertices stack "stack" - createBasicMesh(outMesh, Fstack, stack); - - dialog->setStatusLabel("Done"); - - CMeshO::FaceIterator fi; - for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) - {(*fi).ClearS(); for(int i=0; i<3; i++) (*fi).V(i)->ClearS(); } - - outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); - if(tri::Clean::CountNonManifoldEdgeFF(outMesh.cm)==0) - for(int i=0; isetStatusLabel("Iter: "+QString("%1").arg(i+1)); - - // This is che core point of the retopology plugin: - // here "Refine" is called with "NearestMidPoint" and "midSampler" - // - midSampler uses an uniform grid to get the closest point - // for each given vertex, and "builds" the new mesh by adapting - // it over the existing "in" meshmodel - // If the midSampler fails (for example if a hole is found), each - // vertex is marked with SetS() and will be smoothed later - // - outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); - Refine >(outMesh.cm, *midSampler, 0, false, 0); - outMesh.clearDataMask( MeshModel::MM_VERTFACETOPO); - dialog->setBarVal(i+1); - } - - outMesh.setFileName("Retopology.ply"); - tri::UpdateBounding::Box(outMesh.cm); - - dialog->setStatusLabel("Normals"); - - // Recalculate new model's face normals and select faces with selected vertices - for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) - { - (*fi).N()=((fi->V(0)->N() + fi->V(1)->N() + fi->V(2)->N())/3); - (*fi).ClearS(); - - for(int i=0; i<3; i++) - if((*fi).V(i)->IsS()) - (*fi).SetS(); - } - - // Expand selected faces to obtain a more refined smooth - for(int i=0; i<(1+(int)(iterations/4)); i++) - for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) - if((*fi).IsS()) - for(int i=0; i<3; i++) - (*fi).FFp(i)->SetS(); - - dialog->setStatusLabel("Lapl smooth"); - - // Laplacian smooth for selected faces - tri::UpdateSelection::VertexFromFaceStrict(outMesh.cm); - tri::Smooth::VertexCoordLaplacian(outMesh.cm,3,true,0); - dialog->setStatusLabel("Done"); - } - - - - - - //********************************************************************************************// - // - // Creates a retop mesh for the "filter" mode (not used in edit_topo) - // - userMesh = The low level mesh selected by the user as new basic topology - // - inMesh = The original mesh from where the userMesh has been created - // - it = Number of iterations (from 0 to 10) - // - dist = % for incremental distance (from 0.01 to 0.99) - // - outMesh = The output retopology mesh - // - // - //********************************************************************************************// - bool applyTopoMesh(MeshModel &userTopoMesh, MeshModel &inModel, int it, float dist, MeshModel &outMesh) - { - // turn off debug mode - midSampler->DEBUG = false; - - midSampler->distPerc = dist; - outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO); - - // Update topology for in mesh, to be sure that the model can be refined - bool oriented,orientable; - tri::Clean::IsOrientedMesh(outMesh.cm, oriented,orientable); - vcg::tri::UpdateTopology::FaceFace(outMesh.cm); - vcg::tri::UpdateTopology::TestFaceFace(outMesh.cm); - vcg::tri::UpdateNormals::PerVertexNormalizedPerFace(outMesh.cm); - outMesh.clearDataMask(MeshModel::MM_FACEFACETOPO); - - // Clear faces and vertices selection - CMeshO::FaceIterator fi; - for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) - {(*fi).ClearS(); for(int i=0; i<3; i++) (*fi).V(i)->ClearS(); } - - outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); - if(tri::Clean::CountNonManifoldEdgeFF(outMesh.cm)==0) - { - for(int i=0; i >(outMesh.cm, *midSampler, 0, false, 0); - outMesh.clearDataMask( MeshModel::MM_VERTFACETOPO); - } - } - else return false; - - outMesh.setFileName("Retopology.ply"); - tri::UpdateBounding::Box(outMesh.cm); - - // compute face normals, and select faces for not found vertices (to smooth them) - for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) - { - (*fi).N()=((fi->V(0)->N() + fi->V(1)->N() + fi->V(2)->N())/3); - (*fi).ClearS(); - - for(int i=0; i<3; i++) - if((*fi).V(i)->IsS()) - (*fi).SetS(); - } - - for(int i=0; i<(1+(int)(it/4)); i++) - for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) - if((*fi).IsS()) - for(int i=0; i<3; i++) - (*fi).FFp(i)->SetS(); - - // Laplacian smooth for not-found vertices - tri::UpdateSelection::VertexFromFaceStrict(outMesh.cm); - tri::Smooth::VertexCoordLaplacian(outMesh.cm,3,true,0); - - return true; - } - - - -private: - // Creates the flat initial mesh from the user defined topology - void createBasicMesh(MeshModel &outMesh, QList Fstack, QList Vstack) - { - // Elaborate topology relations - QVector nStack(Vstack.count()); - QVector nFstack(Fstack.count()); nFstack = Fstack.toVector(); - for(int i=0; i::AddVertices(outMesh.cm, nStack.count()); - vcg::tri::Allocator::AddFaces(outMesh.cm, allFce); - - QVector ivp(Vstack.count()); - - int v =0; - CMeshO::VertexIterator vi; - for(vi=outMesh.cm.vert.begin(); vi!=outMesh.cm.vert.end(); vi++) - { - ivp[v] = &*vi; - (*vi).P() = Point3f(nStack[v].V.X(), nStack[v].V.Y(), nStack[v].V.Z()); - - Point3f closestPt; - vcg::face::PointDistanceBaseFunctor PDistFunct; - - const CMeshO::CoordType &startPt = (*vi).P(); - CMeshO::FaceType *nearestF=0; - - float d1,d2; d1 = d2 = 1000; - - // Use the sampler to get original vertices normals - nearestF = midSampler->unifGrid.GetClosest(PDistFunct, - midSampler->markerFunctor, - startPt, - d1, - d2, - closestPt); - - (*vi).C().lerp(nearestF->V(0)->C(),nearestF->V(1)->C(),.5f); - (*vi).N() = ((nearestF->V(0)->N() + nearestF->V(1)->N() + nearestF->V(2)->N())/3).normalized(); - - ++v; - } - - int f = 0; - CMeshO::FaceIterator fi; - for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) - { - Fce fce = nFstack[f]; - - if(fce.selected) - { - QList allV; - for(int i=0; i<3; i++) - for(int j=0; j<2; j++) - if(!allV.contains(fce.e[i].v[j])) - allV.push_back(fce.e[i].v[j]); - - int ivpId0 = allV.at(0).vName.toInt(); - int ivpId1 = allV.at(1).vName.toInt(); - int ivpId2 = allV.at(2).vName.toInt(); - - (*fi).V(0) = ivp.at(ivpId0); - (*fi).V(1) = ivp.at(ivpId1); - (*fi).V(2) = ivp.at(ivpId2); - f++; - } - } - outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO); - - // Re-orient new mesh - bool oriented,orientable; - tri::Clean::IsOrientedMesh(outMesh.cm, oriented,orientable); - vcg::tri::UpdateTopology::FaceFace(outMesh.cm); - vcg::tri::UpdateTopology::TestFaceFace(outMesh.cm); - - outMesh.clearDataMask(MeshModel::MM_FACEFACETOPO); - } -}; - - - - - - - - - - - - - - - - - - - - - - - - - - -#endif - - +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2008 \/)\/ * +* 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 edit_topomeshbuilder_H +#define edit_topomeshbuilder_H + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "edit_topodialog.h" + + + + +//************************************************************** +// template class NearestMidPoint +// This class is used by the retopology algorithm +// to obtain the closest point to each "ideal" new +// mesh vertex +// +// The operator () is called by the standard vcg "Refine<,>" +// method to obtain the new vertices coordinates +// +// Because of the great reuse of that operator, this class +// needs to be initialized with the original "source" model. +// This can be done by calling the "init" method +// +template +class NearestMidPoint : public std::unary_function, typename MESH_TYPE::CoordType> +{ + typedef GridStaticPtr MetroMeshGrid; + +public: + // if DEBUG value is true, the class will fill + // the LoutMid QList with ALL the "failed" vertices. + // So, LoutMid will contain all vertices that have not + // been found by the UnifGrid.GetClosest() function + bool DEBUG; + QList * LoutMid; + + // Uniform grid, init by the "init()" method + MetroMeshGrid unifGrid; + + // Marker + typedef tri::FaceTmark MarkerFace; + MarkerFace markerFunctor; + + // All of the data structures used by the retopology algo have + // to be initialized *before* the function call. + // + // This is necessary in order to reduce comput time + void init(MESH_TYPE *_m, float dist) + { + m=_m; + if(m) + { + // Set up uniform grid + unifGrid.Set(m->face.begin(),m->face.end()); + markerFunctor.SetMesh(m); + dist_upper_bound = dist; + } + } + + // Standard operator called by Refine<> + // + // If you want to change the way new vertices are generated + // you have to modify the "VertexTypr nv" output coords + void operator()(typename MESH_TYPE::VertexType &nv, face::Pos ep) + { + Point3f closestPt, normf, bestq, ip; + + float dist = dist_upper_bound; + vcg::face::PointDistanceBaseFunctor PDistFunct; + + // startPt is the point from where the "GetClosest" query will start + const typename MESH_TYPE::CoordType &startPt= (ep.f->V(ep.z)->P()+ep.f->V1(ep.z)->P())/2.0; + CMeshO::FaceType *nearestF=0; + + // in "dist" will be returned the closest point distance from startPt + dist=dist_upper_bound; + + Point3f p1 = ep.f->V(ep.z)->P(); + Point3f p2 = ep.f->V1(ep.z)->P(); + float incDist = sqrt(math::Sqr(p1.X()-p2.X())+math::Sqr(p1.Y()-p2.Y())+math::Sqr(p1.Z()-p2.Z())); + + // distPerc is the % distance used to evaluate the maximum query distance + incDist = incDist * distPerc; + + // dist_ upper_bound is the maximum query distance, evaluated + // with a % factor given by the user + dist_upper_bound = incDist; + + // Query the uniform grid and get the original mesh's point nearest to startPt + nearestF = unifGrid.GetClosest(PDistFunct, + markerFunctor, + startPt, + dist_upper_bound, + dist, + closestPt); + + // Output distance has not changed: no closest point found. + // The original "ideal" point will be used, and then will be + // smoothed with laplacian smooth algorithm + if(dist == dist_upper_bound) + { + nv.P()= startPt; + nv.N()= ((ep.f->V(ep.z)->N() + ep.f->V(ep.z)->N())/2).normalized(); + nv.C().lerp(ep.f->V(ep.z)->C(),ep.f->V1(ep.z)->C(),.5f); + nv.Q() = ((ep.f->V(ep.z)->Q()+ep.f->V1(ep.z)->Q())) / 2.0; + + // Mark it as selected to smooth it + nv.SetS(); + + qDebug("Unable to find closest point. Marked for smoothing"); + + // If debug mode is on, the point will be drawn in meshlab + if(DEBUG) LoutMid->push_back(startPt); + } + // distance has changed: got the closest point + else + { + nv.P()= closestPt; + + Point3f interp; + // Try to interpolate vertex colors and normals + if(InterpolationParameters(*nearestF,(*nearestF).cN(), closestPt, interp[0], interp[1], interp[2])) + { + interp[2]=1.0-interp[1]-interp[0]; + + nv.P()= closestPt; + nv.N()= ((nearestF->V(0)->N() + nearestF->V(1)->N() + nearestF->V(2)->N())/3).normalized(); + nv.C().lerp(nearestF->V(0)->C(),nearestF->V(1)->C(),nearestF->V(2)->C(),interp); + nv.Q() = nearestF->V(0)->Q()*interp[0] + nearestF->V(1)->Q()*interp[1] + nearestF->V(2)->Q()*interp[2]; + + nv.ClearS(); + } + } + } + + // Color interpolation called by Refine<,> + Color4 WedgeInterp(Color4 &c0, Color4 &c1) + { + Color4 cc; + return cc.lerp(c0,c1,0.5f); + } + + // Color interpolation called by Refine<,> + template + TexCoord2 WedgeInterp(TexCoord2 &t0, TexCoord2 &t1) + { + TexCoord2 tmp; + assert(t0.n()== t1.n()); + tmp.n()=t0.n(); + tmp.t()=(t0.t()+t1.t())/2.0; + return tmp; + } + + float dist_upper_bound; // maximum upper distance (See below "distPerc") + float distPerc; // distance for getClosest() is evalutated as a % of the edge's length (float from 0.01 to 0.99) + +private: + // Internal mesh model + CMeshO *m; +}; + + + + + + + + + + + +//************************************************************** +// class RetopMeshBuilder +// This class contains the retopology algorithm, +// and is used for "edit" and "filter" plugin modes +// +class RetopMeshBuilder +{ +public: + // Mid point sampler object, used by "Refine" in the retopo process + NearestMidPoint * midSampler; + + // This list will be filled (in debug mode) with all the "not found" closest vertices + QList Lout; + + RetopMeshBuilder() {}; + + // init mid point sampler object + void init(MeshModel *_mm, double dist) + { + _mm->updateDataMask(MeshModel::MM_FACEMARK); + midSampler = new NearestMidPoint(); + midSampler->init(&_mm->cm, dist); + } + + // + // Creates the retopology mesh in edit mode (edit_topo plugin) + // + void createRefinedMesh(MeshModel &outMesh, /*MeshModel &in,*/ float dist, int iterations, QList Fstack, QList stack, edit_topodialog *dialog, bool DEBUG) + { + dialog->setBarMax(iterations); + dialog->setStatusLabel("Init topo"); + + midSampler->DEBUG = DEBUG; + midSampler->distPerc = dist; + midSampler->LoutMid = &Lout; + + // Create a "flat" mesh from the user defined topology defined + // in faces stack "Fstack" and vertices stack "stack" + createBasicMesh(outMesh, Fstack, stack); + + dialog->setStatusLabel("Done"); + + CMeshO::FaceIterator fi; + for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) + {(*fi).ClearS(); for(int i=0; i<3; i++) (*fi).V(i)->ClearS(); } + + outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); + if(tri::Clean::CountNonManifoldEdgeFF(outMesh.cm)==0) + for(int i=0; isetStatusLabel("Iter: "+QString("%1").arg(i+1)); + + // This is che core point of the retopology plugin: + // here "Refine" is called with "NearestMidPoint" and "midSampler" + // - midSampler uses an uniform grid to get the closest point + // for each given vertex, and "builds" the new mesh by adapting + // it over the existing "in" meshmodel + // If the midSampler fails (for example if a hole is found), each + // vertex is marked with SetS() and will be smoothed later + // + outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); + Refine >(outMesh.cm, *midSampler, 0, false, 0); + outMesh.clearDataMask( MeshModel::MM_VERTFACETOPO); + dialog->setBarVal(i+1); + } + + outMesh.setFileName("Retopology.ply"); + tri::UpdateBounding::Box(outMesh.cm); + + dialog->setStatusLabel("Normals"); + + // Recalculate new model's face normals and select faces with selected vertices + for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) + { + (*fi).N()=((fi->V(0)->N() + fi->V(1)->N() + fi->V(2)->N())/3); + (*fi).ClearS(); + + for(int i=0; i<3; i++) + if((*fi).V(i)->IsS()) + (*fi).SetS(); + } + + // Expand selected faces to obtain a more refined smooth + for(int i=0; i<(1+(int)(iterations/4)); i++) + for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) + if((*fi).IsS()) + for(int i=0; i<3; i++) + (*fi).FFp(i)->SetS(); + + dialog->setStatusLabel("Lapl smooth"); + + // Laplacian smooth for selected faces + tri::UpdateSelection::VertexFromFaceStrict(outMesh.cm); + tri::Smooth::VertexCoordLaplacian(outMesh.cm,3,true,0); + dialog->setStatusLabel("Done"); + } + + + + + + //********************************************************************************************// + // + // Creates a retop mesh for the "filter" mode (not used in edit_topo) + // - userMesh = The low level mesh selected by the user as new basic topology + // - inMesh = The original mesh from where the userMesh has been created + // - it = Number of iterations (from 0 to 10) + // - dist = % for incremental distance (from 0.01 to 0.99) + // - outMesh = The output retopology mesh + // + // + //********************************************************************************************// + bool applyTopoMesh(MeshModel &userTopoMesh, MeshModel &inModel, int it, float dist, MeshModel &outMesh) + { + // turn off debug mode + midSampler->DEBUG = false; + + midSampler->distPerc = dist; + outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO); + + // Update topology for in mesh, to be sure that the model can be refined + bool oriented,orientable; + tri::Clean::IsOrientedMesh(outMesh.cm, oriented,orientable); + vcg::tri::UpdateTopology::FaceFace(outMesh.cm); + vcg::tri::UpdateTopology::TestFaceFace(outMesh.cm); + vcg::tri::UpdateNormals::PerVertexNormalizedPerFace(outMesh.cm); + outMesh.clearDataMask(MeshModel::MM_FACEFACETOPO); + + // Clear faces and vertices selection + CMeshO::FaceIterator fi; + for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) + {(*fi).ClearS(); for(int i=0; i<3; i++) (*fi).V(i)->ClearS(); } + + outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER); + if(tri::Clean::CountNonManifoldEdgeFF(outMesh.cm)==0) + { + for(int i=0; i >(outMesh.cm, *midSampler, 0, false, 0); + outMesh.clearDataMask( MeshModel::MM_VERTFACETOPO); + } + } + else return false; + + outMesh.setFileName("Retopology.ply"); + tri::UpdateBounding::Box(outMesh.cm); + + // compute face normals, and select faces for not found vertices (to smooth them) + for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) + { + (*fi).N()=((fi->V(0)->N() + fi->V(1)->N() + fi->V(2)->N())/3); + (*fi).ClearS(); + + for(int i=0; i<3; i++) + if((*fi).V(i)->IsS()) + (*fi).SetS(); + } + + for(int i=0; i<(1+(int)(it/4)); i++) + for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) + if((*fi).IsS()) + for(int i=0; i<3; i++) + (*fi).FFp(i)->SetS(); + + // Laplacian smooth for not-found vertices + tri::UpdateSelection::VertexFromFaceStrict(outMesh.cm); + tri::Smooth::VertexCoordLaplacian(outMesh.cm,3,true,0); + + return true; + } + + + +private: + // Creates the flat initial mesh from the user defined topology + void createBasicMesh(MeshModel &outMesh, QList Fstack, QList Vstack) + { + // Elaborate topology relations + QVector nStack(Vstack.count()); + QVector nFstack(Fstack.count()); nFstack = Fstack.toVector(); + for(int i=0; i::AddVertices(outMesh.cm, nStack.count()); + vcg::tri::Allocator::AddFaces(outMesh.cm, allFce); + + QVector ivp(Vstack.count()); + + int v =0; + CMeshO::VertexIterator vi; + for(vi=outMesh.cm.vert.begin(); vi!=outMesh.cm.vert.end(); vi++) + { + ivp[v] = &*vi; + (*vi).P() = Point3f(nStack[v].V.X(), nStack[v].V.Y(), nStack[v].V.Z()); + + Point3f closestPt; + vcg::face::PointDistanceBaseFunctor PDistFunct; + + const CMeshO::CoordType &startPt = (*vi).P(); + CMeshO::FaceType *nearestF=0; + + float d1,d2; d1 = d2 = 1000; + + // Use the sampler to get original vertices normals + nearestF = midSampler->unifGrid.GetClosest(PDistFunct, + midSampler->markerFunctor, + startPt, + d1, + d2, + closestPt); + + (*vi).C().lerp(nearestF->V(0)->C(),nearestF->V(1)->C(),.5f); + (*vi).N() = ((nearestF->V(0)->N() + nearestF->V(1)->N() + nearestF->V(2)->N())/3).normalized(); + + ++v; + } + + int f = 0; + CMeshO::FaceIterator fi; + for(fi=outMesh.cm.face.begin(); fi!=outMesh.cm.face.end(); fi++) + { + Fce fce = nFstack[f]; + + if(fce.selected) + { + QList allV; + for(int i=0; i<3; i++) + for(int j=0; j<2; j++) + if(!allV.contains(fce.e[i].v[j])) + allV.push_back(fce.e[i].v[j]); + + int ivpId0 = allV.at(0).vName.toInt(); + int ivpId1 = allV.at(1).vName.toInt(); + int ivpId2 = allV.at(2).vName.toInt(); + + (*fi).V(0) = ivp.at(ivpId0); + (*fi).V(1) = ivp.at(ivpId1); + (*fi).V(2) = ivp.at(ivpId2); + f++; + } + } + outMesh.updateDataMask(MeshModel::MM_FACEFACETOPO); + + // Re-orient new mesh + bool oriented,orientable; + tri::Clean::IsOrientedMesh(outMesh.cm, oriented,orientable); + vcg::tri::UpdateTopology::FaceFace(outMesh.cm); + vcg::tri::UpdateTopology::TestFaceFace(outMesh.cm); + + outMesh.clearDataMask(MeshModel::MM_FACEFACETOPO); + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif + + diff --git a/src/fgt/edit_topo/filter_topo/filter_topo.cpp b/src/fgt/edit_topo/filter_topo/filter_topo.cpp index 6dbf9499f..b2d6b4846 100644 --- a/src/fgt/edit_topo/filter_topo/filter_topo.cpp +++ b/src/fgt/edit_topo/filter_topo/filter_topo.cpp @@ -1,134 +1,134 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2008 \/)\/ * -* 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 - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "filter_topo.h" -#include "../edit_topo/edit_topomeshbuilder.h" - - - -FilterTopoPlugin::FilterTopoPlugin() -{ - typeList << FP_RE_TOPO; - - foreach(FilterIDType tt , types()) - actionList << new QAction(filterName(tt), this); -} - - QString FilterTopoPlugin::filterName(FilterIDType filterId) -{ - switch(filterId) { - case FP_RE_TOPO : return QString("Create mesh from basic topology"); - default : assert(0); - } -} - - QString FilterTopoPlugin::filterInfo(FilterIDType filterId) -{ - switch(filterId) { - case FP_RE_TOPO : return QString("Creates a new mesh from a basic topology model applied to an high resolution model"); - default : assert(0); - } -} - -// -// Filter interface start up -// -void FilterTopoPlugin::initParameterSet(QAction *action, MeshDocument & md, RichParameterSet & parlst) -{ - MeshModel *target= md.mm(); - foreach (target, md.meshList) - if (target != md.mm()) break; - - doc = &md; - - switch(ID(action)) { - case FP_RE_TOPO : - // Iterations editbox - parlst.addParam(new RichInt( "it", - 4, - "Number of refinement iterations used to build the new mesh", - "As higher is this value, as well defined will be the new mesh. Consider that more than 5 iterations may slow down your system")); - // Distance editbox - parlst.addParam(new RichAbsPerc( "dist", 0.3f, 0.01f, 0.99f, - "Incremental distance %", - "This param represents the % distance for the local search algorithm used for new vertices allocation. Generally, 0.25-0.30 is a good value")); - // Topology mesh list - parlst.addParam(new RichMesh( "userMesh", md.mm(), - "Topology mesh", - "This mesh will be used as the new base topology, and will be replaced by the new mesh")); - // Original mesh list - parlst.addParam(new RichMesh( "inMesh", target, - "Original mesh", - "The new mesh will be elaborated using this model")); - break; - - default : assert(0); - } -} - -// -// Apply filter -// -bool FilterTopoPlugin::applyFilter(QAction *filter, MeshModel &m, RichParameterSet & par, vcg::CallBackPos *cb) -{ - // To run the retopology algorithm an istance of RetopoMeshBuilder is needed - RetopMeshBuilder rm; - - // Load topology mesh - MeshModel *userMesh = par.getMesh("userMesh"); - // Load (input) original mesh - MeshModel *inMesh = par.getMesh("inMesh"); - // Load iterations value - int it = par.getInt("it"); - // Load distance value - float dist = par.getAbsPerc("dist"); - - // Destination meshmodel: retopology mesh will replace flat topology mesh - MeshModel * outM = par.getMesh("userMesh"); - - // Prepare mesh - inMesh->updateDataMask(MeshModel::MM_FACEMARK); - tri::UpdateNormals::PerFaceNormalized(inMesh->cm); - tri::UpdateFlags::FaceProjection(inMesh->cm); - - // Init the retopology builder with original input mesh and distance value - rm.init(inMesh, dist); - // Apply the algorithm - return rm.applyTopoMesh(*userMesh, *inMesh, it, dist, *outM); -} - -Q_EXPORT_PLUGIN(FilterTopoPlugin) +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2008 \/)\/ * +* 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 + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "filter_topo.h" +#include "../edit_topo/edit_topomeshbuilder.h" + + + +FilterTopoPlugin::FilterTopoPlugin() +{ + typeList << FP_RE_TOPO; + + foreach(FilterIDType tt , types()) + actionList << new QAction(filterName(tt), this); +} + + QString FilterTopoPlugin::filterName(FilterIDType filterId) +{ + switch(filterId) { + case FP_RE_TOPO : return QString("Create mesh from basic topology"); + default : assert(0); + } +} + + QString FilterTopoPlugin::filterInfo(FilterIDType filterId) +{ + switch(filterId) { + case FP_RE_TOPO : return QString("Creates a new mesh from a basic topology model applied to an high resolution model"); + default : assert(0); + } +} + +// +// Filter interface start up +// +void FilterTopoPlugin::initParameterSet(QAction *action, MeshDocument & md, RichParameterSet & parlst) +{ + MeshModel *target= md.mm(); + foreach (target, md.meshList) + if (target != md.mm()) break; + + doc = &md; + + switch(ID(action)) { + case FP_RE_TOPO : + // Iterations editbox + parlst.addParam(new RichInt( "it", + 4, + "Number of refinement iterations used to build the new mesh", + "As higher is this value, as well defined will be the new mesh. Consider that more than 5 iterations may slow down your system")); + // Distance editbox + parlst.addParam(new RichAbsPerc( "dist", 0.3f, 0.01f, 0.99f, + "Incremental distance %", + "This param represents the % distance for the local search algorithm used for new vertices allocation. Generally, 0.25-0.30 is a good value")); + // Topology mesh list + parlst.addParam(new RichMesh( "userMesh", md.mm(), + "Topology mesh", + "This mesh will be used as the new base topology, and will be replaced by the new mesh")); + // Original mesh list + parlst.addParam(new RichMesh( "inMesh", target, + "Original mesh", + "The new mesh will be elaborated using this model")); + break; + + default : assert(0); + } +} + +// +// Apply filter +// +bool FilterTopoPlugin::applyFilter(QAction *filter, MeshModel &m, RichParameterSet & par, vcg::CallBackPos *cb) +{ + // To run the retopology algorithm an istance of RetopoMeshBuilder is needed + RetopMeshBuilder rm; + + // Load topology mesh + MeshModel *userMesh = par.getMesh("userMesh"); + // Load (input) original mesh + MeshModel *inMesh = par.getMesh("inMesh"); + // Load iterations value + int it = par.getInt("it"); + // Load distance value + float dist = par.getAbsPerc("dist"); + + // Destination meshmodel: retopology mesh will replace flat topology mesh + MeshModel * outM = par.getMesh("userMesh"); + + // Prepare mesh + inMesh->updateDataMask(MeshModel::MM_FACEMARK); + tri::UpdateNormals::PerFaceNormalized(inMesh->cm); + tri::UpdateFlags::FaceProjection(inMesh->cm); + + // Init the retopology builder with original input mesh and distance value + rm.init(inMesh, dist); + // Apply the algorithm + return rm.applyTopoMesh(*userMesh, *inMesh, it, dist, *outM); +} + +Q_EXPORT_PLUGIN(FilterTopoPlugin) diff --git a/src/fgt/edit_virtual_scan/vs/sampler.h b/src/fgt/edit_virtual_scan/vs/sampler.h index 966b148a6..dfd9fe587 100644 --- a/src/fgt/edit_virtual_scan/vs/sampler.h +++ b/src/fgt/edit_virtual_scan/vs/sampler.h @@ -1,195 +1,195 @@ -#ifndef SAMPLER_H -#define SAMPLER_H - -#include "stages.h" - -#include -#include -#include - -#include - -namespace vs -{ - class SamplerListener - { - - public: - virtual void startingSetup ( void ) = 0; - virtual void setupComplete ( int povs ) = 0; - virtual void povProcessed ( int pov, int samples ) = 0; - virtual void startingFeatureSampling ( void ) = 0; - - }; - - template< class MeshType > - class Sampler - { - - public: - - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::CoordType CoordType; - - static void generateSamples - ( VSParameters* params, - MeshModel* inputMeshModel, - MeshType* uniformSamplesMesh, - MeshType* featureSamplesMesh, - SamplerListener* listener = 0 ) - { - if( listener ){ listener->startingSetup(); } - - // OpenGL initialization - GLenum err = glGetError(); - if( err != GL_NO_ERROR ) - { - const GLubyte* errStr = gluErrorString( err ); - qDebug( "OpenGL error: %s", (const char*)errStr ); - assert( 0 ); - } - - glClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); - glEnable( GL_DEPTH_TEST ); - glEnable( GL_TEXTURE_2D ); - - // prepare input/output mesh - vcg::tri::UpdateBounding< CMeshO >::Box( inputMeshModel->cm ); - uniformSamplesMesh->Clear(); - featureSamplesMesh->Clear(); - - // initializes resources - Resources resources( params ); - resources.initialize(); - resources.fbo->bind(); - - // builds stages - AttributesExtractor extractor ( inputMeshModel, &resources ); - ConeFilter coneFilter ( &resources ); - Compactor inputCompactor ( &resources, "out_mask", "input_", "best_" ); - Killer killer ( &resources ); - MaskUpdater maskUpdater ( &resources ); - Compactor povCompactor ( &resources, "pov_alive_mask", "input_", "current_best_" ); - Compactor deadsCompactor ( &resources, "killer_map", "dead_map", "compacted_deads", true ); - DeadMasker deadMasker ( &resources ); - AliveMasker aliveMasker ( &resources ); - Compactor aliveCompactor ( &resources, "alive_mask", "best_", "alive_" ); - FinalCompactor finalCompactor ( &resources ); - FeatureDetector detector ( &resources ); - - GLint* samplesCount = &( resources.buffers[ "best_position" ]->elements ); - if( listener ){ listener->setupComplete( resources.params->povs ); } - - // *** sampling *** - - for( int i=0; i<2; i++ ) - { - if( i==1 ) - { - if( listener ){ listener->startingFeatureSampling(); } - resources.changeResolution(); - extractor.currentPov = 0; - } - - // first pov - extractor.go(); - if( i==0 ){ coneFilter.go(); }else{ detector.go(); } - inputCompactor.go(); - if( listener ){ listener->povProcessed( 1, *samplesCount ); } - - // subsequent povs - while( extractor.nextPov() ) - { - extractor.go(); - - if( i==0 ) - { - coneFilter.go(); - } - else - { - detector.go(); - } - - killer.go(); - maskUpdater.go(); - povCompactor.go(); - deadsCompactor.go(); - deadMasker.go(); - aliveMasker.go(); - aliveCompactor.go(); - finalCompactor.go(); - - if( listener ){ listener->povProcessed( extractor.currentPov + 1, *samplesCount ); } - } - - // download samples - downloadSamples( &resources, (i==0)? uniformSamplesMesh : featureSamplesMesh ); - } - - // **************** - - // finalize resources - resources.fbo->unbind(); - resources.finalize(); - - err = glGetError(); - if( err != GL_NO_ERROR ) - { - const GLubyte* errStr = gluErrorString( err ); - qDebug( "OpenGL error: %s", (const char*)errStr ); - assert( 0 ); - } - } - - private: - - static void downloadSamples( Resources* resources, MeshType* target ) - { - // download samples from the gpu - PixelData* position = resources->buffers[ "best_position" ]; - PixelData* normal = resources->buffers[ "best_normal" ]; - PixelData* color = resources->buffers[ "best_color" ]; - GLfloat* pos = position->download(); - GLfloat* nrm = normal->download(); - GLfloat* col = color->download(); - - GLfloat* posPix = pos; - GLfloat* nrmPix = nrm; - GLfloat* colPix = col; - - // append samples to output mesh - int samples = position->elements; - VertexIterator vi = vcg::tri::Allocator< MeshType >::AddVertices( *target, samples ); - - while( vi != target->vert.end() ) - { - (*vi).P() = CoordType( posPix[0], posPix[1], posPix[2] ); - posPix = &(posPix[3]); - - (*vi).N() = CoordType( nrmPix[0], nrmPix[1], nrmPix[2] ); - nrmPix = &(nrmPix[3]); - - for( int i=0; i<3; i++ ) - { - (*vi).C()[i] = (unsigned char)( colPix[i] * 255 ); - } - (*vi).C()[3] = (unsigned char)255; - colPix = &( colPix[3] ); - - vi++; - } - - // free downloaded samples - free( pos ); - free( nrm ); - free( col ); - - // re-compute bounding box - vcg::tri::UpdateBounding< MeshType >::Box( *target ); - } - }; - -} - -#endif // SAMPLER_H +#ifndef SAMPLER_H +#define SAMPLER_H + +#include "stages.h" + +#include +#include +#include + +#include + +namespace vs +{ + class SamplerListener + { + + public: + virtual void startingSetup ( void ) = 0; + virtual void setupComplete ( int povs ) = 0; + virtual void povProcessed ( int pov, int samples ) = 0; + virtual void startingFeatureSampling ( void ) = 0; + + }; + + template< class MeshType > + class Sampler + { + + public: + + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::CoordType CoordType; + + static void generateSamples + ( VSParameters* params, + MeshModel* inputMeshModel, + MeshType* uniformSamplesMesh, + MeshType* featureSamplesMesh, + SamplerListener* listener = 0 ) + { + if( listener ){ listener->startingSetup(); } + + // OpenGL initialization + GLenum err = glGetError(); + if( err != GL_NO_ERROR ) + { + const GLubyte* errStr = gluErrorString( err ); + qDebug( "OpenGL error: %s", (const char*)errStr ); + assert( 0 ); + } + + glClearColor( 1.0f, 1.0f, 1.0f, 1.0f ); + glEnable( GL_DEPTH_TEST ); + glEnable( GL_TEXTURE_2D ); + + // prepare input/output mesh + vcg::tri::UpdateBounding< CMeshO >::Box( inputMeshModel->cm ); + uniformSamplesMesh->Clear(); + featureSamplesMesh->Clear(); + + // initializes resources + Resources resources( params ); + resources.initialize(); + resources.fbo->bind(); + + // builds stages + AttributesExtractor extractor ( inputMeshModel, &resources ); + ConeFilter coneFilter ( &resources ); + Compactor inputCompactor ( &resources, "out_mask", "input_", "best_" ); + Killer killer ( &resources ); + MaskUpdater maskUpdater ( &resources ); + Compactor povCompactor ( &resources, "pov_alive_mask", "input_", "current_best_" ); + Compactor deadsCompactor ( &resources, "killer_map", "dead_map", "compacted_deads", true ); + DeadMasker deadMasker ( &resources ); + AliveMasker aliveMasker ( &resources ); + Compactor aliveCompactor ( &resources, "alive_mask", "best_", "alive_" ); + FinalCompactor finalCompactor ( &resources ); + FeatureDetector detector ( &resources ); + + GLint* samplesCount = &( resources.buffers[ "best_position" ]->elements ); + if( listener ){ listener->setupComplete( resources.params->povs ); } + + // *** sampling *** + + for( int i=0; i<2; i++ ) + { + if( i==1 ) + { + if( listener ){ listener->startingFeatureSampling(); } + resources.changeResolution(); + extractor.currentPov = 0; + } + + // first pov + extractor.go(); + if( i==0 ){ coneFilter.go(); }else{ detector.go(); } + inputCompactor.go(); + if( listener ){ listener->povProcessed( 1, *samplesCount ); } + + // subsequent povs + while( extractor.nextPov() ) + { + extractor.go(); + + if( i==0 ) + { + coneFilter.go(); + } + else + { + detector.go(); + } + + killer.go(); + maskUpdater.go(); + povCompactor.go(); + deadsCompactor.go(); + deadMasker.go(); + aliveMasker.go(); + aliveCompactor.go(); + finalCompactor.go(); + + if( listener ){ listener->povProcessed( extractor.currentPov + 1, *samplesCount ); } + } + + // download samples + downloadSamples( &resources, (i==0)? uniformSamplesMesh : featureSamplesMesh ); + } + + // **************** + + // finalize resources + resources.fbo->unbind(); + resources.finalize(); + + err = glGetError(); + if( err != GL_NO_ERROR ) + { + const GLubyte* errStr = gluErrorString( err ); + qDebug( "OpenGL error: %s", (const char*)errStr ); + assert( 0 ); + } + } + + private: + + static void downloadSamples( Resources* resources, MeshType* target ) + { + // download samples from the gpu + PixelData* position = resources->buffers[ "best_position" ]; + PixelData* normal = resources->buffers[ "best_normal" ]; + PixelData* color = resources->buffers[ "best_color" ]; + GLfloat* pos = position->download(); + GLfloat* nrm = normal->download(); + GLfloat* col = color->download(); + + GLfloat* posPix = pos; + GLfloat* nrmPix = nrm; + GLfloat* colPix = col; + + // append samples to output mesh + int samples = position->elements; + VertexIterator vi = vcg::tri::Allocator< MeshType >::AddVertices( *target, samples ); + + while( vi != target->vert.end() ) + { + (*vi).P() = CoordType( posPix[0], posPix[1], posPix[2] ); + posPix = &(posPix[3]); + + (*vi).N() = CoordType( nrmPix[0], nrmPix[1], nrmPix[2] ); + nrmPix = &(nrmPix[3]); + + for( int i=0; i<3; i++ ) + { + (*vi).C()[i] = (unsigned char)( colPix[i] * 255 ); + } + (*vi).C()[3] = (unsigned char)255; + colPix = &( colPix[3] ); + + vi++; + } + + // free downloaded samples + free( pos ); + free( nrm ); + free( col ); + + // re-compute bounding box + vcg::tri::UpdateBounding< MeshType >::Box( *target ); + } + }; + +} + +#endif // SAMPLER_H diff --git a/src/fgt/edit_virtual_scan/vs/simple_renderer.h b/src/fgt/edit_virtual_scan/vs/simple_renderer.h index ee16982a5..9075cead1 100644 --- a/src/fgt/edit_virtual_scan/vs/simple_renderer.h +++ b/src/fgt/edit_virtual_scan/vs/simple_renderer.h @@ -1,210 +1,210 @@ -#ifndef SIMPLE_RENDERER_H -#define SIMPLE_RENDERER_H - -#include -#include -#include -#include -#include -#include - -#include "assert.h" -#include - -#include - -namespace vs -{ - template< class MeshType > - class SimpleRenderer - { - - public: - SimpleRenderer( MeshType* m ) - { - assert(m && m->vert.size() > 0 && m->face.size() > 0 ); - this->m = m; - this->buffersOk = false; - //createBuffers(); - } - - ~SimpleRenderer( void ) - { - //glDeleteBuffers( 4, buffer ); - } - - void render( void ) - { - /* - for( int i=0; i<4; i++ ) - { - assert( glIsBuffer( buffer[i] ) == GL_TRUE ); - } - - glBindBuffer( GL_ARRAY_BUFFER, buffer[0] ); // coordinates - glVertexPointer( (GLint)3, GL_FLOAT, 0, 0 ); - glEnableClientState( GL_VERTEX_ARRAY ); - - glBindBuffer( GL_ARRAY_BUFFER, buffer[1] ); // normals - glNormalPointer( GL_FLOAT, 0, 0 ); - glEnableClientState( GL_NORMAL_ARRAY ); - - glBindBuffer( GL_ARRAY_BUFFER, buffer[2] ); // colors - glColorPointer( (GLint)4, GL_UNSIGNED_BYTE, 0, 0 ); - glEnableClientState( GL_COLOR_ARRAY ); - - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffer[3] ); // indices - - glDrawElements( GL_TRIANGLES, elementsToDraw, GL_UNSIGNED_INT, 0 ); - - glDisableClientState( GL_COLOR_ARRAY ); - glDisableClientState( GL_NORMAL_ARRAY ); - glDisableClientState( GL_VERTEX_ARRAY ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); - glBindBuffer( GL_ARRAY_BUFFER, 0 ); - */ - - // immediate-mode rendering - if( m->vert.size() == 0 ) return; - - typename MeshType::FaceIterator fi; - int i = 0; - vcg::Point3f* pp = 0; - vcg::Point3f* np = 0; - - glBegin( GL_TRIANGLES ); - - for( fi = m->face.begin(); fi != m->face.end(); ++fi ) - { - for( i = 0; i < 3; i++ ) - { - np = &( (*fi).V(i)->N() ); - glNormal3f( np->X(), np->Y(), np->Z() ); - - pp = &( (*fi).V(i)->P() ); - glVertex3f( pp->X(), pp->Y(), pp->Z() ); - } - } - - glEnd(); - } - - private: - - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::ScalarType ScalarType; - - MeshType* m; - GLuint buffer[4]; // coords, normals, colors, indices - GLsizei elementsToDraw; // 3 * face_number - bool buffersOk; // true => use vbo's - - // create the buffer objects to hold mesh data - void createBuffers( void ) - { - assert( glGetError() == GL_NO_ERROR ); - glGenBuffers( 4, buffer ); - - // prepare buffers - size_t scalarTypeSize = sizeof( ScalarType ); // size of scalar type - size_t vertexSize = 3 * scalarTypeSize; // size of a vertex - size_t verticesSize = m->vn * vertexSize; // size of vertices - - void* vData = malloc( verticesSize ); // vertices buffer - void* nData = malloc( verticesSize ); // normals buffer - assert( vData && nData ); - - - // assume that the color type is Color4b - size_t colorSize = 4 * m->vn; - void* cData = malloc( colorSize ); - assert( cData ); - bool perVertexColor = m->HasPerVertexColor(); - - // if per-vertex color is not available, we use per-mesh color - vcg::Color4b defaultColor = m->C(); - - ScalarType* vP = (ScalarType*)vData; - ScalarType* nP = (ScalarType*)nData; - unsigned char* cP = (unsigned char*)cData; - map< VertexPointer, unsigned int >* ptrToInt = new map< VertexPointer, unsigned int >(); - unsigned int vertexIndex = 0; - - for( VertexIterator vi = m->vert.begin(); vi != m->vert.end(); ++vi ) - { - for( int i=0; i<3; i++ ) - { - vP[i] = (*vi).P()[i]; - nP[i] = (*vi).N()[i]; - } - - for( int i=0; i<4; i++ ) - { - cP[i] = (perVertexColor? (*vi).C()[i] : defaultColor[i] ); - } - - vP = &( vP[3] ); - nP = &( nP[3] ); - cP = &( cP[4] ); - (*ptrToInt)[ &(*vi) ] = vertexIndex; - vertexIndex++; - } - - // fills coordinates buffer - glBindBuffer( GL_ARRAY_BUFFER, buffer[0] ); - glBufferData( GL_ARRAY_BUFFER, verticesSize, vData, GL_STATIC_DRAW ); - glVertexPointer( (GLint)3, GL_FLOAT, 0, 0 ); - glBindBuffer( GL_ARRAY_BUFFER, 0 ); - free( vData ); - - assert( glGetError() == GL_NO_ERROR ); - - // fills normals buffer - glBindBuffer( GL_ARRAY_BUFFER, buffer[1] ); - glBufferData( GL_ARRAY_BUFFER, verticesSize, nData, GL_STATIC_DRAW ); - glBindBuffer( GL_ARRAY_BUFFER, 0 ); - free( nData ); - - assert( glGetError() == GL_NO_ERROR ); - - // fills colors buffer - glBindBuffer( GL_ARRAY_BUFFER, buffer[2] ); - glBufferData( GL_ARRAY_BUFFER, colorSize, cData, GL_STATIC_DRAW ); - glBindBuffer( GL_ARRAY_BUFFER, 0 ); - free( cData ); - - assert( glGetError() == GL_NO_ERROR ); - - // prepare indices buffer - elementsToDraw = (GLsizei)( m->fn * 3 ); // every face has three indices - size_t indicesSize = ((size_t)elementsToDraw) * sizeof(unsigned int); - void* iData = malloc( indicesSize ); - assert( iData ); - unsigned int* iP = (unsigned int*)iData; - for( FaceIterator fi = m->face.begin(); fi != m->face.end(); ++fi ) - { - for( unsigned int i = 0; i < 3; i++ ) - { - iP[ i ] = (*ptrToInt)[ (*fi).V(i) ]; - } - iP = &( iP[3] ); - } - - // fills indices buffer - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffer[3] ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, indicesSize, iData, GL_STATIC_DRAW ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); - free( iData ); - delete ptrToInt; - - assert( glGetError() == GL_NO_ERROR ); - } - - }; -} - - -#endif // SIMPLE_RENDERER_H +#ifndef SIMPLE_RENDERER_H +#define SIMPLE_RENDERER_H + +#include +#include +#include +#include +#include +#include + +#include "assert.h" +#include + +#include + +namespace vs +{ + template< class MeshType > + class SimpleRenderer + { + + public: + SimpleRenderer( MeshType* m ) + { + assert(m && m->vert.size() > 0 && m->face.size() > 0 ); + this->m = m; + this->buffersOk = false; + //createBuffers(); + } + + ~SimpleRenderer( void ) + { + //glDeleteBuffers( 4, buffer ); + } + + void render( void ) + { + /* + for( int i=0; i<4; i++ ) + { + assert( glIsBuffer( buffer[i] ) == GL_TRUE ); + } + + glBindBuffer( GL_ARRAY_BUFFER, buffer[0] ); // coordinates + glVertexPointer( (GLint)3, GL_FLOAT, 0, 0 ); + glEnableClientState( GL_VERTEX_ARRAY ); + + glBindBuffer( GL_ARRAY_BUFFER, buffer[1] ); // normals + glNormalPointer( GL_FLOAT, 0, 0 ); + glEnableClientState( GL_NORMAL_ARRAY ); + + glBindBuffer( GL_ARRAY_BUFFER, buffer[2] ); // colors + glColorPointer( (GLint)4, GL_UNSIGNED_BYTE, 0, 0 ); + glEnableClientState( GL_COLOR_ARRAY ); + + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffer[3] ); // indices + + glDrawElements( GL_TRIANGLES, elementsToDraw, GL_UNSIGNED_INT, 0 ); + + glDisableClientState( GL_COLOR_ARRAY ); + glDisableClientState( GL_NORMAL_ARRAY ); + glDisableClientState( GL_VERTEX_ARRAY ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + */ + + // immediate-mode rendering + if( m->vert.size() == 0 ) return; + + typename MeshType::FaceIterator fi; + int i = 0; + vcg::Point3f* pp = 0; + vcg::Point3f* np = 0; + + glBegin( GL_TRIANGLES ); + + for( fi = m->face.begin(); fi != m->face.end(); ++fi ) + { + for( i = 0; i < 3; i++ ) + { + np = &( (*fi).V(i)->N() ); + glNormal3f( np->X(), np->Y(), np->Z() ); + + pp = &( (*fi).V(i)->P() ); + glVertex3f( pp->X(), pp->Y(), pp->Z() ); + } + } + + glEnd(); + } + + private: + + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::ScalarType ScalarType; + + MeshType* m; + GLuint buffer[4]; // coords, normals, colors, indices + GLsizei elementsToDraw; // 3 * face_number + bool buffersOk; // true => use vbo's + + // create the buffer objects to hold mesh data + void createBuffers( void ) + { + assert( glGetError() == GL_NO_ERROR ); + glGenBuffers( 4, buffer ); + + // prepare buffers + size_t scalarTypeSize = sizeof( ScalarType ); // size of scalar type + size_t vertexSize = 3 * scalarTypeSize; // size of a vertex + size_t verticesSize = m->vn * vertexSize; // size of vertices + + void* vData = malloc( verticesSize ); // vertices buffer + void* nData = malloc( verticesSize ); // normals buffer + assert( vData && nData ); + + + // assume that the color type is Color4b + size_t colorSize = 4 * m->vn; + void* cData = malloc( colorSize ); + assert( cData ); + bool perVertexColor = m->HasPerVertexColor(); + + // if per-vertex color is not available, we use per-mesh color + vcg::Color4b defaultColor = m->C(); + + ScalarType* vP = (ScalarType*)vData; + ScalarType* nP = (ScalarType*)nData; + unsigned char* cP = (unsigned char*)cData; + map< VertexPointer, unsigned int >* ptrToInt = new map< VertexPointer, unsigned int >(); + unsigned int vertexIndex = 0; + + for( VertexIterator vi = m->vert.begin(); vi != m->vert.end(); ++vi ) + { + for( int i=0; i<3; i++ ) + { + vP[i] = (*vi).P()[i]; + nP[i] = (*vi).N()[i]; + } + + for( int i=0; i<4; i++ ) + { + cP[i] = (perVertexColor? (*vi).C()[i] : defaultColor[i] ); + } + + vP = &( vP[3] ); + nP = &( nP[3] ); + cP = &( cP[4] ); + (*ptrToInt)[ &(*vi) ] = vertexIndex; + vertexIndex++; + } + + // fills coordinates buffer + glBindBuffer( GL_ARRAY_BUFFER, buffer[0] ); + glBufferData( GL_ARRAY_BUFFER, verticesSize, vData, GL_STATIC_DRAW ); + glVertexPointer( (GLint)3, GL_FLOAT, 0, 0 ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + free( vData ); + + assert( glGetError() == GL_NO_ERROR ); + + // fills normals buffer + glBindBuffer( GL_ARRAY_BUFFER, buffer[1] ); + glBufferData( GL_ARRAY_BUFFER, verticesSize, nData, GL_STATIC_DRAW ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + free( nData ); + + assert( glGetError() == GL_NO_ERROR ); + + // fills colors buffer + glBindBuffer( GL_ARRAY_BUFFER, buffer[2] ); + glBufferData( GL_ARRAY_BUFFER, colorSize, cData, GL_STATIC_DRAW ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + free( cData ); + + assert( glGetError() == GL_NO_ERROR ); + + // prepare indices buffer + elementsToDraw = (GLsizei)( m->fn * 3 ); // every face has three indices + size_t indicesSize = ((size_t)elementsToDraw) * sizeof(unsigned int); + void* iData = malloc( indicesSize ); + assert( iData ); + unsigned int* iP = (unsigned int*)iData; + for( FaceIterator fi = m->face.begin(); fi != m->face.end(); ++fi ) + { + for( unsigned int i = 0; i < 3; i++ ) + { + iP[ i ] = (*ptrToInt)[ (*fi).V(i) ]; + } + iP = &( iP[3] ); + } + + // fills indices buffer + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffer[3] ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, indicesSize, iData, GL_STATIC_DRAW ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); + free( iData ); + delete ptrToInt; + + assert( glGetError() == GL_NO_ERROR ); + } + + }; +} + + +#endif // SIMPLE_RENDERER_H diff --git a/src/fgt/editpaint/editpaint.cpp b/src/fgt/editpaint/editpaint.cpp index ea8255017..1cb70dc9d 100644 --- a/src/fgt/editpaint/editpaint.cpp +++ b/src/fgt/editpaint/editpaint.cpp @@ -22,17 +22,7 @@ ****************************************************************************/ #include "editpaint.h" -#include -#include - -#include -#include #include -#include -#include -#include -#include -#include #include using namespace std; diff --git a/src/fgt/filter_aging/filter_aging.cpp b/src/fgt/filter_aging/filter_aging.cpp index f4a04c56c..26a55c9ba 100644 --- a/src/fgt/filter_aging/filter_aging.cpp +++ b/src/fgt/filter_aging/filter_aging.cpp @@ -22,18 +22,12 @@ ****************************************************************************/ -/* Standard includes */ -#include -#include - -/* Local includes */ #include "filter_aging.h" using namespace vcg; /* VCG includes */ -#include -#include -#include -#include +#include +#include +#include #include diff --git a/src/fgt/filter_aging/filter_aging.h b/src/fgt/filter_aging/filter_aging.h index 77854d223..25ac51a2d 100644 --- a/src/fgt/filter_aging/filter_aging.h +++ b/src/fgt/filter_aging/filter_aging.h @@ -25,11 +25,8 @@ #ifndef GEOMETRYAGINGPLUGIN_H #define GEOMETRYAGINGPLUGIN_H - -#include - #include -#include +#include #include #include "edgepred.h"