blender/extern/mantaflow/preprocessed/edgecollapse.cpp
Sebastián Barschkis 4ff7c5eed6 Mantaflow [Part 1]: Added preprocessed Mantaflow source files
Includes preprocessed Mantaflow source files for both OpenMP and TBB (if OpenMP is not present, TBB files will be used instead).

These files come directly from the Mantaflow repository. Future updates to the core fluid solver will take place by updating the files.

Reviewed By: sergey, mont29

Maniphest Tasks: T59995

Differential Revision: https://developer.blender.org/D3850
2019-12-16 16:27:26 +01:00

701 lines
26 KiB
C++

// 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