First almost working version of stitching line feature

master
Jeremy HU 2022-10-01 21:20:03 +10:00
parent 8f61fe168c
commit 7668818ab4
4 changed files with 167 additions and 46 deletions

View File

@ -375,35 +375,43 @@ 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,
void MeshGenerator::flattenLinks(const std::unordered_map<size_t, size_t> &links,
std::vector<size_t> *array,
bool *isCircle)
{
if (links.empty())
return;
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) {
if (links.end() == links.find(it.second)) {
*isCircle = false;
std::unordered_map<size_t, size_t> reversedLinks;
for (const auto &it: links)
reversedLinks.insert({it.second, it.first});
size_t current = it.second;
for (;;) {
array->push_back(current);
auto findNext = reversedLinks.find(current);
if (findNext == reversedLinks.end())
break;
current = findNext->second;
}
std::reverse(array->begin(), array->end());
return;
}
}
*isCircle = true;
size_t startIndex = links.begin()->first;
size_t current = startIndex;
for (;;) {
array->push_back(current);
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;
current = findNext->second;
if (current == startIndex)
break;
}
}
break;
}
}
// TODO:
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const std::vector<std::string> &partIdStrings)
{
@ -430,7 +438,7 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const st
});
}
std::unordered_map<size_t, std::unordered_set<size_t>> builderNodeLinks;
std::unordered_map<size_t, size_t> builderNodeLinks;
for (const auto &edgeIdString: m_partEdgeIds[partIdString]) {
auto findEdge = m_snapshot->edges.find(edgeIdString);
if (findEdge == m_snapshot->edges.end()) {
@ -447,12 +455,12 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const st
auto findTo = builderNodeIdStringToIndexMap.find(toNodeIdString);
if (findTo == builderNodeIdStringToIndexMap.end())
continue;
builderNodeLinks[findFrom->second].insert(findTo->second);
builderNodeLinks[findFrom->second] = findTo->second;
}
std::vector<size_t> orderedIndices;
bool isCircle = false;
convertLinksToOrdered(builderNodeLinks, &orderedIndices, &isCircle);
flattenLinks(builderNodeLinks, &orderedIndices, &isCircle);
std::vector<StitchMeshBuilder::Node> orderedBuilderNodes(orderedIndices.size());
for (size_t i = 0; i < orderedIndices.size(); ++i)
orderedBuilderNodes[i] = builderNodes[orderedIndices[i]];
@ -465,8 +473,12 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const st
auto stitchMeshBuilder = std::make_unique<StitchMeshBuilder>(std::move(splines));
stitchMeshBuilder->build();
return std::make_unique<MeshCombiner::Mesh>(stitchMeshBuilder->generatedVertices(),
auto mesh = std::make_unique<MeshCombiner::Mesh>(stitchMeshBuilder->generatedVertices(),
stitchMeshBuilder->generatedFaces());
if (mesh && mesh->isNull())
mesh.reset();
return mesh;
}
std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combinePartMesh(const std::string &partIdString, bool *hasError, bool *retryable, bool addIntermediateNodes)

View File

@ -160,8 +160,8 @@ 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,
static void flattenLinks(const std::unordered_map<size_t, size_t> &links,
std::vector<size_t> *array,
bool *isCircle);
};

View File

