1115 lines
28 KiB
C
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
|