Implement stitching line back closing

master
Jeremy HU 2022-10-02 04:19:34 +11:00
parent 7668818ab4
commit 0be42e485b
5 changed files with 172 additions and 31 deletions

View File

@ -34,8 +34,8 @@ public:
}
void setRadius(float toRadius)
{
if (toRadius < 0.005f)
toRadius = 0.005f;
if (toRadius < 0.001f)
toRadius = 0.001f;
else if (toRadius > 1)
toRadius = 1;
radius = toRadius;

View File

@ -203,6 +203,14 @@ public:
return *this;
}
inline Vector3 &operator-=(const Vector3 &other)
{
m_data[0] -= other.x();
m_data[1] -= other.y();
m_data[2] -= other.z();
return *this;
}
inline Vector3 &operator*=(double number)
{
m_data[0] *= number;

View File

@ -460,13 +460,22 @@ std::unique_ptr<MeshCombiner::Mesh> MeshGenerator::combineStitchingMesh(const st
std::vector<size_t> orderedIndices;
bool isCircle = false;
bool isClosing = false;
std::vector<StitchMeshBuilder::Node> orderedBuilderNodes;
if (!builderNodeLinks.empty()) {
flattenLinks(builderNodeLinks, &orderedIndices, &isCircle);
std::vector<StitchMeshBuilder::Node> orderedBuilderNodes(orderedIndices.size());
orderedBuilderNodes.resize(orderedIndices.size());
for (size_t i = 0; i < orderedIndices.size(); ++i)
orderedBuilderNodes[i] = builderNodes[orderedIndices[i]];
} else {
orderedBuilderNodes.push_back(builderNodes[0]);
isClosing = true;
}
splines.emplace_back(StitchMeshBuilder::Spline {
std::move(orderedBuilderNodes),
isCircle
isCircle,
isClosing
});
}

View File

@ -20,6 +20,7 @@
* SOFTWARE.
*/
#include <unordered_set>
#include <dust3d/base/debug.h>
#include <dust3d/mesh/stitch_mesh_builder.h>
@ -41,12 +42,13 @@ const std::vector<std::vector<size_t>> &StitchMeshBuilder::generatedFaces()
return m_generatedFaces;
}
std::vector<std::vector<StitchMeshBuilder::StitchingPoint>> StitchMeshBuilder::convertSplinesToStitchingPoints(const std::vector<Spline> &splines)
void StitchMeshBuilder::interpolateSplinesToHaveEqualSizeOfNodesExceptClosingSplines()
{
std::vector<std::vector<StitchingPoint>> stitchingPoints(splines.size());
for (size_t i = 0; i < splines.size(); ++i) {
const auto &spline = splines[i];
std::vector<Spline> interpolatedSplines = m_splines;
for (size_t i = 0; i < m_splines.size(); ++i) {
const auto &spline = m_splines[i];
if (spline.isClosing)
continue;
std::vector<Vector3> polyline(spline.nodes.size());
std::vector<double> radiuses(spline.nodes.size());
for (size_t j = 0; j < spline.nodes.size(); ++j) {
@ -56,11 +58,27 @@ std::vector<std::vector<StitchMeshBuilder::StitchingPoint>> StitchMeshBuilder::c
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) {
auto &interpolatedSpline = interpolatedSplines[i];
interpolatedSpline.nodes.resize(segmentPoints.size());
for (size_t j = 0; j < spline.nodes.size(); ++j) {
interpolatedSpline.nodes[j].origin = segmentPoints[j];
interpolatedSpline.nodes[j].radius = segmentRadiuses[j];
}
}
m_splines = std::move(interpolatedSplines);
}
std::vector<std::vector<StitchMeshBuilder::StitchingPoint>> StitchMeshBuilder::convertSplinesToStitchingPoints(const std::vector<Spline> &splines)
{
std::vector<std::vector<StitchingPoint>> stitchingPoints(splines.size());
for (size_t i = 0; i < splines.size(); ++i) {
const auto &spline = splines[i];
stitchingPoints[i].resize(spline.nodes.size());
for (size_t k = 0; k < spline.nodes.size(); ++k) {
stitchingPoints[i][k].originVertex = m_generatedVertices.size();
stitchingPoints[i][k].radius = segmentRadiuses[k];
m_generatedVertices.push_back(segmentPoints[k]);
stitchingPoints[i][k].radius = spline.nodes[k].radius;
m_generatedVertices.push_back(spline.nodes[k].origin);
m_generatedStitchingPoints.push_back(stitchingPoints[i][k]);
}
}
@ -159,8 +177,80 @@ void StitchMeshBuilder::generateMeshFromStitchingPoints(const std::vector<Stitch
}
}
void StitchMeshBuilder::interpolateSplinesForBackClosing()
{
if (m_splines.size() < 2) {
dust3dDebug << "Expected at least two splines for back closing interpoloating, current:" << m_splines.size();
return;
}
Vector3 sourceOrigin;
Vector3 targetPosition = m_splines.back().nodes.front().origin;
const auto &nodes = m_splines[m_splines.size() - 2].nodes;
std::vector<Vector3> sourcePositions(nodes.size());
for (size_t i = 0; i < nodes.size(); ++i) {
sourcePositions[i] = nodes[i].origin;
sourceOrigin += sourcePositions[i];
}
sourceOrigin /= nodes.size();
Vector3 targetDirection = (targetPosition - sourceOrigin).normalized();
std::vector<Vector3> sourceVectors(nodes.size());
for (size_t i = 0; i < nodes.size(); ++i) {
sourceVectors[i] = (nodes[i].origin - sourceOrigin).normalized();
}
std::vector<Vector3> interpolatedPositions(nodes.size());
std::vector<double> interpolatedRadiuses(nodes.size());
for (size_t i = 0; i < nodes.size(); ++i) {
interpolatedPositions[i] = sourceOrigin +
sourceVectors[i].rotated(Vector3::crossProduct(sourceVectors[i], targetDirection), Math::Pi * 0.25) *
((nodes[i].origin - sourceOrigin).length() + (nodes[i].origin - targetPosition).length() * 0.5) * 0.5;
interpolatedRadiuses[i] = nodes[i].radius * 0.5;
}
m_splines.back().nodes.resize(nodes.size());
for (size_t i = 0; i < nodes.size(); ++i) {
m_splines.back().nodes[i].origin = interpolatedPositions[i];
m_splines.back().nodes[i].radius = interpolatedRadiuses[i];
}
}
void StitchMeshBuilder::addQuadButMaybeTriangle(const std::vector<size_t> &quadButMaybeTriangle)
{
std::vector<size_t> finalFace;
std::unordered_set<size_t> used;
finalFace.reserve(4);
for (const auto &it: quadButMaybeTriangle) {
auto insertResult = used.insert(it);
if (insertResult.second)
finalFace.push_back(it);
}
m_generatedFaces.emplace_back(finalFace);
}
void StitchMeshBuilder::build()
{
if (m_splines.empty())
return;
// Calculate target segments
m_targetSegments = 1;
for (const auto &it: m_splines) {
m_targetSegments = std::max(m_targetSegments, it.nodes.size() - 1);
}
// TODO: Make sure there is no closing nodes in the middle
// Interpolate splines to make sure every spline have equal size of nodes, except the closing splines
interpolateSplinesToHaveEqualSizeOfNodesExceptClosingSplines();
// Preprocess back closing
if (m_splines.back().isClosing)
interpolateSplinesForBackClosing();
// TODO: Preprocess front closing
// Update to the real interploated segments
m_targetSegments = m_splines.back().nodes.size() - 1;
// Generate one side faces
std::vector<std::vector<StitchingPoint>> stitchingPoints = convertSplinesToStitchingPoints(m_splines);
generateMeshFromStitchingPoints(stitchingPoints);
@ -179,29 +269,34 @@ void StitchMeshBuilder::build()
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_generatedVertices.emplace_back(m_generatedVertices[i]);
}
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];
// The following quad vertices should follow the order of 2,1,0,3 strictly,
// This is to allow 2,1,0 to be grouped as triangle in the later quad to triangles processing.
// If not follow this order, the front triangle and back triangle maybe cross over because of not be parallel.
m_generatedFaces.emplace_back(std::vector<size_t> {
oneSideVertexCount + quad[3],
oneSideVertexCount + quad[2],
oneSideVertexCount + quad[1],
oneSideVertexCount + quad[0]
oneSideVertexCount + quad[0],
oneSideVertexCount + quad[3]
});
}
// Move all vertices off distance at radius
for (size_t i = 0; i < oneSideVertexCount; ++i) {
auto moveDistance = m_generatedNormals[i] * m_generatedStitchingPoints[i].radius;
m_generatedVertices[i] += moveDistance;
m_generatedVertices[i + oneSideVertexCount] -= moveDistance;
}
// Stitch layers for first stitching line
for (size_t j = 1; j <= m_targetSegments; ++j) {
size_t i = j - 1;
@ -215,6 +310,30 @@ void StitchMeshBuilder::build()
// Stitch layers for last stitching line
size_t offsetBetweenFirstAndLastBorder = oneSideVertexCount - (m_targetSegments + 1);
if (m_splines.back().isClosing) {
size_t half = m_targetSegments / 2;
for (size_t j = 1; j <= half; ++j) {
size_t i = j - 1;
addQuadButMaybeTriangle(std::vector<size_t> {
oneSideVertexCount + j + offsetBetweenFirstAndLastBorder,
oneSideVertexCount + i + offsetBetweenFirstAndLastBorder,
oneSideVertexCount + (m_targetSegments - i) + offsetBetweenFirstAndLastBorder,
oneSideVertexCount + (m_targetSegments - j) + offsetBetweenFirstAndLastBorder
});
addQuadButMaybeTriangle(std::vector<size_t> {
(m_targetSegments - j) + offsetBetweenFirstAndLastBorder,
(m_targetSegments - i) + offsetBetweenFirstAndLastBorder,
i + offsetBetweenFirstAndLastBorder,
j + offsetBetweenFirstAndLastBorder
});
}
m_generatedFaces.emplace_back(std::vector<size_t> {
(m_targetSegments - 0) + offsetBetweenFirstAndLastBorder,
0 + offsetBetweenFirstAndLastBorder,
oneSideVertexCount + 0 + offsetBetweenFirstAndLastBorder,
oneSideVertexCount + (m_targetSegments - 0) + offsetBetweenFirstAndLastBorder
});
} else {
for (size_t j = 1; j <= m_targetSegments; ++j) {
size_t i = j - 1;
m_generatedFaces.emplace_back(std::vector<size_t> {
@ -224,6 +343,7 @@ void StitchMeshBuilder::build()
oneSideVertexCount + i + offsetBetweenFirstAndLastBorder
});
}
}
// Stitch layers for all head nodes of stitching lines
for (size_t j = 1; j < m_splines.size(); ++j) {

View File

@ -41,6 +41,7 @@ public:
{
std::vector<Node> nodes;
bool isCircle = false;
bool isClosing = false;
};
StitchMeshBuilder(std::vector<Spline> &&splines);
@ -60,8 +61,9 @@ private:
std::vector<Vector3> m_generatedVertices;
std::vector<std::vector<size_t>> m_generatedFaces;
std::vector<Vector3> m_generatedNormals;
size_t m_targetSegments = 5;
size_t m_targetSegments = 15;
void interpolateSplinesToHaveEqualSizeOfNodesExceptClosingSplines();
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,
@ -72,6 +74,8 @@ private:
std::vector<Vector3> *targetPoints,
std::vector<double> *targetRadiuses);
double segmentsLength(const std::vector<Vector3> &segmentPoints);
void interpolateSplinesForBackClosing();
void addQuadButMaybeTriangle(const std::vector<size_t> &quadButMaybeTriangle);
};
}