Added IsCoherentlyOrientedMesh and cleaned up a bit the self intersection
This commit is contained in:
parent
9acdf598a1
commit
98e49178ba
|
@ -120,7 +120,7 @@ private:
|
||||||
typedef typename MeshType::ConstVertexIterator ConstVertexIterator;
|
typedef typename MeshType::ConstVertexIterator ConstVertexIterator;
|
||||||
typedef typename MeshType::EdgeIterator EdgeIterator;
|
typedef typename MeshType::EdgeIterator EdgeIterator;
|
||||||
typedef typename MeshType::EdgePointer EdgePointer;
|
typedef typename MeshType::EdgePointer EdgePointer;
|
||||||
typedef typename MeshType::CoordType CoordType;
|
typedef typename MeshType::CoordType CoordType;
|
||||||
typedef typename MeshType::ScalarType ScalarType;
|
typedef typename MeshType::ScalarType ScalarType;
|
||||||
typedef typename MeshType::FaceType FaceType;
|
typedef typename MeshType::FaceType FaceType;
|
||||||
typedef typename MeshType::FacePointer FacePointer;
|
typedef typename MeshType::FacePointer FacePointer;
|
||||||
|
@ -308,8 +308,8 @@ private:
|
||||||
*/
|
*/
|
||||||
static int RemoveDuplicateEdge( MeshType & m) // V1.0
|
static int RemoveDuplicateEdge( MeshType & m) // V1.0
|
||||||
{
|
{
|
||||||
//assert(m.fn == 0 && m.en >0); // just to be sure we are using an edge mesh...
|
//assert(m.fn == 0 && m.en >0); // just to be sure we are using an edge mesh...
|
||||||
if (m.en==0)return 0;
|
if (m.en==0)return 0;
|
||||||
std::vector<SortedPair> eVec;
|
std::vector<SortedPair> eVec;
|
||||||
for(EdgeIterator ei=m.edge.begin();ei!=m.edge.end();++ei)
|
for(EdgeIterator ei=m.edge.begin();ei!=m.edge.end();++ei)
|
||||||
if(!(*ei).IsD())
|
if(!(*ei).IsD())
|
||||||
|
@ -944,117 +944,115 @@ private:
|
||||||
return nonManifoldCnt;
|
return nonManifoldCnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CountEdges( MeshType & m, int &count_e, int &boundary_e )
|
static void CountEdges( MeshType & m, int &count_e, int &boundary_e )
|
||||||
|
{
|
||||||
|
tri::RequireFFAdjacency(m);
|
||||||
|
count_e=0;
|
||||||
|
boundary_e=0;
|
||||||
|
UpdateFlags<MeshType>::FaceClearV(m);
|
||||||
|
bool counted =false;
|
||||||
|
for(FaceIterator fi=m.face.begin();fi!=m.face.end();fi++)
|
||||||
|
{
|
||||||
|
if(!((*fi).IsD()))
|
||||||
|
{
|
||||||
|
(*fi).SetV();
|
||||||
|
count_e +=3; //assume that we have to increase the number of edges with three
|
||||||
|
for(int j=0; j<3; j++)
|
||||||
{
|
{
|
||||||
count_e=0;
|
if (face::IsBorder(*fi,j)) //If this edge is a border edge
|
||||||
boundary_e=0;
|
boundary_e++; // then increase the number of boundary edges
|
||||||
UpdateFlags<MeshType>::FaceClearV(m);
|
else if (IsManifold(*fi,j))//If this edge is manifold
|
||||||
FaceIterator fi;
|
{
|
||||||
vcg::face::Pos<FaceType> he;
|
if((*fi).FFp(j)->IsV()) //If the face on the other side of the edge is already selected
|
||||||
vcg::face::Pos<FaceType> hei;
|
count_e--; // we counted one edge twice
|
||||||
bool counted =false;
|
}
|
||||||
for(fi=m.face.begin();fi!=m.face.end();fi++)
|
else//We have a non-manifold edge
|
||||||
|
{
|
||||||
|
vcg::face::Pos<FaceType> hei(&(*fi), j , fi->V(j));
|
||||||
|
vcg::face::Pos<FaceType> he=hei;
|
||||||
|
he.NextF();
|
||||||
|
while (he.f!=hei.f)// so we have to iterate all faces that are connected to this edge
|
||||||
{
|
{
|
||||||
if(!((*fi).IsD()))
|
if (he.f->IsV())// if one of the other faces was already visited than this edge was counted already.
|
||||||
{
|
{
|
||||||
(*fi).SetV();
|
counted=true;
|
||||||
count_e +=3; //assume that we have to increase the number of edges with three
|
break;
|
||||||
for(int j=0; j<3; j++)
|
}
|
||||||
{
|
else
|
||||||
if (face::IsBorder(*fi,j)) //If this edge is a border edge
|
{
|
||||||
boundary_e++; // then increase the number of boundary edges
|
he.NextF();
|
||||||
else if (IsManifold(*fi,j))//If this edge is manifold
|
}
|
||||||
{
|
|
||||||
if((*fi).FFp(j)->IsV()) //If the face on the other side of the edge is already selected
|
|
||||||
count_e--; // we counted one edge twice
|
|
||||||
}
|
|
||||||
else//We have a non-manifold edge
|
|
||||||
{
|
|
||||||
hei.Set(&(*fi), j , fi->V(j));
|
|
||||||
he=hei;
|
|
||||||
he.NextF();
|
|
||||||
while (he.f!=hei.f)// so we have to iterate all faces that are connected to this edge
|
|
||||||
{
|
|
||||||
if (he.f->IsV())// if one of the other faces was already visited than this edge was counted already.
|
|
||||||
{
|
|
||||||
counted=true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
he.NextF();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (counted)
|
|
||||||
{
|
|
||||||
count_e--;
|
|
||||||
counted=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if (counted)
|
||||||
|
|
||||||
|
|
||||||
static int CountHoles( MeshType & m)
|
|
||||||
{
|
|
||||||
int numholev=0;
|
|
||||||
FaceIterator fi;
|
|
||||||
|
|
||||||
FaceIterator gi;
|
|
||||||
vcg::face::Pos<FaceType> he;
|
|
||||||
vcg::face::Pos<FaceType> hei;
|
|
||||||
|
|
||||||
std::vector< std::vector<Point3x> > holes; //indices of vertices
|
|
||||||
|
|
||||||
vcg::tri::UpdateFlags<MeshType>::VertexClearS(m);
|
|
||||||
|
|
||||||
gi=m.face.begin(); fi=gi;
|
|
||||||
|
|
||||||
for(fi=m.face.begin();fi!=m.face.end();fi++)//for all faces do
|
|
||||||
{
|
{
|
||||||
for(int j=0;j<3;j++)//for all edges
|
count_e--;
|
||||||
{
|
counted=false;
|
||||||
if(fi->V(j)->IsS()) continue;
|
|
||||||
|
|
||||||
if(face::IsBorder(*fi,j))//found an unvisited border edge
|
|
||||||
{
|
|
||||||
he.Set(&(*fi),j,fi->V(j)); //set the face-face iterator to the current face, edge and vertex
|
|
||||||
std::vector<Point3x> hole; //start of a new hole
|
|
||||||
hole.push_back(fi->P(j)); // including the first vertex
|
|
||||||
numholev++;
|
|
||||||
he.v->SetS(); //set the current vertex as selected
|
|
||||||
he.NextB(); //go to the next boundary edge
|
|
||||||
|
|
||||||
|
|
||||||
while(fi->V(j) != he.v)//will we do not encounter the first boundary edge.
|
|
||||||
{
|
|
||||||
Point3x newpoint = he.v->P(); //select its vertex.
|
|
||||||
if(he.v->IsS())//check if this vertex was selected already, because then we have an additional hole.
|
|
||||||
{
|
|
||||||
//cut and paste the additional hole.
|
|
||||||
std::vector<Point3x> hole2;
|
|
||||||
int index = static_cast<int>(find(hole.begin(),hole.end(),newpoint)
|
|
||||||
- hole.begin());
|
|
||||||
for(unsigned int i=index; i<hole.size(); i++)
|
|
||||||
hole2.push_back(hole[i]);
|
|
||||||
|
|
||||||
hole.resize(index);
|
|
||||||
if(hole2.size()!=0) //annoying in degenerate cases
|
|
||||||
holes.push_back(hole2);
|
|
||||||
}
|
|
||||||
hole.push_back(newpoint);
|
|
||||||
numholev++;
|
|
||||||
he.v->SetS(); //set the current vertex as selected
|
|
||||||
he.NextB(); //go to the next boundary edge
|
|
||||||
}
|
|
||||||
holes.push_back(hole);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return static_cast<int>(holes.size());
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int CountHoles( MeshType & m)
|
||||||
|
{
|
||||||
|
int numholev=0;
|
||||||
|
FaceIterator fi;
|
||||||
|
|
||||||
|
FaceIterator gi;
|
||||||
|
vcg::face::Pos<FaceType> he;
|
||||||
|
vcg::face::Pos<FaceType> hei;
|
||||||
|
|
||||||
|
std::vector< std::vector<Point3x> > holes; //indices of vertices
|
||||||
|
|
||||||
|
vcg::tri::UpdateFlags<MeshType>::VertexClearS(m);
|
||||||
|
|
||||||
|
gi=m.face.begin(); fi=gi;
|
||||||
|
|
||||||
|
for(fi=m.face.begin();fi!=m.face.end();fi++)//for all faces do
|
||||||
|
{
|
||||||
|
for(int j=0;j<3;j++)//for all edges
|
||||||
|
{
|
||||||
|
if(fi->V(j)->IsS()) continue;
|
||||||
|
|
||||||
|
if(face::IsBorder(*fi,j))//found an unvisited border edge
|
||||||
|
{
|
||||||
|
he.Set(&(*fi),j,fi->V(j)); //set the face-face iterator to the current face, edge and vertex
|
||||||
|
std::vector<Point3x> hole; //start of a new hole
|
||||||
|
hole.push_back(fi->P(j)); // including the first vertex
|
||||||
|
numholev++;
|
||||||
|
he.v->SetS(); //set the current vertex as selected
|
||||||
|
he.NextB(); //go to the next boundary edge
|
||||||
|
|
||||||
|
|
||||||
|
while(fi->V(j) != he.v)//will we do not encounter the first boundary edge.
|
||||||
|
{
|
||||||
|
Point3x newpoint = he.v->P(); //select its vertex.
|
||||||
|
if(he.v->IsS())//check if this vertex was selected already, because then we have an additional hole.
|
||||||
|
{
|
||||||
|
//cut and paste the additional hole.
|
||||||
|
std::vector<Point3x> hole2;
|
||||||
|
int index = static_cast<int>(find(hole.begin(),hole.end(),newpoint)
|
||||||
|
- hole.begin());
|
||||||
|
for(unsigned int i=index; i<hole.size(); i++)
|
||||||
|
hole2.push_back(hole[i]);
|
||||||
|
|
||||||
|
hole.resize(index);
|
||||||
|
if(hole2.size()!=0) //annoying in degenerate cases
|
||||||
|
holes.push_back(hole2);
|
||||||
|
}
|
||||||
|
hole.push_back(newpoint);
|
||||||
|
numholev++;
|
||||||
|
he.v->SetS(); //set the current vertex as selected
|
||||||
|
he.NextB(); //go to the next boundary edge
|
||||||
|
}
|
||||||
|
holes.push_back(hole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return static_cast<int>(holes.size());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compute the set of connected components of a given mesh
|
Compute the set of connected components of a given mesh
|
||||||
|
@ -1212,103 +1210,105 @@ private:
|
||||||
Semiregular = false;
|
Semiregular = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// static void IsOrientedMesh(MeshType &m, bool &Oriented, bool &Orientable)
|
|
||||||
static void OrientCoherentlyMesh(MeshType &m, bool &Oriented, bool &Orientable)
|
|
||||||
{
|
|
||||||
RequireFFAdjacency(m);
|
|
||||||
assert(&Oriented != &Orientable);
|
|
||||||
|
|
||||||
// This algorithms require FF topology initialized
|
|
||||||
assert(m.face.back().FFp(0));
|
|
||||||
|
|
||||||
|
|
||||||
Orientable = true;
|
static bool IsCoherentlyOrientedMesh(MeshType &m)
|
||||||
Oriented = true;
|
{
|
||||||
|
for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
|
||||||
|
if (!fi->IsD())
|
||||||
|
for(int i=0;i<3;++i)
|
||||||
|
if(!face::CheckOrientation(*fi,i))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Ensure that each face is deselected
|
return true;
|
||||||
FaceIterator fi;
|
}
|
||||||
for (fi = m.face.begin(); fi != m.face.end(); ++fi)
|
|
||||||
fi->ClearS();
|
|
||||||
|
|
||||||
// initialize stack
|
static void OrientCoherentlyMesh(MeshType &m, bool &Oriented, bool &Orientable)
|
||||||
std::stack<FacePointer> faces;
|
{
|
||||||
|
RequireFFAdjacency(m);
|
||||||
|
assert(&Oriented != &Orientable);
|
||||||
|
assert(m.face.back().FFp(0)); // This algorithms require FF topology initialized
|
||||||
|
|
||||||
// for each face of the mesh
|
Orientable = true;
|
||||||
FacePointer fp,fpaux;
|
Oriented = true;
|
||||||
int iaux;
|
|
||||||
for (fi = m.face.begin(); fi != m.face.end(); ++fi)
|
|
||||||
{
|
|
||||||
if (!fi->IsD() && !fi->IsS())
|
|
||||||
{
|
|
||||||
// each face put in the stack is selected (and oriented)
|
|
||||||
fi->SetS();
|
|
||||||
faces.push(&(*fi));
|
|
||||||
|
|
||||||
// empty the stack
|
tri::UpdateSelection<MeshType>::FaceClear(m);
|
||||||
while (!faces.empty())
|
std::stack<FacePointer> faces;
|
||||||
{
|
for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
|
||||||
fp = faces.top();
|
{
|
||||||
faces.pop();
|
if (!fi->IsD() && !fi->IsS())
|
||||||
|
{
|
||||||
|
// each face put in the stack is selected (and oriented)
|
||||||
|
fi->SetS();
|
||||||
|
faces.push(&(*fi));
|
||||||
|
|
||||||
// make consistently oriented the adjacent faces
|
// empty the stack
|
||||||
for (int j = 0; j < 3; j++)
|
while (!faces.empty())
|
||||||
{
|
{
|
||||||
// get one of the adjacent face
|
FacePointer fp = faces.top();
|
||||||
fpaux = fp->FFp(j);
|
faces.pop();
|
||||||
iaux = fp->FFi(j);
|
|
||||||
|
|
||||||
if (!fpaux->IsD() && fpaux != fp && face::IsManifold<FaceType>(*fp, j))
|
// make consistently oriented the adjacent faces
|
||||||
{
|
for (int j = 0; j < 3; j++)
|
||||||
if (!CheckOrientation(*fpaux, iaux))
|
{
|
||||||
{
|
// get one of the adjacent face
|
||||||
Oriented = false;
|
FacePointer fpaux = fp->FFp(j);
|
||||||
|
int iaux = fp->FFi(j);
|
||||||
|
|
||||||
if (!fpaux->IsS())
|
if (!fpaux->IsD() && fpaux != fp && face::IsManifold<FaceType>(*fp, j))
|
||||||
{
|
{
|
||||||
face::SwapEdge<FaceType,true>(*fpaux, iaux);
|
if (!CheckOrientation(*fpaux, iaux))
|
||||||
assert(CheckOrientation(*fpaux, iaux));
|
{
|
||||||
}
|
Oriented = false;
|
||||||
else
|
|
||||||
{
|
|
||||||
Orientable = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// put the oriented face into the stack
|
if (!fpaux->IsS())
|
||||||
|
{
|
||||||
|
face::SwapEdge<FaceType,true>(*fpaux, iaux);
|
||||||
|
assert(CheckOrientation(*fpaux, iaux));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Orientable = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!fpaux->IsS())
|
// put the oriented face into the stack
|
||||||
{
|
|
||||||
fpaux->SetS();
|
|
||||||
faces.push(fpaux);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Orientable) break;
|
if (!fpaux->IsS())
|
||||||
}
|
{
|
||||||
}
|
fpaux->SetS();
|
||||||
/// Flip the orientation of the whole mesh flipping all the faces (by swapping the first two vertices)
|
faces.push(fpaux);
|
||||||
static void FlipMesh(MeshType &m, bool selected=false)
|
}
|
||||||
{
|
}
|
||||||
for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD())
|
}
|
||||||
if(!selected || (*fi).IsS())
|
}
|
||||||
{
|
}
|
||||||
face::SwapEdge<FaceType,false>((*fi), 0);
|
|
||||||
if (HasPerWedgeTexCoord(m))
|
if (!Orientable) break;
|
||||||
std::swap((*fi).WT(0),(*fi).WT(1));
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/// Flip a mesh so that its normals are orented outside.
|
|
||||||
/// Just for safety it uses a voting scheme.
|
/// Flip the orientation of the whole mesh flipping all the faces (by swapping the first two vertices)
|
||||||
/// It assumes that
|
static void FlipMesh(MeshType &m, bool selected=false)
|
||||||
/// mesh has already has coherent normals.
|
{
|
||||||
/// mesh is watertight and signle component.
|
for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD())
|
||||||
static bool FlipNormalOutside(MeshType &m)
|
if(!selected || (*fi).IsS())
|
||||||
{
|
{
|
||||||
if(m.vert.empty()) return false;
|
face::SwapEdge<FaceType,false>((*fi), 0);
|
||||||
|
if (HasPerWedgeTexCoord(m))
|
||||||
|
std::swap((*fi).WT(0),(*fi).WT(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Flip a mesh so that its normals are orented outside.
|
||||||
|
/// Just for safety it uses a voting scheme.
|
||||||
|
/// It assumes that
|
||||||
|
/// mesh has already has coherent normals.
|
||||||
|
/// mesh is watertight and signle component.
|
||||||
|
static bool FlipNormalOutside(MeshType &m)
|
||||||
|
{
|
||||||
|
if(m.vert.empty()) return false;
|
||||||
|
|
||||||
tri::UpdateNormal<MeshType>::PerVertexAngleWeighted(m);
|
tri::UpdateNormal<MeshType>::PerVertexAngleWeighted(m);
|
||||||
tri::UpdateNormal<MeshType>::NormalizePerVertex(m);
|
tri::UpdateNormal<MeshType>::NormalizePerVertex(m);
|
||||||
|
@ -1494,43 +1494,42 @@ private:
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool SelfIntersections(MeshType &m, std::vector<FaceType*> &ret)
|
static bool SelfIntersections(MeshType &m, std::vector<FaceType*> &ret)
|
||||||
{
|
{
|
||||||
RequirePerFaceMark(m);
|
RequirePerFaceMark(m);
|
||||||
Box3< ScalarType> bbox;
|
ret.clear();
|
||||||
TriMeshGrid gM;
|
int referredBit = FaceType::NewBitFlag();
|
||||||
ret.clear();
|
tri::UpdateFlags<MeshType>::FaceClear(m,referredBit);
|
||||||
FaceIterator fi;
|
|
||||||
int referredBit = FaceType::NewBitFlag();
|
|
||||||
tri::UpdateFlags<MeshType>::FaceClear(m,referredBit);
|
|
||||||
|
|
||||||
std::vector<FaceType*> inBox;
|
TriMeshGrid gM;
|
||||||
gM.Set(m.face.begin(),m.face.end());
|
gM.Set(m.face.begin(),m.face.end());
|
||||||
|
|
||||||
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
||||||
{
|
{
|
||||||
(*fi).SetUserBit(referredBit);
|
(*fi).SetUserBit(referredBit);
|
||||||
(*fi).GetBBox(bbox);
|
Box3< ScalarType> bbox;
|
||||||
vcg::tri::GetInBoxFace(m, gM, bbox,inBox);
|
(*fi).GetBBox(bbox);
|
||||||
bool Intersected=false;
|
std::vector<FaceType*> inBox;
|
||||||
typename std::vector<FaceType*>::iterator fib;
|
vcg::tri::GetInBoxFace(m, gM, bbox,inBox);
|
||||||
for(fib=inBox.begin();fib!=inBox.end();++fib)
|
bool Intersected=false;
|
||||||
{
|
typename std::vector<FaceType*>::iterator fib;
|
||||||
if(!(*fib)->IsUserBit(referredBit) && (*fib != &*fi) )
|
for(fib=inBox.begin();fib!=inBox.end();++fib)
|
||||||
if(TestFaceFaceIntersection(&*fi,*fib)){
|
{
|
||||||
ret.push_back(*fib);
|
if(!(*fib)->IsUserBit(referredBit) && (*fib != &*fi) )
|
||||||
if(!Intersected) {
|
if(Clean<MeshType>::TestFaceFaceIntersection(&*fi,*fib)){
|
||||||
ret.push_back(&*fi);
|
ret.push_back(*fib);
|
||||||
Intersected=true;
|
if(!Intersected) {
|
||||||
}
|
ret.push_back(&*fi);
|
||||||
|
Intersected=true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
inBox.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
FaceType::DeleteBitFlag(referredBit);
|
|
||||||
return (ret.size()>0);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
inBox.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
FaceType::DeleteBitFlag(referredBit);
|
||||||
|
return (ret.size()>0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This function simply test that the vn and fn counters be consistent with the size of the containers and the number of deleted simplexes.
|
This function simply test that the vn and fn counters be consistent with the size of the containers and the number of deleted simplexes.
|
||||||
|
@ -1623,8 +1622,19 @@ private:
|
||||||
int i0,i1; ScalarType a,b;
|
int i0,i1; ScalarType a,b;
|
||||||
face::FindSharedVertex(f0,f1,i0,i1);
|
face::FindSharedVertex(f0,f1,i0,i1);
|
||||||
Point3f shP = f0->V(i0)->P()*0.5;
|
Point3f shP = f0->V(i0)->P()*0.5;
|
||||||
if(vcg::IntersectionSegmentTriangle(Segment3<ScalarType>((*f0).V1(i0)->P()*0.5+shP,(*f0).V2(i0)->P()*0.5+shP), *f1, a, b) ) return true;
|
if(vcg::IntersectionSegmentTriangle(Segment3<ScalarType>((*f0).V1(i0)->P()*0.5+shP,(*f0).V2(i0)->P()*0.5+shP), *f1, a, b) )
|
||||||
if(vcg::IntersectionSegmentTriangle(Segment3<ScalarType>((*f1).V1(i1)->P()*0.5+shP,(*f1).V2(i1)->P()*0.5+shP), *f0, a, b) ) return true;
|
{
|
||||||
|
// a,b are the param coords of the intersection point of the segment.
|
||||||
|
if(a+b>=1 || a<=EPSIL || b<=EPSIL ) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(vcg::IntersectionSegmentTriangle(Segment3<ScalarType>((*f1).V1(i1)->P()*0.5+shP,(*f1).V2(i1)->P()*0.5+shP), *f0, a, b) )
|
||||||
|
{
|
||||||
|
// a,b are the param coords of the intersection point of the segment.
|
||||||
|
if(a+b>=1 || a<=EPSIL || b<=EPSIL ) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue