diff --git a/vcg/complex/trimesh/clip.h b/vcg/complex/trimesh/clip.h new file mode 100644 index 00000000..139a6f6c --- /dev/null +++ b/vcg/complex/trimesh/clip.h @@ -0,0 +1,1057 @@ +/**************************************************************************** +* 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 +#include + +namespace vcg +{ +namespace tri +{ + +template +class TriMeshClipper +{ +public: + + typedef TriMeshClipper 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 & 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 + static inline void Box(const Box3 & b, VERTEXINTEPOLATOR & vInterp, TriMeshType & m) + { + std::vector facesToDelete; + ClassType::Box(b, vInterp, m, facesToDelete); + for (size_t i=0; i + static inline void Box(const Box3 & b, VERTEXINTEPOLATOR & vInterp, TriMeshType & m, FACEINDEXCONTAINER & facesToDelete) + { + if (m.fn <= 0) + { + return; + } + + class VertexInfo + { + public: + typedef VertexInfo ClassType; + + ScalarType fU; + ScalarType fV; + unsigned int idx; + unsigned int tref; + }; + + typedef std::vector VertexInfoVec; + + class TriangleInfo + { + public: + typedef TriangleInfo ClassType; + + unsigned int v[3]; + unsigned int idx; + }; + + typedef std::vector 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 UIntHMap; + typedef typename UIntHMap::iterator UIntHMap_i; + typedef typename UIntHMap::value_type UIntHMap_v; + + typedef stdext::hash_map EdgeMap; + typedef typename EdgeMap::iterator EdgeMap_i; + typedef typename EdgeMap::value_type EdgeMap_v; + + typedef typename TriMeshType::FaceIterator FaceIterator; + + EdgeMap edges; + VertexInfoVec 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(); + + VertexInfo 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 mi = edges.insert(std::make_pair(vmin[1], emptyMap)); + std::pair 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 mi = edges.insert(std::make_pair(vmin[0], emptyMap)); + std::pair 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 mi = edges.insert(std::make_pair(vmin[2], emptyMap)); + std::pair 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 TriMeshAllocatorType; + + TriMeshAllocatorType::AddVertices(m, numVertices); + TriMeshAllocatorType::AddFaces(m, numTriangles); + + unsigned int j = vSize; + for (size_t i=0; i= 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 & 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 + static inline void Box(const Box3 & b, VERTEXINTEPOLATOR & vInterp, const TriMeshType & m, TriMeshType & r) + { + r.Clear(); + + if (m.fn <= 0) + { + return; + } + + class VertexInfo + { + public: + typedef VertexInfo ClassType; + + ScalarType fU; + ScalarType fV; + unsigned int idx; + unsigned int tref; + }; + + typedef std::vector VertexInfoVec; + + class TriangleInfo + { + public: + typedef TriangleInfo ClassType; + + unsigned int v[3]; + unsigned int idx; + }; + + typedef std::vector 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 UIntHMap; + typedef typename UIntHMap::iterator UIntHMap_i; + typedef typename UIntHMap::value_type UIntHMap_v; + + typedef stdext::hash_map EdgeMap; + typedef typename EdgeMap::iterator EdgeMap_i; + typedef typename EdgeMap::value_type EdgeMap_v; + + typedef stdext::hash_map UIHMap; + typedef typename UIHMap::iterator UIHMap_i; + + typedef typename TriMeshType::ConstFaceIterator ConstFaceIterator; + + UIHMap origVertsMap; + EdgeMap edges; + VertexInfoVec 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; + VertexInfo vnfo; + + tnfo.idx = tIdx++; + + for (int i=0; i<3; ++i) + { + const unsigned int v = (*it).V(i) - &(*(m.vert.begin())); + std::pair 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(); + + VertexInfo 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 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 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 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 mi = edges.insert(std::make_pair(vmin[1], emptyMap)); + std::pair 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 mi = edges.insert(std::make_pair(vmin[0], emptyMap)); + std::pair 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 mi = edges.insert(std::make_pair(vmin[2], emptyMap)); + std::pair 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 TriMeshAllocatorType; + + TriMeshAllocatorType::AddVertices(r, (int)(vInfos.size())); + TriMeshAllocatorType::AddFaces(r, (int)(tInfos.size())); + + for (size_t i=0; i 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> 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