Builds a mesh with multiple connected components (here, a 3x3 grid torn down its center line), extracts each component as an independent mesh, runs ABF++ + LSCM on each, packs the flattened charts into a shared coordinate frame with OpenABF::PackCharts, and writes the packed atlas to a single .obj file.
Charts are flattened defensively: not every chart topology is solvable, so a chart that throws OpenABF::SolverException is reported and skipped rather than aborting the atlas.
The original mesh is never modified — the extracted sub-meshes own their own vertices and per-edge state, and each is parameterized in isolation before being placed into the common frame.
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include "OpenABF/OpenABF.hpp"
int main()
{
auto mesh = Mesh::New();
mesh->insert_vertices({
{0.f, 0.f, 0.f},
{1.f, 0.f, 0.f},
{2.f, 0.f, 0.f},
{0.f, 1.f, 0.f},
{1.f, 1.f, 0.f},
{2.f, 1.f, 0.f},
{0.f, 2.f, 0.f},
{1.f, 2.f, 0.f},
{2.f, 2.f, 0.f},
});
mesh->insert_faces({
{0, 3, 1},
{1, 3, 4},
{1, 4, 2},
{2, 4, 5},
{3, 6, 4},
{4, 6, 7},
{4, 7, 5},
{5, 7, 8},
});
std::cout << "Before split: " << mesh->num_connected_components() << " component(s)\n";
mesh->split_path({1, 4, 7});
std::cout << "After split: " << mesh->num_connected_components() << " component(s)\n";
auto charts = mesh->extract_connected_components();
std::cout << "Extracted " << charts.size() << " chart(s)\n";
std::vector<Mesh::Pointer> chartMeshes;
for (std::size_t i = 0; i < charts.size(); ++i) {
auto& cc = charts[i];
std::size_t iters{0};
try {
std::cout << "Chart " << i << ": " << cc.mesh->num_vertices() << " vertices, "
<< cc.mesh->num_faces() << " faces, " << iters << " ABF++ iters\n";
chartMeshes.push_back(cc.mesh);
std::cout << "Chart " << i << ": skipped, could not be flattened (" << e.what()
<< ")\n";
}
}
if (chartMeshes.empty()) {
std::cerr << "No chart could be flattened; no atlas written\n";
return EXIT_FAILURE;
}
std::cout << "Packed atlas extent: [" << extent.min[0] << ", " << extent.min[1] << "] -> ["
<< extent.max[0] << ", " << extent.max[1] << "]\n";
const std::string out = "openabf_example_multi_chart_packed.obj";
std::cout << "Wrote packed atlas: " << merged.mesh->num_vertices() << " vertices, "
<< merged.mesh->num_faces() << " faces -> " << out << "\n";
std::cout << "Source mesh 3D positions intact: " << mesh->num_vertices() << " vertices, "
<< mesh->num_faces() << " faces\n";
}
Compute parameterized interior angles using ABF++.
Definition OpenABF.hpp:2830
static void Compute(typename Mesh::Pointer &mesh, std::size_t &iters, T &gradient, const std::size_t maxIters=10, T gradThreshold=T(0.001))
Compute parameterized interior angles.
Definition OpenABF.hpp:2882
MeshType Mesh
Mesh type alias.
Definition OpenABF.hpp:2833
Compute parameterized mesh using Angle-based LSCM.
Definition OpenABF.hpp:3499
static void Compute(typename Mesh::Pointer &mesh)
Compute the parameterized mesh using automatic pin selection.
Definition OpenABF.hpp:3562
Solver exception.
Definition OpenABF.hpp:33
void WriteMesh(const std::filesystem::path &path, const MeshPtr &mesh)
Write a HalfEdgeMesh to a file.
Definition OpenABF.hpp:6083
constexpr T INF
Inf, templated for floating-point type.
Definition OpenABF.hpp:69
Options controlling PackCharts behavior.
Definition OpenABF.hpp:5082
bool normalize
Fit the packed atlas into the unit square [0,1]^2
Definition OpenABF.hpp:5105
T padding
Gutter added around every chart, in chart/absolute units.
Definition OpenABF.hpp:5126