2015-12-29 08:22:13 +01:00
/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
2016-06-13 07:29:25 +02:00
* Copyright ( C ) 2004 - 2016 \ / ) \ / *
2015-12-29 08:22:13 +01:00
* 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 __VCGLIB_CURVE_ON_SURF_H
# define __VCGLIB_CURVE_ON_SURF_H
# include <vcg/complex/complex.h>
# include <vcg/simplex/face/topology.h>
# include <vcg/complex/algorithms/update/topology.h>
# include <vcg/complex/algorithms/update/color.h>
# include <vcg/complex/algorithms/update/normal.h>
# include <vcg/complex/algorithms/update/quality.h>
# include <vcg/complex/algorithms/clean.h>
# include <vcg/complex/algorithms/refine.h>
# include <vcg/complex/algorithms/create/platonic.h>
2017-09-05 00:38:43 +02:00
# include <vcg/complex/algorithms/point_sampling.h>
2015-12-29 08:22:13 +01:00
# include <vcg/space/index/grid_static_ptr.h>
# include <vcg/space/index/kdtree/kdtree.h>
# include <vcg/math/histogram.h>
# include <vcg/space/distance3.h>
2015-12-31 12:47:13 +01:00
# include <vcg/complex/algorithms/attribute_seam.h>
2016-04-12 10:35:21 +02:00
# include <wrap/io_trimesh/export_ply.h>
2015-12-29 08:22:13 +01:00
namespace vcg {
namespace tri {
/// \ingroup trimesh
/// \brief A class for managing curves on a 2manifold.
/**
This class is used to project / simplify / smooth polylines over a triangulated surface .
*/
template < class MeshType >
class CoM
{
public :
typedef typename MeshType : : ScalarType ScalarType ;
2017-09-07 19:02:13 +02:00
typedef typename MeshType : : CoordType CoordType ;
2015-12-29 08:22:13 +01:00
typedef typename MeshType : : VertexType VertexType ;
typedef typename MeshType : : VertexPointer VertexPointer ;
typedef typename MeshType : : VertexIterator VertexIterator ;
typedef typename MeshType : : EdgeIterator EdgeIterator ;
typedef typename MeshType : : EdgeType EdgeType ;
typedef typename MeshType : : FaceType FaceType ;
typedef typename MeshType : : FacePointer FacePointer ;
typedef typename MeshType : : FaceIterator FaceIterator ;
2017-09-07 19:02:13 +02:00
typedef Box3 < ScalarType > Box3Type ;
typedef Segment3 < ScalarType > Segment3Type ;
2015-12-29 08:22:13 +01:00
typedef typename vcg : : GridStaticPtr < FaceType , ScalarType > MeshGrid ;
typedef typename vcg : : GridStaticPtr < EdgeType , ScalarType > EdgeGrid ;
typedef typename face : : Pos < FaceType > PosType ;
2017-08-30 16:03:46 +02:00
typedef typename tri : : UpdateTopology < MeshType > : : PEdge PEdge ;
2015-12-29 08:22:13 +01:00
class Param
{
public :
ScalarType surfDistThr ; // Distance between surface and curve; used in simplify and refine
ScalarType polyDistThr ; // Distance between the
ScalarType minRefEdgeLen ; // Minimal admitted Edge Lenght (used in refine: never make edge shorther than this value)
2017-09-05 00:38:43 +02:00
ScalarType maxSimpEdgeLen ; // Maximal admitted Edge Lenght (used in simplify: never make edges longer than this value)
2015-12-29 08:22:13 +01:00
ScalarType maxSmoothDelta ; // The maximum movement that is admitted during smoothing.
2015-12-31 12:47:13 +01:00
ScalarType maxSnapThr ; // The maximum distance allowed when snapping a vertex of the polyline onto a mesh vertex
ScalarType gridBailout ; // The maximum distance bailout used in grid sampling
2017-08-30 16:03:46 +02:00
ScalarType barycentricSnapThr ; // The maximum distance bailout used in grid sampling
2015-12-29 08:22:13 +01:00
Param ( MeshType & m ) { Default ( m ) ; }
void Default ( MeshType & m )
{
2016-04-12 10:35:21 +02:00
surfDistThr = m . bbox . Diag ( ) / 1000.0 ;
2016-01-11 16:06:35 +01:00
polyDistThr = m . bbox . Diag ( ) / 5000.0 ;
2015-12-31 12:47:13 +01:00
minRefEdgeLen = m . bbox . Diag ( ) / 16000.0 ;
2017-08-30 16:03:46 +02:00
maxSimpEdgeLen = m . bbox . Diag ( ) / 100.0 ;
2015-12-31 12:47:13 +01:00
maxSmoothDelta = m . bbox . Diag ( ) / 100.0 ;
2017-08-30 16:03:46 +02:00
maxSnapThr = m . bbox . Diag ( ) / 1000.0 ;
2015-12-31 12:47:13 +01:00
gridBailout = m . bbox . Diag ( ) / 20.0 ;
2017-08-30 16:03:46 +02:00
barycentricSnapThr = 0.05 ;
2015-12-29 08:22:13 +01:00
}
void Dump ( ) const
{
2015-12-31 12:47:13 +01:00
printf ( " surfDistThr = %6.4f \n " , surfDistThr ) ;
printf ( " polyDistThr = %6.4f \n " , polyDistThr ) ;
printf ( " minRefEdgeLen = %6.4f \n " , minRefEdgeLen ) ;
printf ( " maxSimpEdgeLen = %6.4f \n " , maxSimpEdgeLen ) ;
printf ( " maxSmoothDelta = %6.4f \n " , maxSmoothDelta ) ;
2015-12-29 08:22:13 +01:00
}
} ;
// The Data Members
MeshType & base ;
MeshGrid uniformGrid ;
2016-04-12 10:35:21 +02:00
2015-12-29 08:22:13 +01:00
Param par ;
CoM ( MeshType & _m ) : base ( _m ) , par ( _m ) { }
2017-08-30 16:03:46 +02:00
FaceType * GetClosestFace ( const CoordType & p )
2016-04-12 10:35:21 +02:00
{
2017-09-05 00:38:43 +02:00
ScalarType closestDist ;
2017-08-30 16:03:46 +02:00
CoordType closestP ;
return vcg : : tri : : GetClosestFaceBase ( base , uniformGrid , p , p . gridBailout , closestDist , closestP ) ;
2016-04-12 10:35:21 +02:00
}
2017-08-30 16:03:46 +02:00
FaceType * GetClosestFaceIP ( const CoordType & p , CoordType & ip )
2016-04-12 10:35:21 +02:00
{
2017-09-05 00:38:43 +02:00
ScalarType closestDist ;
2017-08-30 16:03:46 +02:00
CoordType closestP , closestN ;
return vcg : : tri : : GetClosestFaceBase ( base , uniformGrid , p , this - > par . gridBailout , closestDist , closestP , closestN , ip ) ;
2016-04-12 10:35:21 +02:00
}
2017-08-30 16:03:46 +02:00
2017-11-23 19:14:02 +01:00
FaceType * GetClosestFaceIP ( const CoordType & p , CoordType & ip , CoordType & in )
{
ScalarType closestDist ;
CoordType closestP ;
return vcg : : tri : : GetClosestFaceBase ( base , uniformGrid , p , this - > par . gridBailout , closestDist , closestP , in , ip ) ;
}
2017-08-30 16:03:46 +02:00
FaceType * GetClosestFacePoint ( const CoordType & p , CoordType & closestP )
{
2017-09-05 00:38:43 +02:00
ScalarType closestDist ;
2017-08-30 16:03:46 +02:00
return vcg : : tri : : GetClosestFaceBase ( base , uniformGrid , p , this - > par . gridBailout , closestDist , closestP ) ;
2016-04-12 10:35:21 +02:00
}
2017-08-30 16:03:46 +02:00
bool IsSnappedEdge ( CoordType & ip , int & ei )
2016-06-13 06:53:48 +02:00
{
2017-08-30 16:03:46 +02:00
for ( int i = 0 ; i < 3 ; + + i )
if ( ip [ i ] > 0.0 & & ip [ ( i + 1 ) % 3 ] > 0.0 & & ip [ ( i + 2 ) % 3 ] = = 0.0 ) {
ei = i ;
return true ;
2016-06-13 06:53:48 +02:00
}
2017-08-30 16:03:46 +02:00
ei = - 1 ;
return false ;
2016-06-13 06:53:48 +02:00
}
2017-08-30 16:03:46 +02:00
// Given a baricentric coordinate finds that we assume that snaps onto an edge, it finds the vertex on which it is snapping
bool IsSnappedVertex ( CoordType & ip , int & vi )
2015-12-29 08:22:13 +01:00
{
2017-08-30 16:03:46 +02:00
for ( int i = 0 ; i < 3 ; + + i )
if ( ip [ i ] = = 1.0 & & ip [ ( i + 1 ) % 3 ] = = 0.0 & & ip [ ( i + 2 ) % 3 ] = = 0.0 ) {
vi = i ;
return true ;
2015-12-29 08:22:13 +01:00
}
2017-08-30 16:03:46 +02:00
vi = - 1 ;
return false ;
2015-12-29 08:22:13 +01:00
}
2017-08-30 16:03:46 +02:00
// Given a baricentric coordinate finds that we assume that snaps onto an edge, it finds the vertex on which it is snapping
VertexPointer FindVertexSnap ( FacePointer fp , CoordType & ip )
2015-12-29 08:22:13 +01:00
{
for ( int i = 0 ; i < 3 ; + + i )
2017-08-30 16:03:46 +02:00
if ( ip [ i ] = = 1.0 & & ip [ ( i + 1 ) % 3 ] = = 0.0 & & ip [ ( i + 2 ) % 3 ] = = 0.0 ) return fp - > V ( i ) ;
return 0 ;
}
2015-12-29 08:22:13 +01:00
2016-04-12 10:35:21 +02:00
2017-08-30 16:03:46 +02:00
/**
* @ brief MarkFauxEdgeWithPolyLine marks the edges of basemesh as non - faux when they coincide with the polyline ones *
* @ param poly
* @ return true if all the edges of the polyline are snapped onto the mesh .
*
2017-09-05 00:38:43 +02:00
* Use this function together with the CutMeshAlongCrease function to actually cut the mesh with a snapped polyline .
2016-04-12 10:35:21 +02:00
*
*/
2017-12-21 01:16:03 +01:00
bool MarkFauxEdgeWithPolyLine ( MeshType & poly , bool markFlag = true )
2016-04-12 10:35:21 +02:00
{
2017-12-21 01:16:03 +01:00
if ( markFlag ) tri : : UpdateFlags < MeshType > : : FaceSetF ( base ) ;
2017-08-30 16:03:46 +02:00
tri : : UpdateTopology < MeshType > : : VertexFace ( base ) ;
tri : : UpdateTopology < MeshType > : : FaceFace ( base ) ;
2017-12-21 01:16:03 +01:00
2017-08-30 16:03:46 +02:00
for ( EdgeIterator ei = poly . edge . begin ( ) ; ei ! = poly . edge . end ( ) ; + + ei )
2016-04-12 10:35:21 +02:00
{
2017-09-05 00:38:43 +02:00
CoordType ip0 , ip1 ;
2017-08-30 16:03:46 +02:00
FaceType * f0 = GetClosestFaceIP ( ei - > cP ( 0 ) , ip0 ) ;
FaceType * f1 = GetClosestFaceIP ( ei - > cP ( 1 ) , ip1 ) ;
if ( BarycentricSnap ( ip0 ) & & BarycentricSnap ( ip1 ) )
2016-04-12 10:35:21 +02:00
{
2017-08-30 16:03:46 +02:00
VertexPointer v0 = FindVertexSnap ( f0 , ip0 ) ;
VertexPointer v1 = FindVertexSnap ( f1 , ip1 ) ;
2017-12-21 01:18:19 +01:00
2017-12-21 01:16:03 +01:00
if ( v0 = = 0 | | v1 = = 0 ) return false ;
if ( v0 = = v1 ) return false ;
2017-12-21 01:18:19 +01:00
2017-08-30 16:03:46 +02:00
FacePointer ff0 , ff1 ;
int e0 , e1 ;
2017-12-21 01:16:03 +01:00
bool ret = face : : FindSharedFaces < FaceType > ( v0 , v1 , ff0 , ff1 , e0 , e1 ) ;
if ( ret ) {
assert ( ret ) ;
2017-09-05 00:38:43 +02:00
assert ( ff0 - > V ( e0 ) = = v0 | | ff0 - > V ( e0 ) = = v1 ) ;
ff0 - > ClearF ( e0 ) ;
2017-12-21 01:16:03 +01:00
ff1 - > ClearF ( e1 ) ;
}
else {
return false ;
2017-09-05 00:38:43 +02:00
}
2016-04-12 10:35:21 +02:00
}
2017-12-21 01:16:03 +01:00
else {
return false ;
}
2016-04-12 10:35:21 +02:00
}
2017-12-21 01:16:03 +01:00
return true ;
2016-04-12 10:35:21 +02:00
}
2017-12-21 01:16:03 +01:00
2017-08-30 16:03:46 +02:00
2017-09-05 00:38:43 +02:00
ScalarType MinDistOnEdge ( CoordType samplePnt , EdgeGrid & edgeGrid , MeshType & poly , CoordType & closestPoint )
2015-12-31 12:47:13 +01:00
{
2017-09-05 00:38:43 +02:00
ScalarType polyDist ;
2015-12-31 12:47:13 +01:00
EdgeType * cep = vcg : : tri : : GetClosestEdgeBase ( poly , edgeGrid , samplePnt , par . gridBailout , polyDist , closestPoint ) ;
return polyDist ;
}
2015-12-29 08:22:13 +01:00
// Given an edge of a mesh, supposedly intersecting the polyline,
// we search on it the closest point to the polyline
2017-09-05 00:38:43 +02:00
static ScalarType MinDistOnEdge ( VertexType * v0 , VertexType * v1 , EdgeGrid & edgeGrid , MeshType & poly , CoordType & closestPoint )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
ScalarType minPolyDist = std : : numeric_limits < ScalarType > : : max ( ) ;
const ScalarType sampleNum = 50 ;
const ScalarType maxDist = poly . bbox . Diag ( ) / 10.0 ;
for ( ScalarType k = 0 ; k < sampleNum + 1 ; + + k )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
ScalarType polyDist ;
CoordType closestPPoly ;
CoordType samplePnt = ( v0 - > P ( ) * k + v1 - > P ( ) * ( sampleNum - k ) ) / sampleNum ;
2015-12-29 08:22:13 +01:00
EdgeType * cep = vcg : : tri : : GetClosestEdgeBase ( poly , edgeGrid , samplePnt , maxDist , polyDist , closestPPoly ) ;
if ( polyDist < minPolyDist )
{
minPolyDist = polyDist ;
2015-12-31 12:47:13 +01:00
closestPoint = samplePnt ;
// closestPoint = closestPPoly;
2015-12-29 08:22:13 +01:00
}
}
return minPolyDist ;
}
2015-12-31 12:47:13 +01:00
/**
* @ brief ExtractVertex
* must extract an unambiguous representation of a vertex
* to be used with attribute_seam . h
*
*/
static inline void ExtractVertex ( const MeshType & srcMesh , const FaceType & f , int whichWedge , const MeshType & dstMesh , VertexType & v )
{
( void ) srcMesh ;
( void ) dstMesh ;
// This is done to preserve every single perVertex property
// perVextex Texture Coordinate is instead obtained from perWedge one.
v . ImportData ( * f . cV ( whichWedge ) ) ;
v . C ( ) = f . cC ( ) ;
}
static inline bool CompareVertex ( const MeshType & m , const VertexType & vA , const VertexType & vB )
{
( void ) m ;
if ( vA . C ( ) = = Color4b ( Color4b : : Red ) & & vB . C ( ) = = Color4b ( Color4b : : Blue ) ) return false ;
if ( vA . C ( ) = = Color4b ( Color4b : : Blue ) & & vB . C ( ) = = Color4b ( Color4b : : Red ) ) return false ;
return true ;
}
2017-09-05 00:38:43 +02:00
static CoordType QLerp ( VertexType * v0 , VertexType * v1 )
2015-12-31 12:47:13 +01:00
{
2017-09-05 00:38:43 +02:00
ScalarType qSum = fabs ( v0 - > Q ( ) ) + fabs ( v1 - > Q ( ) ) ;
ScalarType w0 = ( qSum - fabs ( v0 - > Q ( ) ) ) / qSum ;
ScalarType w1 = ( qSum - fabs ( v1 - > Q ( ) ) ) / qSum ;
2015-12-31 12:47:13 +01:00
return v0 - > P ( ) * w0 + v1 - > P ( ) * w1 ;
}
2015-12-29 08:22:13 +01:00
2017-08-30 16:03:46 +02:00
/**
* @ brief SnapPolyline snaps the vertexes of a polyline onto the base mesh
* @ param poly
* @ param newVertVec the vector of the indexes of the snapped vertices
*
* Polyline vertices can be snapped either on vertexes or on edges .
2017-09-05 00:38:43 +02:00
* Usually the only points that we should allow to not be snapped are the endpoints and non manifold points .
* Vertexes are colored according to their snapping state
2017-08-30 16:03:46 +02:00
*/
2016-04-12 10:35:21 +02:00
2017-08-30 16:03:46 +02:00
void SnapPolyline ( MeshType & poly )
2015-12-29 08:22:13 +01:00
{
2017-08-30 16:03:46 +02:00
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
tri : : UpdateTopology < MeshType > : : VertexEdge ( poly ) ;
int vertSnapCnt = 0 ;
int edgeSnapCnt = 0 ;
int borderCnt = 0 , midCnt = 0 , nonmanifCnt = 0 ;
for ( VertexIterator vi = poly . vert . begin ( ) ; vi ! = poly . vert . end ( ) ; + + vi )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
CoordType ip ;
2017-08-30 16:03:46 +02:00
FaceType * f = GetClosestFaceIP ( vi - > cP ( ) , ip ) ;
if ( BarycentricSnap ( ip ) )
2015-12-29 08:22:13 +01:00
{
2017-08-30 16:03:46 +02:00
if ( ip [ 0 ] > 0 & & ip [ 1 ] > 0 ) { vi - > P ( ) = f - > P ( 0 ) * ip [ 0 ] + f - > P ( 1 ) * ip [ 1 ] ; edgeSnapCnt + + ; assert ( ip [ 2 ] = = 0 ) ; vi - > C ( ) = Color4b : : White ; }
if ( ip [ 0 ] > 0 & & ip [ 2 ] > 0 ) { vi - > P ( ) = f - > P ( 0 ) * ip [ 0 ] + f - > P ( 2 ) * ip [ 2 ] ; edgeSnapCnt + + ; assert ( ip [ 1 ] = = 0 ) ; vi - > C ( ) = Color4b : : White ; }
if ( ip [ 1 ] > 0 & & ip [ 2 ] > 0 ) { vi - > P ( ) = f - > P ( 1 ) * ip [ 1 ] + f - > P ( 2 ) * ip [ 2 ] ; edgeSnapCnt + + ; assert ( ip [ 0 ] = = 0 ) ; vi - > C ( ) = Color4b : : White ; }
2015-12-29 08:22:13 +01:00
2017-08-30 16:03:46 +02:00
if ( ip [ 0 ] = = 1.0 ) { vi - > P ( ) = f - > P ( 0 ) ; vertSnapCnt + + ; assert ( ip [ 1 ] = = 0 & & ip [ 2 ] = = 0 ) ; vi - > C ( ) = Color4b : : Black ; }
if ( ip [ 1 ] = = 1.0 ) { vi - > P ( ) = f - > P ( 1 ) ; vertSnapCnt + + ; assert ( ip [ 0 ] = = 0 & & ip [ 2 ] = = 0 ) ; vi - > C ( ) = Color4b : : Black ; }
if ( ip [ 2 ] = = 1.0 ) { vi - > P ( ) = f - > P ( 2 ) ; vertSnapCnt + + ; assert ( ip [ 0 ] = = 0 & & ip [ 1 ] = = 0 ) ; vi - > C ( ) = Color4b : : Black ; }
2015-12-29 08:22:13 +01:00
}
2017-08-30 16:03:46 +02:00
else
2015-12-31 12:47:13 +01:00
{
2017-08-30 16:03:46 +02:00
int deg = edge : : VEDegree < EdgeType > ( & * vi ) ;
if ( deg > 2 ) { nonmanifCnt + + ; vi - > C ( ) = Color4b : : Magenta ; }
if ( deg < 2 ) { borderCnt + + ; vi - > C ( ) = Color4b : : Green ; }
if ( deg = = 2 ) { midCnt + + ; vi - > C ( ) = Color4b : : Blue ; }
2015-12-31 12:47:13 +01:00
}
}
2017-08-30 16:03:46 +02:00
printf ( " SnapPolyline %i vertices: snapped %i onto vert and %i onto edges %i nonmanif, %i border, %i mid \n " ,
poly . vn , vertSnapCnt , edgeSnapCnt , nonmanifCnt , borderCnt , midCnt ) ; fflush ( stdout ) ;
int dupCnt = tri : : Clean < MeshType > : : RemoveDuplicateVertex ( poly ) ;
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
if ( dupCnt ) printf ( " SnapPolyline: Removed %i Duplicated vertices \n " , dupCnt ) ;
2015-12-31 12:47:13 +01:00
}
2017-09-05 00:38:43 +02:00
void SelectBoundaryVertex ( MeshType & poly )
{
tri : : UpdateSelection < MeshType > : : VertexClear ( poly ) ;
tri : : UpdateTopology < MeshType > : : VertexEdge ( poly ) ;
ForEachVertex ( poly , [ & ] ( VertexType & v ) {
if ( edge : : VEDegree < EdgeType > ( & v ) = = 1 ) v . SetS ( ) ;
} ) ;
}
void SelectUniformlyDistributed ( MeshType & poly , int k )
{
tri : : TrivialPointerSampler < MeshType > tps ;
ScalarType samplingRadius = tri : : Stat < MeshType > : : ComputeEdgeLengthSum ( poly ) / ScalarType ( k ) ;
tri : : SurfaceSampling < MeshType , typename tri : : TrivialPointerSampler < MeshType > > : : EdgeMeshUniform ( poly , tps , samplingRadius ) ;
for ( int i = 0 ; i < tps . sampleVec . size ( ) ; + + i )
tps . sampleVec [ i ] - > SetS ( ) ;
}
2015-12-31 12:47:13 +01:00
2015-12-29 08:22:13 +01:00
/*
* Make an edge mesh 1 - manifold by splitting all the
* vertexes that have more than two incident edges
*
* It performs the split in three steps .
2015-12-31 12:47:13 +01:00
* - First it collects and counts the vertices to be splitten .
* - Then it adds the vertices to the mesh and
* - lastly it updates the poly with the newly added vertices .
2015-12-29 08:22:13 +01:00
*
2015-12-31 12:47:13 +01:00
* singSplitFlag allows to ubersplit each singularity in a number of vertex of the same order of its degree .
* This is not really necessary but helps the management of sharp turns in the poly mesh .
* \ todo add corner detection and split .
2015-12-29 08:22:13 +01:00
*/
2015-12-31 12:47:13 +01:00
void DecomposeNonManifoldPolyline ( MeshType & poly , bool singSplitFlag = true )
2015-12-29 08:22:13 +01:00
{
2015-12-31 12:47:13 +01:00
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
std : : vector < int > degreeVec ( poly . vn , 0 ) ;
2015-12-29 08:22:13 +01:00
tri : : UpdateTopology < MeshType > : : VertexEdge ( poly ) ;
int neededVert = 0 ;
int delta ;
if ( singSplitFlag ) delta = 1 ;
2015-12-31 12:47:13 +01:00
else delta = 2 ;
2015-12-29 08:22:13 +01:00
for ( VertexIterator vi = poly . vert . begin ( ) ; vi ! = poly . vert . end ( ) ; + + vi )
{
std : : vector < EdgeType * > starVec ;
edge : : VEStarVE ( & * vi , starVec ) ;
degreeVec [ tri : : Index ( poly , * vi ) ] = starVec . size ( ) ;
if ( starVec . size ( ) > 2 )
neededVert + = starVec . size ( ) - delta ;
}
2015-12-31 12:47:13 +01:00
printf ( " DecomposeNonManifold Adding %i vert to a polyline of %i vert \n " , neededVert , poly . vn ) ;
2015-12-29 08:22:13 +01:00
VertexIterator firstVi = tri : : Allocator < MeshType > : : AddVertices ( poly , neededVert ) ;
2015-12-31 12:47:13 +01:00
2015-12-29 08:22:13 +01:00
for ( size_t i = 0 ; i < degreeVec . size ( ) ; + + i )
{
if ( degreeVec [ i ] > 2 )
{
std : : vector < EdgeType * > edgeStarVec ;
edge : : VEStarVE ( & ( poly . vert [ i ] ) , edgeStarVec ) ;
assert ( edgeStarVec . size ( ) = = degreeVec [ i ] ) ;
for ( size_t j = delta ; j < edgeStarVec . size ( ) ; + + j )
{
EdgeType * ep = edgeStarVec [ j ] ;
int ind ; // index of the vertex to be changed
if ( tri : : Index ( poly , ep - > V ( 0 ) ) = = i ) ind = 0 ;
else ind = 1 ;
ep - > V ( ind ) = & * firstVi ;
ep - > V ( ind ) - > P ( ) = poly . vert [ i ] . P ( ) ;
ep - > V ( ind ) - > N ( ) = poly . vert [ i ] . N ( ) ;
+ + firstVi ;
}
}
}
2015-12-31 12:47:13 +01:00
assert ( firstVi = = poly . vert . end ( ) ) ;
2015-12-29 08:22:13 +01:00
}
2017-08-30 16:03:46 +02:00
/**
* @ brief SplitMeshWithPolyline
* @ param poly
*
* First it splits the base mesh with all the non snapped points doing a standard 1 to 3 split ;
*
2015-12-29 08:22:13 +01:00
*/
2017-08-30 16:03:46 +02:00
void SplitMeshWithPolyline ( MeshType & poly )
{
std : : vector < std : : pair < int , VertexPointer > > toSplitVec ; // the index of the face to be split and the poly vertex to be used
2015-12-29 08:22:13 +01:00
for ( VertexIterator vi = poly . vert . begin ( ) ; vi ! = poly . vert . end ( ) ; + + vi )
{
2017-09-05 00:38:43 +02:00
CoordType ip ;
2017-08-30 16:03:46 +02:00
FaceType * f = GetClosestFaceIP ( vi - > cP ( ) , ip ) ;
if ( ! BarycentricSnap ( ip ) )
toSplitVec . push_back ( std : : make_pair ( tri : : Index ( base , f ) , & * vi ) ) ;
2015-12-31 12:47:13 +01:00
}
2017-08-31 08:43:26 +02:00
printf ( " SplitMeshWithPolyline found %lu non snapped points \n " , toSplitVec . size ( ) ) ; fflush ( stdout ) ;
2015-12-31 12:47:13 +01:00
2017-08-30 16:03:46 +02:00
FaceIterator newFi = tri : : Allocator < MeshType > : : AddFaces ( base , toSplitVec . size ( ) * 2 ) ;
VertexIterator newVi = tri : : Allocator < MeshType > : : AddVertices ( base , toSplitVec . size ( ) ) ;
tri : : UpdateColor < MeshType > : : PerVertexConstant ( base , Color4b : : White ) ;
2015-12-31 12:47:13 +01:00
2017-08-30 16:03:46 +02:00
for ( size_t i = 0 ; i < toSplitVec . size ( ) ; + + i )
2015-12-31 12:47:13 +01:00
{
2017-08-30 16:03:46 +02:00
newVi - > P ( ) = toSplitVec [ i ] . second - > P ( ) ;
newVi - > C ( ) = Color4b : : Green ;
face : : TriSplit ( & base . face [ toSplitVec [ i ] . first ] , & * ( newFi + + ) , & * ( newFi + + ) , & * ( newVi + + ) ) ;
}
Init ( ) ; // need to reset everthing
SnapPolyline ( poly ) ;
2015-12-29 08:22:13 +01:00
2017-08-30 16:03:46 +02:00
// Second loop to perform the face-face Edge split **********************
std : : map < std : : pair < CoordType , CoordType > , VertexPointer > edgeToPolyVertMap ;
for ( VertexIterator vi = poly . vert . begin ( ) ; vi ! = poly . vert . end ( ) ; + + vi )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
CoordType ip ;
2017-08-30 16:03:46 +02:00
FaceType * f = GetClosestFaceIP ( vi - > cP ( ) , ip ) ;
if ( ! BarycentricSnap ( ip ) ) { assert ( 0 ) ; }
for ( int i = 0 ; i < 3 ; + + i )
2015-12-29 08:22:13 +01:00
{
2017-08-30 16:03:46 +02:00
if ( ip [ i ] > 0 & & ip [ ( i + 1 ) % 3 ] > 0 & & ip [ ( i + 2 ) % 3 ] = = 0 )
{
CoordType p0 = f - > P0 ( i ) ;
CoordType p1 = f - > P1 ( i ) ;
if ( p0 > p1 ) std : : swap ( p0 , p1 ) ;
2017-08-31 08:43:26 +02:00
if ( edgeToPolyVertMap [ make_pair ( p0 , p1 ) ] ) printf ( " Found an already used Edge %lu - %lu %lu!!! \n " , tri : : Index ( base , f - > V0 ( i ) ) , tri : : Index ( base , f - > V1 ( i ) ) , tri : : Index ( poly , & * vi ) ) ;
2017-08-30 16:03:46 +02:00
edgeToPolyVertMap [ make_pair ( p0 , p1 ) ] = & * vi ;
}
2015-12-29 08:22:13 +01:00
}
}
2017-08-31 08:43:26 +02:00
printf ( " SplitMeshWithPolyline: Created a map of %lu edges to be split \n " , edgeToPolyVertMap . size ( ) ) ;
2017-08-30 16:03:46 +02:00
EdgePointPred ePred ( edgeToPolyVertMap ) ;
EdgePointSplit eSplit ( edgeToPolyVertMap ) ;
tri : : UpdateTopology < MeshType > : : FaceFace ( base ) ;
tri : : RefineE ( base , eSplit , ePred ) ;
Init ( ) ; // need to reset everthing
}
2015-12-31 12:47:13 +01:00
2017-08-30 16:03:46 +02:00
2015-12-29 08:22:13 +01:00
2017-08-30 16:03:46 +02:00
void Init ( )
2015-12-29 08:22:13 +01:00
{
2017-08-30 16:03:46 +02:00
// Construction of the uniform grid
UpdateNormal < MeshType > : : PerFaceNormalized ( base ) ;
UpdateTopology < MeshType > : : FaceFace ( base ) ;
uniformGrid . Set ( base . face . begin ( ) , base . face . end ( ) ) ;
2015-12-29 08:22:13 +01:00
}
2017-08-30 16:03:46 +02:00
void SimplifyMidEdge ( MeshType & poly )
2015-12-29 08:22:13 +01:00
{
2017-08-30 16:03:46 +02:00
int startVn ;
int midEdgeCollapseCnt = 0 ;
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
do
{
startVn = poly . vn ;
for ( int ei = 0 ; ei < poly . en ; + + ei )
2015-12-31 12:47:13 +01:00
{
2017-08-30 16:03:46 +02:00
VertexType * v0 = poly . edge [ ei ] . V ( 0 ) ;
VertexType * v1 = poly . edge [ ei ] . V ( 1 ) ;
CoordType ip0 , ip1 ;
FaceType * f0 = GetClosestFaceIP ( v0 - > P ( ) , ip0 ) ;
FaceType * f1 = GetClosestFaceIP ( v1 - > P ( ) , ip1 ) ;
2015-12-29 08:22:13 +01:00
2017-08-30 16:03:46 +02:00
bool snap0 = BarycentricSnap ( ip0 ) ;
bool snap1 = BarycentricSnap ( ip1 ) ;
int e0i , e1i ;
bool e0 = IsSnappedEdge ( ip0 , e0i ) ;
bool e1 = IsSnappedEdge ( ip1 , e1i ) ;
if ( e0 & & e1 )
if ( ( f0 = = f1 & & e0i = = e1i ) | |
( f0 = = f1 - > FFp ( e1i ) & & e0i = = f1 - > FFi ( e1i ) ) | |
( f0 - > FFp ( e0i ) = = f1 & & f0 - > FFi ( e0i ) = = e1i ) | |
( f0 - > FFp ( e0i ) = = f1 - > FFp ( e1i ) & & f0 - > FFi ( e0i ) = = f1 - > FFi ( e1i ) ) )
2015-12-31 12:47:13 +01:00
{
2017-08-30 16:03:46 +02:00
CoordType newp = ( v0 - > P ( ) + v1 - > P ( ) ) / 2.0 ;
v0 - > P ( ) = newp ;
v1 - > P ( ) = newp ;
midEdgeCollapseCnt + + ;
2015-12-31 12:47:13 +01:00
}
2015-12-29 08:22:13 +01:00
}
2017-08-30 16:03:46 +02:00
tri : : Clean < MeshType > : : RemoveDuplicateVertex ( poly ) ;
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
2017-09-05 00:38:43 +02:00
// printf("SimplifyMidEdge %5i -> %5i %i mid %i ve \n",startVn,poly.vn,midEdgeCollapseCnt);
2017-08-30 16:03:46 +02:00
} while ( startVn > poly . vn ) ;
}
2015-12-29 08:22:13 +01:00
2017-08-30 16:03:46 +02:00
/**
2017-09-05 00:38:43 +02:00
* @ brief SimplifyMidFace remove all the vertices that in the mid of a face
* and between two of the points snapped onto the edges of the same face
2017-08-30 16:03:46 +02:00
* @ param poly
*
* It assumes that the mesh has been snapped and refined by the BaseMesh
2017-09-05 00:38:43 +02:00
*
2015-12-29 08:22:13 +01:00
*/
2017-08-30 16:03:46 +02:00
void SimplifyMidFace ( MeshType & poly )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
int startVn = poly . vn ; ;
int midFaceCollapseCnt = 0 ;
int vertexEdgeCollapseCnt = 0 ;
int curVn ;
2017-08-30 16:03:46 +02:00
do
{
2017-09-05 00:38:43 +02:00
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
curVn = poly . vn ;
2017-08-30 16:03:46 +02:00
UpdateTopology < MeshType > : : VertexEdge ( poly ) ;
for ( int i = 0 ; i < poly . vn ; + + i )
2015-12-29 08:22:13 +01:00
{
2017-08-30 16:03:46 +02:00
std : : vector < VertexPointer > starVecVp ;
edge : : VVStarVE ( & ( poly . vert [ i ] ) , starVecVp ) ;
if ( ( starVecVp . size ( ) = = 2 ) )
{
CoordType ipP , ipN , ipI ;
FacePointer fpP = GetClosestFaceIP ( starVecVp [ 0 ] - > P ( ) , ipP ) ;
FacePointer fpN = GetClosestFaceIP ( starVecVp [ 1 ] - > P ( ) , ipN ) ;
FacePointer fpI = GetClosestFaceIP ( poly . vert [ i ] . P ( ) , ipI ) ;
bool snapP = ( BarycentricSnap ( ipP ) ) ;
bool snapN = ( BarycentricSnap ( ipN ) ) ;
bool snapI = ( BarycentricSnap ( ipI ) ) ;
VertexPointer vertexSnapP = 0 ;
VertexPointer vertexSnapN = 0 ;
VertexPointer vertexSnapI = 0 ;
for ( int j = 0 ; j < 3 ; + + j )
2015-12-31 12:47:13 +01:00
{
2017-08-30 16:03:46 +02:00
if ( ipP [ j ] = = 1.0 ) vertexSnapP = fpP - > V ( j ) ;
if ( ipN [ j ] = = 1.0 ) vertexSnapN = fpN - > V ( j ) ;
if ( ipI [ j ] = = 1.0 ) vertexSnapI = fpI - > V ( j ) ;
2015-12-31 12:47:13 +01:00
}
2017-08-30 16:03:46 +02:00
bool collapseFlag = false ;
if ( ( ! snapI & & snapP & & snapN ) | | // First case a vertex that is not snapped between two snapped vertexes
( ! snapI & & ! snapP & & fpI = = fpP ) | | // Or a two vertex not snapped but on the same face
( ! snapI & & ! snapN & & fpI = = fpN ) )
{
collapseFlag = true ;
midFaceCollapseCnt + + ;
}
else // case 2) a vertex snap and edge snap we have to check that the edge do not share the same vertex of the vertex snap
if ( snapI & & snapP & & snapN & & vertexSnapI = = 0 & & ( vertexSnapP ! = 0 | | vertexSnapN ! = 0 ) )
{
for ( int j = 0 ; j < 3 ; + + j ) {
if ( ipI [ j ] ! = 0 & & ( fpI - > V ( j ) = = vertexSnapP | | fpI - > V ( j ) = = vertexSnapN ) ) {
collapseFlag = true ;
vertexEdgeCollapseCnt + + ;
}
}
}
2015-12-31 12:47:13 +01:00
2017-08-30 16:03:46 +02:00
if ( collapseFlag )
edge : : VEEdgeCollapse ( poly , & ( poly . vert [ i ] ) ) ;
2015-12-29 08:22:13 +01:00
}
2017-08-30 16:03:46 +02:00
}
2017-09-05 00:38:43 +02:00
} while ( curVn > poly . vn ) ;
printf ( " SimplifyMidFace %5i -> %5i %i mid %i ve \n " , startVn , poly . vn , midFaceCollapseCnt , vertexEdgeCollapseCnt ) ;
2017-08-30 16:03:46 +02:00
}
2015-12-29 08:22:13 +01:00
2017-09-21 12:19:08 +02:00
void Simplify ( MeshType & poly )
2015-12-29 08:22:13 +01:00
{
int startEn = poly . en ;
Distribution < ScalarType > hist ;
for ( int i = 0 ; i < poly . en ; + + i )
hist . Add ( edge : : Length ( poly . edge [ i ] ) ) ;
UpdateTopology < MeshType > : : VertexEdge ( poly ) ;
for ( int i = 0 ; i < poly . vn ; + + i )
{
std : : vector < VertexPointer > starVecVp ;
2016-04-12 10:35:21 +02:00
edge : : VVStarVE ( & ( poly . vert [ i ] ) , starVecVp ) ;
2017-09-21 12:19:08 +02:00
if ( ( starVecVp . size ( ) = = 2 ) & & ( ! poly . vert [ i ] . IsS ( ) ) )
{
2017-09-05 00:38:43 +02:00
ScalarType newSegLen = Distance ( starVecVp [ 0 ] - > P ( ) , starVecVp [ 1 ] - > P ( ) ) ;
2017-09-07 19:02:13 +02:00
Segment3Type seg ( starVecVp [ 0 ] - > P ( ) , starVecVp [ 1 ] - > P ( ) ) ;
2017-09-05 00:38:43 +02:00
ScalarType segDist ;
CoordType closestPSeg ;
2015-12-29 08:22:13 +01:00
SegmentPointDistance ( seg , poly . vert [ i ] . cP ( ) , closestPSeg , segDist ) ;
2017-09-05 00:38:43 +02:00
CoordType fp , fn ;
ScalarType maxSurfDist = MaxSegDist ( starVecVp [ 0 ] , starVecVp [ 1 ] , fp , fn ) ;
2015-12-29 08:22:13 +01:00
2017-08-30 16:03:46 +02:00
if ( ( maxSurfDist < par . surfDistThr ) & & ( newSegLen < par . maxSimpEdgeLen ) )
2015-12-29 08:22:13 +01:00
{
2017-08-30 16:03:46 +02:00
edge : : VEEdgeCollapse ( poly , & ( poly . vert [ i ] ) ) ;
2015-12-29 08:22:13 +01:00
}
}
}
2016-04-12 10:35:21 +02:00
tri : : UpdateTopology < MeshType > : : TestVertexEdge ( poly ) ;
2015-12-29 08:22:13 +01:00
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
2016-04-12 10:35:21 +02:00
tri : : UpdateTopology < MeshType > : : TestVertexEdge ( poly ) ;
printf ( " Simplify %5i -> %5i (total len %5.2f) \n " , startEn , poly . en , hist . Sum ( ) ) ;
2015-12-29 08:22:13 +01:00
}
void EvaluateHausdorffDistance ( MeshType & poly , Distribution < ScalarType > & dist )
{
dist . Clear ( ) ;
tri : : UpdateTopology < MeshType > : : VertexEdge ( poly ) ;
tri : : UpdateQuality < MeshType > : : VertexConstant ( poly , 0 ) ;
for ( int i = 0 ; i < poly . edge . size ( ) ; + + i )
{
2017-09-05 00:38:43 +02:00
CoordType farthestP , farthestN ;
ScalarType maxDist = MaxSegDist ( poly . edge [ i ] . V ( 0 ) , poly . edge [ i ] . V ( 1 ) , farthestP , farthestN , & dist ) ;
2015-12-29 08:22:13 +01:00
poly . edge [ i ] . V ( 0 ) - > Q ( ) + = maxDist ;
poly . edge [ i ] . V ( 1 ) - > Q ( ) + = maxDist ;
}
for ( int i = 0 ; i < poly . vn ; + + i )
{
ScalarType deg = edge : : VEDegree < EdgeType > ( & poly . vert [ i ] ) ;
poly . vert [ i ] . Q ( ) / = deg ;
}
tri : : UpdateColor < MeshType > : : PerVertexQualityRamp ( poly , 0 , dist . Max ( ) ) ;
}
2015-12-31 12:47:13 +01:00
2017-08-30 16:03:46 +02:00
/**
* @ brief BarycentricSnap
* @ param ip the baricentric coords to be snapped
* @ return true if they have been snapped .
*
* This is the VERY important function that is used everywhere .
2017-09-05 00:38:43 +02:00
* Given a barycentric coord of a point inside a triangle it decides if it should be " snapped " either onto an edge or on a vertex .
* It relies on the barycentricSnapThr parameter
2017-08-30 16:03:46 +02:00
*
*/
bool BarycentricSnap ( CoordType & ip )
{
for ( int i = 0 ; i < 3 ; + + i )
{
if ( ip [ i ] < = par . barycentricSnapThr ) ip [ i ] = 0 ;
if ( ip [ i ] > = 1.0 - par . barycentricSnapThr ) ip [ i ] = 1 ;
}
ScalarType sum = ip [ 0 ] + ip [ 1 ] + ip [ 2 ] ;
for ( int i = 0 ; i < 3 ; + + i )
if ( ip [ i ] ! = 1 ) ip [ i ] / = sum ;
if ( ip [ 0 ] = = 0 | | ip [ 1 ] = = 0 | | ip [ 2 ] = = 0 ) return true ;
return false ;
}
2015-12-31 12:47:13 +01:00
2017-08-30 16:03:46 +02:00
/**
* @ brief TestSplitSegWithMesh Given a poly segment decide if it should be split along elements of base mesh .
* @ param v0
* @ param v1
* @ param splitPt
* @ return true if it should be split
*
* We make a few samples onto the edge and if some of them snaps onto a an edge we use it .
* In case there are more than one candidate we choose the sample closeset to its snapping point .
* We explicitly avoid snapping twice on the same edge by checking the starting and ending edges .
*
* Two cases :
* - poly edge pass near a vertex of the mesh
* - poly edge cross one or more edges
*
* Note that we have to check the case where
*/
2017-09-05 00:38:43 +02:00
bool TestSplitSegWithMesh ( VertexType * v0 , VertexType * v1 , CoordType & splitPt )
2017-08-30 16:03:46 +02:00
{
2017-09-07 19:02:13 +02:00
Segment3Type segPoly ( v0 - > P ( ) , v1 - > P ( ) ) ;
2017-09-05 00:38:43 +02:00
const ScalarType sampleNum = 40 ;
2017-08-30 16:03:46 +02:00
CoordType ip0 , ip1 ;
FaceType * f0 = GetClosestFaceIP ( v0 - > P ( ) , ip0 ) ;
FaceType * f1 = GetClosestFaceIP ( v1 - > P ( ) , ip1 ) ;
if ( f0 = = f1 ) return false ;
bool snap0 = false , snap1 = false ; // true if the segment start/end on a edge/vert
2017-09-07 19:02:13 +02:00
Segment3Type seg0 ; // The two segments to be avoided
Segment3Type seg1 ; // from which the current poly segment can start
2017-08-30 16:03:46 +02:00
VertexPointer vertexSnap0 = 0 ;
VertexPointer vertexSnap1 = 0 ;
if ( BarycentricSnap ( ip0 ) ) {
snap0 = true ;
for ( int i = 0 ; i < 3 ; + + i ) {
if ( ip0 [ i ] = = 1.0 ) vertexSnap0 = f0 - > V ( i ) ;
2017-09-07 19:02:13 +02:00
if ( ip0 [ i ] = = 0.0 ) seg0 = Segment3Type ( f0 - > P1 ( i ) , f0 - > P2 ( i ) ) ;
2017-08-30 16:03:46 +02:00
}
}
if ( BarycentricSnap ( ip1 ) ) {
snap1 = true ;
for ( int i = 0 ; i < 3 ; + + i ) {
if ( ip1 [ i ] = = 1.0 ) vertexSnap1 = f1 - > V ( i ) ;
2017-09-07 19:02:13 +02:00
if ( ip1 [ i ] = = 0.0 ) seg1 = Segment3Type ( f1 - > P1 ( i ) , f1 - > P2 ( i ) ) ;
2017-08-30 16:03:46 +02:00
}
}
CoordType bestSplitPt ( 0 , 0 , 0 ) ;
ScalarType bestDist = std : : numeric_limits < ScalarType > : : max ( ) ;
2017-09-05 00:38:43 +02:00
for ( ScalarType k = 1 ; k < sampleNum ; + + k )
2017-08-30 16:03:46 +02:00
{
2017-09-05 00:38:43 +02:00
CoordType samplePnt = segPoly . Lerp ( k / sampleNum ) ;
2017-08-30 16:03:46 +02:00
CoordType ip ;
FaceType * f = GetClosestFaceIP ( samplePnt , ip ) ;
// BarycentricEdgeSnap(ip);
if ( BarycentricSnap ( ip ) )
{
VertexPointer vertexSnapI = 0 ;
for ( int i = 0 ; i < 3 ; + + i )
if ( ip [ i ] = = 1.0 ) vertexSnapI = f - > V ( i ) ;
CoordType closestPt = f - > P ( 0 ) * ip [ 0 ] + f - > P ( 1 ) * ip [ 1 ] + f - > P ( 2 ) * ip [ 2 ] ;
if ( Distance ( samplePnt , closestPt ) < bestDist )
{
ScalarType dist0 = std : : numeric_limits < ScalarType > : : max ( ) ;
ScalarType dist1 = std : : numeric_limits < ScalarType > : : max ( ) ;
CoordType closestSegPt ;
if ( snap0 ) SegmentPointDistance ( seg0 , closestPt , closestSegPt , dist0 ) ;
if ( snap1 ) SegmentPointDistance ( seg1 , closestPt , closestSegPt , dist1 ) ;
if ( ( ! vertexSnapI & & ( dist0 > par . surfDistThr / 1000 & & dist1 > par . surfDistThr / 1000 ) ) | |
( vertexSnapI ! = vertexSnap0 & & vertexSnapI ! = vertexSnap1 ) )
{
bestDist = Distance ( samplePnt , closestPt ) ;
bestSplitPt = closestPt ;
}
}
}
}
if ( bestDist < par . surfDistThr * 100 )
{
splitPt = bestSplitPt ;
return true ;
}
return false ;
}
/**
* @ brief SnappedOnSameFace Return true if the two points are snapped to a common face ;
* @ param f0
* @ param i0
* @ param f1
* @ param i0
* @ return
*
* Require FFAdj . se assume that both SNAPPED . Three cases :
* - Edge Edge - true iff the two edges belongs to a common face .
* - Vert Edge - true iff there is one of the two snapped edge faces has the vert as non - edge face ;
* - Vert Vert
*
*/
bool SnappedOnSameFace ( FacePointer f0 , CoordType i0 , FacePointer f1 , CoordType i1 )
{
if ( f0 = = f1 ) return true ;
int e0 , e1 ;
int v0 , v1 ;
bool e0Snap = IsSnappedEdge ( i0 , e0 ) ;
bool e1Snap = IsSnappedEdge ( i1 , e1 ) ;
bool v0Snap = IsSnappedVertex ( i0 , v0 ) ;
bool v1Snap = IsSnappedVertex ( i1 , v1 ) ;
FacePointer f0p = 0 ; int e0p = - 1 ; // When Edge snap the other face and the index of the snapped edge on the other face
FacePointer f1p = 0 ; int e1p = - 1 ;
assert ( ( e0Snap ! = v0Snap ) & & ( e1Snap ! = v1Snap ) ) ;
// For EdgeSnap compute the 'other' face stuff
if ( e0Snap ) {
f0p = f0 - > FFp ( e0 ) ; e0p = f0 - > FFi ( e0 ) ; assert ( f0p - > FFp ( e0p ) = = f0 ) ;
}
if ( e1Snap ) {
f1p = f1 - > FFp ( e1 ) ; e1p = f1 - > FFi ( e1 ) ; assert ( f1p - > FFp ( e1p ) = = f1 ) ;
}
if ( e0Snap & & e1Snap ) {
if ( f0 = = f1p | | f0p = = f1p | | f0p = = f1 | | f0 = = f1 ) return true ;
}
if ( e0Snap & & v1Snap ) {
assert ( v1 > = 0 & & v1 < 3 & & v0 = = - 1 & & e1 = = - 1 ) ;
if ( f0 - > V2 ( e0 ) = = f1 - > V ( v1 ) ) return true ;
if ( f0p - > V2 ( e0p ) = = f1 - > V ( v1 ) ) return true ;
}
if ( e1Snap & & v0Snap ) {
assert ( v0 > = 0 & & v0 < 3 & & v1 = = - 1 & & e0 = = - 1 ) ;
if ( f1 - > V2 ( e1 ) = = f0 - > V ( v0 ) ) return true ;
if ( f1p - > V2 ( e1p ) = = f0 - > V ( v0 ) ) return true ;
}
if ( v1Snap & & v0Snap ) {
PosType startPos ( f0 , f0 - > V ( v0 ) ) ;
PosType curPos = startPos ;
do
{
2017-09-05 00:38:43 +02:00
assert ( curPos . V ( ) = = f0 - > V ( v0 ) ) ;
2017-08-30 16:03:46 +02:00
if ( curPos . VFlip ( ) = = f1 - > V ( v1 ) ) return true ;
curPos . FlipE ( ) ;
curPos . FlipF ( ) ;
}
while ( curPos ! = startPos ) ;
}
return false ;
}
/**
* @ brief TestSplitSegWithMesh Given a poly segment decide if it should be split along elements of base mesh .
* @ param v0
* @ param v1
* @ param splitPt
* @ return true if it should be split
*
* We make a few samples onto the edge and if some of them snaps onto a an edge we use it .
* In case there are more than one candidate we choose the sample closeset to its snapping point .
* We explicitly avoid snapping twice on the same edge by checking the starting and ending edges .
*
* Two cases :
* - poly edge pass near a vertex of the mesh
* - poly edge cross one or more edges
*
* Note that we have to check the case where
*/
2017-09-05 00:38:43 +02:00
bool TestSplitSegWithMeshAdapt ( VertexType * v0 , VertexType * v1 , CoordType & splitPt )
2017-08-30 16:03:46 +02:00
{
splitPt = ( v0 - > P ( ) + v1 - > P ( ) ) / 2.0 ;
CoordType ip0 , ip1 , ipm ;
FaceType * f0 = GetClosestFaceIP ( v0 - > P ( ) , ip0 ) ;
FaceType * f1 = GetClosestFaceIP ( v1 - > P ( ) , ip1 ) ;
FaceType * fm = GetClosestFaceIP ( splitPt , ipm ) ;
if ( f0 = = f1 ) return false ;
bool snap0 = BarycentricSnap ( ip0 ) ;
bool snap1 = BarycentricSnap ( ip1 ) ;
bool snapm = BarycentricSnap ( ipm ) ;
2017-09-05 00:38:43 +02:00
splitPt = fm - > P ( 0 ) * ipm [ 0 ] + fm - > P ( 1 ) * ipm [ 1 ] + fm - > P ( 2 ) * ipm [ 2 ] ;
2017-08-30 16:03:46 +02:00
if ( ! snap0 & & ! snap1 ) {
assert ( f0 ! = f1 ) ;
return true ;
}
if ( snap0 & & snap1 )
{
if ( SnappedOnSameFace ( f0 , ip0 , f1 , ip1 ) )
2017-09-05 00:38:43 +02:00
return false ;
2017-08-30 16:03:46 +02:00
}
if ( snap0 ) {
int e0 , v0 ;
if ( IsSnappedEdge ( ip0 , e0 ) ) {
if ( f0 - > FFp ( e0 ) = = f1 ) return false ;
}
if ( IsSnappedVertex ( ip0 , v0 ) ) {
for ( int i = 0 ; i < 3 ; + + i )
if ( f1 - > V ( i ) = = f0 - > V ( v0 ) ) return false ;
}
}
2017-09-05 00:38:43 +02:00
if ( snap1 ) {
int e1 , v1 ;
if ( IsSnappedEdge ( ip1 , e1 ) ) {
if ( f1 - > FFp ( e1 ) = = f0 ) return false ;
}
if ( IsSnappedVertex ( ip1 , v1 ) ) {
for ( int i = 0 ; i < 3 ; + + i )
if ( f0 - > V ( i ) = = f1 - > V ( v1 ) ) return false ;
}
}
2017-08-30 16:03:46 +02:00
return true ;
}
2017-09-05 00:38:43 +02:00
bool TestSplitSegWithMeshAdaptOld ( VertexType * v0 , VertexType * v1 , CoordType & splitPt )
2017-08-30 16:03:46 +02:00
{
2017-09-07 19:02:13 +02:00
Segment3Type segPoly ( v0 - > P ( ) , v1 - > P ( ) ) ;
2017-09-05 00:38:43 +02:00
const ScalarType sampleNum = 40 ;
2017-08-30 16:03:46 +02:00
CoordType ip0 , ip1 ;
FaceType * f0 = GetClosestFaceIP ( v0 - > P ( ) , ip0 ) ;
FaceType * f1 = GetClosestFaceIP ( v1 - > P ( ) , ip1 ) ;
if ( f0 = = f1 ) return false ;
bool snap0 = BarycentricSnap ( ip0 ) ;
bool snap1 = BarycentricSnap ( ip1 ) ;
if ( ! snap0 & & ! snap1 ) {
assert ( f0 ! = f1 ) ;
splitPt = ( v0 - > P ( ) + v1 - > P ( ) ) / 2.0 ;
return true ;
}
if ( snap0 & & snap1 )
{
if ( SnappedOnSameFace ( f0 , ip0 , f1 , ip1 ) )
return false ;
}
if ( snap0 ) {
int e0 , v0 ;
if ( IsSnappedEdge ( ip0 , e0 ) ) {
if ( f0 - > FFp ( e0 ) = = f1 ) return false ;
}
if ( IsSnappedVertex ( ip0 , v0 ) ) {
for ( int i = 0 ; i < 3 ; + + i )
if ( f1 - > V ( i ) = = f0 - > V ( v0 ) ) return false ;
}
}
splitPt = ( v0 - > P ( ) + v1 - > P ( ) ) / 2.0 ;
return true ;
}
2016-04-12 10:35:21 +02:00
2015-12-29 08:22:13 +01:00
// Given a segment find the maximum distance from it to the original surface.
2017-08-30 16:03:46 +02:00
// It is used to evaluate the Haustdorff distance of a Segment from the mesh.
2017-09-05 00:38:43 +02:00
ScalarType MaxSegDist ( VertexType * v0 , VertexType * v1 , CoordType & farthestPointOnSurf , CoordType & farthestN , Distribution < ScalarType > * dist = 0 )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
ScalarType maxSurfDist = 0 ;
const ScalarType sampleNum = 10 ;
const ScalarType maxDist = base . bbox . Diag ( ) / 10.0 ;
for ( ScalarType k = 1 ; k < sampleNum ; + + k )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
ScalarType surfDist ;
CoordType closestPSurf ;
CoordType samplePnt = ( v0 - > P ( ) * k + v1 - > P ( ) * ( sampleNum - k ) ) / sampleNum ;
2015-12-29 08:22:13 +01:00
FaceType * f = vcg : : tri : : GetClosestFaceBase ( base , uniformGrid , samplePnt , maxDist , surfDist , closestPSurf ) ;
if ( dist )
dist - > Add ( surfDist ) ;
assert ( f ) ;
if ( surfDist > maxSurfDist )
{
maxSurfDist = surfDist ;
farthestPointOnSurf = closestPSurf ;
farthestN = f - > N ( ) ;
}
}
return maxSurfDist ;
}
2017-08-30 16:03:46 +02:00
/**
* @ brief RefineCurve
* @ param poly the curve to be refined
* @ param uniformFlag
*
* Make one pass of refinement for all the edges of the curve that are distant from the basemesh
* uses two parameters :
* - par . minRefEdgeLen
* - par . surfDistThr
*/
void RefineCurveByDistance ( MeshType & poly )
2015-12-29 08:22:13 +01:00
{
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
int startEdgeSize = poly . en ;
for ( int i = 0 ; i < startEdgeSize ; + + i )
{
2016-04-12 10:35:21 +02:00
EdgeType & ei = poly . edge [ i ] ;
if ( edge : : Length ( ei ) > par . minRefEdgeLen )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
CoordType farthestP , farthestN ;
ScalarType maxDist = MaxSegDist ( ei . V ( 0 ) , ei . V ( 1 ) , farthestP , farthestN ) ;
2015-12-29 08:22:13 +01:00
if ( maxDist > par . surfDistThr )
{
2016-04-12 10:35:21 +02:00
edge : : VEEdgeSplit ( poly , & ei , farthestP , farthestN ) ;
}
2015-12-29 08:22:13 +01:00
}
}
2016-04-12 10:35:21 +02:00
// tri::Allocator<MeshType>::CompactEveryVector(poly);
2015-12-29 08:22:13 +01:00
printf ( " Refine %i -> %i \n " , startEdgeSize , poly . en ) ; fflush ( stdout ) ;
}
2017-08-30 16:03:46 +02:00
/**
* @ brief RefineCurveByBaseMesh
* @ param poly
*/
void RefineCurveByBaseMesh ( MeshType & poly )
2016-04-12 10:35:21 +02:00
{
2017-08-30 16:03:46 +02:00
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
2017-09-05 00:38:43 +02:00
std : : vector < int > edgeToRefineVec ;
for ( int i = 0 ; i < poly . en ; + + i )
edgeToRefineVec . push_back ( i ) ;
int startEn = poly . en ;
int iterCnt = 0 ;
while ( ! edgeToRefineVec . empty ( ) & & iterCnt < 100 ) {
iterCnt + + ;
std : : vector < int > edgeToRefineVecNext ;
for ( int i = 0 ; i < edgeToRefineVec . size ( ) ; + + i )
2016-04-12 10:35:21 +02:00
{
2017-09-05 00:38:43 +02:00
EdgeType & e = poly . edge [ edgeToRefineVec [ i ] ] ;
2017-08-30 16:03:46 +02:00
CoordType splitPt ;
2017-09-05 00:38:43 +02:00
if ( TestSplitSegWithMeshAdapt ( e . V ( 0 ) , e . V ( 1 ) , splitPt ) )
{
edge : : VEEdgeSplit ( poly , & e , splitPt ) ;
edgeToRefineVecNext . push_back ( edgeToRefineVec [ i ] ) ;
edgeToRefineVecNext . push_back ( poly . en - 1 ) ;
}
}
2017-08-30 16:03:46 +02:00
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
2017-09-05 00:38:43 +02:00
swap ( edgeToRefineVecNext , edgeToRefineVec ) ;
printf ( " RefineCurveByBaseMesh %i en -> %i en \n " , startEn , poly . en ) ; fflush ( stdout ) ;
}
//
2017-08-30 16:03:46 +02:00
SimplifyMidFace ( poly ) ;
SimplifyMidEdge ( poly ) ;
SnapPolyline ( poly ) ;
2017-09-05 00:38:43 +02:00
printf ( " RefineCurveByBaseMesh %i en -> %i en \n " , startEn , poly . en ) ; fflush ( stdout ) ;
2016-04-12 10:35:21 +02:00
}
2015-12-31 12:47:13 +01:00
2017-09-05 00:38:43 +02:00
2015-12-31 12:47:13 +01:00
/**
* @ brief SmoothProject
* @ param poly
* @ param iterNum
* @ param smoothWeight [ 0. .1 ] range ;
* @ param projectWeight [ 0. .1 ] range ;
*
* The very important function to adapt a polyline onto the base mesh
* The projection process must be done slowly to guarantee some empirical convergence . . .
* For each iteration it choose a new position of each vertex of the polyline .
* The new position is a blend between the smoothed position , the closest point on the surface and the original position .
* You need a good balance . . .
* after each iteration the polyline is refined and simplified .
*/
2015-12-29 08:22:13 +01:00
void SmoothProject ( MeshType & poly , int iterNum , ScalarType smoothWeight , ScalarType projectWeight )
{
2016-04-12 10:35:21 +02:00
tri : : RequireCompactness ( poly ) ;
tri : : UpdateTopology < MeshType > : : VertexEdge ( poly ) ;
printf ( " SmoothProject: Selected vert num %i \n " , tri : : UpdateSelection < MeshType > : : VertexCount ( poly ) ) ;
2015-12-29 08:22:13 +01:00
assert ( poly . en > 0 & & base . fn > 0 ) ;
for ( int k = 0 ; k < iterNum ; + + k )
{
2017-08-30 16:03:46 +02:00
if ( k = = iterNum - 1 ) projectWeight = 1 ;
2017-09-05 00:38:43 +02:00
std : : vector < CoordType > posVec ( poly . vn , CoordType ( 0 , 0 , 0 ) ) ;
2015-12-29 08:22:13 +01:00
std : : vector < int > cntVec ( poly . vn , 0 ) ;
for ( int i = 0 ; i < poly . en ; + + i )
{
for ( int j = 0 ; j < 2 ; + + j )
{
2017-09-05 00:38:43 +02:00
int vertInd = tri : : Index ( poly , poly . edge [ i ] . V0 ( j ) ) ;
2015-12-29 08:22:13 +01:00
posVec [ vertInd ] + = poly . edge [ i ] . V1 ( j ) - > P ( ) ;
cntVec [ vertInd ] + = 1 ;
}
}
2017-09-05 00:38:43 +02:00
const ScalarType maxDist = base . bbox . Diag ( ) / 10.0 ;
2015-12-29 08:22:13 +01:00
for ( int i = 0 ; i < poly . vn ; + + i )
2016-04-12 10:35:21 +02:00
if ( ! poly . vert [ i ] . IsS ( ) )
2015-12-29 08:22:13 +01:00
{
2017-09-05 00:38:43 +02:00
CoordType smoothPos = ( poly . vert [ i ] . P ( ) + posVec [ i ] ) / ScalarType ( cntVec [ i ] + 1 ) ;
2016-04-12 10:35:21 +02:00
2017-09-05 00:38:43 +02:00
CoordType newP = poly . vert [ i ] . P ( ) * ( 1.0 - smoothWeight ) + smoothPos * smoothWeight ;
2016-04-12 10:35:21 +02:00
2017-09-05 00:38:43 +02:00
// CoordType delta = newP - poly.vert[i].P();
// if(delta.Norm() > par.maxSmoothDelta)
// {
// newP = poly.vert[i].P() + ( delta / delta.Norm()) * maxDist*0.5;
// }
2016-04-12 10:35:21 +02:00
2017-09-05 00:38:43 +02:00
ScalarType minDist ;
CoordType closestP ;
2016-04-12 10:35:21 +02:00
FaceType * f = vcg : : tri : : GetClosestFaceBase ( base , uniformGrid , newP , maxDist , minDist , closestP ) ;
assert ( f ) ;
poly . vert [ i ] . P ( ) = newP * ( 1.0 - projectWeight ) + closestP * projectWeight ;
poly . vert [ i ] . N ( ) = f - > N ( ) ;
2015-12-29 08:22:13 +01:00
}
2017-08-30 16:03:46 +02:00
// Refine(poly);
2016-04-12 10:35:21 +02:00
tri : : UpdateTopology < MeshType > : : TestVertexEdge ( poly ) ;
2017-08-30 16:03:46 +02:00
RefineCurveByDistance ( poly ) ;
2016-04-12 10:35:21 +02:00
tri : : UpdateTopology < MeshType > : : TestVertexEdge ( poly ) ;
2017-08-30 16:03:46 +02:00
Simplify ( poly ) ;
2016-04-12 10:35:21 +02:00
tri : : UpdateTopology < MeshType > : : TestVertexEdge ( poly ) ;
int dupVertNum = Clean < MeshType > : : RemoveDuplicateVertex ( poly ) ;
if ( dupVertNum ) {
printf ( " ****REMOVED %i Duplicated \n " , dupVertNum ) ;
tri : : Allocator < MeshType > : : CompactEveryVector ( poly ) ;
tri : : UpdateTopology < MeshType > : : VertexEdge ( poly ) ;
}
2015-12-29 08:22:13 +01:00
}
}
2017-08-30 16:03:46 +02:00
class EdgePointPred
{
public :
std : : map < std : : pair < CoordType , CoordType > , VertexPointer > & edgeToPolyVertMap ;
EdgePointPred ( std : : map < std : : pair < CoordType , CoordType > , VertexPointer > & _edgeToPolyVertMap ) : edgeToPolyVertMap ( _edgeToPolyVertMap ) { } ;
bool operator ( ) ( face : : Pos < FaceType > ep ) const
{
CoordType p0 = ep . V ( ) - > P ( ) ;
CoordType p1 = ep . VFlip ( ) - > P ( ) ;
if ( p0 > p1 ) std : : swap ( p0 , p1 ) ;
VertexPointer vp = edgeToPolyVertMap [ make_pair ( p0 , p1 ) ] ;
return vp ! = 0 ;
}
} ;
2017-09-05 00:38:43 +02:00
struct EdgePointSplit : public std : : unary_function < face : : Pos < FaceType > , CoordType >
2017-08-30 16:03:46 +02:00
{
public :
std : : map < std : : pair < CoordType , CoordType > , VertexPointer > & edgeToPolyVertMap ;
EdgePointSplit ( std : : map < std : : pair < CoordType , CoordType > , VertexPointer > & _edgeToPolyVertMap ) : edgeToPolyVertMap ( _edgeToPolyVertMap ) { } ;
void operator ( ) ( VertexType & nv , face : : Pos < FaceType > ep )
{
CoordType p0 = ep . V ( ) - > P ( ) ;
CoordType p1 = ep . VFlip ( ) - > P ( ) ;
if ( p0 > p1 ) std : : swap ( p0 , p1 ) ;
VertexPointer vp = edgeToPolyVertMap [ make_pair ( p0 , p1 ) ] ;
assert ( vp ) ;
nv . P ( ) = vp - > P ( ) ;
return ;
}
Color4b WedgeInterp ( Color4b & c0 , Color4b & c1 )
{
Color4b cc ;
cc . lerp ( c0 , c1 , 0.5f ) ;
return Color4b : : Red ;
}
TexCoord2f WedgeInterp ( TexCoord2f & t0 , TexCoord2f & t1 )
{
TexCoord2f tmp ;
assert ( t0 . n ( ) = = t1 . n ( ) ) ;
tmp . n ( ) = t0 . n ( ) ;
tmp . t ( ) = ( t0 . t ( ) + t1 . t ( ) ) / 2.0 ;
return tmp ;
}
2015-12-29 08:22:13 +01:00
} ;
2017-08-30 16:03:46 +02:00
} ;
2015-12-29 08:22:13 +01:00
} // end namespace tri
} // end namespace vcg
# endif // __VCGLIB_CURVE_ON_SURF_H