diff options
Diffstat (limited to 'extern/mantaflow/preprocessed/edgecollapse.cpp')
-rw-r--r-- | extern/mantaflow/preprocessed/edgecollapse.cpp | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/extern/mantaflow/preprocessed/edgecollapse.cpp b/extern/mantaflow/preprocessed/edgecollapse.cpp new file mode 100644 index 00000000000..72c76ca9200 --- /dev/null +++ b/extern/mantaflow/preprocessed/edgecollapse.cpp @@ -0,0 +1,700 @@ + + +// DO NOT EDIT ! +// This file is generated using the MantaFlow preprocessor (prep generate). + +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Mesh edge collapse and subdivision + * + ******************************************************************************/ + +/******************************************************************************/ +// Copyright note: +// +// These functions (C) Chris Wojtan +// Long-term goal is to unify with his split&merge codebase +// +/******************************************************************************/ + +#include "edgecollapse.h" +#include <queue> + +using namespace std; + +namespace Manta { + +// 8-point butterfly subdivision scheme (as described by Brochu&Bridson 2009) +Vec3 ButterflySubdivision(Mesh &m, const Corner &ca, const Corner &cb) +{ + Vec3 p = m.nodes(m.corners(ca.prev).node).pos + m.nodes(m.corners(ca.next).node).pos; + Vec3 q = m.nodes(ca.node).pos + m.nodes(cb.node).pos; + Vec3 r = m.nodes(m.corners(m.corners(ca.next).opposite).node).pos + + m.nodes(m.corners(m.corners(ca.prev).opposite).node).pos + + m.nodes(m.corners(m.corners(cb.next).opposite).node).pos + + m.nodes(m.corners(m.corners(cb.prev).opposite).node).pos; + return (8 * p + 2 * q - r) / 16.0; +} + +// Modified Butterfly Subdivision Scheme from: +// Interpolating Subdivision for Meshes with Arbitrary Topology +// Denis Zorin, Peter Schroder, and Wim Sweldens +// input the Corner that satisfies the following: +// c.prev.node is the extraordinary vertex, +// and c.next.node is the other vertex involved in the subdivision +Vec3 OneSidedButterflySubdivision(Mesh &m, const int valence, const Corner &c) +{ + Vec3 out; + Vec3 p0 = m.nodes(m.corners(c.prev).node).pos; + Vec3 p1 = m.nodes(m.corners(c.next).node).pos; + + if (valence == 3) { + Vec3 p2 = m.nodes(c.node).pos; + Vec3 p3 = m.nodes(m.corners(m.corners(c.next).opposite).node).pos; + out = (5.0 / 12.0) * p1 - (1.0 / 12.0) * (p2 + p3) + 0.75 * p0; + } + else if (valence == 4) { + Vec3 p2 = m.nodes(m.corners(m.corners(c.next).opposite).node).pos; + out = 0.375 * p1 - 0.125 * p2 + 0.75 * p0; + } + else { + // rotate around extraordinary vertex, + // calculate subdivision weights, + // and interpolate vertex position + double rv = 1.0 / (double)valence; + out = 0.0; + int current = c.prev; + for (int j = 0; j < valence; j++) { + double s = (0.25 + cos(2 * M_PI * j * rv) + 0.5 * cos(4 * M_PI * j * rv)) * rv; + Vec3 p = m.nodes(m.corners(m.corners(current).prev).node).pos; + + out += s * p; + current = m.corners(m.corners(m.corners(current).next).opposite).next; + } + out += 0.75 * m.nodes(m.corners(c.prev).node).pos; + } + return out; +} + +// Modified Butterfly Subdivision Scheme from: +// Interpolating Subdivision for Meshes with Arbitrary Topology +// Denis Zorin, Peter Schroder, and Wim Sweldens +Vec3 ModifiedButterflySubdivision(Mesh &m, + const Corner &ca, + const Corner &cb, + const Vec3 &fallback) +{ + // calculate the valence of the two parent vertices + int start = ca.prev; + int current = start; + int valenceA = 0; + do { + valenceA++; + int op = m.corners(m.corners(current).next).opposite; + if (op < 0) + return fallback; + current = m.corners(op).next; + } while (current != start); + start = ca.next; + current = start; + int valenceB = 0; + do { + valenceB++; + int op = m.corners(m.corners(current).next).opposite; + if (op < 0) + return fallback; + current = m.corners(op).next; + } while (current != start); + + // if both vertices have valence 6, use butterfly subdivision + if (valenceA == 6 && valenceB == 6) { + return ButterflySubdivision(m, ca, cb); + } + else if (valenceA == 6) // use a one-sided scheme + { + return OneSidedButterflySubdivision(m, valenceB, cb); + } + else if (valenceB == 6) // use a one-sided scheme + { + return OneSidedButterflySubdivision(m, valenceA, ca); + } + else // average the results from two one-sided schemes + { + return 0.5 * (OneSidedButterflySubdivision(m, valenceA, ca) + + OneSidedButterflySubdivision(m, valenceB, cb)); + } +} + +bool gAbort = false; + +// collapse an edge on triangle "trinum". +// "which" is 0,1, or 2, +// where which==0 is the triangle edge from p0 to p1, +// which==1 is the triangle edge from p1 to p2, +// and which==2 is the triangle edge from p2 to p0, +void CollapseEdge(Mesh &m, + const int trinum, + const int which, + const Vec3 &edgevect, + const Vec3 &endpoint, + vector<int> &deletedNodes, + std::map<int, bool> &taintedTris, + int &numCollapses, + bool doTubeCutting) +{ + if (gAbort) + return; + // I wanted to draw a pretty picture of an edge collapse, + // but I don't know how to make wacky angled lines in ASCII. + // Instead, I will show the before case and tell you what needs to be done. + + // BEFORE: + // * + // / \. + // /C0 \. + // / \. + // / \. + // / B \. + // / \. + // /C1 C2 \. + // P0 *---------------* P1 + // \C2 C1 / + // \ / + // \ A / + // \ / + // \ / + // \C0 / + // \ / + // * + // + // We are going to collapse the edge between P0 and P1 + // by deleting P1, + // and taking all references to P1, + // and rerouting them to P0 instead + // + // What we need to do: + // Move position of P0 + // Preserve connectivity in both triangles: + // (C1.opposite).opposite = C2.o + // (C2.opposite).opposite = C1.o + // Delete references to Corners of deleted triangles in both P0 and P1's Corner list + // Reassign references to P1: + // loop through P1 triangles: + // rename P1 references to P0 in p lists. + // rename Corner.v references + // Copy P1's list of Corners over to P0's list of Corners + // Delete P1 + + Corner ca_old[3], cb_old[3]; + ca_old[0] = m.corners(trinum, which); + ca_old[1] = m.corners(ca_old[0].next); + ca_old[2] = m.corners(ca_old[0].prev); + bool haveB = false; + if (ca_old[0].opposite >= 0) { + cb_old[0] = m.corners(ca_old[0].opposite); + cb_old[1] = m.corners(cb_old[0].next); + cb_old[2] = m.corners(cb_old[0].prev); + haveB = true; + } + if (!haveB) { + // for now, don't collapse + return; + } + + int P0 = ca_old[2].node; + int P1 = ca_old[1].node; + + /////////////// + // avoid creating nonmanifold edges + bool nonmanifold = false; + bool nonmanifold2 = false; + + set<int> &ring0 = m.get1Ring(P0).nodes; + set<int> &ring1 = m.get1Ring(P1).nodes; + + // check for intersections of the 1-rings of P0,P1 + int cl = 0, commonVert = -1; + for (set<int>::iterator it = ring1.begin(); it != ring1.end(); ++it) + if (ring0.find(*it) != ring0.end()) { + cl++; + if (*it != ca_old[0].node && *it != cb_old[0].node) + commonVert = *it; + } + + nonmanifold = cl > 2; + nonmanifold2 = cl > 3; + + if (nonmanifold && ca_old[1].opposite >= 0 && cb_old[1].opposite >= 0 && + ca_old[2].opposite >= 0 && + cb_old[2].opposite >= 0) // collapsing this edge would create a non-manifold edge + { + if (nonmanifold2) + return; + + bool topTet = false; + bool botTet = false; + // check if collapsing this edge will collapse a tet. + if (m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node) + botTet = true; + + if (m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node) + topTet = true; + + if (topTet ^ botTet) { + + // safe pyramid case. + // collapse the whole tet! + // First collapse the top of the pyramid, + // then carry on collapsing the original verts. + Corner cc_old[3], cd_old[3]; + if (botTet) + cc_old[0] = m.corners(ca_old[1].opposite); + else // topTet + cc_old[0] = cb_old[2]; + cc_old[1] = m.corners(cc_old[0].next); + cc_old[2] = m.corners(cc_old[0].prev); + if (cc_old[0].opposite < 0) + return; + cd_old[0] = m.corners(cc_old[0].opposite); + cd_old[1] = m.corners(cd_old[0].next); + cd_old[2] = m.corners(cd_old[0].prev); + int P2 = cc_old[2].node; + int P3 = cc_old[1].node; + + // update tri props of all adjacent triangles of P0,P1 (do before CT updates!) + for (int i = 0; i < m.numTriChannels(); i++) { + }; // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]); + + m.mergeNode(P2, P3); + + // Preserve connectivity in both triangles + if (cc_old[1].opposite >= 0) + m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite; + if (cc_old[2].opposite >= 0) + m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite; + if (cd_old[1].opposite >= 0) + m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite; + if (cd_old[2].opposite >= 0) + m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite; + + //////////////////// + // mark the two triangles and the one node for deletion + int tmpTrinum = cc_old[0].tri; + int tmpOthertri = cd_old[0].tri; + m.removeTriFromLookup(tmpTrinum); + m.removeTriFromLookup(tmpOthertri); + taintedTris[tmpTrinum] = true; + taintedTris[tmpOthertri] = true; + deletedNodes.push_back(P3); + + numCollapses++; + + // recompute Corners for triangles A and B + if (botTet) + ca_old[0] = m.corners(ca_old[2].opposite); + else + ca_old[0] = m.corners(ca_old[1].prev); + ca_old[1] = m.corners(ca_old[0].next); + ca_old[2] = m.corners(ca_old[0].prev); + cb_old[0] = m.corners(ca_old[0].opposite); + cb_old[1] = m.corners(cb_old[0].next); + cb_old[2] = m.corners(cb_old[0].prev); + + /////////////// + // avoid creating nonmanifold edges... again + ring0 = m.get1Ring(ca_old[2].node).nodes; + ring1 = m.get1Ring(ca_old[1].node).nodes; + + // check for intersections of the 1-rings of P0,P1 + cl = 0; + for (set<int>::iterator it = ring1.begin(); it != ring1.end(); ++it) + if (*it != ca_old[0].node && ring0.find(*it) != ring0.end()) + cl++; + + if (cl > 2) { // nonmanifold + // this can happen if collapsing the first tet leads to another similar collapse that + // requires the collapse of a tet. for now, just move on and pick this up later. + + // if the original component was very small, this first collapse could have led to a tiny + // piece of nonmanifold geometry. in this case, just delete everything that remains. + if (m.corners(ca_old[0].opposite).tri == cb_old[0].tri && + m.corners(ca_old[1].opposite).tri == cb_old[0].tri && + m.corners(ca_old[2].opposite).tri == cb_old[0].tri) { + taintedTris[ca_old[0].tri] = true; + taintedTris[cb_old[0].tri] = true; + m.removeTriFromLookup(ca_old[0].tri); + m.removeTriFromLookup(cb_old[0].tri); + deletedNodes.push_back(ca_old[0].node); + deletedNodes.push_back(ca_old[1].node); + deletedNodes.push_back(ca_old[2].node); + } + return; + } + } + else if (topTet && botTet && ca_old[1].opposite >= 0 && ca_old[2].opposite >= 0 && + cb_old[1].opposite >= 0 && cb_old[2].opposite >= 0) { + if (!(m.corners(ca_old[1].opposite).node == m.corners(ca_old[2].opposite).node && + m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node && + (m.corners(ca_old[1].opposite).node == m.corners(cb_old[1].opposite).node || + (m.corners(ca_old[1].opposite).node == cb_old[0].node && + m.corners(cb_old[1].opposite).node == ca_old[0].node)))) { + // just collapse one for now. + + // collapse the whole tet! + // First collapse the top of the pyramid, + // then carry on collapsing the original verts. + Corner cc_old[3], cd_old[3]; + + // collapse top + { + cc_old[0] = m.corners(ca_old[1].opposite); + cc_old[1] = m.corners(cc_old[0].next); + cc_old[2] = m.corners(cc_old[0].prev); + if (cc_old[0].opposite < 0) + return; + cd_old[0] = m.corners(cc_old[0].opposite); + cd_old[1] = m.corners(cd_old[0].next); + cd_old[2] = m.corners(cd_old[0].prev); + int P2 = cc_old[2].node; + int P3 = cc_old[1].node; + + // update tri props of all adjacent triangles of P0,P1 (do before CT updates!) + // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]); + + m.mergeNode(P2, P3); + + // Preserve connectivity in both triangles + if (cc_old[1].opposite >= 0) + m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite; + if (cc_old[2].opposite >= 0) + m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite; + if (cd_old[1].opposite >= 0) + m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite; + if (cd_old[2].opposite >= 0) + m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite; + + //////////////////// + // mark the two triangles and the one node for deletion + int tmpTrinum = cc_old[0].tri; + int tmpOthertri = cd_old[0].tri; + taintedTris[tmpTrinum] = true; + taintedTris[tmpOthertri] = true; + m.removeTriFromLookup(tmpTrinum); + m.removeTriFromLookup(tmpOthertri); + deletedNodes.push_back(P3); + + numCollapses++; + } + // then collapse bottom + { + // cc_old[0] = [ca_old[1].opposite; + cc_old[0] = cb_old[2]; + cc_old[1] = m.corners(cc_old[0].next); + cc_old[2] = m.corners(cc_old[0].prev); + if (cc_old[0].opposite < 0) + return; + cd_old[0] = m.corners(cc_old[0].opposite); + cd_old[1] = m.corners(cd_old[0].next); + cd_old[2] = m.corners(cd_old[0].prev); + int P2 = cc_old[2].node; + int P3 = cc_old[1].node; + + // update tri props of all adjacent triangles of P0,P1 (do before CT updates!) + // TODO: handleTriPropertyEdgeCollapse(trinum, P2,P3, cc_old[0], cd_old[0]); + + m.mergeNode(P2, P3); + + // Preserve connectivity in both triangles + if (cc_old[1].opposite >= 0) + m.corners(cc_old[1].opposite).opposite = cc_old[2].opposite; + if (cc_old[2].opposite >= 0) + m.corners(cc_old[2].opposite).opposite = cc_old[1].opposite; + if (cd_old[1].opposite >= 0) + m.corners(cd_old[1].opposite).opposite = cd_old[2].opposite; + if (cd_old[2].opposite >= 0) + m.corners(cd_old[2].opposite).opposite = cd_old[1].opposite; + + //////////////////// + // mark the two triangles and the one node for deletion + int tmpTrinum = cc_old[0].tri; + int tmpOthertri = cd_old[0].tri; + taintedTris[tmpTrinum] = true; + taintedTris[tmpOthertri] = true; + deletedNodes.push_back(P3); + + numCollapses++; + } + + // Though we've collapsed a lot of stuff, we still haven't collapsed the original edge. + // At this point we still haven't guaranteed that this original collapse weill be safe. + // quit for now, and we'll catch the remaining short edges the next time this function is + // called. + return; + } + } + else if (doTubeCutting) { + // tube case + // cout<<"CollapseEdge:tube case" << endl; + + // find the edges that touch the common vert + int P2 = commonVert; + int P1P2 = -1, P2P1, P2P0 = -1, P0P2 = -1; // corners across from the cutting seam + int start = ca_old[0].next; + int end = cb_old[0].prev; + int current = start; + do { + // rotate around vertex P1 counter-clockwise + int op = m.corners(m.corners(current).next).opposite; + if (op < 0) + errMsg("tube cutting failed, no opposite"); + current = m.corners(op).next; + + if (m.corners(m.corners(current).prev).node == commonVert) + P1P2 = m.corners(current).next; + } while (current != end); + + start = ca_old[0].prev; + end = cb_old[0].next; + current = start; + do { + // rotate around vertex P0 clockwise + int op = m.corners(m.corners(current).prev).opposite; + if (op < 0) + errMsg("tube cutting failed, no opposite"); + + current = m.corners(op).prev; + if (m.corners(m.corners(current).next).node == commonVert) + P2P0 = m.corners(current).prev; + } while (current != end); + + if (P1P2 < 0 || P2P0 < 0) + errMsg("tube cutting failed, ill geometry"); + + P2P1 = m.corners(P1P2).opposite; + P0P2 = m.corners(P2P0).opposite; + + // duplicate vertices on the top half of the cut, + // and use them to split the tube at this seam + int P0b = m.addNode(Node(m.nodes(P0).pos)); + int P1b = m.addNode(Node(m.nodes(P1).pos)); + int P2b = m.addNode(Node(m.nodes(P2).pos)); + for (int i = 0; i < m.numNodeChannels(); i++) { + m.nodeChannel(i)->addInterpol(P0, P0, 0.5); + m.nodeChannel(i)->addInterpol(P1, P1, 0.5); + m.nodeChannel(i)->addInterpol(P2, P2, 0.5); + } + + // offset the verts in the normal directions to avoid self intersections + Vec3 offsetVec = cross(m.nodes(P1).pos - m.nodes(P0).pos, m.nodes(P2).pos - m.nodes(P0).pos); + normalize(offsetVec); + offsetVec *= 0.01; // HACK: + m.nodes(P0).pos -= offsetVec; + m.nodes(P1).pos -= offsetVec; + m.nodes(P2).pos -= offsetVec; + m.nodes(P0b).pos += offsetVec; + m.nodes(P1b).pos += offsetVec; + m.nodes(P2b).pos += offsetVec; + + // create a list of all triangles which touch P0, P1, and P2 from the top, + map<int, bool> topTris; + start = cb_old[0].next; + end = m.corners(P0P2).prev; + current = start; + topTris[start / 3] = true; + do { + // rotate around vertex P0 counter-clockwise + current = m.corners(m.corners(m.corners(current).next).opposite).next; + topTris[current / 3] = true; + } while (current != end); + start = m.corners(P0P2).next; + end = m.corners(P2P1).prev; + current = start; + topTris[start / 3] = true; + do { + // rotate around vertex P0 counter-clockwise + current = m.corners(m.corners(m.corners(current).next).opposite).next; + topTris[current / 3] = true; + } while (current != end); + start = m.corners(P2P1).next; + end = cb_old[0].prev; + current = start; + topTris[start / 3] = true; + do { + // rotate around vertex P0 counter-clockwise + current = m.corners(m.corners(m.corners(current).next).opposite).next; + topTris[current / 3] = true; + } while (current != end); + + // create two new triangles, + int Ta = m.addTri(Triangle(P0, P1, P2)); + int Tb = m.addTri(Triangle(P1b, P0b, P2b)); + for (int i = 0; i < m.numTriChannels(); i++) { + m.triChannel(i)->addNew(); + m.triChannel(i)->addNew(); + } + + // sew the tris to close the cut on each side + for (int c = 0; c < 3; c++) + m.addCorner(Corner(Ta, m.tris(Ta).c[c])); + for (int c = 0; c < 3; c++) + m.addCorner(Corner(Tb, m.tris(Tb).c[c])); + for (int c = 0; c < 3; c++) { + m.corners(Ta, c).next = 3 * Ta + ((c + 1) % 3); + m.corners(Ta, c).prev = 3 * Ta + ((c + 2) % 3); + m.corners(Tb, c).next = 3 * Tb + ((c + 1) % 3); + m.corners(Tb, c).prev = 3 * Tb + ((c + 2) % 3); + } + m.corners(Ta, 0).opposite = P1P2; + m.corners(Ta, 1).opposite = P2P0; + m.corners(Ta, 2).opposite = ca_old[1].prev; + m.corners(Tb, 0).opposite = P0P2; + m.corners(Tb, 1).opposite = P2P1; + m.corners(Tb, 2).opposite = cb_old[1].prev; + for (int c = 0; c < 3; c++) { + m.corners(m.corners(Ta, c).opposite).opposite = 3 * Ta + c; + m.corners(m.corners(Tb, c).opposite).opposite = 3 * Tb + c; + } + // replace P0,P1,P2 on the top with P0b,P1b,P2b. + for (map<int, bool>::iterator tti = topTris.begin(); tti != topTris.end(); tti++) { + // cout << "H " << tti->first << " : " << m.tris(tti->first).c[0] << " " << + // m.tris(tti->first).c[1] << " " << m.tris(tti->first).c[2] << " " << endl; + for (int i = 0; i < 3; i++) { + int cn = m.tris(tti->first).c[i]; + set<int> &ring = m.get1Ring(cn).nodes; + + if (ring.find(P0) != ring.end() && cn != P0 && cn != P1 && cn != P2 && cn != P0b && + cn != P1b && cn != P2b) { + ring.erase(P0); + ring.insert(P0b); + m.get1Ring(P0).nodes.erase(cn); + m.get1Ring(P0b).nodes.insert(cn); + } + if (ring.find(P1) != ring.end() && cn != P0 && cn != P1 && cn != P2 && cn != P0b && + cn != P1b && cn != P2b) { + ring.erase(P1); + ring.insert(P1b); + m.get1Ring(P1).nodes.erase(cn); + m.get1Ring(P1b).nodes.insert(cn); + } + if (ring.find(P2) != ring.end() && cn != P0 && cn != P1 && cn != P2 && cn != P0b && + cn != P1b && cn != P2b) { + ring.erase(P2); + ring.insert(P2b); + m.get1Ring(P2).nodes.erase(cn); + m.get1Ring(P2b).nodes.insert(cn); + } + if (cn == P0) { + m.tris(tti->first).c[i] = P0b; + m.corners(tti->first, i).node = P0b; + m.get1Ring(P0).tris.erase(tti->first); + m.get1Ring(P0b).tris.insert(tti->first); + } + else if (cn == P1) { + m.tris(tti->first).c[i] = P1b; + m.corners(tti->first, i).node = P1b; + m.get1Ring(P1).tris.erase(tti->first); + m.get1Ring(P1b).tris.insert(tti->first); + } + else if (cn == P2) { + m.tris(tti->first).c[i] = P2b; + m.corners(tti->first, i).node = P2b; + m.get1Ring(P2).tris.erase(tti->first); + m.get1Ring(P2b).tris.insert(tti->first); + } + } + } + + // m.sanityCheck(true, &deletedNodes, &taintedTris); + + return; + } + return; + } + if (ca_old[1].opposite >= 0 && ca_old[2].opposite >= 0 && cb_old[1].opposite >= 0 && + cb_old[2].opposite >= 0 && ca_old[0].opposite >= 0 && cb_old[0].opposite >= 0 && + ((m.corners(ca_old[1].opposite).node == + m.corners(ca_old[2].opposite).node && // two-pyramid tubey case (6 tris, 5 verts) + m.corners(cb_old[1].opposite).node == m.corners(cb_old[2].opposite).node && + (m.corners(ca_old[1].opposite).node == m.corners(cb_old[1].opposite).node || + (m.corners(ca_old[1].opposite).node == cb_old[0].node && // single tetrahedron case + m.corners(cb_old[1].opposite).node == ca_old[0].node))) || + (m.corners(ca_old[0].opposite).tri == m.corners(cb_old[0].opposite).tri && + m.corners(ca_old[1].opposite).tri == m.corners(cb_old[0].opposite).tri && + m.corners(ca_old[2].opposite).tri == + m.corners(cb_old[0].opposite).tri // nonmanifold: 2 tris, 3 verts + && m.corners(cb_old[0].opposite).tri == m.corners(ca_old[0].opposite).tri && + m.corners(cb_old[1].opposite).tri == m.corners(ca_old[0].opposite).tri && + m.corners(cb_old[2].opposite).tri == m.corners(ca_old[0].opposite).tri))) { + // both top and bottom are closed pyramid caps, or it is a single tet + // delete the whole component! + // flood fill to mark all triangles in the component + map<int, bool> markedTris; + queue<int> triQ; + triQ.push(trinum); + markedTris[trinum] = true; + int iters = 0; + while (!triQ.empty()) { + int trival = triQ.front(); + triQ.pop(); + for (int i = 0; i < 3; i++) { + int newtri = m.corners(m.corners(trival, i).opposite).tri; + if (markedTris.find(newtri) == markedTris.end()) { + triQ.push(newtri); + markedTris[newtri] = true; + } + } + iters++; + } + map<int, bool> markedverts; + for (map<int, bool>::iterator mit = markedTris.begin(); mit != markedTris.end(); mit++) { + taintedTris[mit->first] = true; + markedverts[m.tris(mit->first).c[0]] = true; + markedverts[m.tris(mit->first).c[1]] = true; + markedverts[m.tris(mit->first).c[2]] = true; + } + for (map<int, bool>::iterator mit = markedverts.begin(); mit != markedverts.end(); mit++) + deletedNodes.push_back(mit->first); + return; + } + + ////////////////////////// + // begin original edge collapse + + // update tri props of all adjacent triangles of P0,P1 (do before CT updates!) + // TODO: handleTriPropertyEdgeCollapse(trinum, P0,P1, ca_old[0], cb_old[0]); + + m.mergeNode(P0, P1); + + // Move position of P0 + m.nodes(P0).pos = endpoint + 0.5 * edgevect; + + // Preserve connectivity in both triangles + if (ca_old[1].opposite >= 0) + m.corners(ca_old[1].opposite).opposite = ca_old[2].opposite; + if (ca_old[2].opposite >= 0) + m.corners(ca_old[2].opposite).opposite = ca_old[1].opposite; + if (haveB && cb_old[1].opposite >= 0) + m.corners(cb_old[1].opposite).opposite = cb_old[2].opposite; + if (haveB && cb_old[2].opposite >= 0) + m.corners(cb_old[2].opposite).opposite = cb_old[1].opposite; + + //////////////////// + // mark the two triangles and the one node for deletion + taintedTris[ca_old[0].tri] = true; + m.removeTriFromLookup(ca_old[0].tri); + if (haveB) { + taintedTris[cb_old[0].tri] = true; + m.removeTriFromLookup(cb_old[0].tri); + } + deletedNodes.push_back(P1); + numCollapses++; +} + +} // namespace Manta |