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) void setRadius(float toRadius)
{ {
if (toRadius < 0.005f) if (toRadius < 0.001f)
toRadius = 0.005f; toRadius = 0.001f;
else if (toRadius > 1) else if (toRadius > 1)
toRadius = 1; toRadius = 1;
radius = toRadius; radius = toRadius;

View File

@ -203,6 +203,14 @@ public:
return *this; 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) inline Vector3 &operator*=(double number)
{ {
m_data[0] *= 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; std::vector<size_t> orderedIndices;
bool isCircle = false; bool isCircle = false;
flattenLinks(builderNodeLinks, &orderedIndices, &isCircle); bool isClosing = false;
std::vector<StitchMeshBuilder::Node> orderedBuilderNodes(orderedIndices.size()); std::vector<StitchMeshBuilder::Node> orderedBuilderNodes;
for (size_t i = 0; i < orderedIndices.size(); ++i) if (!builderNodeLinks.empty()) {
orderedBuilderNodes[i] = builderNodes[orderedIndices[i]]; flattenLinks(builderNodeLinks, &orderedIndices, &isCircle);
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 { splines.emplace_back(StitchMeshBuilder::Spline {
std::move(orderedBuilderNodes), std::move(orderedBuilderNodes),
isCircle isCircle,
isClosing
}); });
} }

View File

@ -20,6 +20,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <unordered_set>
#include <dust3d/base/debug.h> #include <dust3d/base/debug.h>
#include <dust3d/mesh/stitch_mesh_builder.h> #include <dust3d/mesh/stitch_mesh_builder.h>
@ -41,12 +42,13 @@ const std::vector<std::vector<size_t>> &StitchMeshBuilder::generatedFaces()
return m_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()); std::vector<Spline> interpolatedSplines = m_splines;
for (size_t i = 0; i < m_splines.size(); ++i) {
for (size_t i = 0; i < splines.size(); ++i) { const auto &spline = m_splines[i];
const auto &spline = splines[i]; if (spline.isClosing)
continue;
std::vector<Vector3> polyline(spline.nodes.size()); std::vector<Vector3> polyline(spline.nodes.size());
std::vector<double> radiuses(spline.nodes.size()); std::vector<double> radiuses(spline.nodes.size());
for (size_t j = 0; j < spline.nodes.size(); ++j) { 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<Vector3> segmentPoints;
std::vector<double> segmentRadiuses; std::vector<double> segmentRadiuses;
splitPolylineToSegments(polyline, radiuses, m_targetSegments, &segmentPoints, &segmentRadiuses); splitPolylineToSegments(polyline, radiuses, m_targetSegments, &segmentPoints, &segmentRadiuses);
stitchingPoints[i].resize(segmentPoints.size()); auto &interpolatedSpline = interpolatedSplines[i];
for (size_t k = 0; k < segmentPoints.size(); ++k) { 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].originVertex = m_generatedVertices.size();
stitchingPoints[i][k].radius = segmentRadiuses[k]; stitchingPoints[i][k].radius = spline.nodes[k].radius;
m_generatedVertices.push_back(segmentPoints[k]); m_generatedVertices.push_back(spline.nodes[k].origin);
m_generatedStitchingPoints.push_back(stitchingPoints[i][k]); 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() 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); std::vector<std::vector<StitchingPoint>> stitchingPoints = convertSplinesToStitchingPoints(m_splines);
generateMeshFromStitchingPoints(stitchingPoints); generateMeshFromStitchingPoints(stitchingPoints);
@ -179,29 +269,34 @@ void StitchMeshBuilder::build()
for (auto &it: m_generatedNormals) for (auto &it: m_generatedNormals)
it.normalize(); 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 // Generate other side of faces
auto oneSideVertexCount = m_generatedVertices.size(); auto oneSideVertexCount = m_generatedVertices.size();
m_generatedVertices.reserve(oneSideVertexCount * 2); m_generatedVertices.reserve(oneSideVertexCount * 2);
for (size_t i = 0; i < oneSideVertexCount; ++i) { 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); m_generatedFaces.reserve(m_generatedFaces.size() * 2);
auto oneSideFaceCount = m_generatedFaces.size(); auto oneSideFaceCount = m_generatedFaces.size();
for (size_t i = 0; i < oneSideFaceCount; ++i) { for (size_t i = 0; i < oneSideFaceCount; ++i) {
auto quad = m_generatedFaces[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> { m_generatedFaces.emplace_back(std::vector<size_t> {
oneSideVertexCount + quad[3],
oneSideVertexCount + quad[2], oneSideVertexCount + quad[2],
oneSideVertexCount + quad[1], 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 // Stitch layers for first stitching line
for (size_t j = 1; j <= m_targetSegments; ++j) { for (size_t j = 1; j <= m_targetSegments; ++j) {
size_t i = j - 1; size_t i = j - 1;
@ -215,14 +310,39 @@ void StitchMeshBuilder::build()
// Stitch layers for last stitching line // Stitch layers for last stitching line
size_t offsetBetweenFirstAndLastBorder = oneSideVertexCount - (m_targetSegments + 1); size_t offsetBetweenFirstAndLastBorder = oneSideVertexCount - (m_targetSegments + 1);
for (size_t j = 1; j <= m_targetSegments; ++j) { if (m_splines.back().isClosing) {
size_t i = j - 1; 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_generatedFaces.emplace_back(std::vector<size_t> {
oneSideVertexCount + j + offsetBetweenFirstAndLastBorder, (m_targetSegments - 0) + offsetBetweenFirstAndLastBorder,
j + offsetBetweenFirstAndLastBorder, 0 + offsetBetweenFirstAndLastBorder,
i + offsetBetweenFirstAndLastBorder, oneSideVertexCount + 0 + offsetBetweenFirstAndLastBorder,
oneSideVertexCount + i + 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> {
oneSideVertexCount + j + offsetBetweenFirstAndLastBorder,
j + offsetBetweenFirstAndLastBorder,
i + offsetBetweenFirstAndLastBorder,
oneSideVertexCount + i + offsetBetweenFirstAndLastBorder
});
}
} }
// Stitch layers for all head nodes of stitching lines // Stitch layers for all head nodes of stitching lines

View File

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