diff --git a/dust3d/mesh/mesh_generator.cc b/dust3d/mesh/mesh_generator.cc index 6824fe07..9152af76 100644 --- a/dust3d/mesh/mesh_generator.cc +++ b/dust3d/mesh/mesh_generator.cc @@ -20,13 +20,13 @@ * SOFTWARE. */ -#include #include #include #include #include #include #include +#include #include #include #include @@ -375,6 +375,100 @@ void MeshGenerator::cutFaceStringToCutTemplate(const std::string &cutFaceString, } } +void MeshGenerator::convertLinksToOrdered(const std::unordered_map> &links, + std::vector *ordered, + bool *isCircle) +{ + for (const auto &it: links) { + if (1 == it.second.size()) { + std::unordered_set 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 MeshGenerator::combineStitchingMesh(const std::vector &partIdStrings) +{ + std::vector splines; + splines.reserve(partIdStrings.size()); + for (const auto &partIdString: partIdStrings) { + std::vector builderNodes; + std::map 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> 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 orderedIndices; + bool isCircle = false; + convertLinksToOrdered(builderNodeLinks, &orderedIndices, &isCircle); + std::vector 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(std::move(splines)); + stitchMeshBuilder->build(); + + return std::make_unique(stitchMeshBuilder->generatedVertices(), + stitchMeshBuilder->generatedFaces()); +} + std::unique_ptr 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 MeshGenerator::combineComponentMesh(const st std::vector>> combineGroups; int currentGroupIndex = -1; auto lastCombineMode = CombineMode::Count; + std::vector stitchingParts; + std::vector 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 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); } diff --git a/dust3d/mesh/mesh_generator.h b/dust3d/mesh/mesh_generator.h index 786f6a53..709a2dbb 100644 --- a/dust3d/mesh/mesh_generator.h +++ b/dust3d/mesh/mesh_generator.h @@ -24,6 +24,8 @@ #define DUST3D_MESH_MESH_GENERATOR_H_ #include +#include +#include #include #include #include @@ -146,6 +148,7 @@ private: std::unique_ptr combineComponentChildGroupMesh(const std::vector &componentIdStrings, GeneratedComponent &componentCache); std::unique_ptr combineMultipleMeshes(std::vector, CombineMode, std::string>> &&multipleMeshes, bool recombine=true); + std::unique_ptr combineStitchingMesh(const std::vector &partIdStrings); std::string componentColorName(const std::map *component); void collectUncombinedComponent(const std::string &componentIdString); void cutFaceStringToCutTemplate(const std::string &cutFaceString, std::vector &cutTemplate); @@ -157,6 +160,9 @@ private: static void chamferFace(std::vector *face); static bool isWatertight(const std::vector> &faces); + static void convertLinksToOrdered(const std::unordered_map> &links, + std::vector *ordered, + bool *isCircle); }; }