diff --git a/vcg/complex/algorithms/symmetry.h b/vcg/complex/algorithms/symmetry.h new file mode 100644 index 00000000..20bd2289 --- /dev/null +++ b/vcg/complex/algorithms/symmetry.h @@ -0,0 +1,230 @@ +#ifndef VCG_SYMMETRY_H +#define VCG_SYMMETRY_H + +#include +#include +#include +#include +#include + +namespace vcg { +namespace tri { + +template +class ExtrinsicPlaneSymmetry +{ + typedef typename TriMeshType::VertexType VertexType; + typedef typename TriMeshType::FaceType FaceType; + typedef typename TriMeshType::CoordType CoordType; + typedef typename TriMeshType::ScalarType ScalarType; + + TriMeshType &tri_mesh; + + CoordType AlignZeroTr; + + std::vector > Weight; + //std::vector > > VotingVertx; + std::vector > > VotingPos; + + std::vector Votes; + + TriMeshType *sphere; + typename vcg::GridStaticPtr GridSph; + + ScalarType RadiusInterval; + ScalarType MaxRadius; + int radiusSph; + + std::vector > SortedPlanes; + std::vector > SymmetricPlanes; + + int Bucket(const vcg::Plane3 &Pl) + { + ScalarType Offset=Pl.Offset(); + CoordType Direction=Pl.Direction(); + Direction.Normalize(); + ///get the offset interval + int OffsetI=floor((Offset/RadiusInterval)+0.5); + assert(OffsetIbbox.Diag(); + ScalarType MinD; + CoordType ClosePt; + FaceType *choosen=NULL; + choosen=vcg::tri::GetClosestFaceBase(*sphere,GridSph,Direction,MaxD,MinD,ClosePt); + assert(choosen!=NULL); + int IndexF=choosen-&(sphere->face[0]); + ///compose the final index + int OffsetRadius=OffsetI * (sphere->face.size()); + return(OffsetRadius+IndexF); + } + + void Elect(CoordType p0,CoordType p1) + { + CoordType AvP=(p0+p1)/2.0; + AvP-=AlignZeroTr; + CoordType Direction=p0-p1; + Direction.Normalize(); + vcg::Plane3 Pl; + Pl.Init(AvP,Direction); + //invert if needed + if (Pl.Offset()<0) + { + ScalarType Off=Pl.Offset(); + CoordType Dir=Pl.Direction(); + Pl.Set(-Dir,-Off); + } + int index=Bucket(Pl); + assert(index>=0); + assert(index<(int)Votes.size()); + ScalarType VoteValue=1; + Votes[index]+=VoteValue; + Weight[index].push_back(VoteValue); + VotingPos[index].push_back(std::pair (p0,p1)); + } + + vcg::Plane3 GetInterpolatedPlane(int &Index) + { + ///then fit the plane + CoordType AvDir=CoordType(0,0,0); + ScalarType WSum=0; + ScalarType AvOffset=0; + for (size_t i=0;i Pl; + Pl.Set(AvDir,AvOffset); + return Pl; + } + + vcg::Plane3 GetBasePlane(int &Index) + { + ///get offset value + int OffsetIndex=Index/sphere->face.size(); + ScalarType OffsetVal=OffsetIndex*RadiusInterval; + int DirectionIndex=Index % sphere->face.size(); + CoordType PlaneDirection=(sphere->face[DirectionIndex].P(0)+ + sphere->face[DirectionIndex].P(1)+ + sphere->face[DirectionIndex].P(2))/3.0; + PlaneDirection.Normalize(); + CoordType CenterPl=PlaneDirection*OffsetVal; + CenterPl+=AlignZeroTr; + vcg::Plane3 RetPl; + RetPl.Init(CenterPl,PlaneDirection); + return RetPl; + } + + void InitSymmetricPlanes(const int SubN=4) + { + assert(SortedPlanes.size()>0); + SymmetricPlanes.clear(); + int BestN=pow((ScalarType)2,(ScalarType)SubN); + if (BestN>=(int)SortedPlanes.size())BestN=SortedPlanes.size()-1; + for (size_t j=SortedPlanes.size()-1;j>SortedPlanes.size()-1-SubN;j--) + { + int Index=SortedPlanes[j].second; + SymmetricPlanes.push_back(GetInterpolatedPlane(Index)); + } + } + + +public: + + void GetPlanes(std::vector > &Planes,int Num) + { + if (SymmetricPlanes.size()==0)return; + + for (int i=0;i::FaceFace(tri_mesh); + vcg::tri::UpdateFlags::FaceBorderFromFF(tri_mesh); + vcg::tri::UpdateFlags::VertexBorderFromFace(tri_mesh); + } + AlignZeroTr=tri_mesh.bbox.Center(); + + ///initialize the mesh + if (sphere!=NULL) + sphere->Clear(); + else + sphere=new TriMeshType(); + + //create the sphere + vcg::tri::Sphere(*sphere,SubDirections); + sphere->UpdateAttributes(); + + ///initialize grid + GridSph.Set(sphere->face.begin(),sphere->face.end()); + + ///then get radius division steps + ScalarType MaxRadius=tri_mesh.bbox.Diag()/2; + int AreaSph=sphere->fn; + radiusSph=ceil(sqrt((ScalarType)AreaSph/4.0*M_PI)); + RadiusInterval=MaxRadius/(ScalarType)radiusSph; + + ///and finally allocate space for votes + Votes.resize(radiusSph*sphere->fn,0); + + Weight.resize(radiusSph*sphere->fn); + VotingPos.resize(radiusSph*sphere->fn); + + ///then count votes + for (size_t i=0;iIsB())&&(v1->IsB()))))continue; + Elect(v0->P(),v1->P()); + } + + SortedPlanes.resize(Votes.size()); + for (size_t i=0;i(Votes[i],i); + + std::sort(SortedPlanes.begin(),SortedPlanes.end()); + + InitSymmetricPlanes(NumberBestPlanes); + + } + + ExtrinsicPlaneSymmetry(TriMeshType &_tri_mesh):tri_mesh(_tri_mesh) + { + sphere=NULL; + RadiusInterval=-1; + radiusSph=-1; + } + +}; + +}///end namespace vcg +}///end namespace tri +#endif