#include #include #include #include #include #include #include "fixholes.h" #include "util.h" void fixHoles(const std::vector &verticies, std::vector> &faces) { std::map, std::unordered_set> edgeToFaceSetMap; for (decltype(faces.size()) index = 0; index < faces.size(); ++index) { const auto &face = faces[index]; for (size_t i = 0; i < face.size(); i++) { size_t j = (i + 1) % face.size(); edgeToFaceSetMap[{face[i], face[j]}].insert(index); } } std::unordered_set invalidFaces; std::map, size_t> edgeToFaceMap; for (const auto &it: edgeToFaceSetMap) { if (1 == it.second.size()) { continue; } for (const auto &loopFaceIndex: it.second) { invalidFaces.insert(loopFaceIndex); } } for (const auto &it: edgeToFaceSetMap) { if (1 == it.second.size()) { size_t index = *it.second.begin(); if (invalidFaces.find(index) == invalidFaces.end()) { edgeToFaceMap.insert({it.first, index}); } } } std::unordered_set newInvalidFaces; for (size_t index = 0; index < faces.size(); ++index) { if (invalidFaces.find(index) != invalidFaces.end()) continue; const auto &face = faces[index]; size_t validNeighborNum = 0; for (size_t i = 0; i < face.size(); i++) { size_t j = (i + 1) % face.size(); auto findOppositeFaceResult = edgeToFaceMap.find({face[j], face[i]}); if (findOppositeFaceResult != edgeToFaceMap.end()) ++validNeighborNum; } if (validNeighborNum < face.size() - validNeighborNum) { invalidFaces.insert(index); newInvalidFaces.insert(index); continue; } } for (const auto &index: newInvalidFaces) { const auto &face = faces[index]; for (size_t i = 0; i < face.size(); i++) { size_t j = (i + 1) % face.size(); edgeToFaceMap.erase({face[i], face[j]}); } } std::map> holeVertexLink; std::vector startVertices; for (size_t index = 0; index < faces.size(); ++index) { if (invalidFaces.find(index) != invalidFaces.end()) continue; const auto &face = faces[index]; for (size_t i = 0; i < face.size(); i++) { size_t j = (i + 1) % face.size(); auto findOppositeFaceResult = edgeToFaceMap.find({face[j], face[i]}); if (findOppositeFaceResult != edgeToFaceMap.end()) continue; holeVertexLink[face[j]].push_back(face[i]); startVertices.push_back(face[j]); } } std::vector, double>> holeRings; auto findRing = [&](size_t startVertex) { while (true) { bool foundRing = false; std::vector ring; std::unordered_set visited; std::set> visitedPath; double ringLength = 0; while (!foundRing) { ring.clear(); visited.clear(); //ringLength = 0; auto first = startVertex; auto index = first; auto prev = first; ring.push_back(first); visited.insert(first); while (true) { auto findLinkResult = holeVertexLink.find(index); if (findLinkResult == holeVertexLink.end()) { //if (index != first) // qDebug() << "fixHoles Search ring failed, index:" << index << "first:" << first; return false; } for (const auto &item: findLinkResult->second) { if (item == first) { foundRing = true; break; } } if (foundRing) break; if (findLinkResult->second.size() > 1) { bool foundNewPath = false; for (const auto &item: findLinkResult->second) { if (visitedPath.find({prev, item}) == visitedPath.end()) { index = item; foundNewPath = true; break; } } if (!foundNewPath) { //qDebug() << "fixHoles No new path to try"; return false; } visitedPath.insert({prev, index}); } else { index = *findLinkResult->second.begin(); } if (visited.find(index) != visited.end()) { while (index != *ring.begin()) ring.erase(ring.begin()); foundRing = true; break; } ring.push_back(index); visited.insert(index); //ringLength += (verticies[index] - verticies[prev]).length(); prev = index; } } if (ring.size() < 3) { //qDebug() << "fixHoles Ring too short, size:" << ring.size(); return false; } holeRings.push_back({ring, ringLength}); for (size_t i = 0; i < ring.size(); ++i) { size_t j = (i + 1) % ring.size(); auto findLinkResult = holeVertexLink.find(ring[i]); for (auto it = findLinkResult->second.begin(); it != findLinkResult->second.end(); ++it) { if (*it == ring[j]) { findLinkResult->second.erase(it); if (findLinkResult->second.empty()) holeVertexLink.erase(ring[i]); break; } } } return true; } return false; }; for (const auto &startVertex: startVertices) findRing(startVertex); std::vector simpleuvVertices(verticies.size()); for (size_t i = 0; i < simpleuvVertices.size(); ++i) { const auto &src = verticies[i]; simpleuvVertices[i] = simpleuv::Vertex {{src.x(), src.y(), src.z()}}; } std::vector newFaces; for (size_t i = 0; i < holeRings.size(); ++i) { simpleuv::triangulate(simpleuvVertices, newFaces, holeRings[i].first); } //saveAsObj("fixholes_input.obj", verticies, faces); //std::vector> addedFaces; //std::vector> removedFaces; std::vector> fixedFaces; for (size_t i = 0; i < faces.size(); ++i) { if (invalidFaces.find(i) != invalidFaces.end()) { //removedFaces.push_back(faces[i]); continue; } fixedFaces.push_back(faces[i]); } //saveAsObj("fixholes_output_without_newfaces.obj", verticies, fixedFaces); for (const auto &it: newFaces) { fixedFaces.push_back(std::vector {it.indices[0], it.indices[1], it.indices[2]}); //addedFaces.push_back(std::vector {it.indices[0], it.indices[1], it.indices[2]}); } //saveAsObj("fixholes_output.obj", verticies, fixedFaces); //saveAsObj("fixholes_added.obj", verticies, addedFaces); //saveAsObj("fixholes_removed.obj", verticies, removedFaces); faces = fixedFaces; //qDebug() << "fixHoles holeRings:" << holeRings.size() << "newFaces:" << newFaces.size() << "removedFaces:" << removedFaces.size(); }