vcglib/vcg/complex/algorithms/clip.h

1115 lines
28 KiB
C++

/****************************************************************************
* 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. *
* *
****************************************************************************/
/****************************************************************************
History
$Log: not supported by cvs2svn $
****************************************************************************/
#ifndef __VCGLIB_TRI_CLIP
#define __VCGLIB_TRI_CLIP
#include <vector>
#ifdef _WIN32
#ifndef __MINGW32__
#include <hash_map>
#define STDEXT stdext
#else
#include <ext/hash_map>
#define STDEXT __gnu_cxx
#endif
#else
#include <ext/hash_map>
#define STDEXT __gnu_cxx
#endif
namespace vcg
{
namespace tri
{
template <typename MESH_TYPE>
class GenericVertexInterpolator
{
public:
typedef typename MESH_TYPE::VertexType VertexType;
typedef GenericVertexInterpolator<MESH_TYPE> ClassType;
typedef typename VertexType::CoordType CoordType;
typedef typename CoordType::ScalarType ScalarType;
GenericVertexInterpolator(MESH_TYPE &_m) : m(_m) {}
private:
MESH_TYPE &m;
public:
inline void operator () (const VertexType & v0, const VertexType & v1, const VertexType & v2, const ScalarType & a, const ScalarType & b, VertexType & r) const
{
// position
r.P() = v0.P() + (v1.P() - v0.P()) * a + (v2.P() - v0.P()) * b;
// normal
if (tri::HasPerVertexNormal(m))
{
r.N() = v0.cN() + (v1.cN() - v0.cN()) * a + (v2.cN() - v0.cN()) * b;
}
// color
if (tri::HasPerVertexColor(m))
{
vcg::Point4<ScalarType> vc[3];
vc[0].Import(v0.cC());
vc[1].Import(v1.cC());
vc[2].Import(v2.cC());
const vcg::Point4<ScalarType> rc = (vc[0] + (vc[1] - vc[0]) * a + (vc[2] - vc[0]) * b);
r.C()[0] = (typename vcg::Color4b::ScalarType)(rc[0]);
r.C()[1] = (typename vcg::Color4b::ScalarType)(rc[1]);
r.C()[2] = (typename vcg::Color4b::ScalarType)(rc[2]);
r.C()[3] = (typename vcg::Color4b::ScalarType)(rc[3]);
}
// texcoord
if (tri::HasPerVertexTexCoord(m))
{
const short nt = 1; //typename VertexType::TextureType::N();
for (short i=0; i<nt; ++i)
{
r.T().t(i) = v0.cT().t(i) + (v1.cT().t(i) - v0.cT().t(i)) * a + (v2.cT().t(i) - v0.cT().t(i)) * b;
}
}
}
};
template <typename TRIMESHTYPE>
class TriMeshClipper
{
public:
typedef TriMeshClipper<TRIMESHTYPE> ClassType;
typedef TRIMESHTYPE TriMeshType;
typedef typename TriMeshType::FaceType FaceType;
typedef typename FaceType::VertexType VertexType;
typedef typename VertexType::CoordType CoordType;
typedef typename CoordType::ScalarType ScalarType;
/*
static inline void Box(const Box3<ScalarType> & b, VERTEXINTEPOLATOR & vInterp, TriMeshType & m);
Clip mesh "m" against an axis aligned box (in place version);
Notes:
1) faces marked as deleted are skipped;
2) faces completely outside box are marked as deleted;
3) faces completely inside box are left unchanged;
4) faces intersecting box's sides are marked as deleted:
they are replaced with proper tesselation; new vertices and faces
are created, so reallocation could occour; previously saved pointers
could not to be valid anymore, thus they should be updated;
5) vInterp functor must implement a n operator with signature
void operator () (const VERTEX & v0, const VERTEX & v1, const VERTEX & v2, const Scalar & a, const Scalar & b, VERTEX & r);
its semantic is to intepolate vertex attribute across triangle; a typical implementation is;
r.P() = v0.P() + a * (v1.P() - v0.P()) + b * (v2.P() - v0.P()); // interpolate position
r.N() = v0.N() + a * (v1.N() - v0.N()) + b * (v2.N() - v0.N()); // interpolate normal
... // interpolate other vertex attributes
*/
template <class ScalarType>
class VertexClipInfo
{
public:
// typedef VertexClipInfo ClassType;
ScalarType fU;
ScalarType fV;
unsigned int idx;
unsigned int tref;
};
typedef typename std::vector< VertexClipInfo<ScalarType> > VertexClipInfoVec;
class TriangleInfo
{
public:
typedef TriangleInfo ClassType;
unsigned int v[3];
unsigned int idx;
};
typedef std::vector<TriangleInfo> TriangleInfoVec;
class EdgeIsect
{
public:
CoordType p;
unsigned int idx;
};
template <typename VERTEXINTEPOLATOR>
static inline void Box(const Box3<ScalarType> & b, VERTEXINTEPOLATOR & vInterp, TriMeshType & m)
{
std::vector<unsigned int> facesToDelete;
ClassType::Box(b, vInterp, m, facesToDelete);
for (size_t i=0; i<facesToDelete.size(); ++i)
{
m.face[facesToDelete[i]].SetD();
}
}
class EdgeIntersections
{
public:
unsigned int n;
EdgeIsect isects[6];
EdgeIntersections(void)
{
this->n = 0;
}
};
typedef STDEXT::hash_map<unsigned int, EdgeIntersections> UIntHMap;
typedef typename UIntHMap::iterator UIntHMap_i;
typedef typename UIntHMap::value_type UIntHMap_v;
typedef STDEXT::hash_map<unsigned int, UIntHMap> EdgeMap;
typedef typename EdgeMap::iterator EdgeMap_i;
typedef typename EdgeMap::value_type EdgeMap_v;
typedef typename TriMeshType::FaceIterator FaceIterator;
template <typename VERTEXINTEPOLATOR, typename FACEINDEXCONTAINER>
static inline void Box(const Box3<ScalarType> & b, VERTEXINTEPOLATOR & vInterp, TriMeshType & m, FACEINDEXCONTAINER & facesToDelete)
{
if (m.fn <= 0)
{
return;
}
EdgeMap edges;
VertexClipInfoVec vInfos;
TriangleInfoVec tInfos;
CoordType vTriangle[4];
CoordType vClipped[64];
CoordType pvP0[64];
CoordType pvP1[64];
unsigned int numDeletedTris = 0;
unsigned int numTriangles = 0;
unsigned int numVertices = 0;
unsigned int vIdx = (unsigned int)(m.vn);
unsigned int tIdx = (unsigned int)(m.fn);
ScalarType boxOffsets[6];
boxOffsets[0] = b.min[0];
boxOffsets[1] = -b.max[0];
boxOffsets[2] = b.min[1];
boxOffsets[3] = -b.max[1];
boxOffsets[4] = b.min[2];
boxOffsets[5] = -b.max[2];
UIntHMap emptyMap;
EdgeIntersections emptyIsects;
const ScalarType eps = (ScalarType)(1e-6);
for (FaceIterator it=m.face.begin(); it!=m.face.end(); ++it)
{
if ((*it).IsD())
{
continue;
}
unsigned int cc[3];
cc[0] = ClassType::BoxClipCode(boxOffsets, (*it).V(0)->P());
cc[1] = ClassType::BoxClipCode(boxOffsets, (*it).V(1)->P());
cc[2] = ClassType::BoxClipCode(boxOffsets, (*it).V(2)->P());
if ((cc[0] | cc[1] | cc[2]) == 0)
{
continue;
}
const unsigned int refT = (unsigned int)(std::distance(m.face.begin(), it));
if ((cc[0] & cc[1] & cc[2]) != 0)
{
facesToDelete.push_back(refT);
(*it).SetD();
numDeletedTris++;
continue;
}
facesToDelete.push_back(refT);
vTriangle[0] = (*it).V(0)->P();
vTriangle[1] = (*it).V(1)->P();
vTriangle[2] = (*it).V(2)->P();
vTriangle[3] = (*it).V(0)->P();
unsigned int n, n0, n1;
ClipPolygonLine(0, b.min[0], vTriangle, 4, pvP1, n1);
ClipPolygonLine(1, b.max[0], pvP1, n1, pvP0, n0);
ClipPolygonLine(2, b.min[1], pvP0, n0, pvP1, n1);
ClipPolygonLine(3, b.max[1], pvP1, n1, pvP0, n0);
ClipPolygonLine(4, b.min[2], pvP0, n0, pvP1, n1);
ClipPolygonLine(5, b.max[2], pvP1, n1, vClipped, n);
assert(n < 64);
unsigned int firstV, lastV;
if (n > 2)
{
if (vClipped[0] == vClipped[n - 1])
{
n--;
}
const CoordType vU = vTriangle[1] - vTriangle[0];
const CoordType vV = vTriangle[2] - vTriangle[0];
const ScalarType tArea = (vU ^ vV).SquaredNorm();
if (tArea < eps)
{
continue;
}
unsigned int tvidx[3];
tvidx[0] = (*it).V(0) - &(*(m.vert.begin()));
tvidx[1] = (*it).V(1) - &(*(m.vert.begin()));
tvidx[2] = (*it).V(2) - &(*(m.vert.begin()));
numTriangles += n - 2;
// size_t vBegin = vInfos.size();
VertexClipInfo<ScalarType> vnfo;
TriangleInfo tnfo;
unsigned int vmin[3];
unsigned int vmax[3];
if (tvidx[0] < tvidx[1])
{
vmin[0] = tvidx[0];
vmax[0] = tvidx[1];
}
else
{
vmin[0] = tvidx[1];
vmax[0] = tvidx[0];
}
if (tvidx[0] < tvidx[2])
{
vmin[1] = tvidx[0];
vmax[1] = tvidx[2];
}
else
{
vmin[1] = tvidx[2];
vmax[1] = tvidx[0];
}
if (tvidx[1] < tvidx[2])
{
vmin[2] = tvidx[1];
vmax[2] = tvidx[2];
}
else
{
vmin[2] = tvidx[2];
vmax[2] = tvidx[1];
}
for (unsigned int i=0; i<n; ++i)
{
vnfo.tref = refT;
const CoordType vP = vClipped[i] - vTriangle[0];
ScalarType tAreaU = (vU ^ vP).SquaredNorm();
ScalarType tAreaV = (vP ^ vV).SquaredNorm();
vnfo.fU = (ScalarType)(sqrt(tAreaU / tArea));
vnfo.fV = (ScalarType)(sqrt(tAreaV / tArea));
if (vClipped[i] == vTriangle[0])
{
vnfo.idx = tvidx[0];
}
else if (vClipped[i] == vTriangle[1])
{
vnfo.idx = tvidx[1];
}
else if (vClipped[i] == vTriangle[2])
{
vnfo.idx = tvidx[2];
}
else if (vnfo.fV < eps)
{
std::pair<EdgeMap_i, bool> mi = edges.insert(std::make_pair(vmin[1], emptyMap));
std::pair<UIntHMap_i, bool> hi = (*(mi.first)).second.insert(std::make_pair(vmax[1], emptyIsects));
bool found = false;
for (unsigned int s=0; s<(*(hi.first)).second.n; ++s)
{
if (vClipped[i] == (*(hi.first)).second.isects[s].p)
{
found = true;
vnfo.idx = (*(hi.first)).second.isects[s].idx;
break;
}
}
if (!found)
{
vnfo.idx = vIdx++;
numVertices++;
vInfos.push_back(vnfo);
(*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i];
(*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vnfo.idx;
(*(hi.first)).second.n++;
}
}
else if (vnfo.fU < eps)
{
std::pair<EdgeMap_i, bool> mi = edges.insert(std::make_pair(vmin[0], emptyMap));
std::pair<UIntHMap_i, bool> hi = (*(mi.first)).second.insert(std::make_pair(vmax[0], emptyIsects));
bool found = false;
for (unsigned int s=0; s<(*(hi.first)).second.n; ++s)
{
if (vClipped[i] == (*(hi.first)).second.isects[s].p)
{
found = true;
vnfo.idx = (*(hi.first)).second.isects[s].idx;
break;
}
}
if (!found)
{
vnfo.idx = vIdx++;
numVertices++;
vInfos.push_back(vnfo);
(*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i];
(*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vnfo.idx;
(*(hi.first)).second.n++;
}
}
else if ((vnfo.fU + vnfo.fV) >= ((ScalarType)(1.0 - 1e-5)))
{
std::pair<EdgeMap_i, bool> mi = edges.insert(std::make_pair(vmin[2], emptyMap));
std::pair<UIntHMap_i, bool> hi = (*(mi.first)).second.insert(std::make_pair(vmax[2], emptyIsects));
bool found = false;
for (unsigned int s=0; s<(*(hi.first)).second.n; ++s)
{
if (vClipped[i] == (*(hi.first)).second.isects[s].p)
{
found = true;
vnfo.idx = (*(hi.first)).second.isects[s].idx;
break;
}
}
if (!found)
{
vnfo.idx = vIdx++;
numVertices++;
vInfos.push_back(vnfo);
(*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i];
(*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vnfo.idx;
(*(hi.first)).second.n++;
}
}
else
{
vnfo.idx = vIdx++;
numVertices++;
vInfos.push_back(vnfo);
}
if (i == 0)
{
firstV = vnfo.idx;
}
if (i > 1)
{
tnfo.idx = tIdx++;
tnfo.v[0] = firstV;
tnfo.v[1] = lastV;
tnfo.v[2] = vnfo.idx;
tInfos.push_back(tnfo);
}
lastV = vnfo.idx;
}
}
}
if (numTriangles == 0)
{
return;
}
const unsigned int vSize = (unsigned int)(m.vn);
const unsigned int tSize = (unsigned int)(m.fn);
typedef Allocator<TriMeshType> TriMeshAllocatorType;
TriMeshAllocatorType::AddVertices(m, numVertices);
TriMeshAllocatorType::AddFaces(m, numTriangles);
unsigned int j = vSize;
for (size_t i=0; i<vInfos.size(); ++i)
{
if (vInfos[i].idx >= vSize)
{
const unsigned int tref = vInfos[i].tref;
vInterp(*(m.face[tref].V(0)), *(m.face[tref].V(1)), *(m.face[tref].V(2)), vInfos[i].fV, vInfos[i].fU, m.vert[j]);
j++;
}
}
j = tSize;
for (size_t i=0; i<tInfos.size(); ++i)
{
m.face[j].V(0) = &(m.vert[tInfos[i].v[0]]);
m.face[j].V(1) = &(m.vert[tInfos[i].v[1]]);
m.face[j].V(2) = &(m.vert[tInfos[i].v[2]]);
j++;
}
}
/*
static inline void Box(const Box3<ScalarType> & b, VERTEXINTEPOLATOR & vInterp, const TriMeshType & m, TriMeshType & r);
Clip mesh "m" against an axis aligned box and put resulting data in mesh "r" (out of place version);
Notes:
1) input mesh is not modified;
2) faces marked as deleted are skipped;
3) vInterp functor must implement a n operator with signature
void operator () (const VERTEX & v0, const VERTEX & v1, const VERTEX & v2, const Scalar & a, const Scalar & b, VERTEX & r);
its semantic is to intepolate vertex attribute across triangle; a typical implementation is;
r.P() = v0.P() + a * (v1.P() - v0.P()) + b * (v2.P() - v0.P()); // interpolate position
r.N() = v0.N() + a * (v1.N() - v0.N()) + b * (v2.N() - v0.N()); // interpolate normal
... // interpolate other vertex attributes
*/
template <typename VERTEXINTEPOLATOR>
static inline void Box(const Box3<ScalarType> & b, VERTEXINTEPOLATOR & vInterp, const TriMeshType & m, TriMeshType & r)
{
r.Clear();
if (m.fn <= 0)
{
return;
}
class VertexClipInfo
{
public:
typedef VertexClipInfo ClassType;
ScalarType fU;
ScalarType fV;
unsigned int idx;
unsigned int tref;
};
typedef std::vector<VertexClipInfo> VertexClipInfoVec;
class TriangleInfo
{
public:
typedef TriangleInfo ClassType;
unsigned int v[3];
unsigned int idx;
};
typedef std::vector<TriangleInfo> TriangleInfoVec;
class EdgeIsect
{
public:
CoordType p;
unsigned int idx;
};
class EdgeIntersections
{
public:
unsigned int n;
EdgeIsect isects[6];
EdgeIntersections(void)
{
this->n = 0;
}
};
typedef STDEXT::hash_map<unsigned int, EdgeIntersections> UIntHMap;
typedef typename UIntHMap::iterator UIntHMap_i;
typedef typename UIntHMap::value_type UIntHMap_v;
typedef STDEXT::hash_map<unsigned int, UIntHMap> EdgeMap;
typedef typename EdgeMap::iterator EdgeMap_i;
typedef typename EdgeMap::value_type EdgeMap_v;
typedef STDEXT::hash_map<unsigned int, unsigned int> UIHMap;
typedef typename UIHMap::iterator UIHMap_i;
typedef typename TriMeshType::ConstFaceIterator ConstFaceIterator;
UIHMap origVertsMap;
EdgeMap edges;
VertexClipInfoVec vInfos;
TriangleInfoVec tInfos;
CoordType vTriangle[4];
CoordType vClipped[64];
CoordType pvP0[64];
CoordType pvP1[64];
unsigned int numDeletedTris = 0;
unsigned int numTriangles = 0;
unsigned int numVertices = 0;
unsigned int vIdx = 0;
unsigned int tIdx = 0;
ScalarType boxOffsets[6];
boxOffsets[0] = b.min[0];
boxOffsets[1] = -b.max[0];
boxOffsets[2] = b.min[1];
boxOffsets[3] = -b.max[1];
boxOffsets[4] = b.min[2];
boxOffsets[5] = -b.max[2];
UIntHMap emptyMap;
EdgeIntersections emptyIsects;
const ScalarType eps = (ScalarType)(1e-6);
for (ConstFaceIterator it=m.face.begin(); it!=m.face.end(); ++it)
{
if ((*it).IsD())
{
continue;
}
unsigned int cc[3];
cc[0] = ClassType::BoxClipCode(boxOffsets, (*it).V(0)->P());
cc[1] = ClassType::BoxClipCode(boxOffsets, (*it).V(1)->P());
cc[2] = ClassType::BoxClipCode(boxOffsets, (*it).V(2)->P());
if ((cc[0] | cc[1] | cc[2]) == 0)
{
TriangleInfo tnfo;
VertexClipInfo vnfo;
tnfo.idx = tIdx++;
for (int i=0; i<3; ++i)
{
const unsigned int v = (*it).V(i) - &(*(m.vert.begin()));
std::pair<UIHMap_i, bool> hi = origVertsMap.insert(std::make_pair(v, vIdx));
if (hi.second)
{
vnfo.idx = v;
vInfos.push_back(vnfo);
tnfo.v[i] = vIdx++;
}
else
{
tnfo.v[i] = (*(hi.first)).second;
}
}
tInfos.push_back(tnfo);
continue;
}
if ((cc[0] & cc[1] & cc[2]) != 0)
{
numDeletedTris++;
continue;
}
vTriangle[0] = (*it).V(0)->P();
vTriangle[1] = (*it).V(1)->P();
vTriangle[2] = (*it).V(2)->P();
vTriangle[3] = (*it).V(0)->P();
unsigned int n, n0, n1;
ClipPolygonLine(0, b.min[0], vTriangle, 4, pvP1, n1);
ClipPolygonLine(1, b.max[0], pvP1, n1, pvP0, n0);
ClipPolygonLine(2, b.min[1], pvP0, n0, pvP1, n1);
ClipPolygonLine(3, b.max[1], pvP1, n1, pvP0, n0);
ClipPolygonLine(4, b.min[2], pvP0, n0, pvP1, n1);
ClipPolygonLine(5, b.max[2], pvP1, n1, vClipped, n);
assert(n < 64);
unsigned int firstV, lastV;
if (n > 2)
{
if (vClipped[0] == vClipped[n - 1])
{
n--;
}
const CoordType vU = vTriangle[1] - vTriangle[0];
const CoordType vV = vTriangle[2] - vTriangle[0];
const ScalarType tArea = (vU ^ vV).SquaredNorm();
if (tArea < eps)
{
continue;
}
unsigned int tvidx[3];
tvidx[0] = (*it).V(0) - &(*(m.vert.begin()));
tvidx[1] = (*it).V(1) - &(*(m.vert.begin()));
tvidx[2] = (*it).V(2) - &(*(m.vert.begin()));
unsigned int refT = (unsigned int)(std::distance(m.face.begin(), it));
numTriangles += n - 2;
size_t vBegin = vInfos.size();
VertexClipInfo vnfo;
TriangleInfo tnfo;
unsigned int vmin[3];
unsigned int vmax[3];
if (tvidx[0] < tvidx[1])
{
vmin[0] = tvidx[0];
vmax[0] = tvidx[1];
}
else
{
vmin[0] = tvidx[1];
vmax[0] = tvidx[0];
}
if (tvidx[0] < tvidx[2])
{
vmin[1] = tvidx[0];
vmax[1] = tvidx[2];
}
else
{
vmin[1] = tvidx[2];
vmax[1] = tvidx[0];
}
if (tvidx[1] < tvidx[2])
{
vmin[2] = tvidx[1];
vmax[2] = tvidx[2];
}
else
{
vmin[2] = tvidx[2];
vmax[2] = tvidx[1];
}
for (unsigned int i=0; i<n; ++i)
{
vnfo.tref = refT;
const CoordType vP = vClipped[i] - vTriangle[0];
ScalarType tAreaU = (vU ^ vP).SquaredNorm();
ScalarType tAreaV = (vP ^ vV).SquaredNorm();
vnfo.fU = (ScalarType)(sqrt(tAreaU / tArea));
vnfo.fV = (ScalarType)(sqrt(tAreaV / tArea));
unsigned int currVIdx;
if (vClipped[i] == vTriangle[0])
{
std::pair<UIHMap_i, bool> hi = origVertsMap.insert(std::make_pair(tvidx[0], vIdx));
if (hi.second)
{
vnfo.idx = tvidx[0];
vInfos.push_back(vnfo);
currVIdx = vIdx++;
}
else
{
currVIdx = (*(hi.first)).second;
}
}
else if (vClipped[i] == vTriangle[1])
{
std::pair<UIHMap_i, bool> hi = origVertsMap.insert(std::make_pair(tvidx[1], vIdx));
if (hi.second)
{
vnfo.idx = tvidx[1];
vInfos.push_back(vnfo);
currVIdx = vIdx++;
}
else
{
currVIdx = (*(hi.first)).second;
}
}
else if (vClipped[i] == vTriangle[2])
{
std::pair<UIHMap_i, bool> hi = origVertsMap.insert(std::make_pair(tvidx[2], vIdx));
if (hi.second)
{
vnfo.idx = tvidx[2];
vInfos.push_back(vnfo);
currVIdx = vIdx++;
}
else
{
currVIdx = (*(hi.first)).second;
}
}
else if (vnfo.fV < eps)
{
std::pair<EdgeMap_i, bool> mi = edges.insert(std::make_pair(vmin[1], emptyMap));
std::pair<UIntHMap_i, bool> hi = (*(mi.first)).second.insert(std::make_pair(vmax[1], emptyIsects));
bool found = false;
for (unsigned int s=0; s<(*(hi.first)).second.n; ++s)
{
if (vClipped[i] == (*(hi.first)).second.isects[s].p)
{
found = true;
vnfo.idx = (unsigned int)(-1);
currVIdx = (*(hi.first)).second.isects[s].idx;
break;
}
}
if (!found)
{
(*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i];
(*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vIdx;
(*(hi.first)).second.n++;
vnfo.idx = (unsigned int)(-1);
numVertices++;
vInfos.push_back(vnfo);
currVIdx = vIdx++;
}
}
else if (vnfo.fU < eps)
{
std::pair<EdgeMap_i, bool> mi = edges.insert(std::make_pair(vmin[0], emptyMap));
std::pair<UIntHMap_i, bool> hi = (*(mi.first)).second.insert(std::make_pair(vmax[0], emptyIsects));
bool found = false;
for (unsigned int s=0; s<(*(hi.first)).second.n; ++s)
{
if (vClipped[i] == (*(hi.first)).second.isects[s].p)
{
found = true;
vnfo.idx = (unsigned int)(-1);
currVIdx = (*(hi.first)).second.isects[s].idx;
break;
}
}
if (!found)
{
(*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i];
(*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vIdx;
(*(hi.first)).second.n++;
vnfo.idx = (unsigned int)(-1);
numVertices++;
vInfos.push_back(vnfo);
currVIdx = vIdx++;
}
}
else if ((vnfo.fU + vnfo.fV) >= ((ScalarType)(1.0 - 1e-5)))
{
std::pair<EdgeMap_i, bool> mi = edges.insert(std::make_pair(vmin[2], emptyMap));
std::pair<UIntHMap_i, bool> hi = (*(mi.first)).second.insert(std::make_pair(vmax[2], emptyIsects));
bool found = false;
for (unsigned int s=0; s<(*(hi.first)).second.n; ++s)
{
if (vClipped[i] == (*(hi.first)).second.isects[s].p)
{
found = true;
vnfo.idx = (unsigned int)(-1);
currVIdx = (*(hi.first)).second.isects[s].idx;
break;
}
}
if (!found)
{
(*(hi.first)).second.isects[(*(hi.first)).second.n].p = vClipped[i];
(*(hi.first)).second.isects[(*(hi.first)).second.n].idx = vIdx;
(*(hi.first)).second.n++;
vnfo.idx = (unsigned int)(-1);
numVertices++;
vInfos.push_back(vnfo);
currVIdx = vIdx++;
}
}
else
{
vnfo.idx = (unsigned int)(-1);
numVertices++;
vInfos.push_back(vnfo);
currVIdx = vIdx++;
}
if (i == 0)
{
firstV = currVIdx;
}
if (i > 1)
{
tnfo.idx = tIdx++;
tnfo.v[0] = firstV;
tnfo.v[1] = lastV;
tnfo.v[2] = currVIdx;
tInfos.push_back(tnfo);
}
lastV = currVIdx;
}
}
}
if (tInfos.empty())
{
return;
}
const unsigned int vSize = (unsigned int)(m.vn);
const unsigned int tSize = (unsigned int)(m.fn);
typedef Allocator<TriMeshType> TriMeshAllocatorType;
TriMeshAllocatorType::AddVertices(r, (int)(vInfos.size()));
TriMeshAllocatorType::AddFaces(r, (int)(tInfos.size()));
for (size_t i=0; i<vInfos.size(); ++i)
{
if (vInfos[i].idx != ((unsigned int)(-1)))
{
r.vert[i] = m.vert[vInfos[i].idx];
}
else
{
const unsigned int tref = vInfos[i].tref;
vInterp(*(m.face[tref].V(0)), *(m.face[tref].V(1)), *(m.face[tref].V(2)), vInfos[i].fV, vInfos[i].fU, r.vert[i]);
}
}
for (size_t i=0; i<tInfos.size(); ++i)
{
r.face[i].V(0) = &(r.vert[tInfos[i].v[0]]);
r.face[i].V(1) = &(r.vert[tInfos[i].v[1]]);
r.face[i].V(2) = &(r.vert[tInfos[i].v[2]]);
}
}
protected:
static inline unsigned int BoxClipCode(const ScalarType * offsets, const CoordType & p)
{
//const ScalarType eps = (ScalarType)(-1e-5);
const ScalarType eps = (ScalarType)(0);
unsigned int code = 0;
code |= ((( p[0] - offsets[0]) < eps) ? (1 << 0) : (0));
code |= (((-p[0] - offsets[1]) < eps) ? (1 << 1) : (0));
code |= ((( p[1] - offsets[2]) < eps) ? (1 << 2) : (0));
code |= (((-p[1] - offsets[3]) < eps) ? (1 << 3) : (0));
code |= ((( p[2] - offsets[4]) < eps) ? (1 << 4) : (0));
code |= (((-p[2] - offsets[5]) < eps) ? (1 << 5) : (0));
return (code);
}
static inline unsigned int InRegion(int mode, const ScalarType & value, const CoordType & p_in)
{
//const ScalarType eps = (ScalarType)(-1e-5);
const ScalarType eps = (ScalarType)(0);
unsigned int flag = 0;
switch(mode)
{
case 0:
flag = p_in[0] + eps < value;
break;
case 1:
flag = p_in[0] > value + eps;
break;
case 2:
flag = p_in[1] + eps < value;
break;
case 3:
flag = p_in[1] > value + eps;
break;
case 4:
flag = p_in[2] + eps < value;
break;
case 5:
flag = p_in[2] > value + eps;
break;
default:
break;
}
return (flag);
}
static inline void CrossPoint(int mode, const ScalarType & value, const CoordType & SP, const CoordType & PP, CoordType & p_out)
{
switch(mode)
{
case 0:
case 1:
p_out[0] = value;
if ((PP[0] - SP[0]) == ((ScalarType)(0)))
{
p_out[1] = PP[1];
p_out[2] = PP[2];
}
else
{
p_out[1] = SP[1] + (value - SP[0]) * (PP[1] - SP[1]) / (PP[0] - SP[0]);
p_out[2] = SP[2] + (value - SP[0]) * (PP[2] - SP[2]) / (PP[0] - SP[0]);
}
break;
case 2:
case 3:
p_out[1] = value;
if ((PP[1] - SP[1]) == ((ScalarType)(0)))
{
p_out[0] = PP[0];
p_out[2] = PP[2];
}
else
{
p_out[0] = SP[0] + (value - SP[1]) * (PP[0] - SP[0]) / (PP[1] - SP[1]);
p_out[2] = SP[2] + (value - SP[1]) * (PP[2] - SP[2]) / (PP[1] - SP[1]);
}
break;
case 4:
case 5:
p_out[2] = value;
if ((PP[2] - SP[2]) == ((ScalarType)(0)))
{
p_out[0] = PP[0];
p_out[1] = PP[1];
}
else
{
p_out[0] = SP[0] + (value - SP[2]) * (PP[0] - SP[0]) / (PP[2] - SP[2]);
p_out[1] = SP[1] + (value - SP[2]) * (PP[1] - SP[1]) / (PP[2] - SP[2]);
}
break;
default:
break;
}
}
static inline void ClipPolygonLine(int mode, const ScalarType & value, CoordType * P_in, unsigned int n_in, CoordType * P_out, unsigned int & n_out)
{
unsigned int ps;
CoordType * SP;
CoordType * PP;
n_out = 0;
SP = &P_in[n_in-1];
if (ClassType::InRegion(mode, value, *SP))
{
ps = 0;
}
else
{
ps = 2;
}
for(unsigned int i=0; i<n_in; ++i)
{
PP = &(P_in[i]);
ps = (ps >> 1) | ((ClassType::InRegion(mode, value, *PP)) ? (0) : (2));
switch(ps)
{
case 0:
break;
case 1:
ClassType::CrossPoint(mode, value, *SP, *PP, P_out[n_out]);
n_out++;
break;
case 2:
ClassType::CrossPoint(mode, value, *SP, *PP, P_out[n_out]);
n_out++;
P_out[n_out] = *PP;
n_out++;
break;
case 3:
P_out[n_out] = *PP;
n_out++;
break;
default:
break;
}
SP = PP;
}
}
};
} // end namespace tri
} // end namespace vcg
#endif // __VCGLIB_TRI_CLIP