diff options
Diffstat (limited to 'sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp')
| -rwxr-xr-x[-rw-r--r--] | sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp | 3252 |
1 files changed, 1626 insertions, 1626 deletions
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp index 602ae75..167ffd4 100644..100755 --- a/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp +++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp @@ -1,1626 +1,1626 @@ - -#include <PxVec3.h> -#include <PxVec2.h> -#include <vector> -#include <queue> -#include <map> - -#include <NvBlastExtAuthoringMeshCleanerImpl.h> -#include <NvBlastExtAuthoringMeshImpl.h> -#include <NvBlastExtAuthoringInternalCommon.h> -#include <boost/multiprecision/cpp_int.hpp> - - - - -using physx::PxVec3; -using physx::PxVec2; - -using namespace Nv::Blast; -using namespace boost::multiprecision; - -/** - Exact rational vector types. -*/ -struct RVec3 -{ - cpp_rational x, y, z; - RVec3() - { - - } - - bool isZero() - { - return x.is_zero() && y.is_zero() && z.is_zero(); - } - - RVec3(cpp_rational _x, cpp_rational _y, cpp_rational _z) - { - x = _x; - y = _y; - z = _z; - } - - RVec3(const PxVec3& p) - { - x = cpp_rational(p.x); - y = cpp_rational(p.y); - z = cpp_rational(p.z); - } - PxVec3 toVec3() - { - return PxVec3(x.convert_to<float>(), y.convert_to<float>(), z.convert_to<float>()); - } - - RVec3 operator-(const RVec3& b) const - { - return RVec3(x - b.x, y - b.y, z - b.z); - } - RVec3 operator+(const RVec3& b) const - { - return RVec3(x + b.x, y + b.y, z + b.z); - } - RVec3 cross(const RVec3& in) const - { - return RVec3(y * in.z - in.y * z, in.x * z - x * in.z, x * in.y - in.x * y); - } - cpp_rational dot(const RVec3& in) const - { - return x * in.x + y * in.y + z * in.z; - } - RVec3 operator*(const cpp_rational& in) const - { - return RVec3(x * in, y * in, z * in); - } - - -}; - -struct RVec2 -{ - cpp_rational x, y; - RVec2() - { - - } - - RVec2(cpp_rational _x, cpp_rational _y) - { - x = _x; - y = _y; - } - - RVec2(const PxVec2& p) - { - x = cpp_rational(p.x); - y = cpp_rational(p.y); - } - PxVec2 toVec2() - { - return PxVec2(x.convert_to<float>(), y.convert_to<float>()); - } - - RVec2 operator-(const RVec2& b) const - { - return RVec2(x - b.x, y - b.y); - } - RVec2 operator+(const RVec2& b) const - { - return RVec2(x + b.x, y + b.y); - } - cpp_rational cross(const RVec2& in) const - { - return x * in.y - y * in.x; - } - cpp_rational dot(const RVec2& in) const - { - return x * in.x + y * in.y; - } - RVec2 operator*(const cpp_rational& in) const - { - return RVec2(x * in, y * in); - } -}; -struct RatPlane -{ - RVec3 n; - cpp_rational d; - - RatPlane(const RVec3& a, const RVec3& b, const RVec3& c) - { - n = (b - a).cross(c - a); - d = -n.dot(a); - }; - cpp_rational distance(RVec3& in) - { - return n.dot(in) + d; - } -}; - -bool isSame(const RatPlane& a, const RatPlane& b) -{ - if (a.d != b.d) return false; - if (a.n.x != b.n.x || a.n.y != b.n.y || a.n.z != b.n.z) return false; - return true; -} - -RVec3 planeSegmInters(RVec3& a, RVec3& b, RatPlane& pl) -{ - cpp_rational t = -(a.dot(pl.n) + pl.d) / pl.n.dot(b - a); - RVec3 on = a + (b - a) * t; - return on; -} - -enum POINT_CLASS -{ - ON_AB = 0, - ON_BC = 1, - ON_AC = 2, - INSIDE_TR, - OUTSIDE_TR, - ON_VERTEX -}; - - -int32_t isPointInside(const RVec2& a, const RVec2& b, const RVec2& c, const RVec2& p) -{ - cpp_rational v1 = (b - a).cross(p - a); - cpp_rational v2 = (c - b).cross(p - b); - cpp_rational v3 = (a - c).cross(p - c); - - - - int32_t v1s = v1.sign(); - int32_t v2s = v2.sign(); - int32_t v3s = v3.sign(); - - if (v1s * v2s < 0 || v1s * v3s < 0 || v2s * v3s < 0) return OUTSIDE_TR; - - if (v1s == 0 && v2s == 0) return OUTSIDE_TR; - if (v1s == 0 && v3s == 0) return OUTSIDE_TR; - if (v2s == 0 && v3s == 0) return OUTSIDE_TR; - - if (v1s == 0) return ON_AB; - if (v2s == 0) return ON_BC; - if (v3s == 0) return ON_AC; - - return INSIDE_TR; -} - -RVec2 getProjectedPointWithWinding(const RVec3& point, ProjectionDirections dir) -{ - if (dir & YZ_PLANE) - { - if (dir & OPPOSITE_WINDING) - { - return RVec2(point.z, point.y); - } - else - return RVec2(point.y, point.z); - } - if (dir & ZX_PLANE) - { - if (dir & OPPOSITE_WINDING) - { - return RVec2(point.z, point.x); - } - return RVec2(point.x, point.z); - } - if (dir & OPPOSITE_WINDING) - { - return RVec2(point.y, point.x); - } - return RVec2(point.x, point.y); -} - -struct DelTriangle -{ - int32_t p[3]; - int32_t n[3]; - int32_t parentTriangle; - int32_t getEdWP(int32_t vrt) - { - if (p[0] == vrt) return 1; - if (p[1] == vrt) return 2; - if (p[2] == vrt) return 0; - return -1; - } - int32_t getEdId(int32_t v1, int32_t v2) - { - if (p[0] == v1 && p[1] == v2) return 0; - if (p[1] == v1 && p[2] == v2) return 1; - if (p[2] == v1 && p[0] == v2) return 2; - return -1; - } - int32_t getOppP(int32_t v1, int32_t v2) - { - if (p[0] == v1 && p[1] == v2) return 2; - if (p[1] == v1 && p[2] == v2) return 0; - if (p[2] == v1 && p[0] == v2) return 1; - return -1; - } - - int32_t getOppPoint(int32_t v1, int32_t v2) - { - if (p[0] != v1 && p[0] != v2) return p[0]; - if (p[1] != v1 && p[1] != v2) return p[1]; - if (p[2] != v1 && p[2] != v2) return p[2]; - return -1; - } - bool compare(const DelTriangle& t) const - { - if (p[0] == t.p[0] && p[1] == t.p[1] && p[2] == t.p[2]) return true; - if (p[1] == t.p[0] && p[2] == t.p[1] && p[0] == t.p[2]) return true; - if (p[2] == t.p[0] && p[0] == t.p[1] && p[1] == t.p[2]) return true; - return false; - } - -}; - -struct DelEdge -{ - int32_t s, e; - int32_t nr, nl; -}; - - -bool isIntersectsTriangle(RVec2& a, RVec2& b, RVec2& c, RVec2& s, RVec2& e) -{ - RVec2 vec = e - s; - - if ((a - s).cross(vec) * (b - s).cross(vec) < 0) - { - RVec2 vec2 = b - a; - if ((s - a).cross(vec2) * (e - a).cross(vec) < 0) return true; - } - - if ((b - s).cross(vec) * (c - s).cross(vec) < 0) - { - RVec2 vec2 = c - b; - if ((s - b).cross(vec2) * (e - b).cross(vec) < 0) return true; - } - - if ((a - s).cross(vec) * (c - s).cross(vec) < 0) - { - RVec2 vec2 = a - c; - if ((s - c).cross(vec2) * (e - c).cross(vec) < 0) return true; - } - - return false; -} - - -inline int32_t inCircumcircle(RVec2& a, RVec2& b, RVec2& c, RVec2& p) -{ - RVec2 ta = a - p; - RVec2 tb = b - p; - RVec2 tc = c - p; - cpp_rational ad = ta.dot(ta); - cpp_rational bd = tb.dot(tb); - cpp_rational cd = tc.dot(tc); - - cpp_rational pred = ta.x * (tb.y * cd - tc.y * bd) - ta.y * (tb.x * cd - tc.x * bd) + ad * (tb.x * tc.y - tc.x * tb.y); - - - if (pred > 0) return 1; - if (pred < 0) return -1; - return 0; -} - -int32_t getEdge(std::vector<DelEdge>& edges, int32_t s, int32_t e) -{ - for (uint32_t i = 0; i < edges.size(); ++i) - { - if (edges[i].s == s && edges[i].e == e) return i; - } - - edges.push_back(DelEdge()); - edges.back().s = s; - edges.back().e = e; - return edges.size() - 1; -} - -void reubildAdjacency(std::vector<DelTriangle>& state) -{ - for (uint32_t i = 0; i < state.size(); ++i) - { - state[i].n[0] = state[i].n[1] = state[i].n[2] = -1; - } - for (uint32_t i = 0; i < state.size(); ++i) - { - if (state[i].p[0] == -1) continue; - for (uint32_t j = i + 1; j < state.size(); ++j) - { - if (state[j].p[0] == -1) continue; - for (uint32_t k = 0; k < 3; ++k) - { - for (uint32_t c = 0; c < 3; ++c) - { - if (state[i].p[k] == state[j].p[(c + 1) % 3] && state[i].p[(k + 1) % 3] == state[j].p[c]) { state[i].n[k] = j; state[j].n[c] = i; } - } - } - } - } -} - -void insertPoint(std::vector<RVec2>& vertices, std::vector<DelTriangle>& state, int32_t p, const std::vector<Edge>& edges) -{ - std::queue<int32_t> triangleToCheck; - - for (uint32_t i = 0; i < state.size(); ++i) - { - if (state[i].p[0] == -1) continue; - DelTriangle ctr = state[i]; - int32_t cv = isPointInside(vertices[ctr.p[0]], vertices[ctr.p[1]], vertices[ctr.p[2]], vertices[p]); - - if (cv == OUTSIDE_TR) continue; - if (cv == INSIDE_TR) - { - uint32_t taInd = state.size(); - uint32_t tbInd = state.size() + 1; - uint32_t tcInd = state.size() + 2; - state.resize(state.size() + 3); - - state[taInd].p[0] = ctr.p[2]; - state[taInd].p[1] = ctr.p[0]; - state[taInd].p[2] = p; - - state[taInd].n[0] = ctr.n[2]; - state[taInd].n[1] = tbInd; - state[taInd].n[2] = tcInd; - - state[tbInd].p[0] = ctr.p[0]; - state[tbInd].p[1] = ctr.p[1]; - state[tbInd].p[2] = p; - - state[tbInd].n[0] = ctr.n[0]; - state[tbInd].n[1] = tcInd; - state[tbInd].n[2] = taInd; - - state[tcInd].p[0] = ctr.p[1]; - state[tcInd].p[1] = ctr.p[2]; - state[tcInd].p[2] = p; - - state[tcInd].n[0] = ctr.n[1]; - state[tcInd].n[1] = taInd; - state[tcInd].n[2] = tbInd; - - - triangleToCheck.push(taInd); - triangleToCheck.push(tbInd); - triangleToCheck.push(tcInd); - - - /** - Change neighboors - */ - int32_t nb = state[i].n[0]; - if (nb != -1) - state[nb].n[state[nb].getEdId(state[i].p[1], state[i].p[0])] = tbInd; - nb = state[i].n[1]; - if (nb != -1) - state[nb].n[state[nb].getEdId(state[i].p[2], state[i].p[1])] = tcInd; - nb = state[i].n[2]; - if (nb != -1) - state[nb].n[state[nb].getEdId(state[i].p[0], state[i].p[2])] = taInd; - - - state[i].p[0] = -1; - } - else - { - uint32_t taInd = state.size(); - uint32_t tbInd = state.size() + 1; - state.resize(state.size() + 2); - - int32_t bPoint = state[i].p[(cv + 2) % 3]; - - state[taInd].p[0] = bPoint; - state[taInd].p[1] = state[i].p[cv]; - state[taInd].p[2] = p; - - state[tbInd].p[0] = bPoint; - state[tbInd].p[1] = p; - state[tbInd].p[2] = state[i].p[(cv + 1) % 3]; - - state[taInd].n[0] = state[i].n[(cv + 2) % 3]; - state[taInd].n[1] = -1; - state[taInd].n[2] = tbInd; - - state[tbInd].n[0] = taInd; - state[tbInd].n[1] = -1; - state[tbInd].n[2] = state[i].n[(cv + 1) % 3]; - - if (state[i].n[(cv + 1) % 3] != -1) - for (int32_t k = 0; k < 3; ++k) - if (state[state[i].n[(cv + 1) % 3]].n[k] == (int32_t)i) { - state[state[i].n[(cv + 1) % 3]].n[k] = tbInd; break; - } - if (state[i].n[(cv + 2) % 3] != -1) - for (int32_t k = 0; k < 3; ++k) - if (state[state[i].n[(cv + 2) % 3]].n[k] == (int32_t)i) { - state[state[i].n[(cv + 2) % 3]].n[k] = taInd; break; - } - - triangleToCheck.push(taInd); - triangleToCheck.push(tbInd); - - int32_t total = 2; - int32_t oppositeTr = 0; - if (state[i].n[cv] != -1) - { - oppositeTr = state[i].n[cv]; - total += 2; - uint32_t tcInd = state.size(); - uint32_t tdInd = state.size() + 1; - state.resize(state.size() + 2); - - int32_t oped = state[oppositeTr].getEdId(state[i].p[(cv + 1) % 3], state[i].p[cv]); - - - state[tcInd].n[0] = state[oppositeTr].n[(oped + 2) % 3]; - state[tcInd].n[1] = tbInd; - state[tbInd].n[1] = tcInd; - state[tcInd].n[2] = tdInd; - - state[tdInd].n[0] = tcInd; - state[tdInd].n[1] = taInd; - state[taInd].n[1] = tdInd; - state[tdInd].n[2] = state[oppositeTr].n[(oped + 1) % 3]; - if (state[oppositeTr].n[(oped + 2) % 3] != -1) - for (int32_t k = 0; k < 3; ++k) - if (state[state[oppositeTr].n[(oped + 2) % 3]].n[k] == oppositeTr) { - state[state[oppositeTr].n[(oped + 2) % 3]].n[k] = tcInd; break; - } - if (state[oppositeTr].n[(oped + 1) % 3] != -1) - for (int32_t k = 0; k < 3; ++k) - if (state[state[oppositeTr].n[(oped + 1) % 3]].n[k] == oppositeTr) { - state[state[oppositeTr].n[(oped + 1) % 3]].n[k] = tdInd; break; - } - - int32_t pop = state[oppositeTr].p[(oped + 2) % 3]; - state[tcInd].p[0] = pop; - state[tcInd].p[1] = state[i].p[(cv + 1) % 3]; - state[tcInd].p[2] = p; - - state[tdInd].p[0] = pop; - state[tdInd].p[1] = p; - state[tdInd].p[2] = state[i].p[cv]; - - - state[oppositeTr].p[0] = -1; - triangleToCheck.push(tcInd); - triangleToCheck.push(tdInd); - } - state[i].p[0] = -1; - } - break; - } - - while (!triangleToCheck.empty()) - { - int32_t ctrid = triangleToCheck.front(); - triangleToCheck.pop(); - DelTriangle& ctr = state[ctrid]; - int32_t oppTr = -5; - int32_t ced = 0; - for (uint32_t i = 0; i < 3; ++i) - { - if (ctr.p[i] != p && ctr.p[(i + 1) % 3] != p) - { - ced = i; - oppTr = ctr.n[i]; - break; - } - } - if (oppTr == -1) continue; - bool toCont = false; - for (size_t i = 0; i < edges.size(); ++i) - { - if ((int32_t)edges[i].s == ctr.p[ced] && ctr.p[(ced + 1) % 3] == (int32_t)edges[i].e) { toCont = true; break; } - if ((int32_t)edges[i].e == ctr.p[ced] && ctr.p[(ced + 1) % 3] == (int32_t)edges[i].s) { toCont = true; break; } - } - if (toCont) continue; - - - DelTriangle& otr = state[oppTr]; - - if (inCircumcircle(vertices[state[oppTr].p[0]], vertices[state[oppTr].p[1]], vertices[state[oppTr].p[2]], vertices[p]) > 0) - { - int32_t notPIndx = 0; - for (; notPIndx < 3; ++notPIndx) - { - if (otr.p[notPIndx] != ctr.p[0] && otr.p[notPIndx] != ctr.p[1] && otr.p[notPIndx] != ctr.p[2]) - break; - } - - int32_t oppCed = state[oppTr].getEdId(ctr.p[(ced + 1) % 3], ctr.p[ced]); - - int32_t ntr1 = ctrid, ntr2 = oppTr; - - DelTriangle nt1, nt2; - nt1.p[0] = state[oppTr].p[notPIndx]; - nt1.p[1] = p; - nt1.n[0] = ntr2; - nt1.p[2] = ctr.p[ced]; - nt1.n[1] = ctr.n[(ced + 2) % 3]; - nt1.n[2] = otr.n[(oppCed + 1) % 3]; - - if (nt1.n[2] != -1) - for (uint32_t k = 0; k < 3; ++k) - if (state[nt1.n[2]].n[k] == oppTr) state[nt1.n[2]].n[k] = ntr1; - - nt2.p[0] = p; - nt2.p[1] = state[oppTr].p[notPIndx]; - nt2.n[0] = ntr1; - nt2.p[2] = ctr.p[(ced + 1) % 3]; - nt2.n[1] = otr.n[(oppCed + 2) % 3]; - nt2.n[2] = ctr.n[(ced + 1) % 3]; - if (nt2.n[2] != -1) - for (uint32_t k = 0; k < 3; ++k) - if (state[nt2.n[2]].n[k] == ctrid) state[nt2.n[2]].n[k] = ntr2; - state[ntr1] = nt1; - state[ntr2] = nt2; - triangleToCheck.push(ntr1); - triangleToCheck.push(ntr2); - } - } - -} - -bool edgeIsIntersected(const RVec2& a, const RVec2& b, const RVec2& es, const RVec2& ee) -{ - RVec2 t = b - a; - cpp_rational temp = (es - a).cross(t) * (ee - a).cross(t); - - if (temp < 0) - { - t = es - ee; - if ((a - ee).cross(t) * (b - ee).cross(t) <= 0) return true; - } - return false; -} - -void triangulatePseudoPolygon(std::vector<RVec2>& vertices, int32_t ba, int32_t bb, std::vector<int32_t>& pseudo, std::vector<DelTriangle>& output) -{ - if (pseudo.empty()) return; - - int32_t c = 0; - if (pseudo.size() > 1) - { - for (uint32_t i = 1; i < pseudo.size(); ++i) - { - if (inCircumcircle(vertices[ba], vertices[bb], vertices[pseudo[c]], vertices[pseudo[i]]) > 0) - { - c = i; - } - } - std::vector<int32_t> toLeft; - std::vector<int32_t> toRight; - - for (int32_t t = 0; t < c; ++t) - { - toLeft.push_back(pseudo[t]); - } - for (size_t t = c + 1; t < pseudo.size(); ++t) - { - toRight.push_back(pseudo[t]); - } - if (toLeft.size() > 0) - triangulatePseudoPolygon(vertices, ba, pseudo[c], toLeft, output); - if (toRight.size() > 0) - triangulatePseudoPolygon(vertices, pseudo[c], bb, toRight, output); - } - output.push_back(DelTriangle()); - output.back().p[0] = ba; - output.back().p[1] = bb; - output.back().p[2] = pseudo[c]; -} - - - -void insertEdge(std::vector<RVec2>& vertices, std::vector<DelTriangle>& output, int32_t edBeg, int32_t edEnd) -{ - bool hasEdge = false; - for (auto& it : output) - { - for (uint32_t i = 0; i < 3; ++i) - if ((it.p[i] == edBeg || it.p[i] == edEnd) && (it.p[(i + 1) % 3] == edBeg || it.p[(i + 1) % 3] == edEnd)) - { - hasEdge = true; - } - } - if (hasEdge) return; - - int32_t startTriangle = -1; - int32_t edg = -1; - for (uint32_t i = 0; i < output.size(); ++i) - { - if (output[i].p[0] == -1) continue; - - if (output[i].p[0] == edBeg || output[i].p[1] == edBeg || output[i].p[2] == edBeg) - { - edg = output[i].getEdWP(edBeg); - if (edgeIsIntersected(vertices[edBeg], vertices[edEnd], vertices[output[i].p[edg]], vertices[output[i].p[(edg + 1) % 3]])) - { - startTriangle = i; - break; - } - } - } - if (startTriangle == -1) - { - return; - } - int32_t cvertex = edBeg; - - std::vector<int32_t> pointsAboveEdge; - std::vector<int32_t> pointsBelowEdge; - - RVec2 vec = vertices[edEnd] - vertices[edBeg]; - - if (vec.cross(vertices[output[startTriangle].p[edg]] - vertices[edBeg]) > 0) - { - pointsAboveEdge.push_back(output[startTriangle].p[edg]); - pointsBelowEdge.push_back(output[startTriangle].p[(edg + 1) % 3]); - } - else - { - pointsBelowEdge.push_back(output[startTriangle].p[edg]); - pointsAboveEdge.push_back(output[startTriangle].p[(edg + 1) % 3]); - } - - while (1) - { - DelTriangle& ctr = output[startTriangle]; - int32_t oed = ctr.getEdWP(cvertex); - int32_t nextTriangle = ctr.n[oed]; - - if (output[nextTriangle].p[0] == edEnd || output[nextTriangle].p[1] == edEnd || output[nextTriangle].p[2] == edEnd) - { - ctr.p[0] = -1; - output[nextTriangle].p[0] = -1; - break; - } - - DelTriangle& otr = output[nextTriangle]; - int32_t opp = otr.p[otr.getOppP(ctr.p[(oed + 1) % 3], ctr.p[oed % 3])]; - - int32_t nextPoint = 0; - if (vec.cross((vertices[opp] - vertices[edBeg])) > 0) - { - pointsAboveEdge.push_back(opp); - if (vec.cross(vertices[ctr.p[(oed + 1) % 3]] - vertices[edBeg]) > 0) - { - nextPoint = ctr.p[(oed + 1) % 3]; - } - else - { - nextPoint = ctr.p[oed]; - } - } - else - { - pointsBelowEdge.push_back(opp); - - if (vec.cross(vertices[ctr.p[(oed + 1) % 3]] - vertices[edBeg]) < 0) - { - nextPoint = ctr.p[(oed + 1) % 3]; - } - else - { - nextPoint = ctr.p[oed]; - } - } - startTriangle = nextTriangle; - cvertex = nextPoint; - ctr.p[0] = -1; - } - triangulatePseudoPolygon(vertices, edBeg, edEnd, pointsAboveEdge, output); - std::reverse(pointsBelowEdge.begin(), pointsBelowEdge.end()); - triangulatePseudoPolygon(vertices, edEnd, edBeg, pointsBelowEdge, output); - reubildAdjacency(output); -} - - - - - - -void buildCDT(std::vector<RVec3>& vertices, std::vector<Edge>& edges, std::vector<DelTriangle>& output, ProjectionDirections dr) -{ - std::vector<DelTriangle> state; - - DelTriangle crt; - std::vector<bool> added(vertices.size(), false); - - for (uint32_t i = 0; i < 3; ++i) - { - crt.p[i] = edges[i].s; - added[edges[i].s] = true; - crt.n[i] = -1; // dont have neighboors; - } - state.push_back(crt); - - - std::vector<RVec2> p2d(vertices.size()); - for (uint32_t i = 0; i < vertices.size(); ++i) - { - p2d[i] = getProjectedPointWithWinding(vertices[i], dr); - } - - for (size_t i = 0; i < edges.size(); ++i) - { - if (!added[edges[i].s]) - { - insertPoint(p2d, state, edges[i].s, edges); - added[edges[i].s] = true; - } - if (!added[edges[i].e]) - { - insertPoint(p2d, state, edges[i].e, edges); - added[edges[i].e] = true; - } - if (edges[i].s != edges[i].e) - { - insertEdge(p2d, state, edges[i].s, edges[i].e); - } - } - - for (uint32_t t = 0; t < state.size(); ++t) - { - if (state[t].p[0] != -1) - { - output.push_back(state[t]); - } - } -} - -int32_t intersectSegments(RVec3& s1, RVec3& e1, RVec3& s2, RVec3& e2, ProjectionDirections dir, std::vector<cpp_rational>& t1v, std::vector<cpp_rational>& t2v); - -void getTriangleIntersectionCoplanar(uint32_t tr1, uint32_t tr2, std::vector<std::vector<RVec3>>& stencil, ProjectionDirections dr) -{ - std::vector<cpp_rational> intr1[3]; - std::vector<cpp_rational> intr2[3]; - - RVec3 p1[3]; - p1[0] = stencil[tr1][0]; - p1[1] = stencil[tr1][1]; - p1[2] = stencil[tr1][3]; - - RVec3 p2[3]; - p2[0] = stencil[tr2][0]; - p2[1] = stencil[tr2][1]; - p2[2] = stencil[tr2][3]; - - for (uint32_t i = 0; i < 3; ++i) - { - for (uint32_t j = 0; j < 3; ++j) - { - intersectSegments(p1[i], p1[(i + 1) % 3], p2[j], p2[(j + 1) % 3], dr, intr1[i], intr2[j]); - } - } - - int32_t inRel1[3]; - for (uint32_t i = 0; i < 3; ++i) - { - inRel1[i] = isPointInside(getProjectedPointWithWinding(p2[0], dr), getProjectedPointWithWinding(p2[1], dr), getProjectedPointWithWinding(p2[2], dr), getProjectedPointWithWinding(p1[i], dr)); - } - - int32_t inRel2[3]; - for (uint32_t i = 0; i < 3; ++i) - { - inRel2[i] = isPointInside(getProjectedPointWithWinding(p1[0], dr), getProjectedPointWithWinding(p1[1], dr), getProjectedPointWithWinding(p1[2], dr), getProjectedPointWithWinding(p2[i], dr)); - } - - for (uint32_t i = 0; i < 3; ++i) - { - if (inRel1[i] == INSIDE_TR && inRel1[(i + 1) % 3] == INSIDE_TR) - { - stencil[tr2].push_back(p1[i]); - stencil[tr2].push_back(p1[(i + 1) % 3]); - } - else - { - if (inRel1[i] == INSIDE_TR && intr1[i].size() == 1) - { - stencil[tr2].push_back(p1[i]); - stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]); - } - if (inRel1[(i + 1) % 3] == INSIDE_TR && intr1[i].size() == 1) - { - stencil[tr2].push_back(p1[(i + 1) % 3]); - stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]); - } - if (intr1[i].size() == 2) - { - stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]); - stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][1] + p1[i]); - } - } - } - - for (uint32_t i = 0; i < 3; ++i) - { - if (inRel2[i] == INSIDE_TR && inRel2[(i + 1) % 3] == INSIDE_TR) - { - stencil[tr1].push_back(p2[i]); - stencil[tr1].push_back(p2[(i + 1) % 3]); - } - else - { - if (inRel2[i] == INSIDE_TR && intr2[i].size() == 1) - { - stencil[tr1].push_back(p2[i]); - stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]); - } - if (inRel2[(i + 1) % 3] == INSIDE_TR && intr2[i].size() == 1) - { - stencil[tr1].push_back(p2[(i + 1) % 3]); - stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]); - } - if (intr2[i].size() == 2) - { - stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]); - stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][1] + p2[i]); - } - } - } -} - - -int32_t getTriangleIntersection3d(uint32_t tr1, uint32_t tr2, std::vector<std::vector<RVec3>>& stencil, ProjectionDirections dr) -{ - RatPlane pl1(stencil[tr1][0], stencil[tr1][1], stencil[tr1][3]); - if (pl1.n.isZero()) - { - std::swap(tr1, tr2); - pl1 = RatPlane(stencil[tr1][0], stencil[tr1][1], stencil[tr1][3]); - if (pl1.n.isZero()) return 0; - } - - - cpp_rational d1 = pl1.distance(stencil[tr2][0]); - cpp_rational d2 = pl1.distance(stencil[tr2][1]); - cpp_rational d3 = pl1.distance(stencil[tr2][3]); - - int32_t sd1 = d1.sign(); - int32_t sd2 = d2.sign(); - int32_t sd3 = d3.sign(); - - - if (sd1 == 0 && sd2 == 0 && sd3 == 0) - { - getTriangleIntersectionCoplanar(tr1, tr2, stencil, dr); - return 0; - } - /** - Never intersected - */ - if (sd1 < 0 && sd2 < 0 && sd3 < 0) - return 0; - if (sd1 > 0 && sd2 > 0 && sd3 > 0) - return 0; - - RVec3 tb0 = stencil[tr2][0]; - RVec3 tb1 = stencil[tr2][1]; - RVec3 tb2 = stencil[tr2][3]; - - if (sd1 * sd3 > 0) - { - std::swap(tb1, tb2); - std::swap(d2, d3); - } - else - { - if (sd2 * sd3 > 0) - { - std::swap(tb0, tb2); - std::swap(d1, d3); - } - else - { - if (sd3 == 0 && sd1 * sd2 < 0) - { - std::swap(tb0, tb2); - std::swap(d1, d3); - } - } - } - - RatPlane pl2(stencil[tr2][0], stencil[tr2][1], stencil[tr2][3]); - - cpp_rational d21 = pl2.distance(stencil[tr1][0]); - cpp_rational d22 = pl2.distance(stencil[tr1][1]); - cpp_rational d23 = pl2.distance(stencil[tr1][3]); - - int32_t sd21 = d21.sign(); - int32_t sd22 = d22.sign(); - int32_t sd23 = d23.sign(); - - if (sd21 < 0 && sd22 < 0 && sd23 < 0) - return 0; - if (sd21 > 0 && sd22 > 0 && sd23 > 0) - return 0; - - - RVec3 ta0 = stencil[tr1][0]; - RVec3 ta1 = stencil[tr1][1]; - RVec3 ta2 = stencil[tr1][3]; - - - if (sd21 * sd23 > 0) - { - std::swap(ta1, ta2); - std::swap(d22, d23); - } - else - { - if (sd22 * sd23 > 0) - { - std::swap(ta0, ta2); - std::swap(d21, d23); - } - else - { - if (sd23 == 0 && sd21 * sd22 < 0) - { - std::swap(ta0, ta2); - std::swap(d21, d23); - } - } - } - ////////////////////////////////////////////////// - RVec3 dir = ta2 - ta0; - - cpp_rational dirPlaneDot = dir.dot(pl2.n); - - - RVec3 pointOnIntersectionLine; - if (dirPlaneDot != 0) - { - pointOnIntersectionLine = ta0 - dir * (d21 / dirPlaneDot); - } - else - { - pointOnIntersectionLine = ta0; - } - RVec3 interLineDir = pl1.n.cross(pl2.n); - cpp_rational sqd = interLineDir.dot(interLineDir); - if (sqd.is_zero()) return 0; - - cpp_rational t1p2 = (ta1 - pointOnIntersectionLine).dot(interLineDir) / sqd; - cpp_rational t1p3 = (ta2 - pointOnIntersectionLine).dot(interLineDir) / sqd; - cpp_rational t1p2param = t1p2; - if (d22 != d23) - { - t1p2param = t1p2 + (t1p3 - t1p2) * (d22 / (d22 - d23)); - } - - t1p2 = (tb0 - pointOnIntersectionLine).dot(interLineDir) / sqd; - t1p3 = (tb2 - pointOnIntersectionLine).dot(interLineDir) / sqd; - cpp_rational t2p1param = t1p2; - if (d1 != d3) - { - t2p1param = t1p2 + (t1p3 - t1p2) * d1 / (d1 - d3); - } - - t1p2 = (tb1 - pointOnIntersectionLine).dot(interLineDir) / sqd; - cpp_rational t2p2param = t1p2; - if (d2 != d3) - { - t2p2param = t1p2 + (t1p3 - t1p2) * d2 / (d2 - d3); - } - cpp_rational beg1 = 0; - - if (t1p2param < 0) - { - std::swap(beg1, t1p2param); - } - if (t2p2param < t2p1param) - { - std::swap(t2p2param, t2p1param); - } - cpp_rational minEnd = std::min(t1p2param, t2p2param); - cpp_rational maxBeg = std::max(beg1, t2p1param); - - if (minEnd > maxBeg) - { - RVec3 p1 = pointOnIntersectionLine + interLineDir * maxBeg; - RVec3 p2 = pointOnIntersectionLine + interLineDir * minEnd; - - stencil[tr1].push_back(p1); - stencil[tr1].push_back(p2); - - stencil[tr2].push_back(p1); - stencil[tr2].push_back(p2); - return 1; - } - return 0; -} - -int32_t intersectSegments(RVec3& s1, RVec3& e1, RVec3& s2, RVec3& e2, ProjectionDirections dir, std::vector<cpp_rational>& t1v, std::vector<cpp_rational>& t2v) -{ - RVec2 s1p = getProjectedPointWithWinding(s1, dir); - RVec2 e1p = getProjectedPointWithWinding(e1, dir); - - RVec2 s2p = getProjectedPointWithWinding(s2, dir); - RVec2 e2p = getProjectedPointWithWinding(e2, dir); - - RVec2 dir1 = e1p - s1p; - RVec2 dir2 = s2p - e2p; - - cpp_rational crs = dir1.cross(dir2); - if (crs != 0) - { - cpp_rational c1 = s2p.x - s1p.x; - cpp_rational c2 = s2p.y - s1p.y; - - cpp_rational det1 = c1 * dir2.y - c2 * dir2.x; - cpp_rational det2 = dir1.x * c2 - dir1.y * c1; - - cpp_rational t1 = det1 / crs; - cpp_rational t2 = det2 / crs; - - if (t1 > 0 && t1 < 1 && (t2 >= 0 && t2 <= 1)) - { - t1v.push_back(t1); - } - if (t2 > 0 && t2 < 1 && (t1 >= 0 && t1 <= 1)) - { - t2v.push_back(t2); - } - - } - else - { - if (dir1.cross(s2p - s1p) == 0) - { - if (dir1.x != 0) - { - cpp_rational t1 = (s2p.x - s1p.x) / dir1.x; - cpp_rational t2 = (e2p.x - s1p.x) / dir1.x; - if (t1 > 0 && t1 < 1) t1v.push_back(t1); - if (t2 > 0 && t2 < 1) t1v.push_back(t2); - } - else - { - if (dir1.y != 0) - { - cpp_rational t1 = (s2p.y - s1p.y) / dir1.y; - cpp_rational t2 = (e2p.y - s1p.y) / dir1.y; - if (t1 > 0 && t1 < 1) t1v.push_back(t1); - if (t2 > 0 && t2 < 1) t1v.push_back(t2); - } - } - } - if (dir2.cross(s1p - s2p) == 0) - { - dir2 = e2p - s2p; - if (dir2.x != 0) - { - cpp_rational t1 = (s1p.x - s2p.x) / dir2.x; - cpp_rational t2 = (e1p.x - s2p.x) / dir2.x; - if (t1 > 0 && t1 < 1) t2v.push_back(t1); - if (t2 > 0 && t2 < 1) t2v.push_back(t2); - } - else - { - if (dir2.y != 0) - { - cpp_rational t1 = (s1p.y - s2p.y) / dir2.y; - cpp_rational t2 = (e1p.y - s2p.y) / dir2.y; - if (t1 > 0 && t1 < 1) t2v.push_back(t1); - if (t2 > 0 && t2 < 1) t2v.push_back(t2); - } - } - } - } - return 1; -} - -struct RVec3Comparer -{ - bool operator()(const RVec3& a, const RVec3& b) const - { - if (a.x < b.x) return true; - if (a.x > b.x) return false; - if (a.y < b.y) return true; - if (a.y > b.y) return false; - if (a.z < b.z) return true; - return false; - } -}; - -void getBarycentricCoords(PxVec2& a, PxVec2& b, PxVec2& c, PxVec2& p, float& u, float& v) -{ - PxVec3 v1(b.x - a.x, c.x - a.x, a.x - p.x); - PxVec3 v2(b.y - a.y, c.y - a.y, a.y - p.y); - - PxVec3 resl = v1.cross(v2); - u = resl.x / resl.z; - v = resl.y / resl.z; -} - - -Mesh* MeshCleanerImpl::cleanMesh(const Mesh* mesh) -{ - /** - ======= Get mesh data =========== - */ - std::vector<Vertex> vertices; - std::vector<Edge> edges; - std::vector<Facet> facets; - - vertices.resize(mesh->getVerticesCount()); - edges.resize(mesh->getEdgesCount()); - facets.resize(mesh->getFacetCount()); - - PxBounds3 bnd; - bnd.setEmpty(); - - for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i) - { - vertices[i] = mesh->getVertices()[i]; - bnd.include(vertices[i].p); - } - for (uint32_t i = 0; i < mesh->getEdgesCount(); ++i) - { - edges[i] = mesh->getEdges()[i]; - } - for (uint32_t i = 0; i < mesh->getFacetCount(); ++i) - { - facets[i] = mesh->getFacetsBuffer()[i]; - } - //====================================== - - /** - Transform vertices to fit unit cube and snap them to grid. - **/ - float scale = 1.0f / bnd.getExtents().abs().maxElement(); - - int32_t gridSize = 10000; // Grid resolution to which vertices position will be snapped. - - for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i) - { - vertices[i].p = (vertices[i].p - bnd.minimum) * scale; - vertices[i].p.x = std::floor(vertices[i].p.x * gridSize) / gridSize; - vertices[i].p.y = std::floor(vertices[i].p.y * gridSize) / gridSize; - vertices[i].p.z = std::floor(vertices[i].p.z * gridSize) / gridSize; - } - - std::vector<std::vector<RVec3>> triangleStencil(facets.size()); - - std::vector<PxVec3> facetsNormals(facets.size()); - std::vector<PxBounds3> facetBound(facets.size()); - - - for (uint32_t tr1 = 0; tr1 < facets.size(); ++tr1) - { - if (facets[tr1].edgesCount != 3) - { - return nullptr; - } - int32_t fed = facets[tr1].firstEdgeNumber; - triangleStencil[tr1].push_back(vertices[edges[fed].s].p); - triangleStencil[tr1].push_back(vertices[edges[fed].e].p); - triangleStencil[tr1].push_back(vertices[edges[fed + 1].s].p); - triangleStencil[tr1].push_back(vertices[edges[fed + 1].e].p); - triangleStencil[tr1].push_back(vertices[edges[fed + 2].s].p); - triangleStencil[tr1].push_back(vertices[edges[fed + 2].e].p); - - facetBound[tr1].setEmpty(); - facetBound[tr1].include(vertices[edges[fed].s].p); - facetBound[tr1].include(vertices[edges[fed].e].p); - facetBound[tr1].include(vertices[edges[fed + 2].s].p); - facetBound[tr1].fattenFast(0.001f); - - facetsNormals[tr1] = (vertices[edges[fed + 1].s].p - vertices[edges[fed].s].p).cross(vertices[edges[fed + 2].s].p - vertices[edges[fed].s].p); - } - - /** - Build intersections between all pairs of triangles. - */ - for (uint32_t tr1 = 0; tr1 < facets.size(); ++tr1) - { - if (triangleStencil[tr1].empty()) continue; - for (uint32_t tr2 = tr1 + 1; tr2 < facets.size(); ++tr2) - { - if (triangleStencil[tr2].empty()) continue; - if (facetBound[tr1].intersects(facetBound[tr2]) == false) continue; - - getTriangleIntersection3d(tr1, tr2, triangleStencil, getProjectionDirection(facetsNormals[tr1])); - } - } - - /** - Reintersect all segments - */ - for (uint32_t tr = 0; tr < triangleStencil.size(); ++tr) - { - std::vector<RVec3>& ctr = triangleStencil[tr]; - std::vector<std::vector<cpp_rational> > perSegmentInters(ctr.size() / 2); - for (uint32_t sg1 = 6; sg1 < ctr.size(); sg1 += 2) - { - for (uint32_t sg2 = sg1 + 2; sg2 < ctr.size(); sg2 += 2) - { - intersectSegments(ctr[sg1], ctr[sg1 + 1], ctr[sg2], ctr[sg2 + 1], getProjectionDirection(facetsNormals[tr]), perSegmentInters[sg1 / 2], perSegmentInters[sg2 / 2]); - } - } - - std::vector<RVec3> newStencil; - newStencil.reserve(ctr.size()); - - for (uint32_t i = 0; i < ctr.size(); i += 2) - { - int32_t csm = i / 2; - if (perSegmentInters[csm].size() == 0) - { - newStencil.push_back(ctr[i]); - newStencil.push_back(ctr[i + 1]); - } - else - { - cpp_rational current = 0; - newStencil.push_back(ctr[i]); - std::sort(perSegmentInters[csm].begin(), perSegmentInters[csm].end()); - for (size_t j = 0; j < perSegmentInters[csm].size(); ++j) - { - if (perSegmentInters[csm][j] > current) - { - current = perSegmentInters[csm][j]; - RVec3 pnt = (ctr[i + 1] - ctr[i]) * current + ctr[i]; - newStencil.push_back(pnt); - newStencil.push_back(pnt); - } - } - newStencil.push_back(ctr[i + 1]); - } - } - ctr = newStencil; - } - - std::vector<RVec3> finalPoints; - - std::vector<std::vector<Edge>> tsten(facets.size()); - - { - std::map<RVec3, uint32_t, RVec3Comparer> mapping; - for (uint32_t tr1 = 0; tr1 < triangleStencil.size(); ++tr1) - { - for (uint32_t j = 0; j < triangleStencil[tr1].size(); j += 2) - { - - auto it = mapping.find(triangleStencil[tr1][j]); - int32_t pt = 0; - if (it == mapping.end()) - { - mapping[triangleStencil[tr1][j]] = finalPoints.size(); - pt = finalPoints.size(); - finalPoints.push_back(triangleStencil[tr1][j]); - } - else - { - pt = it->second; - } - - Edge newed; - - newed.s = pt; - - it = mapping.find(triangleStencil[tr1][j + 1]); - if (it == mapping.end()) - { - mapping[triangleStencil[tr1][j + 1]] = finalPoints.size(); - pt = finalPoints.size(); - finalPoints.push_back(triangleStencil[tr1][j + 1]); - } - else - { - pt = it->second; - } - newed.e = pt; - bool hasNewEdge = false; - for (uint32_t e = 0; e < tsten[tr1].size(); ++e) - { - if (tsten[tr1][e].s == newed.s && tsten[tr1][e].e == newed.e) - { - hasNewEdge = true; - break; - } - if (tsten[tr1][e].e == newed.s && tsten[tr1][e].s == newed.e) - { - hasNewEdge = true; - break; - } - } - if (!hasNewEdge) tsten[tr1].push_back(newed); - } - } - } - - /** - Build constrained DT - */ - std::vector<DelTriangle> trs; - for (uint32_t i = 0; i < tsten.size(); ++i) - { - - if (tsten[i].size() < 3) continue; - if (tsten[i].size() > 3) - { - int32_t oldSize = trs.size(); - buildCDT(finalPoints, tsten[i], trs, getProjectionDirection(facetsNormals[i])); - for (uint32_t k = oldSize; k < trs.size(); ++k) - trs[k].parentTriangle = i; - } - else - { - trs.push_back(DelTriangle()); - trs.back().parentTriangle = i; - for (uint32_t v = 0; v < 3; ++v) - trs.back().p[v] = tsten[i][v].s; - } - - } - - /** - Remove 'deleted' triangles from array. - */ - { - std::vector < DelTriangle > trstemp; - trstemp.reserve(trs.size()); - for (uint32_t i = 0; i < trs.size(); ++i) - { - if (trs[i].p[0] != -1) - trstemp.push_back(trs[i]); - } - trs = trstemp; - } - - /** - Filter exterior surface - */ - std::vector<bool> fillingMask(trs.size(), false); - - std::map<std::pair<int32_t, int32_t>, int32_t> edgeMap; - std::vector<std::vector<int32_t> > edgeToTriangleMapping; - - for (uint32_t i = 0; i < trs.size(); ++i) - { - if (trs[i].p[0] == -1) continue; - if (trs[i].p[0] == trs[i].p[1] || trs[i].p[2] == trs[i].p[1] || trs[i].p[2] == trs[i].p[0]) - { - trs[i].p[0] = -1; - continue; - } - #if 0 // Filter null-area triangles. - if ((finalPoints[trs[i].p[1]] - finalPoints[trs[i].p[0]]).cross(finalPoints[trs[i].p[2]] - finalPoints[trs[i].p[0]]).isZero()) - { - trs[i].p[0] = -1; - continue; - } - #endif - for (uint32_t k = 0; k < 3; ++k) - { - int32_t es = trs[i].p[k]; - int32_t ee = trs[i].p[(k + 1) % 3]; - if (es > ee) - { - std::swap(es, ee); - } - auto pr = std::make_pair(es, ee); - auto iter = edgeMap.find(pr); - if (iter == edgeMap.end()) - { - edgeMap[pr] = edgeToTriangleMapping.size(); - trs[i].n[k] = edgeToTriangleMapping.size(); - edgeToTriangleMapping.resize(edgeToTriangleMapping.size() + 1); - edgeToTriangleMapping.back().push_back(i); - } - else - { - for (uint32_t j = 0; j < edgeToTriangleMapping[iter->second].size(); ++j) - { - if (trs[edgeToTriangleMapping[iter->second][j]].compare(trs[i])) - { - trs[i].p[0] = -1; - break; - } - } - if (trs[i].p[0] != -1) - { - trs[i].n[k] = iter->second; - edgeToTriangleMapping[iter->second].push_back(i); - } - } - } - } - - std::queue<int32_t> trque; - float maxx = -1000; - int32_t best = 0; - for (uint32_t i = 0; i < trs.size(); ++i) - { - if (trs[i].p[0] == -1) continue; - float m = std::max(finalPoints[trs[i].p[0]].x.convert_to<float>(), std::max(finalPoints[trs[i].p[1]].x.convert_to<float>(), finalPoints[trs[i].p[2]].x.convert_to<float>())); - if (m > maxx && facetsNormals[trs[i].parentTriangle].x > 0) - { - maxx = m; - best = i; - } - } - - trque.push(best); - while (!trque.empty()) - { - int32_t trid = trque.front(); - fillingMask[trid] = true; - DelTriangle& tr = trs[trque.front()]; - trque.pop(); - - for (uint32_t ed = 0; ed < 3; ++ed) - { - auto& tlist = edgeToTriangleMapping[tr.n[ed]]; - if (tlist.size() == 2) - { - for (uint32_t k = 0; k < tlist.size(); ++k) - { - int32_t to = tlist[k]; - if (to != trid && !fillingMask[to] && edgeToTriangleMapping[trs[to].n[0]].size() > 0 && edgeToTriangleMapping[trs[to].n[1]].size() > 0 && edgeToTriangleMapping[trs[to].n[2]].size() > 0) - { - trque.push(tlist[k]); - fillingMask[tlist[k]] = true; - } - } - } - if (tlist.size() > 2) - { - int32_t bestPath = (tlist[0] == trid) ? tlist[1] : tlist[0]; - RVec3 start = finalPoints[trs[trid].p[ed]]; - RVec3 axis = finalPoints[trs[trid].p[(ed + 1) % 3]] - start; - RVec3 nAxis = finalPoints[trs[trid].p[(ed + 2) % 3]] - start; - RVec3 normal = axis.cross(nAxis); - - - uint32_t op = trs[bestPath].getOppPoint(trs[trid].p[ed], trs[trid].p[(ed + 1) % 3]); - - RVec3 dir2 = (finalPoints[op] - start); - RVec3 normal2 = dir2.cross(axis); - cpp_rational bestDir = normal.cross(normal2).dot(axis); - cpp_rational oldDist = normal2.dot(normal2); - for (uint32_t k = 0; k < tlist.size(); ++k) - { - if (tlist[k] == trid) continue; - op = trs[tlist[k]].getOppPoint(trs[trid].p[ed], trs[trid].p[(ed + 1) % 3]); - dir2 = (finalPoints[op] - start); - normal2 = dir2.cross(axis); - cpp_rational newOne = normal.cross(normal2).dot(axis); - - if (newOne * oldDist < bestDir * normal2.dot(normal2)) - { - oldDist = normal2.dot(normal2); - bestPath = tlist[k]; - bestDir = newOne; - } - } - if (!fillingMask[bestPath] && edgeToTriangleMapping[trs[bestPath].n[0]].size() > 0 && edgeToTriangleMapping[trs[bestPath].n[1]].size() > 0 && edgeToTriangleMapping[trs[bestPath].n[2]].size() > 0) - { - trque.push(bestPath); - fillingMask[bestPath] = true; - } - } - edgeToTriangleMapping[tr.n[ed]].clear(); - } - - } - for (uint32_t id = 0; id < trs.size(); ++id) - { - if (!fillingMask[id]) - { - trs[id].p[0] = -1; // Remove triangle - } - } - ///////////////////////////////////////////////////////////////////////////////////////////// - - std::vector<PxVec3> newVertices; - newVertices.resize(finalPoints.size()); - for (uint32_t i = 0; i < finalPoints.size(); ++i) - { - newVertices[i].x = finalPoints[i].x.convert_to<float>(); - newVertices[i].y = finalPoints[i].y.convert_to<float>(); - newVertices[i].z = finalPoints[i].z.convert_to<float>(); - } - /** - Rescale mesh to initial coordinates. - */ - for (uint32_t i = 0; i < finalPoints.size(); ++i) - { - newVertices[i] = newVertices[i] * (1.0f / scale) + bnd.minimum; - } - for (uint32_t i = 0; i < vertices.size(); ++i) - { - vertices[i].p = vertices[i].p * (1.0f / scale) + bnd.minimum; - } - - std::vector<Triangle> result; - result.reserve(trs.size()); - { - std::vector<PxVec2> projectedTriangles(facets.size() * 3); - std::vector<Vertex> normalTriangles(facets.size() * 3); - - for (uint32_t i = 0; i < facets.size(); ++i) - { - for (uint32_t k = 0; k < 3; ++k) - { - normalTriangles[i * 3 + k] = vertices[edges[facets[i].firstEdgeNumber + k].s]; - projectedTriangles[i * 3 + k] = getProjectedPointWithWinding(vertices[edges[facets[i].firstEdgeNumber + k].s].p, getProjectionDirection(facetsNormals[i])); - } - } - - for (uint32_t i = 0; i < trs.size(); ++i) - { - if (trs[i].p[0] == -1) continue; - int32_t id = 0; - int32_t parentTriangle = trs[i].parentTriangle; - float u = 0, v = 0; - result.resize(result.size() + 1); - result.back().materialId = facets[parentTriangle].materialId; - result.back().smoothingGroup = facets[parentTriangle].smoothingGroup; - for (auto vert : { &result.back().a, &result.back().b , &result.back().c }) - { - vert->p = newVertices[trs[i].p[id]]; - PxVec2 p = getProjectedPointWithWinding(vert->p, getProjectionDirection(facetsNormals[parentTriangle])); - getBarycentricCoords(projectedTriangles[parentTriangle * 3], projectedTriangles[parentTriangle * 3 + 1], projectedTriangles[parentTriangle * 3 + 2], p, u, v); - vert->uv[0] = (1 - u - v) * normalTriangles[parentTriangle * 3].uv[0] + u * normalTriangles[parentTriangle * 3 + 1].uv[0] + v * normalTriangles[parentTriangle * 3 + 2].uv[0]; - vert->n = (1 - u - v) * normalTriangles[parentTriangle * 3].n + u * normalTriangles[parentTriangle * 3 + 1].n + v * normalTriangles[parentTriangle * 3 + 2].n; - ++id; - } - } - } - - /** - Reuse old buffers to create Mesh - */ - std::vector<PxVec3> newMeshVertices(result.size() * 3); - std::vector<PxVec3> newMeshNormals(result.size() * 3); - std::vector<PxVec2> newMeshUvs(result.size() * 3); - - std::vector<int32_t> newMaterialIds(result.size()); - std::vector<int32_t> newSmoothingGroups(result.size()); - - - for (uint32_t i = 0; i < result.size(); ++i) - { - Vertex* arr[3] = { &result[i].a, &result[i].b , &result[i].c }; - for (uint32_t k = 0; k < 3; ++k) - { - newMeshVertices[i * 3 + k] = arr[k]->p; - newMeshNormals[i * 3 + k] = arr[k]->n; - newMeshUvs[i * 3 + k] = arr[k]->uv[0]; - } - } - std::vector<uint32_t> serializedIndices; - serializedIndices.reserve(result.size() * 3); - int32_t cindex = 0; - for (uint32_t i = 0; i < result.size(); ++i) - { - newMaterialIds[i] = result[i].materialId; - newSmoothingGroups[i] = result[i].smoothingGroup; - - for (uint32_t pi = 0; pi < 3; ++pi) - serializedIndices.push_back(cindex++); - } - - MeshImpl* rMesh = new MeshImpl(newMeshVertices.data(), newMeshNormals.data(), newMeshUvs.data(), static_cast<uint32_t>(newMeshVertices.size()), serializedIndices.data(), static_cast<uint32_t>(serializedIndices.size())); - rMesh->setMaterialId(newMaterialIds.data()); - rMesh->setSmoothingGroup(newSmoothingGroups.data()); - return rMesh; -} - -void MeshCleanerImpl::release() -{ - delete this; -} - +
+#include <PxVec3.h>
+#include <PxVec2.h>
+#include <vector>
+#include <queue>
+#include <map>
+
+#include <NvBlastExtAuthoringMeshCleanerImpl.h>
+#include <NvBlastExtAuthoringMeshImpl.h>
+#include <NvBlastExtAuthoringInternalCommon.h>
+#include <boost/multiprecision/cpp_int.hpp>
+
+
+
+
+using physx::PxVec3;
+using physx::PxVec2;
+
+using namespace Nv::Blast;
+using namespace boost::multiprecision;
+
+/**
+ Exact rational vector types.
+*/
+struct RVec3
+{
+ cpp_rational x, y, z;
+ RVec3()
+ {
+
+ }
+
+ bool isZero()
+ {
+ return x.is_zero() && y.is_zero() && z.is_zero();
+ }
+
+ RVec3(cpp_rational _x, cpp_rational _y, cpp_rational _z)
+ {
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ RVec3(const PxVec3& p)
+ {
+ x = cpp_rational(p.x);
+ y = cpp_rational(p.y);
+ z = cpp_rational(p.z);
+ }
+ PxVec3 toVec3()
+ {
+ return PxVec3(x.convert_to<float>(), y.convert_to<float>(), z.convert_to<float>());
+ }
+
+ RVec3 operator-(const RVec3& b) const
+ {
+ return RVec3(x - b.x, y - b.y, z - b.z);
+ }
+ RVec3 operator+(const RVec3& b) const
+ {
+ return RVec3(x + b.x, y + b.y, z + b.z);
+ }
+ RVec3 cross(const RVec3& in) const
+ {
+ return RVec3(y * in.z - in.y * z, in.x * z - x * in.z, x * in.y - in.x * y);
+ }
+ cpp_rational dot(const RVec3& in) const
+ {
+ return x * in.x + y * in.y + z * in.z;
+ }
+ RVec3 operator*(const cpp_rational& in) const
+ {
+ return RVec3(x * in, y * in, z * in);
+ }
+
+
+};
+
+struct RVec2
+{
+ cpp_rational x, y;
+ RVec2()
+ {
+
+ }
+
+ RVec2(cpp_rational _x, cpp_rational _y)
+ {
+ x = _x;
+ y = _y;
+ }
+
+ RVec2(const PxVec2& p)
+ {
+ x = cpp_rational(p.x);
+ y = cpp_rational(p.y);
+ }
+ PxVec2 toVec2()
+ {
+ return PxVec2(x.convert_to<float>(), y.convert_to<float>());
+ }
+
+ RVec2 operator-(const RVec2& b) const
+ {
+ return RVec2(x - b.x, y - b.y);
+ }
+ RVec2 operator+(const RVec2& b) const
+ {
+ return RVec2(x + b.x, y + b.y);
+ }
+ cpp_rational cross(const RVec2& in) const
+ {
+ return x * in.y - y * in.x;
+ }
+ cpp_rational dot(const RVec2& in) const
+ {
+ return x * in.x + y * in.y;
+ }
+ RVec2 operator*(const cpp_rational& in) const
+ {
+ return RVec2(x * in, y * in);
+ }
+};
+struct RatPlane
+{
+ RVec3 n;
+ cpp_rational d;
+
+ RatPlane(const RVec3& a, const RVec3& b, const RVec3& c)
+ {
+ n = (b - a).cross(c - a);
+ d = -n.dot(a);
+ };
+ cpp_rational distance(RVec3& in)
+ {
+ return n.dot(in) + d;
+ }
+};
+
+bool isSame(const RatPlane& a, const RatPlane& b)
+{
+ if (a.d != b.d) return false;
+ if (a.n.x != b.n.x || a.n.y != b.n.y || a.n.z != b.n.z) return false;
+ return true;
+}
+
+RVec3 planeSegmInters(RVec3& a, RVec3& b, RatPlane& pl)
+{
+ cpp_rational t = -(a.dot(pl.n) + pl.d) / pl.n.dot(b - a);
+ RVec3 on = a + (b - a) * t;
+ return on;
+}
+
+enum POINT_CLASS
+{
+ ON_AB = 0,
+ ON_BC = 1,
+ ON_AC = 2,
+ INSIDE_TR,
+ OUTSIDE_TR,
+ ON_VERTEX
+};
+
+
+int32_t isPointInside(const RVec2& a, const RVec2& b, const RVec2& c, const RVec2& p)
+{
+ cpp_rational v1 = (b - a).cross(p - a);
+ cpp_rational v2 = (c - b).cross(p - b);
+ cpp_rational v3 = (a - c).cross(p - c);
+
+
+
+ int32_t v1s = v1.sign();
+ int32_t v2s = v2.sign();
+ int32_t v3s = v3.sign();
+
+ if (v1s * v2s < 0 || v1s * v3s < 0 || v2s * v3s < 0) return OUTSIDE_TR;
+
+ if (v1s == 0 && v2s == 0) return OUTSIDE_TR;
+ if (v1s == 0 && v3s == 0) return OUTSIDE_TR;
+ if (v2s == 0 && v3s == 0) return OUTSIDE_TR;
+
+ if (v1s == 0) return ON_AB;
+ if (v2s == 0) return ON_BC;
+ if (v3s == 0) return ON_AC;
+
+ return INSIDE_TR;
+}
+
+RVec2 getProjectedPointWithWinding(const RVec3& point, ProjectionDirections dir)
+{
+ if (dir & YZ_PLANE)
+ {
+ if (dir & OPPOSITE_WINDING)
+ {
+ return RVec2(point.z, point.y);
+ }
+ else
+ return RVec2(point.y, point.z);
+ }
+ if (dir & ZX_PLANE)
+ {
+ if (dir & OPPOSITE_WINDING)
+ {
+ return RVec2(point.z, point.x);
+ }
+ return RVec2(point.x, point.z);
+ }
+ if (dir & OPPOSITE_WINDING)
+ {
+ return RVec2(point.y, point.x);
+ }
+ return RVec2(point.x, point.y);
+}
+
+struct DelTriangle
+{
+ int32_t p[3];
+ int32_t n[3];
+ int32_t parentTriangle;
+ int32_t getEdWP(int32_t vrt)
+ {
+ if (p[0] == vrt) return 1;
+ if (p[1] == vrt) return 2;
+ if (p[2] == vrt) return 0;
+ return -1;
+ }
+ int32_t getEdId(int32_t v1, int32_t v2)
+ {
+ if (p[0] == v1 && p[1] == v2) return 0;
+ if (p[1] == v1 && p[2] == v2) return 1;
+ if (p[2] == v1 && p[0] == v2) return 2;
+ return -1;
+ }
+ int32_t getOppP(int32_t v1, int32_t v2)
+ {
+ if (p[0] == v1 && p[1] == v2) return 2;
+ if (p[1] == v1 && p[2] == v2) return 0;
+ if (p[2] == v1 && p[0] == v2) return 1;
+ return -1;
+ }
+
+ int32_t getOppPoint(int32_t v1, int32_t v2)
+ {
+ if (p[0] != v1 && p[0] != v2) return p[0];
+ if (p[1] != v1 && p[1] != v2) return p[1];
+ if (p[2] != v1 && p[2] != v2) return p[2];
+ return -1;
+ }
+ bool compare(const DelTriangle& t) const
+ {
+ if (p[0] == t.p[0] && p[1] == t.p[1] && p[2] == t.p[2]) return true;
+ if (p[1] == t.p[0] && p[2] == t.p[1] && p[0] == t.p[2]) return true;
+ if (p[2] == t.p[0] && p[0] == t.p[1] && p[1] == t.p[2]) return true;
+ return false;
+ }
+
+};
+
+struct DelEdge
+{
+ int32_t s, e;
+ int32_t nr, nl;
+};
+
+
+bool isIntersectsTriangle(RVec2& a, RVec2& b, RVec2& c, RVec2& s, RVec2& e)
+{
+ RVec2 vec = e - s;
+
+ if ((a - s).cross(vec) * (b - s).cross(vec) < 0)
+ {
+ RVec2 vec2 = b - a;
+ if ((s - a).cross(vec2) * (e - a).cross(vec) < 0) return true;
+ }
+
+ if ((b - s).cross(vec) * (c - s).cross(vec) < 0)
+ {
+ RVec2 vec2 = c - b;
+ if ((s - b).cross(vec2) * (e - b).cross(vec) < 0) return true;
+ }
+
+ if ((a - s).cross(vec) * (c - s).cross(vec) < 0)
+ {
+ RVec2 vec2 = a - c;
+ if ((s - c).cross(vec2) * (e - c).cross(vec) < 0) return true;
+ }
+
+ return false;
+}
+
+
+inline int32_t inCircumcircle(RVec2& a, RVec2& b, RVec2& c, RVec2& p)
+{
+ RVec2 ta = a - p;
+ RVec2 tb = b - p;
+ RVec2 tc = c - p;
+ cpp_rational ad = ta.dot(ta);
+ cpp_rational bd = tb.dot(tb);
+ cpp_rational cd = tc.dot(tc);
+
+ cpp_rational pred = ta.x * (tb.y * cd - tc.y * bd) - ta.y * (tb.x * cd - tc.x * bd) + ad * (tb.x * tc.y - tc.x * tb.y);
+
+
+ if (pred > 0) return 1;
+ if (pred < 0) return -1;
+ return 0;
+}
+
+int32_t getEdge(std::vector<DelEdge>& edges, int32_t s, int32_t e)
+{
+ for (uint32_t i = 0; i < edges.size(); ++i)
+ {
+ if (edges[i].s == s && edges[i].e == e) return i;
+ }
+
+ edges.push_back(DelEdge());
+ edges.back().s = s;
+ edges.back().e = e;
+ return edges.size() - 1;
+}
+
+void reubildAdjacency(std::vector<DelTriangle>& state)
+{
+ for (uint32_t i = 0; i < state.size(); ++i)
+ {
+ state[i].n[0] = state[i].n[1] = state[i].n[2] = -1;
+ }
+ for (uint32_t i = 0; i < state.size(); ++i)
+ {
+ if (state[i].p[0] == -1) continue;
+ for (uint32_t j = i + 1; j < state.size(); ++j)
+ {
+ if (state[j].p[0] == -1) continue;
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ for (uint32_t c = 0; c < 3; ++c)
+ {
+ if (state[i].p[k] == state[j].p[(c + 1) % 3] && state[i].p[(k + 1) % 3] == state[j].p[c]) { state[i].n[k] = j; state[j].n[c] = i; }
+ }
+ }
+ }
+ }
+}
+
+void insertPoint(std::vector<RVec2>& vertices, std::vector<DelTriangle>& state, int32_t p, const std::vector<Edge>& edges)
+{
+ std::queue<int32_t> triangleToCheck;
+
+ for (uint32_t i = 0; i < state.size(); ++i)
+ {
+ if (state[i].p[0] == -1) continue;
+ DelTriangle ctr = state[i];
+ int32_t cv = isPointInside(vertices[ctr.p[0]], vertices[ctr.p[1]], vertices[ctr.p[2]], vertices[p]);
+
+ if (cv == OUTSIDE_TR) continue;
+ if (cv == INSIDE_TR)
+ {
+ uint32_t taInd = state.size();
+ uint32_t tbInd = state.size() + 1;
+ uint32_t tcInd = state.size() + 2;
+ state.resize(state.size() + 3);
+
+ state[taInd].p[0] = ctr.p[2];
+ state[taInd].p[1] = ctr.p[0];
+ state[taInd].p[2] = p;
+
+ state[taInd].n[0] = ctr.n[2];
+ state[taInd].n[1] = tbInd;
+ state[taInd].n[2] = tcInd;
+
+ state[tbInd].p[0] = ctr.p[0];
+ state[tbInd].p[1] = ctr.p[1];
+ state[tbInd].p[2] = p;
+
+ state[tbInd].n[0] = ctr.n[0];
+ state[tbInd].n[1] = tcInd;
+ state[tbInd].n[2] = taInd;
+
+ state[tcInd].p[0] = ctr.p[1];
+ state[tcInd].p[1] = ctr.p[2];
+ state[tcInd].p[2] = p;
+
+ state[tcInd].n[0] = ctr.n[1];
+ state[tcInd].n[1] = taInd;
+ state[tcInd].n[2] = tbInd;
+
+
+ triangleToCheck.push(taInd);
+ triangleToCheck.push(tbInd);
+ triangleToCheck.push(tcInd);
+
+
+ /**
+ Change neighboors
+ */
+ int32_t nb = state[i].n[0];
+ if (nb != -1)
+ state[nb].n[state[nb].getEdId(state[i].p[1], state[i].p[0])] = tbInd;
+ nb = state[i].n[1];
+ if (nb != -1)
+ state[nb].n[state[nb].getEdId(state[i].p[2], state[i].p[1])] = tcInd;
+ nb = state[i].n[2];
+ if (nb != -1)
+ state[nb].n[state[nb].getEdId(state[i].p[0], state[i].p[2])] = taInd;
+
+
+ state[i].p[0] = -1;
+ }
+ else
+ {
+ uint32_t taInd = state.size();
+ uint32_t tbInd = state.size() + 1;
+ state.resize(state.size() + 2);
+
+ int32_t bPoint = state[i].p[(cv + 2) % 3];
+
+ state[taInd].p[0] = bPoint;
+ state[taInd].p[1] = state[i].p[cv];
+ state[taInd].p[2] = p;
+
+ state[tbInd].p[0] = bPoint;
+ state[tbInd].p[1] = p;
+ state[tbInd].p[2] = state[i].p[(cv + 1) % 3];
+
+ state[taInd].n[0] = state[i].n[(cv + 2) % 3];
+ state[taInd].n[1] = -1;
+ state[taInd].n[2] = tbInd;
+
+ state[tbInd].n[0] = taInd;
+ state[tbInd].n[1] = -1;
+ state[tbInd].n[2] = state[i].n[(cv + 1) % 3];
+
+ if (state[i].n[(cv + 1) % 3] != -1)
+ for (int32_t k = 0; k < 3; ++k)
+ if (state[state[i].n[(cv + 1) % 3]].n[k] == (int32_t)i) {
+ state[state[i].n[(cv + 1) % 3]].n[k] = tbInd; break;
+ }
+ if (state[i].n[(cv + 2) % 3] != -1)
+ for (int32_t k = 0; k < 3; ++k)
+ if (state[state[i].n[(cv + 2) % 3]].n[k] == (int32_t)i) {
+ state[state[i].n[(cv + 2) % 3]].n[k] = taInd; break;
+ }
+
+ triangleToCheck.push(taInd);
+ triangleToCheck.push(tbInd);
+
+ int32_t total = 2;
+ int32_t oppositeTr = 0;
+ if (state[i].n[cv] != -1)
+ {
+ oppositeTr = state[i].n[cv];
+ total += 2;
+ uint32_t tcInd = state.size();
+ uint32_t tdInd = state.size() + 1;
+ state.resize(state.size() + 2);
+
+ int32_t oped = state[oppositeTr].getEdId(state[i].p[(cv + 1) % 3], state[i].p[cv]);
+
+
+ state[tcInd].n[0] = state[oppositeTr].n[(oped + 2) % 3];
+ state[tcInd].n[1] = tbInd;
+ state[tbInd].n[1] = tcInd;
+ state[tcInd].n[2] = tdInd;
+
+ state[tdInd].n[0] = tcInd;
+ state[tdInd].n[1] = taInd;
+ state[taInd].n[1] = tdInd;
+ state[tdInd].n[2] = state[oppositeTr].n[(oped + 1) % 3];
+ if (state[oppositeTr].n[(oped + 2) % 3] != -1)
+ for (int32_t k = 0; k < 3; ++k)
+ if (state[state[oppositeTr].n[(oped + 2) % 3]].n[k] == oppositeTr) {
+ state[state[oppositeTr].n[(oped + 2) % 3]].n[k] = tcInd; break;
+ }
+ if (state[oppositeTr].n[(oped + 1) % 3] != -1)
+ for (int32_t k = 0; k < 3; ++k)
+ if (state[state[oppositeTr].n[(oped + 1) % 3]].n[k] == oppositeTr) {
+ state[state[oppositeTr].n[(oped + 1) % 3]].n[k] = tdInd; break;
+ }
+
+ int32_t pop = state[oppositeTr].p[(oped + 2) % 3];
+ state[tcInd].p[0] = pop;
+ state[tcInd].p[1] = state[i].p[(cv + 1) % 3];
+ state[tcInd].p[2] = p;
+
+ state[tdInd].p[0] = pop;
+ state[tdInd].p[1] = p;
+ state[tdInd].p[2] = state[i].p[cv];
+
+
+ state[oppositeTr].p[0] = -1;
+ triangleToCheck.push(tcInd);
+ triangleToCheck.push(tdInd);
+ }
+ state[i].p[0] = -1;
+ }
+ break;
+ }
+
+ while (!triangleToCheck.empty())
+ {
+ int32_t ctrid = triangleToCheck.front();
+ triangleToCheck.pop();
+ DelTriangle& ctr = state[ctrid];
+ int32_t oppTr = -5;
+ int32_t ced = 0;
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ if (ctr.p[i] != p && ctr.p[(i + 1) % 3] != p)
+ {
+ ced = i;
+ oppTr = ctr.n[i];
+ break;
+ }
+ }
+ if (oppTr == -1) continue;
+ bool toCont = false;
+ for (size_t i = 0; i < edges.size(); ++i)
+ {
+ if ((int32_t)edges[i].s == ctr.p[ced] && ctr.p[(ced + 1) % 3] == (int32_t)edges[i].e) { toCont = true; break; }
+ if ((int32_t)edges[i].e == ctr.p[ced] && ctr.p[(ced + 1) % 3] == (int32_t)edges[i].s) { toCont = true; break; }
+ }
+ if (toCont) continue;
+
+
+ DelTriangle& otr = state[oppTr];
+
+ if (inCircumcircle(vertices[state[oppTr].p[0]], vertices[state[oppTr].p[1]], vertices[state[oppTr].p[2]], vertices[p]) > 0)
+ {
+ int32_t notPIndx = 0;
+ for (; notPIndx < 3; ++notPIndx)
+ {
+ if (otr.p[notPIndx] != ctr.p[0] && otr.p[notPIndx] != ctr.p[1] && otr.p[notPIndx] != ctr.p[2])
+ break;
+ }
+
+ int32_t oppCed = state[oppTr].getEdId(ctr.p[(ced + 1) % 3], ctr.p[ced]);
+
+ int32_t ntr1 = ctrid, ntr2 = oppTr;
+
+ DelTriangle nt1, nt2;
+ nt1.p[0] = state[oppTr].p[notPIndx];
+ nt1.p[1] = p;
+ nt1.n[0] = ntr2;
+ nt1.p[2] = ctr.p[ced];
+ nt1.n[1] = ctr.n[(ced + 2) % 3];
+ nt1.n[2] = otr.n[(oppCed + 1) % 3];
+
+ if (nt1.n[2] != -1)
+ for (uint32_t k = 0; k < 3; ++k)
+ if (state[nt1.n[2]].n[k] == oppTr) state[nt1.n[2]].n[k] = ntr1;
+
+ nt2.p[0] = p;
+ nt2.p[1] = state[oppTr].p[notPIndx];
+ nt2.n[0] = ntr1;
+ nt2.p[2] = ctr.p[(ced + 1) % 3];
+ nt2.n[1] = otr.n[(oppCed + 2) % 3];
+ nt2.n[2] = ctr.n[(ced + 1) % 3];
+ if (nt2.n[2] != -1)
+ for (uint32_t k = 0; k < 3; ++k)
+ if (state[nt2.n[2]].n[k] == ctrid) state[nt2.n[2]].n[k] = ntr2;
+ state[ntr1] = nt1;
+ state[ntr2] = nt2;
+ triangleToCheck.push(ntr1);
+ triangleToCheck.push(ntr2);
+ }
+ }
+
+}
+
+bool edgeIsIntersected(const RVec2& a, const RVec2& b, const RVec2& es, const RVec2& ee)
+{
+ RVec2 t = b - a;
+ cpp_rational temp = (es - a).cross(t) * (ee - a).cross(t);
+
+ if (temp < 0)
+ {
+ t = es - ee;
+ if ((a - ee).cross(t) * (b - ee).cross(t) <= 0) return true;
+ }
+ return false;
+}
+
+void triangulatePseudoPolygon(std::vector<RVec2>& vertices, int32_t ba, int32_t bb, std::vector<int32_t>& pseudo, std::vector<DelTriangle>& output)
+{
+ if (pseudo.empty()) return;
+
+ int32_t c = 0;
+ if (pseudo.size() > 1)
+ {
+ for (uint32_t i = 1; i < pseudo.size(); ++i)
+ {
+ if (inCircumcircle(vertices[ba], vertices[bb], vertices[pseudo[c]], vertices[pseudo[i]]) > 0)
+ {
+ c = i;
+ }
+ }
+ std::vector<int32_t> toLeft;
+ std::vector<int32_t> toRight;
+
+ for (int32_t t = 0; t < c; ++t)
+ {
+ toLeft.push_back(pseudo[t]);
+ }
+ for (size_t t = c + 1; t < pseudo.size(); ++t)
+ {
+ toRight.push_back(pseudo[t]);
+ }
+ if (toLeft.size() > 0)
+ triangulatePseudoPolygon(vertices, ba, pseudo[c], toLeft, output);
+ if (toRight.size() > 0)
+ triangulatePseudoPolygon(vertices, pseudo[c], bb, toRight, output);
+ }
+ output.push_back(DelTriangle());
+ output.back().p[0] = ba;
+ output.back().p[1] = bb;
+ output.back().p[2] = pseudo[c];
+}
+
+
+
+void insertEdge(std::vector<RVec2>& vertices, std::vector<DelTriangle>& output, int32_t edBeg, int32_t edEnd)
+{
+ bool hasEdge = false;
+ for (auto& it : output)
+ {
+ for (uint32_t i = 0; i < 3; ++i)
+ if ((it.p[i] == edBeg || it.p[i] == edEnd) && (it.p[(i + 1) % 3] == edBeg || it.p[(i + 1) % 3] == edEnd))
+ {
+ hasEdge = true;
+ }
+ }
+ if (hasEdge) return;
+
+ int32_t startTriangle = -1;
+ int32_t edg = -1;
+ for (uint32_t i = 0; i < output.size(); ++i)
+ {
+ if (output[i].p[0] == -1) continue;
+
+ if (output[i].p[0] == edBeg || output[i].p[1] == edBeg || output[i].p[2] == edBeg)
+ {
+ edg = output[i].getEdWP(edBeg);
+ if (edgeIsIntersected(vertices[edBeg], vertices[edEnd], vertices[output[i].p[edg]], vertices[output[i].p[(edg + 1) % 3]]))
+ {
+ startTriangle = i;
+ break;
+ }
+ }
+ }
+ if (startTriangle == -1)
+ {
+ return;
+ }
+ int32_t cvertex = edBeg;
+
+ std::vector<int32_t> pointsAboveEdge;
+ std::vector<int32_t> pointsBelowEdge;
+
+ RVec2 vec = vertices[edEnd] - vertices[edBeg];
+
+ if (vec.cross(vertices[output[startTriangle].p[edg]] - vertices[edBeg]) > 0)
+ {
+ pointsAboveEdge.push_back(output[startTriangle].p[edg]);
+ pointsBelowEdge.push_back(output[startTriangle].p[(edg + 1) % 3]);
+ }
+ else
+ {
+ pointsBelowEdge.push_back(output[startTriangle].p[edg]);
+ pointsAboveEdge.push_back(output[startTriangle].p[(edg + 1) % 3]);
+ }
+
+ while (1)
+ {
+ DelTriangle& ctr = output[startTriangle];
+ int32_t oed = ctr.getEdWP(cvertex);
+ int32_t nextTriangle = ctr.n[oed];
+
+ if (output[nextTriangle].p[0] == edEnd || output[nextTriangle].p[1] == edEnd || output[nextTriangle].p[2] == edEnd)
+ {
+ ctr.p[0] = -1;
+ output[nextTriangle].p[0] = -1;
+ break;
+ }
+
+ DelTriangle& otr = output[nextTriangle];
+ int32_t opp = otr.p[otr.getOppP(ctr.p[(oed + 1) % 3], ctr.p[oed % 3])];
+
+ int32_t nextPoint = 0;
+ if (vec.cross((vertices[opp] - vertices[edBeg])) > 0)
+ {
+ pointsAboveEdge.push_back(opp);
+ if (vec.cross(vertices[ctr.p[(oed + 1) % 3]] - vertices[edBeg]) > 0)
+ {
+ nextPoint = ctr.p[(oed + 1) % 3];
+ }
+ else
+ {
+ nextPoint = ctr.p[oed];
+ }
+ }
+ else
+ {
+ pointsBelowEdge.push_back(opp);
+
+ if (vec.cross(vertices[ctr.p[(oed + 1) % 3]] - vertices[edBeg]) < 0)
+ {
+ nextPoint = ctr.p[(oed + 1) % 3];
+ }
+ else
+ {
+ nextPoint = ctr.p[oed];
+ }
+ }
+ startTriangle = nextTriangle;
+ cvertex = nextPoint;
+ ctr.p[0] = -1;
+ }
+ triangulatePseudoPolygon(vertices, edBeg, edEnd, pointsAboveEdge, output);
+ std::reverse(pointsBelowEdge.begin(), pointsBelowEdge.end());
+ triangulatePseudoPolygon(vertices, edEnd, edBeg, pointsBelowEdge, output);
+ reubildAdjacency(output);
+}
+
+
+
+
+
+
+void buildCDT(std::vector<RVec3>& vertices, std::vector<Edge>& edges, std::vector<DelTriangle>& output, ProjectionDirections dr)
+{
+ std::vector<DelTriangle> state;
+
+ DelTriangle crt;
+ std::vector<bool> added(vertices.size(), false);
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ crt.p[i] = edges[i].s;
+ added[edges[i].s] = true;
+ crt.n[i] = -1; // dont have neighboors;
+ }
+ state.push_back(crt);
+
+
+ std::vector<RVec2> p2d(vertices.size());
+ for (uint32_t i = 0; i < vertices.size(); ++i)
+ {
+ p2d[i] = getProjectedPointWithWinding(vertices[i], dr);
+ }
+
+ for (size_t i = 0; i < edges.size(); ++i)
+ {
+ if (!added[edges[i].s])
+ {
+ insertPoint(p2d, state, edges[i].s, edges);
+ added[edges[i].s] = true;
+ }
+ if (!added[edges[i].e])
+ {
+ insertPoint(p2d, state, edges[i].e, edges);
+ added[edges[i].e] = true;
+ }
+ if (edges[i].s != edges[i].e)
+ {
+ insertEdge(p2d, state, edges[i].s, edges[i].e);
+ }
+ }
+
+ for (uint32_t t = 0; t < state.size(); ++t)
+ {
+ if (state[t].p[0] != -1)
+ {
+ output.push_back(state[t]);
+ }
+ }
+}
+
+int32_t intersectSegments(RVec3& s1, RVec3& e1, RVec3& s2, RVec3& e2, ProjectionDirections dir, std::vector<cpp_rational>& t1v, std::vector<cpp_rational>& t2v);
+
+void getTriangleIntersectionCoplanar(uint32_t tr1, uint32_t tr2, std::vector<std::vector<RVec3>>& stencil, ProjectionDirections dr)
+{
+ std::vector<cpp_rational> intr1[3];
+ std::vector<cpp_rational> intr2[3];
+
+ RVec3 p1[3];
+ p1[0] = stencil[tr1][0];
+ p1[1] = stencil[tr1][1];
+ p1[2] = stencil[tr1][3];
+
+ RVec3 p2[3];
+ p2[0] = stencil[tr2][0];
+ p2[1] = stencil[tr2][1];
+ p2[2] = stencil[tr2][3];
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ for (uint32_t j = 0; j < 3; ++j)
+ {
+ intersectSegments(p1[i], p1[(i + 1) % 3], p2[j], p2[(j + 1) % 3], dr, intr1[i], intr2[j]);
+ }
+ }
+
+ int32_t inRel1[3];
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ inRel1[i] = isPointInside(getProjectedPointWithWinding(p2[0], dr), getProjectedPointWithWinding(p2[1], dr), getProjectedPointWithWinding(p2[2], dr), getProjectedPointWithWinding(p1[i], dr));
+ }
+
+ int32_t inRel2[3];
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ inRel2[i] = isPointInside(getProjectedPointWithWinding(p1[0], dr), getProjectedPointWithWinding(p1[1], dr), getProjectedPointWithWinding(p1[2], dr), getProjectedPointWithWinding(p2[i], dr));
+ }
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ if (inRel1[i] == INSIDE_TR && inRel1[(i + 1) % 3] == INSIDE_TR)
+ {
+ stencil[tr2].push_back(p1[i]);
+ stencil[tr2].push_back(p1[(i + 1) % 3]);
+ }
+ else
+ {
+ if (inRel1[i] == INSIDE_TR && intr1[i].size() == 1)
+ {
+ stencil[tr2].push_back(p1[i]);
+ stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]);
+ }
+ if (inRel1[(i + 1) % 3] == INSIDE_TR && intr1[i].size() == 1)
+ {
+ stencil[tr2].push_back(p1[(i + 1) % 3]);
+ stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]);
+ }
+ if (intr1[i].size() == 2)
+ {
+ stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]);
+ stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][1] + p1[i]);
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ if (inRel2[i] == INSIDE_TR && inRel2[(i + 1) % 3] == INSIDE_TR)
+ {
+ stencil[tr1].push_back(p2[i]);
+ stencil[tr1].push_back(p2[(i + 1) % 3]);
+ }
+ else
+ {
+ if (inRel2[i] == INSIDE_TR && intr2[i].size() == 1)
+ {
+ stencil[tr1].push_back(p2[i]);
+ stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]);
+ }
+ if (inRel2[(i + 1) % 3] == INSIDE_TR && intr2[i].size() == 1)
+ {
+ stencil[tr1].push_back(p2[(i + 1) % 3]);
+ stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]);
+ }
+ if (intr2[i].size() == 2)
+ {
+ stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]);
+ stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][1] + p2[i]);
+ }
+ }
+ }
+}
+
+
+int32_t getTriangleIntersection3d(uint32_t tr1, uint32_t tr2, std::vector<std::vector<RVec3>>& stencil, ProjectionDirections dr)
+{
+ RatPlane pl1(stencil[tr1][0], stencil[tr1][1], stencil[tr1][3]);
+ if (pl1.n.isZero())
+ {
+ std::swap(tr1, tr2);
+ pl1 = RatPlane(stencil[tr1][0], stencil[tr1][1], stencil[tr1][3]);
+ if (pl1.n.isZero()) return 0;
+ }
+
+
+ cpp_rational d1 = pl1.distance(stencil[tr2][0]);
+ cpp_rational d2 = pl1.distance(stencil[tr2][1]);
+ cpp_rational d3 = pl1.distance(stencil[tr2][3]);
+
+ int32_t sd1 = d1.sign();
+ int32_t sd2 = d2.sign();
+ int32_t sd3 = d3.sign();
+
+
+ if (sd1 == 0 && sd2 == 0 && sd3 == 0)
+ {
+ getTriangleIntersectionCoplanar(tr1, tr2, stencil, dr);
+ return 0;
+ }
+ /**
+ Never intersected
+ */
+ if (sd1 < 0 && sd2 < 0 && sd3 < 0)
+ return 0;
+ if (sd1 > 0 && sd2 > 0 && sd3 > 0)
+ return 0;
+
+ RVec3 tb0 = stencil[tr2][0];
+ RVec3 tb1 = stencil[tr2][1];
+ RVec3 tb2 = stencil[tr2][3];
+
+ if (sd1 * sd3 > 0)
+ {
+ std::swap(tb1, tb2);
+ std::swap(d2, d3);
+ }
+ else
+ {
+ if (sd2 * sd3 > 0)
+ {
+ std::swap(tb0, tb2);
+ std::swap(d1, d3);
+ }
+ else
+ {
+ if (sd3 == 0 && sd1 * sd2 < 0)
+ {
+ std::swap(tb0, tb2);
+ std::swap(d1, d3);
+ }
+ }
+ }
+
+ RatPlane pl2(stencil[tr2][0], stencil[tr2][1], stencil[tr2][3]);
+
+ cpp_rational d21 = pl2.distance(stencil[tr1][0]);
+ cpp_rational d22 = pl2.distance(stencil[tr1][1]);
+ cpp_rational d23 = pl2.distance(stencil[tr1][3]);
+
+ int32_t sd21 = d21.sign();
+ int32_t sd22 = d22.sign();
+ int32_t sd23 = d23.sign();
+
+ if (sd21 < 0 && sd22 < 0 && sd23 < 0)
+ return 0;
+ if (sd21 > 0 && sd22 > 0 && sd23 > 0)
+ return 0;
+
+
+ RVec3 ta0 = stencil[tr1][0];
+ RVec3 ta1 = stencil[tr1][1];
+ RVec3 ta2 = stencil[tr1][3];
+
+
+ if (sd21 * sd23 > 0)
+ {
+ std::swap(ta1, ta2);
+ std::swap(d22, d23);
+ }
+ else
+ {
+ if (sd22 * sd23 > 0)
+ {
+ std::swap(ta0, ta2);
+ std::swap(d21, d23);
+ }
+ else
+ {
+ if (sd23 == 0 && sd21 * sd22 < 0)
+ {
+ std::swap(ta0, ta2);
+ std::swap(d21, d23);
+ }
+ }
+ }
+ //////////////////////////////////////////////////
+ RVec3 dir = ta2 - ta0;
+
+ cpp_rational dirPlaneDot = dir.dot(pl2.n);
+
+
+ RVec3 pointOnIntersectionLine;
+ if (dirPlaneDot != 0)
+ {
+ pointOnIntersectionLine = ta0 - dir * (d21 / dirPlaneDot);
+ }
+ else
+ {
+ pointOnIntersectionLine = ta0;
+ }
+ RVec3 interLineDir = pl1.n.cross(pl2.n);
+ cpp_rational sqd = interLineDir.dot(interLineDir);
+ if (sqd.is_zero()) return 0;
+
+ cpp_rational t1p2 = (ta1 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ cpp_rational t1p3 = (ta2 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ cpp_rational t1p2param = t1p2;
+ if (d22 != d23)
+ {
+ t1p2param = t1p2 + (t1p3 - t1p2) * (d22 / (d22 - d23));
+ }
+
+ t1p2 = (tb0 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ t1p3 = (tb2 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ cpp_rational t2p1param = t1p2;
+ if (d1 != d3)
+ {
+ t2p1param = t1p2 + (t1p3 - t1p2) * d1 / (d1 - d3);
+ }
+
+ t1p2 = (tb1 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ cpp_rational t2p2param = t1p2;
+ if (d2 != d3)
+ {
+ t2p2param = t1p2 + (t1p3 - t1p2) * d2 / (d2 - d3);
+ }
+ cpp_rational beg1 = 0;
+
+ if (t1p2param < 0)
+ {
+ std::swap(beg1, t1p2param);
+ }
+ if (t2p2param < t2p1param)
+ {
+ std::swap(t2p2param, t2p1param);
+ }
+ cpp_rational minEnd = std::min(t1p2param, t2p2param);
+ cpp_rational maxBeg = std::max(beg1, t2p1param);
+
+ if (minEnd > maxBeg)
+ {
+ RVec3 p1 = pointOnIntersectionLine + interLineDir * maxBeg;
+ RVec3 p2 = pointOnIntersectionLine + interLineDir * minEnd;
+
+ stencil[tr1].push_back(p1);
+ stencil[tr1].push_back(p2);
+
+ stencil[tr2].push_back(p1);
+ stencil[tr2].push_back(p2);
+ return 1;
+ }
+ return 0;
+}
+
+int32_t intersectSegments(RVec3& s1, RVec3& e1, RVec3& s2, RVec3& e2, ProjectionDirections dir, std::vector<cpp_rational>& t1v, std::vector<cpp_rational>& t2v)
+{
+ RVec2 s1p = getProjectedPointWithWinding(s1, dir);
+ RVec2 e1p = getProjectedPointWithWinding(e1, dir);
+
+ RVec2 s2p = getProjectedPointWithWinding(s2, dir);
+ RVec2 e2p = getProjectedPointWithWinding(e2, dir);
+
+ RVec2 dir1 = e1p - s1p;
+ RVec2 dir2 = s2p - e2p;
+
+ cpp_rational crs = dir1.cross(dir2);
+ if (crs != 0)
+ {
+ cpp_rational c1 = s2p.x - s1p.x;
+ cpp_rational c2 = s2p.y - s1p.y;
+
+ cpp_rational det1 = c1 * dir2.y - c2 * dir2.x;
+ cpp_rational det2 = dir1.x * c2 - dir1.y * c1;
+
+ cpp_rational t1 = det1 / crs;
+ cpp_rational t2 = det2 / crs;
+
+ if (t1 > 0 && t1 < 1 && (t2 >= 0 && t2 <= 1))
+ {
+ t1v.push_back(t1);
+ }
+ if (t2 > 0 && t2 < 1 && (t1 >= 0 && t1 <= 1))
+ {
+ t2v.push_back(t2);
+ }
+
+ }
+ else
+ {
+ if (dir1.cross(s2p - s1p) == 0)
+ {
+ if (dir1.x != 0)
+ {
+ cpp_rational t1 = (s2p.x - s1p.x) / dir1.x;
+ cpp_rational t2 = (e2p.x - s1p.x) / dir1.x;
+ if (t1 > 0 && t1 < 1) t1v.push_back(t1);
+ if (t2 > 0 && t2 < 1) t1v.push_back(t2);
+ }
+ else
+ {
+ if (dir1.y != 0)
+ {
+ cpp_rational t1 = (s2p.y - s1p.y) / dir1.y;
+ cpp_rational t2 = (e2p.y - s1p.y) / dir1.y;
+ if (t1 > 0 && t1 < 1) t1v.push_back(t1);
+ if (t2 > 0 && t2 < 1) t1v.push_back(t2);
+ }
+ }
+ }
+ if (dir2.cross(s1p - s2p) == 0)
+ {
+ dir2 = e2p - s2p;
+ if (dir2.x != 0)
+ {
+ cpp_rational t1 = (s1p.x - s2p.x) / dir2.x;
+ cpp_rational t2 = (e1p.x - s2p.x) / dir2.x;
+ if (t1 > 0 && t1 < 1) t2v.push_back(t1);
+ if (t2 > 0 && t2 < 1) t2v.push_back(t2);
+ }
+ else
+ {
+ if (dir2.y != 0)
+ {
+ cpp_rational t1 = (s1p.y - s2p.y) / dir2.y;
+ cpp_rational t2 = (e1p.y - s2p.y) / dir2.y;
+ if (t1 > 0 && t1 < 1) t2v.push_back(t1);
+ if (t2 > 0 && t2 < 1) t2v.push_back(t2);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+struct RVec3Comparer
+{
+ bool operator()(const RVec3& a, const RVec3& b) const
+ {
+ if (a.x < b.x) return true;
+ if (a.x > b.x) return false;
+ if (a.y < b.y) return true;
+ if (a.y > b.y) return false;
+ if (a.z < b.z) return true;
+ return false;
+ }
+};
+
+void getBarycentricCoords(PxVec2& a, PxVec2& b, PxVec2& c, PxVec2& p, float& u, float& v)
+{
+ PxVec3 v1(b.x - a.x, c.x - a.x, a.x - p.x);
+ PxVec3 v2(b.y - a.y, c.y - a.y, a.y - p.y);
+
+ PxVec3 resl = v1.cross(v2);
+ u = resl.x / resl.z;
+ v = resl.y / resl.z;
+}
+
+
+Mesh* MeshCleanerImpl::cleanMesh(const Mesh* mesh)
+{
+ /**
+ ======= Get mesh data ===========
+ */
+ std::vector<Vertex> vertices;
+ std::vector<Edge> edges;
+ std::vector<Facet> facets;
+
+ vertices.resize(mesh->getVerticesCount());
+ edges.resize(mesh->getEdgesCount());
+ facets.resize(mesh->getFacetCount());
+
+ PxBounds3 bnd;
+ bnd.setEmpty();
+
+ for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i)
+ {
+ vertices[i] = mesh->getVertices()[i];
+ bnd.include(vertices[i].p);
+ }
+ for (uint32_t i = 0; i < mesh->getEdgesCount(); ++i)
+ {
+ edges[i] = mesh->getEdges()[i];
+ }
+ for (uint32_t i = 0; i < mesh->getFacetCount(); ++i)
+ {
+ facets[i] = mesh->getFacetsBuffer()[i];
+ }
+ //======================================
+
+ /**
+ Transform vertices to fit unit cube and snap them to grid.
+ **/
+ float scale = 1.0f / bnd.getExtents().abs().maxElement();
+
+ int32_t gridSize = 10000; // Grid resolution to which vertices position will be snapped.
+
+ for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i)
+ {
+ vertices[i].p = (vertices[i].p - bnd.minimum) * scale;
+ vertices[i].p.x = std::floor(vertices[i].p.x * gridSize) / gridSize;
+ vertices[i].p.y = std::floor(vertices[i].p.y * gridSize) / gridSize;
+ vertices[i].p.z = std::floor(vertices[i].p.z * gridSize) / gridSize;
+ }
+
+ std::vector<std::vector<RVec3>> triangleStencil(facets.size());
+
+ std::vector<PxVec3> facetsNormals(facets.size());
+ std::vector<PxBounds3> facetBound(facets.size());
+
+
+ for (uint32_t tr1 = 0; tr1 < facets.size(); ++tr1)
+ {
+ if (facets[tr1].edgesCount != 3)
+ {
+ return nullptr;
+ }
+ int32_t fed = facets[tr1].firstEdgeNumber;
+ triangleStencil[tr1].push_back(vertices[edges[fed].s].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed].e].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed + 1].s].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed + 1].e].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed + 2].s].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed + 2].e].p);
+
+ facetBound[tr1].setEmpty();
+ facetBound[tr1].include(vertices[edges[fed].s].p);
+ facetBound[tr1].include(vertices[edges[fed].e].p);
+ facetBound[tr1].include(vertices[edges[fed + 2].s].p);
+ facetBound[tr1].fattenFast(0.001f);
+
+ facetsNormals[tr1] = (vertices[edges[fed + 1].s].p - vertices[edges[fed].s].p).cross(vertices[edges[fed + 2].s].p - vertices[edges[fed].s].p);
+ }
+
+ /**
+ Build intersections between all pairs of triangles.
+ */
+ for (uint32_t tr1 = 0; tr1 < facets.size(); ++tr1)
+ {
+ if (triangleStencil[tr1].empty()) continue;
+ for (uint32_t tr2 = tr1 + 1; tr2 < facets.size(); ++tr2)
+ {
+ if (triangleStencil[tr2].empty()) continue;
+ if (facetBound[tr1].intersects(facetBound[tr2]) == false) continue;
+
+ getTriangleIntersection3d(tr1, tr2, triangleStencil, getProjectionDirection(facetsNormals[tr1]));
+ }
+ }
+
+ /**
+ Reintersect all segments
+ */
+ for (uint32_t tr = 0; tr < triangleStencil.size(); ++tr)
+ {
+ std::vector<RVec3>& ctr = triangleStencil[tr];
+ std::vector<std::vector<cpp_rational> > perSegmentInters(ctr.size() / 2);
+ for (uint32_t sg1 = 6; sg1 < ctr.size(); sg1 += 2)
+ {
+ for (uint32_t sg2 = sg1 + 2; sg2 < ctr.size(); sg2 += 2)
+ {
+ intersectSegments(ctr[sg1], ctr[sg1 + 1], ctr[sg2], ctr[sg2 + 1], getProjectionDirection(facetsNormals[tr]), perSegmentInters[sg1 / 2], perSegmentInters[sg2 / 2]);
+ }
+ }
+
+ std::vector<RVec3> newStencil;
+ newStencil.reserve(ctr.size());
+
+ for (uint32_t i = 0; i < ctr.size(); i += 2)
+ {
+ int32_t csm = i / 2;
+ if (perSegmentInters[csm].size() == 0)
+ {
+ newStencil.push_back(ctr[i]);
+ newStencil.push_back(ctr[i + 1]);
+ }
+ else
+ {
+ cpp_rational current = 0;
+ newStencil.push_back(ctr[i]);
+ std::sort(perSegmentInters[csm].begin(), perSegmentInters[csm].end());
+ for (size_t j = 0; j < perSegmentInters[csm].size(); ++j)
+ {
+ if (perSegmentInters[csm][j] > current)
+ {
+ current = perSegmentInters[csm][j];
+ RVec3 pnt = (ctr[i + 1] - ctr[i]) * current + ctr[i];
+ newStencil.push_back(pnt);
+ newStencil.push_back(pnt);
+ }
+ }
+ newStencil.push_back(ctr[i + 1]);
+ }
+ }
+ ctr = newStencil;
+ }
+
+ std::vector<RVec3> finalPoints;
+
+ std::vector<std::vector<Edge>> tsten(facets.size());
+
+ {
+ std::map<RVec3, uint32_t, RVec3Comparer> mapping;
+ for (uint32_t tr1 = 0; tr1 < triangleStencil.size(); ++tr1)
+ {
+ for (uint32_t j = 0; j < triangleStencil[tr1].size(); j += 2)
+ {
+
+ auto it = mapping.find(triangleStencil[tr1][j]);
+ int32_t pt = 0;
+ if (it == mapping.end())
+ {
+ mapping[triangleStencil[tr1][j]] = finalPoints.size();
+ pt = finalPoints.size();
+ finalPoints.push_back(triangleStencil[tr1][j]);
+ }
+ else
+ {
+ pt = it->second;
+ }
+
+ Edge newed;
+
+ newed.s = pt;
+
+ it = mapping.find(triangleStencil[tr1][j + 1]);
+ if (it == mapping.end())
+ {
+ mapping[triangleStencil[tr1][j + 1]] = finalPoints.size();
+ pt = finalPoints.size();
+ finalPoints.push_back(triangleStencil[tr1][j + 1]);
+ }
+ else
+ {
+ pt = it->second;
+ }
+ newed.e = pt;
+ bool hasNewEdge = false;
+ for (uint32_t e = 0; e < tsten[tr1].size(); ++e)
+ {
+ if (tsten[tr1][e].s == newed.s && tsten[tr1][e].e == newed.e)
+ {
+ hasNewEdge = true;
+ break;
+ }
+ if (tsten[tr1][e].e == newed.s && tsten[tr1][e].s == newed.e)
+ {
+ hasNewEdge = true;
+ break;
+ }
+ }
+ if (!hasNewEdge) tsten[tr1].push_back(newed);
+ }
+ }
+ }
+
+ /**
+ Build constrained DT
+ */
+ std::vector<DelTriangle> trs;
+ for (uint32_t i = 0; i < tsten.size(); ++i)
+ {
+
+ if (tsten[i].size() < 3) continue;
+ if (tsten[i].size() > 3)
+ {
+ int32_t oldSize = trs.size();
+ buildCDT(finalPoints, tsten[i], trs, getProjectionDirection(facetsNormals[i]));
+ for (uint32_t k = oldSize; k < trs.size(); ++k)
+ trs[k].parentTriangle = i;
+ }
+ else
+ {
+ trs.push_back(DelTriangle());
+ trs.back().parentTriangle = i;
+ for (uint32_t v = 0; v < 3; ++v)
+ trs.back().p[v] = tsten[i][v].s;
+ }
+
+ }
+
+ /**
+ Remove 'deleted' triangles from array.
+ */
+ {
+ std::vector < DelTriangle > trstemp;
+ trstemp.reserve(trs.size());
+ for (uint32_t i = 0; i < trs.size(); ++i)
+ {
+ if (trs[i].p[0] != -1)
+ trstemp.push_back(trs[i]);
+ }
+ trs = trstemp;
+ }
+
+ /**
+ Filter exterior surface
+ */
+ std::vector<bool> fillingMask(trs.size(), false);
+
+ std::map<std::pair<int32_t, int32_t>, int32_t> edgeMap;
+ std::vector<std::vector<int32_t> > edgeToTriangleMapping;
+
+ for (uint32_t i = 0; i < trs.size(); ++i)
+ {
+ if (trs[i].p[0] == -1) continue;
+ if (trs[i].p[0] == trs[i].p[1] || trs[i].p[2] == trs[i].p[1] || trs[i].p[2] == trs[i].p[0])
+ {
+ trs[i].p[0] = -1;
+ continue;
+ }
+ #if 0 // Filter null-area triangles.
+ if ((finalPoints[trs[i].p[1]] - finalPoints[trs[i].p[0]]).cross(finalPoints[trs[i].p[2]] - finalPoints[trs[i].p[0]]).isZero())
+ {
+ trs[i].p[0] = -1;
+ continue;
+ }
+ #endif
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ int32_t es = trs[i].p[k];
+ int32_t ee = trs[i].p[(k + 1) % 3];
+ if (es > ee)
+ {
+ std::swap(es, ee);
+ }
+ auto pr = std::make_pair(es, ee);
+ auto iter = edgeMap.find(pr);
+ if (iter == edgeMap.end())
+ {
+ edgeMap[pr] = edgeToTriangleMapping.size();
+ trs[i].n[k] = edgeToTriangleMapping.size();
+ edgeToTriangleMapping.resize(edgeToTriangleMapping.size() + 1);
+ edgeToTriangleMapping.back().push_back(i);
+ }
+ else
+ {
+ for (uint32_t j = 0; j < edgeToTriangleMapping[iter->second].size(); ++j)
+ {
+ if (trs[edgeToTriangleMapping[iter->second][j]].compare(trs[i]))
+ {
+ trs[i].p[0] = -1;
+ break;
+ }
+ }
+ if (trs[i].p[0] != -1)
+ {
+ trs[i].n[k] = iter->second;
+ edgeToTriangleMapping[iter->second].push_back(i);
+ }
+ }
+ }
+ }
+
+ std::queue<int32_t> trque;
+ float maxx = -1000;
+ int32_t best = 0;
+ for (uint32_t i = 0; i < trs.size(); ++i)
+ {
+ if (trs[i].p[0] == -1) continue;
+ float m = std::max(finalPoints[trs[i].p[0]].x.convert_to<float>(), std::max(finalPoints[trs[i].p[1]].x.convert_to<float>(), finalPoints[trs[i].p[2]].x.convert_to<float>()));
+ if (m > maxx && facetsNormals[trs[i].parentTriangle].x > 0)
+ {
+ maxx = m;
+ best = i;
+ }
+ }
+
+ trque.push(best);
+ while (!trque.empty())
+ {
+ int32_t trid = trque.front();
+ fillingMask[trid] = true;
+ DelTriangle& tr = trs[trque.front()];
+ trque.pop();
+
+ for (uint32_t ed = 0; ed < 3; ++ed)
+ {
+ auto& tlist = edgeToTriangleMapping[tr.n[ed]];
+ if (tlist.size() == 2)
+ {
+ for (uint32_t k = 0; k < tlist.size(); ++k)
+ {
+ int32_t to = tlist[k];
+ if (to != trid && !fillingMask[to] && edgeToTriangleMapping[trs[to].n[0]].size() > 0 && edgeToTriangleMapping[trs[to].n[1]].size() > 0 && edgeToTriangleMapping[trs[to].n[2]].size() > 0)
+ {
+ trque.push(tlist[k]);
+ fillingMask[tlist[k]] = true;
+ }
+ }
+ }
+ if (tlist.size() > 2)
+ {
+ int32_t bestPath = (tlist[0] == trid) ? tlist[1] : tlist[0];
+ RVec3 start = finalPoints[trs[trid].p[ed]];
+ RVec3 axis = finalPoints[trs[trid].p[(ed + 1) % 3]] - start;
+ RVec3 nAxis = finalPoints[trs[trid].p[(ed + 2) % 3]] - start;
+ RVec3 normal = axis.cross(nAxis);
+
+
+ uint32_t op = trs[bestPath].getOppPoint(trs[trid].p[ed], trs[trid].p[(ed + 1) % 3]);
+
+ RVec3 dir2 = (finalPoints[op] - start);
+ RVec3 normal2 = dir2.cross(axis);
+ cpp_rational bestDir = normal.cross(normal2).dot(axis);
+ cpp_rational oldDist = normal2.dot(normal2);
+ for (uint32_t k = 0; k < tlist.size(); ++k)
+ {
+ if (tlist[k] == trid) continue;
+ op = trs[tlist[k]].getOppPoint(trs[trid].p[ed], trs[trid].p[(ed + 1) % 3]);
+ dir2 = (finalPoints[op] - start);
+ normal2 = dir2.cross(axis);
+ cpp_rational newOne = normal.cross(normal2).dot(axis);
+
+ if (newOne * oldDist < bestDir * normal2.dot(normal2))
+ {
+ oldDist = normal2.dot(normal2);
+ bestPath = tlist[k];
+ bestDir = newOne;
+ }
+ }
+ if (!fillingMask[bestPath] && edgeToTriangleMapping[trs[bestPath].n[0]].size() > 0 && edgeToTriangleMapping[trs[bestPath].n[1]].size() > 0 && edgeToTriangleMapping[trs[bestPath].n[2]].size() > 0)
+ {
+ trque.push(bestPath);
+ fillingMask[bestPath] = true;
+ }
+ }
+ edgeToTriangleMapping[tr.n[ed]].clear();
+ }
+
+ }
+ for (uint32_t id = 0; id < trs.size(); ++id)
+ {
+ if (!fillingMask[id])
+ {
+ trs[id].p[0] = -1; // Remove triangle
+ }
+ }
+ /////////////////////////////////////////////////////////////////////////////////////////////
+
+ std::vector<PxVec3> newVertices;
+ newVertices.resize(finalPoints.size());
+ for (uint32_t i = 0; i < finalPoints.size(); ++i)
+ {
+ newVertices[i].x = finalPoints[i].x.convert_to<float>();
+ newVertices[i].y = finalPoints[i].y.convert_to<float>();
+ newVertices[i].z = finalPoints[i].z.convert_to<float>();
+ }
+ /**
+ Rescale mesh to initial coordinates.
+ */
+ for (uint32_t i = 0; i < finalPoints.size(); ++i)
+ {
+ newVertices[i] = newVertices[i] * (1.0f / scale) + bnd.minimum;
+ }
+ for (uint32_t i = 0; i < vertices.size(); ++i)
+ {
+ vertices[i].p = vertices[i].p * (1.0f / scale) + bnd.minimum;
+ }
+
+ std::vector<Triangle> result;
+ result.reserve(trs.size());
+ {
+ std::vector<PxVec2> projectedTriangles(facets.size() * 3);
+ std::vector<Vertex> normalTriangles(facets.size() * 3);
+
+ for (uint32_t i = 0; i < facets.size(); ++i)
+ {
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ normalTriangles[i * 3 + k] = vertices[edges[facets[i].firstEdgeNumber + k].s];
+ projectedTriangles[i * 3 + k] = getProjectedPointWithWinding(vertices[edges[facets[i].firstEdgeNumber + k].s].p, getProjectionDirection(facetsNormals[i]));
+ }
+ }
+
+ for (uint32_t i = 0; i < trs.size(); ++i)
+ {
+ if (trs[i].p[0] == -1) continue;
+ int32_t id = 0;
+ int32_t parentTriangle = trs[i].parentTriangle;
+ float u = 0, v = 0;
+ result.resize(result.size() + 1);
+ result.back().materialId = facets[parentTriangle].materialId;
+ result.back().smoothingGroup = facets[parentTriangle].smoothingGroup;
+ for (auto vert : { &result.back().a, &result.back().b , &result.back().c })
+ {
+ vert->p = newVertices[trs[i].p[id]];
+ PxVec2 p = getProjectedPointWithWinding(vert->p, getProjectionDirection(facetsNormals[parentTriangle]));
+ getBarycentricCoords(projectedTriangles[parentTriangle * 3], projectedTriangles[parentTriangle * 3 + 1], projectedTriangles[parentTriangle * 3 + 2], p, u, v);
+ vert->uv[0] = (1 - u - v) * normalTriangles[parentTriangle * 3].uv[0] + u * normalTriangles[parentTriangle * 3 + 1].uv[0] + v * normalTriangles[parentTriangle * 3 + 2].uv[0];
+ vert->n = (1 - u - v) * normalTriangles[parentTriangle * 3].n + u * normalTriangles[parentTriangle * 3 + 1].n + v * normalTriangles[parentTriangle * 3 + 2].n;
+ ++id;
+ }
+ }
+ }
+
+ /**
+ Reuse old buffers to create Mesh
+ */
+ std::vector<PxVec3> newMeshVertices(result.size() * 3);
+ std::vector<PxVec3> newMeshNormals(result.size() * 3);
+ std::vector<PxVec2> newMeshUvs(result.size() * 3);
+
+ std::vector<int32_t> newMaterialIds(result.size());
+ std::vector<int32_t> newSmoothingGroups(result.size());
+
+
+ for (uint32_t i = 0; i < result.size(); ++i)
+ {
+ Vertex* arr[3] = { &result[i].a, &result[i].b , &result[i].c };
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ newMeshVertices[i * 3 + k] = arr[k]->p;
+ newMeshNormals[i * 3 + k] = arr[k]->n;
+ newMeshUvs[i * 3 + k] = arr[k]->uv[0];
+ }
+ }
+ std::vector<uint32_t> serializedIndices;
+ serializedIndices.reserve(result.size() * 3);
+ int32_t cindex = 0;
+ for (uint32_t i = 0; i < result.size(); ++i)
+ {
+ newMaterialIds[i] = result[i].materialId;
+ newSmoothingGroups[i] = result[i].smoothingGroup;
+
+ for (uint32_t pi = 0; pi < 3; ++pi)
+ serializedIndices.push_back(cindex++);
+ }
+
+ MeshImpl* rMesh = new MeshImpl(newMeshVertices.data(), newMeshNormals.data(), newMeshUvs.data(), static_cast<uint32_t>(newMeshVertices.size()), serializedIndices.data(), static_cast<uint32_t>(serializedIndices.size()));
+ rMesh->setMaterialId(newMaterialIds.data());
+ rMesh->setSmoothingGroup(newSmoothingGroups.data());
+ return rMesh;
+}
+
+void MeshCleanerImpl::release()
+{
+ delete this;
+}
+
|