Implement stitch mesh builder
parent
8b64425341
commit
8f61fe168c
|
@ -20,13 +20,13 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <unordered_set>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <dust3d/base/string.h>
|
#include <dust3d/base/string.h>
|
||||||
#include <dust3d/base/part_target.h>
|
#include <dust3d/base/part_target.h>
|
||||||
#include <dust3d/base/part_base.h>
|
#include <dust3d/base/part_base.h>
|
||||||
#include <dust3d/base/snapshot_xml.h>
|
#include <dust3d/base/snapshot_xml.h>
|
||||||
#include <dust3d/base/cut_face.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_mesh_builder.h>
|
||||||
#include <dust3d/mesh/stroke_modifier.h>
|
#include <dust3d/mesh/stroke_modifier.h>
|
||||||
#include <dust3d/mesh/mesh_recombiner.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)
|
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combinePartMesh(const std::string &partIdString, bool *hasError, bool *retryable, bool addIntermediateNodes)
|
||||||
{
|
{
|
||||||
auto findPart = m_snapshot->parts.find(partIdString);
|
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;
|
std::vector<std::pair<CombineMode, std::vector<std::string>>> combineGroups;
|
||||||
int currentGroupIndex = -1;
|
int currentGroupIndex = -1;
|
||||||
auto lastCombineMode = CombineMode::Count;
|
auto lastCombineMode = CombineMode::Count;
|
||||||
|
std::vector<std::string> stitchingParts;
|
||||||
|
std::vector<std::string> stitchingComponents;
|
||||||
for (const auto &childIdString: String::split(String::valueOrEmpty(*component, "children"), ',')) {
|
for (const auto &childIdString: String::split(String::valueOrEmpty(*component, "children"), ',')) {
|
||||||
if (childIdString.empty())
|
if (childIdString.empty())
|
||||||
continue;
|
continue;
|
||||||
const auto &child = findComponent(childIdString);
|
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);
|
auto combineMode = componentCombineMode(child);
|
||||||
if (lastCombineMode != combineMode || lastCombineMode == CombineMode::Inversion) {
|
if (lastCombineMode != combineMode || lastCombineMode == CombineMode::Inversion) {
|
||||||
combineGroups.push_back({combineMode, {}});
|
combineGroups.push_back({combineMode, {}});
|
||||||
|
@ -894,6 +1003,11 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineComponentMesh(const st
|
||||||
continue;
|
continue;
|
||||||
groupMeshes.emplace_back(std::make_tuple(std::move(childMesh), group.first, String::join(group.second, "|")));
|
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);
|
mesh = combineMultipleMeshes(std::move(groupMeshes), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#define DUST3D_MESH_MESH_GENERATOR_H_
|
#define DUST3D_MESH_MESH_GENERATOR_H_
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <dust3d/base/position_key.h>
|
#include <dust3d/base/position_key.h>
|
||||||
#include <dust3d/base/uuid.h>
|
#include <dust3d/base/uuid.h>
|
||||||
|
@ -146,6 +148,7 @@ private:
|
||||||
std::unique_ptr<MeshCombiner::Mesh> combineComponentChildGroupMesh(const std::vector<std::string> &componentIdStrings,
|
std::unique_ptr<MeshCombiner::Mesh> combineComponentChildGroupMesh(const std::vector<std::string> &componentIdStrings,
|
||||||
GeneratedComponent &componentCache);
|
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> 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);
|
std::string componentColorName(const std::map<std::string, std::string> *component);
|
||||||
void collectUncombinedComponent(const std::string &componentIdString);
|
void collectUncombinedComponent(const std::string &componentIdString);
|
||||||
void cutFaceStringToCutTemplate(const std::string &cutFaceString, std::vector<Vector2> &cutTemplate);
|
void cutFaceStringToCutTemplate(const std::string &cutFaceString, std::vector<Vector2> &cutTemplate);
|
||||||
|
@ -157,6 +160,9 @@ private:
|
||||||
|
|
||||||
static void chamferFace(std::vector<Vector2> *face);
|
static void chamferFace(std::vector<Vector2> *face);
|
||||||
static bool isWatertight(const std::vector<std::vector<size_t>> &faces);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue