First almost working version of stitching line feature
parent
8f61fe168c
commit
7668818ab4
|
@ -375,34 +375,42 @@ 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) {
|
||||
auto findNext = links.find(current);
|
||||
if (findNext == links.end())
|
||||
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;
|
||||
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;
|
||||
}
|
||||
current = findNext->second;
|
||||
}
|
||||
break;
|
||||
std::reverse(array->begin(), array->end());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO:
|
||||
*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;
|
||||
current = findNext->second;
|
||||
if (current == startIndex)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue