Changeset View
Changeset View
Standalone View
Standalone View
extern/quadriflow/src/parametrizer-flip.cpp
- This file was added.
| #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 | |||||