Implement stitch mesh builder

master
Jeremy HU 2022-10-01 18:38:07 +10:00
parent 8b64425341
commit 8f61fe168c
2 changed files with 121 additions and 1 deletions

View File

@ -20,13 +20,13 @@
* SOFTWARE.
*/
#include <unordered_set>
#include <functional>
#include <dust3d/base/string.h>
#include <dust3d/base/part_target.h>
#include <dust3d/base/part_base.h>
#include <dust3d/base/snapshot_xml.h>
#include <dust3d/base/cut_face.h>
#include <dust3d/mesh/stitch_mesh_builder.h>
#include <dust3d/mesh/stroke_mesh_builder.h>
#include <dust3d/mesh/stroke_modifier.h>
#include <dust3d/mesh/mesh_recombiner.h>
@ -375,6 +375,100 @@ void MeshGenerator::cutFaceStringToCutTemplate(const std::string &cutFaceString,
}
}
void MeshGenerator::convertLinksToOrdered(const std::unordered_map<size_t, std::unordered_set<size_t>> &links,
std::vector<size_t> *ordered,
bool *isCircle)
{
for (const auto &it: links) {
if (1 == it.second.size()) {
std::unordered_set<size_t> used;
size_t current = it.first;
bool foundNext = true;
while (foundNext) {
auto findNext = links.find(current);
if (findNext == links.end())
break;
used.insert(current);
ordered->push_back(current);
foundNext = false;
for (const auto &it: findNext->second) {
if (used.end() != used.find(it))
continue;
current = it;
foundNext = true;
break;
}
}
break;
}
}
// TODO:
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const std::vector<std::string> &partIdStrings)
{
std::vector<StitchMeshBuilder::Spline> splines;
splines.reserve(partIdStrings.size());
for (const auto &partIdString: partIdStrings) {
std::vector<StitchMeshBuilder::Node> builderNodes;
std::map<std::string, size_t> builderNodeIdStringToIndexMap;
for (const auto &nodeIdString: m_partNodeIds[partIdString]) {
auto findNode = m_snapshot->nodes.find(nodeIdString);
if (findNode == m_snapshot->nodes.end()) {
continue;
}
auto &node = findNode->second;
float radius = String::toFloat(String::valueOrEmpty(node, "radius"));
float x = (String::toFloat(String::valueOrEmpty(node, "x")) - m_mainProfileMiddleX);
float y = (m_mainProfileMiddleY - String::toFloat(String::valueOrEmpty(node, "y")));
float z = (m_sideProfileMiddleX - String::toFloat(String::valueOrEmpty(node, "z")));
builderNodeIdStringToIndexMap.insert({nodeIdString, builderNodes.size()});
builderNodes.emplace_back(StitchMeshBuilder::Node {
Vector3((double)x, (double)y, (double)z), (double)radius
});
}
std::unordered_map<size_t, std::unordered_set<size_t>> builderNodeLinks;
for (const auto &edgeIdString: m_partEdgeIds[partIdString]) {
auto findEdge = m_snapshot->edges.find(edgeIdString);
if (findEdge == m_snapshot->edges.end()) {
continue;
}
auto &edge = findEdge->second;
std::string fromNodeIdString = String::valueOrEmpty(edge, "from");
std::string toNodeIdString = String::valueOrEmpty(edge, "to");
auto findFrom = builderNodeIdStringToIndexMap.find(fromNodeIdString);
if (findFrom == builderNodeIdStringToIndexMap.end())
continue;
auto findTo = builderNodeIdStringToIndexMap.find(toNodeIdString);
if (findTo == builderNodeIdStringToIndexMap.end())
continue;
builderNodeLinks[findFrom->second].insert(findTo->second);
}
std::vector<size_t> orderedIndices;
bool isCircle = false;
convertLinksToOrdered(builderNodeLinks, &orderedIndices, &isCircle);
std::vector<StitchMeshBuilder::Node> orderedBuilderNodes(orderedIndices.size());
for (size_t i = 0; i < orderedIndices.size(); ++i)
orderedBuilderNodes[i] = builderNodes[orderedIndices[i]];
splines.emplace_back(StitchMeshBuilder::Spline {
std::move(orderedBuilderNodes),
isCircle
});
}
auto stitchMeshBuilder = std::make_unique<StitchMeshBuilder>(std::move(splines));
stitchMeshBuilder->build();
return std::make_unique<MeshCombiner::Mesh>(stitchMeshBuilder->generatedVertices(),
stitchMeshBuilder->generatedFaces());
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combinePartMesh(const std::string &partIdString, bool *hasError, bool *retryable, bool addIntermediateNodes)
{
auto findPart = m_snapshot->parts.find(partIdString);
@ -872,10 +966,25 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const st
std::vector<std::pair<CombineMode, std::vector<std::string>>> combineGroups;
int currentGroupIndex = -1;
auto lastCombineMode = CombineMode::Count;
std::vector<std::string> stitchingParts;
std::vector<std::string> stitchingComponents;
for (const auto &childIdString: String::split(String::valueOrEmpty(*component, "children"), ',')) {
if (childIdString.empty())
continue;
const auto &child = findComponent(childIdString);
if (nullptr == child)
continue;
if ("partId" == String::valueOrEmpty(*child, "linkDataType")) {
auto partIdString = String::valueOrEmpty(*child, "linkData");
auto findPart = m_snapshot->parts.find(partIdString);
if (findPart != m_snapshot->parts.end()) {
if ("StitchingLine" == String::valueOrEmpty(findPart->second, "target")) {
stitchingParts.emplace_back(partIdString);
stitchingComponents.emplace_back(childIdString);
continue;
}
}
}
auto combineMode = componentCombineMode(child);
if (lastCombineMode != combineMode || lastCombineMode == CombineMode::Inversion) {
combineGroups.push_back({combineMode, {}});
@ -894,6 +1003,11 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const st
continue;
groupMeshes.emplace_back(std::make_tuple(std::move(childMesh), group.first, String::join(group.second, "|")));
}
if (!stitchingParts.empty()) {
auto stitchingMesh = combineStitchingMesh(stitchingParts);
if (stitchingMesh && !stitchingMesh->isNull())
groupMeshes.emplace_back(std::make_tuple(std::move(stitchingMesh), CombineMode::Normal, String::join(stitchingComponents, ":")));
}
mesh = combineMultipleMeshes(std::move(groupMeshes), true);
}

View File

@ -24,6 +24,8 @@
#define DUST3D_MESH_MESH_GENERATOR_H_
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <dust3d/base/position_key.h>
#include <dust3d/base/uuid.h>
@ -146,6 +148,7 @@ private:
std::unique_ptr<MeshCombiner::Mesh> combineComponentChildGroupMesh(const std::vector<std::string> &componentIdStrings,
GeneratedComponent &componentCache);
std::unique_ptr<MeshCombiner::Mesh> combineMultipleMeshes(std::vector<std::tuple<std::unique_ptr<MeshCombiner::Mesh>, CombineMode, std::string>> &&multipleMeshes, bool recombine=true);
std::unique_ptr<MeshCombiner::Mesh> combineStitchingMesh(const std::vector<std::string> &partIdStrings);
std::string componentColorName(const std::map<std::string, std::string> *component);
void collectUncombinedComponent(const std::string &componentIdString);
void cutFaceStringToCutTemplate(const std::string &cutFaceString, std::vector<Vector2> &cutTemplate);
@ -157,6 +160,9 @@ private:
static void chamferFace(std::vector<Vector2> *face);
static bool isWatertight(const std::vector<std::vector<size_t>> &faces);
static void convertLinksToOrdered(const std::unordered_map<size_t, std::unordered_set<size_t>> &links,
std::vector<size_t> *ordered,
bool *isCircle);
};
}