@ -45,18 +45,23 @@ std::vector<std::vector<StitchMeshBuilder::StitchingPoint>> StitchMeshBuilder::c
{
std::vector<std::vector<StitchingPoint>> stitchingPoints(splines.size());
size_t targetSegments = 5; // FIXME: decide target segments by ...
for (size_t i = 0; i < splines.size(); ++i) {
const auto &spline = splines[i];
std::vector<Vector3> polyline(spline.nodes.size());
for (size_t j = 0; j < spline.nodes.size(); ++j)
std::vector<double> radiuses(spline.nodes.size());
for (size_t j = 0; j < spline.nodes.size(); ++j) {
polyline[j] = spline.nodes[j].origin;
auto segmentPoints = splitPolylineToSegments(polyline, targetSegments);
radiuses[j] = spline.nodes[j].radius;
}
std::vector<Vector3> segmentPoints;
std::vector<double> segmentRadiuses;
splitPolylineToSegments(polyline, radiuses, m_targetSegments, &segmentPoints, &segmentRadiuses);
stitchingPoints[i].resize(segmentPoints.size());
for (size_t k = 0; k < segmentPoints.size(); ++k) {
stitchingPoints[i][k].originVertex = m_generatedVertices.size();
// TODO: stitchingPoints[i][k].radius = ...
m_generatedVertices.emplace_back(segmentPoints[k]);
stitchingPoints[i][k].radius = segmentRadiuses[k];
m_generatedVertices.push_back(segmentPoints[k]);
m_generatedStitchingPoints.push_back(stitchingPoints[i][k]);
}
}
@ -73,45 +78,55 @@ double StitchMeshBuilder::segmentsLength(const std::vector<Vector3> &segmentPoin
return totalLength;
}
std::vector<Vector3> StitchMeshBuilder::splitPolylineToSegments(const std::vector<Vector3> &polyline,
size_t targetSegments)
void StitchMeshBuilder::splitPolylineToSegments(const std::vector<Vector3> &polyline,
const std::vector<double> &radiuses,
size_t targetSegments,
std::vector<Vector3> *targetPoints,
std::vector<double> *targetRadiuses)
{
std::vector<Vector3> segmentPoints;
if (polyline.size() < 2)
return segmentPoints;
return;
double totalLength = segmentsLength(polyline);
if (Math::isZero(totalLength)) {
Vector3 middle = (polyline.front() + polyline.back()) * 0.5;
double radius = (radiuses.front() + radiuses.back()) * 0.5;
for (size_t i = 0; i < targetSegments + 1; ++i) {
segmentPoints.push_back(middle);
targetPoints->push_back(middle);
targetRadiuses->push_back(radius);
}
return segmentPoints;
return;
}
double segmentLength = totalLength / targetSegments;
double wantLength = segmentLength;
segmentPoints.push_back(polyline.front());
targetPoints->push_back(polyline.front());
targetRadiuses->push_back(radiuses.front());
for (size_t j = 1; j < polyline.size(); ++j) {
size_t i = j - 1;
double lineLength = (polyline[j] - polyline[i]).length();
Vector3 polylineStart = polyline[i];
double radiusStart = radiuses[i];
while (true) {
if (lineLength < wantLength) {
wantLength -= lineLength;
break;
}
Vector3 newPosition = (polylineStart * (lineLength - wantLength) + polyline[j] * wantLength) / lineLength;
segmentPoints.push_back(newPosition);
double newRadius = (radiusStart * (lineLength - wantLength) + radiuses[j] * wantLength) / lineLength;
targetPoints->push_back(newPosition);
targetRadiuses->push_back(newRadius);
lineLength -= wantLength;
polylineStart = newPosition;
radiusStart = newRadius;
wantLength = segmentLength;
}
}
if (segmentPoints.size() < targetSegments + 1) {
segmentPoints.push_back(polyline.back());
if (targetPoints->size() < targetSegments + 1) {
targetPoints->push_back(polyline.back());
targetRadiuses->push_back(radiuses.back());
} else {
segmentPoints.back() = polyline.back();
targetPoints->back() = polyline.back();
targetRadiuses->back() = radiuses.back();
}
return segmentPoints;
}
void StitchMeshBuilder::generateMeshFromStitchingPoints(const std::vector<std::vector<StitchMeshBuilder::StitchingPoint>> &stitchingPoints)
@ -148,6 +163,94 @@ void StitchMeshBuilder::build()
{
std::vector<std::vector<StitchingPoint>> stitchingPoints = convertSplinesToStitchingPoints(m_splines);
generateMeshFromStitchingPoints(stitchingPoints);
// Generate normals for all vertices
m_generatedNormals.resize(m_generatedVertices.size());
for (const auto &quad: m_generatedFaces) {
for (size_t i = 0; i < 4; ++i) {
size_t j = (i + 1) % 4;
size_t k = (j + 1) % 4;
auto faceNormal = Vector3::normal(m_generatedVertices[quad[i]], m_generatedVertices[quad[j]], m_generatedVertices[quad[k]]);
m_generatedNormals[quad[i]] += faceNormal;
m_generatedNormals[quad[j]] += faceNormal;
m_generatedNormals[quad[k]] += faceNormal;
}
}
for (auto &it: m_generatedNormals)
it.normalize();
// Move all vertices off distance at radius
for (size_t i = 0; i < m_generatedVertices.size(); ++i) {
m_generatedVertices[i] += m_generatedNormals[i] * m_generatedStitchingPoints[i].radius;
}
// Generate other side of faces
auto oneSideVertexCount = m_generatedVertices.size();
m_generatedVertices.reserve(oneSideVertexCount * 2);
for (size_t i = 0; i < oneSideVertexCount; ++i) {
m_generatedVertices.emplace_back(m_generatedVertices[i] - m_generatedNormals[i] * m_generatedStitchingPoints[i].radius * 2.0);
}
m_generatedFaces.reserve(m_generatedFaces.size() * 2);
auto oneSideFaceCount = m_generatedFaces.size();
for (size_t i = 0; i < oneSideFaceCount; ++i) {
auto quad = m_generatedFaces[i];
m_generatedFaces.emplace_back(std::vector<size_t> {
oneSideVertexCount + quad[3],
oneSideVertexCount + quad[2],
oneSideVertexCount + quad[1],
oneSideVertexCount + quad[0]
});
}
// Stitch layers for first stitching line
for (size_t j = 1; j <= m_targetSegments; ++j) {
size_t i = j - 1;
m_generatedFaces.emplace_back(std::vector<size_t> {
oneSideVertexCount + i,
i,
j,
oneSideVertexCount + j
});
}
// Stitch layers for last stitching line
size_t offsetBetweenFirstAndLastBorder = oneSideVertexCount - (m_targetSegments + 1);
for (size_t j = 1; j <= m_targetSegments; ++j) {
size_t i = j - 1;
m_generatedFaces.emplace_back(std::vector<size_t> {
oneSideVertexCount + j + offsetBetweenFirstAndLastBorder,
j + offsetBetweenFirstAndLastBorder,
i + offsetBetweenFirstAndLastBorder,
oneSideVertexCount + i + offsetBetweenFirstAndLastBorder
});
}
// Stitch layers for all head nodes of stitching lines
for (size_t j = 1; j < m_splines.size(); ++j) {
size_t i = j - 1;
m_generatedFaces.emplace_back(std::vector<size_t> {
oneSideVertexCount + j * (m_targetSegments + 1),
j * (m_targetSegments + 1),
i * (m_targetSegments + 1),
oneSideVertexCount + i * (m_targetSegments + 1)
});
}
// Stitch layers for all tail nodes of stitching lines
size_t offsetBetweenSecondAndThirdBorder = m_targetSegments;
for (size_t j = 1; j < m_splines.size(); ++j) {
size_t i = j - 1;
m_generatedFaces.emplace_back(std::vector<size_t> {
oneSideVertexCount + i * (m_targetSegments + 1) + offsetBetweenSecondAndThirdBorder,
i * (m_targetSegments + 1) + offsetBetweenSecondAndThirdBorder,
j * (m_targetSegments + 1) + offsetBetweenSecondAndThirdBorder,
oneSideVertexCount + j * (m_targetSegments + 1) + offsetBetweenSecondAndThirdBorder
});
}
// TODO: Process circle
// TODO: Process interpolate
}
}

View File

@ -56,15 +56,21 @@ private:
};
std::vector<Spline> m_splines;
std::vector<StitchingPoint> m_generatedStitchingPoints;
std::vector<Vector3> m_generatedVertices;
std::vector<std::vector<size_t>> m_generatedFaces;
std::vector<Vector3> m_generatedNormals;
size_t m_targetSegments = 5;
std::vector<std::vector<StitchingPoint>> convertSplinesToStitchingPoints(const std::vector<Spline> &splines);
void generateMeshFromStitchingPoints(const std::vector<std::vector<StitchingPoint>> &stitchingPoints);
void generateMeshFromStitchingPoints(const std::vector<StitchingPoint> &a,
const std::vector<StitchingPoint> &b);
std::vector<Vector3> splitPolylineToSegments(const std::vector<Vector3> &polyline,
size_t targetSegments);
void splitPolylineToSegments(const std::vector<Vector3> &polyline,
const std::vector<double> &radiuses,
size_t targetSegments,
std::vector<Vector3> *targetPoints,
std::vector<double> *targetRadiuses);
double segmentsLength(const std::vector<Vector3> &segmentPoints);
};