Half-edge based internal structures

Using Solidean with half-edge based data structures that require manifold outputs.

If your internal pipeline is half-edge based and requires strictly manifold meshes, you can directly export Solidean results in a half-edge representation. Solidean guarantees manifoldness at export time if you request it, even when inputs have ambiguous or degenerate structures.

This guide shows how to:

  • Import two cubes that touch along a shared edge
  • Perform a Boolean union
  • Export the result as a half-edge mesh with the Manifold flag

Code

// Assumed to exist:
//   solidean::Context* ctx;
//   solidean::ExactArithmetic* arithmetic;

// Two unit cubes that share a single edge:
// centers at (-0.5, 0, -0.5) and (0.5, 0, 0.5); scale = 1.0
auto cubeA = example::createCube({-0.5f, 0.0f, -0.5f}, 1.0f);
auto cubeB = example::createCube({ 0.5f, 0.0f,  0.5f}, 1.0f);

// Boolean union → export as explicit half-edge with manifold guarantee
auto blob = ctx->execute(*arithmetic, [&](solidean::Operation& op)
{
    auto mA = op.importFromTrianglesF32(solidean::as_triangle3_span(cubeA));
    auto mB = op.importFromTrianglesF32(solidean::as_triangle3_span(cubeB));

    auto mU = op.union_(mA, mB);

    auto opts = solidean::ExportOption::VertexPositionF32
              | solidean::ExportOption::Manifold
              | solidean::ExportOption::HalfedgeToVertex
              | solidean::ExportOption::HalfedgeToNextHalfedge
              | solidean::ExportOption::HalfedgeToOppositeHalfedge
              | solidean::ExportOption::HalfedgeToFace;

    return op.exportMesh(mU, solidean::ExportFormat::HalfedgeExplicit, opts);
});

// Read back half-edge topology and positions (names may vary in your SDK; adapt as needed)
auto posSpan = blob->getPositionsF32<example::pos3>();
std::vector<example::pos3> positions(posSpan.begin(), posSpan.end());

// Half-edge relations (int32 indices)
auto he2vSpan = blob->getHalfedgeToVertex();
auto he2nSpan = blob->getHalfedgeToNextHalfedge();
auto he2oSpan = blob->getHalfedgeToOppositeHalfedge();
auto he2fSpan = blob->getHalfedgeToFace();

auto he_to_vertex = std::vector<int32_t>(he2vSpan.begin(), he2vSpan.end());
auto he_to_next   = std::vector<int32_t>(he2nSpan.begin(), he2nSpan.end());
auto he_to_opp    = std::vector<int32_t>(he2oSpan.begin(), he2oSpan.end());
auto he_to_face   = std::vector<int32_t>(he2fSpan.begin(), he2fSpan.end());

std::cout << "Half-edges: " << he_to_vertex.size() << "\n"
          << "Vertices   : " << positions.size()    << "\n";

// Example: verify manifold export implies valid opposite links for all half-edges
// (Opposite indices are valid; faces/next pointers define per-face cycles.)
bool ok = true;
for (size_t h = 0; h < he_to_vertex.size(); ++h) {
    int32_t const o = he_to_opp[h];
    if (o < 0 || o >= (int32_t)he_to_vertex.size() || he_to_opp[o] != (int32_t)h) { ok = false; break; }
}
std::cout << "Opposite symmetry check: " << (ok ? "OK" : "FAILED") << "\n";

Notes

  • Halfedge format:
    By choosing ExportFormat::HalfedgeExplicit, you request explicit halfedge connectivity.
    Use [ExportOption::HalfedgeToFace] and [ExportOption::HalfedgeToVertex] to retrieve mappings.

  • Manifold guarantee:
    The ExportOption::Manifold flag ensures Solidean will duplicate vertices if necessary, so the resulting mesh is strictly manifold and suitable for half-edge traversal.

  • Performance:
    Manifold remapping is lightweight and does not change geometry — only the topological representation.

  • Alternatives:
    If you don’t need manifold guarantees, you can skip the flag. The output may then contain non-manifold edges if the input required them.

Note:

ExportFormat::HalfedgeImplicitOpposite (opposite halfedge = h ^ 1) and
ExportFormat::HalfedgeImplicitNext (all halfedges of a polygon stored contiguously) are currently under development.
If these formats would significantly benefit your pipeline, please get in touch — we may be able to fast-track support.