584 lines
22 KiB
C++
584 lines
22 KiB
C++
#include "dedge.hpp"
|
|
#include "parametrizer.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <queue>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace qflow {
|
|
|
|
double Parametrizer::QuadEnergy(std::vector<int>& loop_vertices, std::vector<Vector4i>& res_quads,
|
|
int level) {
|
|
if (loop_vertices.size() < 4) return 0;
|
|
if (loop_vertices.size() == 4) {
|
|
double energy = 0;
|
|
for (int j = 0; j < 4; ++j) {
|
|
int v0 = loop_vertices[j];
|
|
int v2 = loop_vertices[(j + 1) % 4];
|
|
int v1 = loop_vertices[(j + 3) % 4];
|
|
Vector3d pt1 = (O_compact[v1] - O_compact[v0]).normalized();
|
|
Vector3d pt2 = (O_compact[v2] - O_compact[v0]).normalized();
|
|
Vector3d n = pt1.cross(pt2);
|
|
double sina = n.norm();
|
|
if (n.dot(N_compact[v0]) < 0) sina = -sina;
|
|
double cosa = pt1.dot(pt2);
|
|
double angle = atan2(sina, cosa) / 3.141592654 * 180.0;
|
|
if (angle < 0) angle = 360 + angle;
|
|
energy += angle * angle;
|
|
}
|
|
res_quads.push_back(
|
|
Vector4i(loop_vertices[0], loop_vertices[3], loop_vertices[2], loop_vertices[1]));
|
|
return energy;
|
|
}
|
|
double max_energy = 1e30;
|
|
for (int seg1 = 2; seg1 < loop_vertices.size(); seg1 += 2) {
|
|
for (int seg2 = seg1 + 1; seg2 < loop_vertices.size(); seg2 += 2) {
|
|
std::vector<Vector4i> quads[4];
|
|
std::vector<int> vertices = {loop_vertices[0], loop_vertices[1], loop_vertices[seg1],
|
|
loop_vertices[seg2]};
|
|
double energy = 0;
|
|
energy += QuadEnergy(vertices, quads[0], level + 1);
|
|
if (seg1 > 2) {
|
|
std::vector<int> vertices(loop_vertices.begin() + 1, loop_vertices.begin() + seg1);
|
|
vertices.push_back(loop_vertices[seg1]);
|
|
energy += QuadEnergy(vertices, quads[1], level + 1);
|
|
}
|
|
if (seg2 != seg1 + 1) {
|
|
std::vector<int> vertices(loop_vertices.begin() + seg1,
|
|
loop_vertices.begin() + seg2);
|
|
vertices.push_back(loop_vertices[seg2]);
|
|
energy += QuadEnergy(vertices, quads[2], level + 2);
|
|
}
|
|
if (seg2 + 1 != loop_vertices.size()) {
|
|
std::vector<int> vertices(loop_vertices.begin() + seg2, loop_vertices.end());
|
|
vertices.push_back(loop_vertices[0]);
|
|
energy += QuadEnergy(vertices, quads[3], level + 1);
|
|
}
|
|
if (max_energy > energy) {
|
|
max_energy = energy;
|
|
res_quads.clear();
|
|
for (int i = 0; i < 4; ++i) {
|
|
for (auto& v : quads[i]) {
|
|
res_quads.push_back(v);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return max_energy;
|
|
}
|
|
|
|
void Parametrizer::FixHoles(std::vector<int>& loop_vertices) {
|
|
std::vector<std::vector<int>> loop_vertices_array;
|
|
std::unordered_map<int, int> map_loops;
|
|
for (int i = 0; i < loop_vertices.size(); ++i) {
|
|
if (map_loops.count(loop_vertices[i])) {
|
|
int j = map_loops[loop_vertices[i]];
|
|
loop_vertices_array.push_back(std::vector<int>());
|
|
if (i - j > 3 && (i - j) % 2 == 0) {
|
|
for (int k = j; k < i; ++k) {
|
|
if (map_loops.count(loop_vertices[k])) {
|
|
loop_vertices_array.back().push_back(loop_vertices[k]);
|
|
map_loops.erase(loop_vertices[k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
map_loops[loop_vertices[i]] = i;
|
|
}
|
|
if (map_loops.size() >= 3) {
|
|
loop_vertices_array.push_back(std::vector<int>());
|
|
for (int k = 0; k < loop_vertices.size(); ++k) {
|
|
if (map_loops.count(loop_vertices[k])) {
|
|
if (map_loops.count(loop_vertices[k])) {
|
|
loop_vertices_array.back().push_back(loop_vertices[k]);
|
|
map_loops.erase(loop_vertices[k]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < loop_vertices_array.size(); ++i) {
|
|
auto& loop_vertices = loop_vertices_array[i];
|
|
if (loop_vertices.size() == 0) return;
|
|
std::vector<Vector4i> quads;
|
|
#ifdef LOG_OUTPUT
|
|
// printf("Compute energy for loop: %d\n", (int)loop_vertices.size());
|
|
#endif
|
|
QuadEnergy(loop_vertices, quads, 0);
|
|
#ifdef LOG_OUTPUT
|
|
// printf("quads: %d\n", quads.size());
|
|
#endif
|
|
for (auto& p : quads) {
|
|
bool flag = false;
|
|
for (int j = 0; j < 4; ++j) {
|
|
int v1 = p[j];
|
|
int v2 = p[(j + 1) % 4];
|
|
auto key = std::make_pair(v1, v2);
|
|
if (Quad_edges.count(key)) {
|
|
flag = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!flag) {
|
|
for (int j = 0; j < 4; ++j) {
|
|
int v1 = p[j];
|
|
int v2 = p[(j + 1) % 4];
|
|
auto key = std::make_pair(v1, v2);
|
|
Quad_edges.insert(key);
|
|
}
|
|
F_compact.push_back(p);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Parametrizer::FixHoles() {
|
|
for (int i = 0; i < F_compact.size(); ++i) {
|
|
for (int j = 0; j < 4; ++j) {
|
|
int v1 = F_compact[i][j];
|
|
int v2 = F_compact[i][(j + 1) % 4];
|
|
auto key = std::make_pair(v1, v2);
|
|
Quad_edges.insert(key);
|
|
}
|
|
}
|
|
std::vector<int> detected_boundary(E2E_compact.size(), 0);
|
|
for (int i = 0; i < E2E_compact.size(); ++i) {
|
|
if (detected_boundary[i] != 0 || E2E_compact[i] != -1) continue;
|
|
std::vector<int> loop_edges;
|
|
int current_e = i;
|
|
|
|
while (detected_boundary[current_e] == 0) {
|
|
detected_boundary[current_e] = 1;
|
|
loop_edges.push_back(current_e);
|
|
current_e = current_e / 4 * 4 + (current_e + 1) % 4;
|
|
while (E2E_compact[current_e] != -1) {
|
|
current_e = E2E_compact[current_e];
|
|
current_e = current_e / 4 * 4 + (current_e + 1) % 4;
|
|
}
|
|
}
|
|
std::vector<int> loop_vertices(loop_edges.size());
|
|
for (int j = 0; j < loop_edges.size(); ++j) {
|
|
loop_vertices[j] = F_compact[loop_edges[j] / 4][loop_edges[j] % 4];
|
|
}
|
|
if (loop_vertices.size() < 25) FixHoles(loop_vertices);
|
|
}
|
|
}
|
|
|
|
void Parametrizer::FixFlipHierarchy() {
|
|
Hierarchy fh;
|
|
fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1);
|
|
fh.FixFlip();
|
|
fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff);
|
|
}
|
|
|
|
void Parametrizer::FixFlipSat() {
|
|
#ifdef LOG_OUTPUT
|
|
printf("Solving SAT!\n");
|
|
#endif
|
|
|
|
if (!this->flag_aggresive_sat) return;
|
|
|
|
for (int threshold = 1; threshold <= 4; ++threshold) {
|
|
lprintf("[FixFlipSat] threshold = %d\n", threshold);
|
|
|
|
Hierarchy fh;
|
|
fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1);
|
|
int nflip = 0;
|
|
for (int depth = std::min(5, (int)fh.mFQ.size() - 1); depth >= 0; --depth) {
|
|
nflip = fh.FixFlipSat(depth, threshold);
|
|
if (depth > 0) fh.PushDownwardFlip(depth);
|
|
if (nflip == 0) break;
|
|
}
|
|
fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff);
|
|
if (nflip == 0) break;
|
|
}
|
|
}
|
|
|
|
void Parametrizer::AdvancedExtractQuad() {
|
|
Hierarchy fh;
|
|
fh.DownsampleEdgeGraph(face_edgeOrients, face_edgeIds, edge_diff, allow_changes, -1);
|
|
auto& V = hierarchy.mV[0];
|
|
auto& F = hierarchy.mF;
|
|
disajoint_tree = DisajointTree(V.cols());
|
|
auto& diffs = fh.mEdgeDiff.front();
|
|
for (int i = 0; i < diffs.size(); ++i) {
|
|
if (diffs[i] == Vector2i::Zero()) {
|
|
disajoint_tree.Merge(edge_values[i].x, edge_values[i].y);
|
|
}
|
|
}
|
|
disajoint_tree.BuildCompactParent();
|
|
auto& F2E = fh.mF2E.back();
|
|
auto& E2F = fh.mE2F.back();
|
|
auto& EdgeDiff = fh.mEdgeDiff.back();
|
|
auto& FQ = fh.mFQ.back();
|
|
|
|
std::vector<int> edge(E2F.size());
|
|
std::vector<int> face(F2E.size());
|
|
for (int i = 0; i < diffs.size(); ++i) {
|
|
int t = i;
|
|
for (int j = 0; j < fh.mToUpperEdges.size(); ++j) {
|
|
t = fh.mToUpperEdges[j][t];
|
|
if (t < 0) break;
|
|
}
|
|
if (t >= 0) edge[t] = i;
|
|
}
|
|
for (int i = 0; i < F.cols(); ++i) {
|
|
int t = i;
|
|
for (int j = 0; j < fh.mToUpperFaces.size(); ++j) {
|
|
t = fh.mToUpperFaces[j][t];
|
|
if (t < 0) break;
|
|
}
|
|
if (t >= 0) face[t] = i;
|
|
}
|
|
fh.UpdateGraphValue(face_edgeOrients, face_edgeIds, edge_diff);
|
|
|
|
auto& O = hierarchy.mO[0];
|
|
auto& Q = hierarchy.mQ[0];
|
|
auto& N = hierarchy.mN[0];
|
|
int num_v = disajoint_tree.CompactNum();
|
|
Vset.resize(num_v);
|
|
O_compact.resize(num_v, Vector3d::Zero());
|
|
Q_compact.resize(num_v, Vector3d::Zero());
|
|
N_compact.resize(num_v, Vector3d::Zero());
|
|
counter.resize(num_v, 0);
|
|
for (int i = 0; i < O.cols(); ++i) {
|
|
int compact_v = disajoint_tree.Index(i);
|
|
Vset[compact_v].push_back(i);
|
|
O_compact[compact_v] += O.col(i);
|
|
N_compact[compact_v] = N_compact[compact_v] * counter[compact_v] + N.col(i);
|
|
N_compact[compact_v].normalize();
|
|
if (counter[compact_v] == 0)
|
|
Q_compact[compact_v] = Q.col(i);
|
|
else {
|
|
auto pairs = compat_orientation_extrinsic_4(Q_compact[compact_v], N_compact[compact_v],
|
|
Q.col(i), N.col(i));
|
|
Q_compact[compact_v] = (pairs.first * counter[compact_v] + pairs.second).normalized();
|
|
}
|
|
counter[compact_v] += 1;
|
|
}
|
|
for (int i = 0; i < O_compact.size(); ++i) {
|
|
O_compact[i] /= counter[i];
|
|
}
|
|
|
|
BuildTriangleManifold(disajoint_tree, edge, face, edge_values, F2E, E2F, EdgeDiff, FQ);
|
|
}
|
|
|
|
void Parametrizer::BuildTriangleManifold(DisajointTree& disajoint_tree, std::vector<int>& edge,
|
|
std::vector<int>& face, std::vector<DEdge>& edge_values,
|
|
std::vector<Vector3i>& F2E, std::vector<Vector2i>& E2F,
|
|
std::vector<Vector2i>& EdgeDiff,
|
|
std::vector<Vector3i>& FQ) {
|
|
auto& F = hierarchy.mF;
|
|
std::vector<int> E2E(F2E.size() * 3, -1);
|
|
for (int i = 0; i < E2F.size(); ++i) {
|
|
int v1 = E2F[i][0];
|
|
int v2 = E2F[i][1];
|
|
int t1 = 0;
|
|
int t2 = 2;
|
|
if (v1 != -1)
|
|
while (F2E[v1][t1] != i) t1 += 1;
|
|
if (v2 != -1)
|
|
while (F2E[v2][t2] != i) t2 -= 1;
|
|
t1 += v1 * 3;
|
|
t2 += v2 * 3;
|
|
if (v1 != -1)
|
|
E2E[t1] = (v2 == -1) ? -1 : t2;
|
|
if (v2 != -1)
|
|
E2E[t2] = (v1 == -1) ? -1 : t1;
|
|
}
|
|
|
|
std::vector<Vector3i> triangle_vertices(F2E.size(), Vector3i(-1, -1, -1));
|
|
int num_v = 0;
|
|
std::vector<Vector3d> N, Q, O;
|
|
std::vector<std::vector<int>> Vs;
|
|
for (int i = 0; i < F2E.size(); ++i) {
|
|
for (int j = 0; j < 3; ++j) {
|
|
if (triangle_vertices[i][j] != -1) continue;
|
|
int f = face[i];
|
|
int v = disajoint_tree.Index(F(j, f));
|
|
Vs.push_back(Vset[v]);
|
|
Q.push_back(Q_compact[v]);
|
|
N.push_back(N_compact[v]);
|
|
O.push_back(O_compact[v]);
|
|
int deid0 = i * 3 + j;
|
|
int deid = deid0;
|
|
do {
|
|
triangle_vertices[deid / 3][deid % 3] = num_v;
|
|
deid = E2E[deid / 3 * 3 + (deid + 2) % 3];
|
|
} while (deid != deid0 && deid != -1);
|
|
if (deid == -1) {
|
|
deid = deid0;
|
|
do {
|
|
deid = E2E[deid];
|
|
if (deid == -1)
|
|
break;
|
|
deid = deid / 3 * 3 + (deid + 1) % 3;
|
|
triangle_vertices[deid/3][deid%3] = num_v;
|
|
} while (deid != -1);
|
|
}
|
|
num_v += 1;
|
|
}
|
|
}
|
|
|
|
int num_v0 = num_v;
|
|
do {
|
|
num_v0 = num_v;
|
|
std::vector<std::vector<int>> vert_to_dedge(num_v);
|
|
for (int i = 0; i < triangle_vertices.size(); ++i) {
|
|
Vector3i pt = triangle_vertices[i];
|
|
if (pt[0] == pt[1] || pt[1] == pt[2] || pt[2] == pt[0]) {
|
|
for (int j = 0; j < 3; ++j) {
|
|
int t = E2E[i * 3 + j];
|
|
if (t != -1) E2E[t] = -1;
|
|
}
|
|
for (int j = 0; j < 3; ++j) {
|
|
E2E[i * 3 + j] = -1;
|
|
}
|
|
} else {
|
|
for (int j = 0; j < 3; ++j)
|
|
vert_to_dedge[triangle_vertices[i][j]].push_back(i * 3 + j);
|
|
}
|
|
}
|
|
std::vector<int> colors(triangle_vertices.size() * 3, -1),
|
|
reverse_colors(triangle_vertices.size() * 3, -1);
|
|
for (int i = 0; i < vert_to_dedge.size(); ++i) {
|
|
int num_color = 0;
|
|
for (int j = 0; j < vert_to_dedge[i].size(); ++j) {
|
|
int deid = vert_to_dedge[i][j];
|
|
if (colors[deid] != -1) continue;
|
|
std::list<int> l;
|
|
int deid0 = deid;
|
|
do {
|
|
l.push_back(deid);
|
|
deid = deid / 3 * 3 + (deid + 2) % 3;
|
|
deid = E2E[deid];
|
|
} while (deid != -1 && deid != deid0);
|
|
if (deid == -1) {
|
|
deid = deid0;
|
|
do {
|
|
deid = E2E[deid];
|
|
if (deid == -1) break;
|
|
deid = deid / 3 * 3 + (deid + 1) % 3;
|
|
if (deid == deid0) break;
|
|
l.push_front(deid);
|
|
} while (true);
|
|
}
|
|
std::vector<int> dedges;
|
|
for (auto& e : l) dedges.push_back(e);
|
|
std::map<std::pair<int, int>, int> loc;
|
|
std::vector<int> deid_colors(dedges.size(), num_color);
|
|
num_color += 1;
|
|
for (int jj = 0; jj < dedges.size(); ++jj) {
|
|
int deid = dedges[jj];
|
|
colors[deid] = 0;
|
|
int v1 = triangle_vertices[deid / 3][deid % 3];
|
|
int v2 = triangle_vertices[deid / 3][(deid + 1) % 3];
|
|
std::pair<int, int> pt(v1, v2);
|
|
if (loc.count(pt)) {
|
|
int s = loc[pt];
|
|
for (int k = s; k < jj; ++k) {
|
|
int deid1 = dedges[k];
|
|
int v11 = triangle_vertices[deid1 / 3][deid1 % 3];
|
|
int v12 = triangle_vertices[deid1 / 3][(deid1 + 1) % 3];
|
|
std::pair<int, int> pt1(v11, v12);
|
|
loc.erase(pt1);
|
|
deid_colors[k] = num_color;
|
|
}
|
|
num_color += 1;
|
|
}
|
|
loc[pt] = jj;
|
|
}
|
|
for (int j = 0; j < dedges.size(); ++j) {
|
|
int deid = dedges[j];
|
|
int color = deid_colors[j];
|
|
if (color > 0) {
|
|
triangle_vertices[deid / 3][deid % 3] = num_v + color - 1;
|
|
}
|
|
}
|
|
}
|
|
if (num_color > 1) {
|
|
for (int j = 0; j < num_color - 1; ++j) {
|
|
Vs.push_back(Vs[i]);
|
|
O.push_back(O[i]);
|
|
N.push_back(N[i]);
|
|
Q.push_back(Q[i]);
|
|
}
|
|
num_v += num_color - 1;
|
|
}
|
|
}
|
|
} while (num_v != num_v0);
|
|
int offset = 0;
|
|
std::vector<Vector3i> triangle_edges, triangle_orients;
|
|
for (int i = 0; i < triangle_vertices.size(); ++i) {
|
|
Vector3i pt = triangle_vertices[i];
|
|
if (pt[0] == pt[1] || pt[1] == pt[2] || pt[2] == pt[0]) continue;
|
|
triangle_vertices[offset++] = triangle_vertices[i];
|
|
triangle_edges.push_back(F2E[i]);
|
|
triangle_orients.push_back(FQ[i]);
|
|
}
|
|
triangle_vertices.resize(offset);
|
|
std::set<int> flip_vertices;
|
|
for (int i = 0; i < triangle_vertices.size(); ++i) {
|
|
Vector2i d1 = rshift90(EdgeDiff[triangle_edges[i][0]], triangle_orients[i][0]);
|
|
Vector2i d2 = rshift90(EdgeDiff[triangle_edges[i][1]], triangle_orients[i][1]);
|
|
int area = d1[0] * d2[1] - d1[1] * d2[0];
|
|
if (area < 0) {
|
|
for (int j = 0; j < 3; ++j) {
|
|
flip_vertices.insert(triangle_vertices[i][j]);
|
|
}
|
|
}
|
|
}
|
|
MatrixXd NV(3, num_v);
|
|
MatrixXi NF(3, triangle_vertices.size());
|
|
memcpy(NF.data(), triangle_vertices.data(), sizeof(int) * 3 * triangle_vertices.size());
|
|
VectorXi NV2E, NE2E, NB, NN;
|
|
compute_direct_graph(NV, NF, NV2E, NE2E, NB, NN);
|
|
|
|
std::map<DEdge, std::pair<Vector3i, Vector3i>> quads;
|
|
for (int i = 0; i < triangle_vertices.size(); ++i) {
|
|
for (int j = 0; j < 3; ++j) {
|
|
int e = triangle_edges[i][j];
|
|
int v1 = triangle_vertices[i][j];
|
|
int v2 = triangle_vertices[i][(j + 1) % 3];
|
|
int v3 = triangle_vertices[i][(j + 2) % 3];
|
|
if (abs(EdgeDiff[e][0]) == 1 && abs(EdgeDiff[e][1]) == 1) {
|
|
DEdge edge(v1, v2);
|
|
if (quads.count(edge))
|
|
quads[edge].second = Vector3i(v1, v2, v3);
|
|
else
|
|
quads[edge] = std::make_pair(Vector3i(v1, v2, v3), Vector3i(-1, -1, -1));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto& p : quads) {
|
|
if (p.second.second[0] != -1 && p.second.first[2] != p.second.second[2]) {
|
|
F_compact.push_back(Vector4i(p.second.first[1], p.second.first[2], p.second.first[0],
|
|
p.second.second[2]));
|
|
}
|
|
}
|
|
std::swap(Vs, Vset);
|
|
std::swap(O_compact, O);
|
|
std::swap(N_compact, N);
|
|
std::swap(Q_compact, Q);
|
|
compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
|
|
nonManifold_compact);
|
|
|
|
while (true) {
|
|
std::vector<int> erasedF(F_compact.size(), 0);
|
|
for (int i = 0; i < F_compact.size(); ++i) {
|
|
for (int j = 0; j < 3; ++j) {
|
|
for (int k = j + 1; k < 4; ++k) {
|
|
if (F_compact[i][j] == F_compact[i][k]) {
|
|
erasedF[i] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < O_compact.size(); ++i) {
|
|
int v = 0;
|
|
int e0 = V2E_compact[i];
|
|
if (e0 == -1) continue;
|
|
std::vector<int> dedges;
|
|
int e = e0;
|
|
do {
|
|
dedges.push_back(e);
|
|
v += 1;
|
|
e = e / 4 * 4 + (e + 3) % 4;
|
|
e = E2E_compact[e];
|
|
} while (e != e0 && e != -1);
|
|
if (e == -1) {
|
|
int e = e0;
|
|
while (true) {
|
|
e = E2E_compact[e];
|
|
if (e == -1) break;
|
|
e = e / 4 * 4 + (e + 1) % 4;
|
|
v += 1;
|
|
dedges.push_back(e);
|
|
}
|
|
}
|
|
if (v == 2) {
|
|
// erasedF[dedges[1] / 4] = 1;
|
|
// F_compact[dedges[0]/4][dedges[0]%4] =
|
|
// F_compact[dedges[1]/4][(dedges[1]+2)%4];
|
|
}
|
|
}
|
|
offset = 0;
|
|
for (int i = 0; i < F_compact.size(); ++i) {
|
|
if (erasedF[i] == 0) F_compact[offset++] = F_compact[i];
|
|
}
|
|
if (offset == F_compact.size()) break;
|
|
F_compact.resize(offset);
|
|
compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
|
|
nonManifold_compact);
|
|
}
|
|
FixHoles();
|
|
compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
|
|
nonManifold_compact);
|
|
|
|
/*
|
|
for (auto& p : flip_vertices) {
|
|
int deid0 = V2E_compact[p];
|
|
int deid = deid0;
|
|
std::list<int> dedges;
|
|
if (deid0 != -1) {
|
|
do {
|
|
dedges.push_back(deid);
|
|
deid = E2E_compact[deid/4*4 + (deid+3) % 4];
|
|
} while (deid != -1 && deid != deid0);
|
|
if (deid == -1) {
|
|
deid = deid0;
|
|
do {
|
|
deid = E2E_compact[deid];
|
|
if (deid == -1)
|
|
break;
|
|
deid = deid/4*4 + (deid +1) % 4;
|
|
dedges.push_front(deid);
|
|
} while (deid != -1 && deid != deid0);
|
|
}
|
|
std::set<int> eraseF;
|
|
std::set<int> valid_dedges;
|
|
std::set<int> boundaries;
|
|
std::vector<int> loop_vertices;
|
|
for (auto& dedge : dedges) {
|
|
int f = dedge / 4;
|
|
eraseF.insert(f);
|
|
valid_dedges.insert(E2E_compact[f * 4 + (dedge+1)%4]);
|
|
valid_dedges.insert(E2E_compact[f * 4 + (dedge+2)%4]);
|
|
loop_vertices.push_back(F_compact[f][(dedge+1)%4]);
|
|
loop_vertices.push_back(F_compact[f][(dedge+2)%4]);
|
|
boundaries.insert(F_compact[f][(dedge+1)%4]);
|
|
boundaries.insert(F_compact[f][(dedge+2)%4]);
|
|
}
|
|
int offset = 0;
|
|
auto it = eraseF.begin();
|
|
for (int i = 0; i < F_compact.size(); ++i) {
|
|
if (it == eraseF.end() || i != *it) {
|
|
bool need_erase = false;
|
|
for (int j = 0; j < 4; ++j) {
|
|
if (valid_dedges.count(i * 4 + j) == 0 && boundaries.count(F_compact[i][j])
|
|
&& boundaries.count(F_compact[i][(j + 1) % 4])) { need_erase = true;
|
|
}
|
|
}
|
|
if (!need_erase)
|
|
F_compact[offset++] = F_compact[i];
|
|
} else {
|
|
it++;
|
|
}
|
|
}
|
|
F_compact.resize(offset);
|
|
compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact,
|
|
boundary_compact, nonManifold_compact); std::reverse(loop_vertices.begin(),
|
|
loop_vertices.end()); FixHoles(loop_vertices); compute_direct_graph_quad(O_compact, F_compact,
|
|
V2E_compact, E2E_compact, boundary_compact, nonManifold_compact);
|
|
}
|
|
}
|
|
FixHoles();
|
|
compute_direct_graph_quad(O_compact, F_compact, V2E_compact, E2E_compact, boundary_compact,
|
|
nonManifold_compact);
|
|
*/
|
|
}
|
|
|
|
} // namespace qflow
|