How to process output: trim_with_solid

103 views Asked by At

trim_with_solid is called:

// Trim mesh A (m_VA and m_FA) with solid B (m_VB and m_FB)
igl::copyleft::cgal::trim_with_solid(
                                     m_VA, m_FA           // input: mesh A
                                     , m_VB, m_FB         // input: solid B
                                     , m_V, m_F, m_D, m_J // output
                                     );

The output is processed:

    // Loop over output vertex data
    for (int i = 0; i < m_V.rows(); ++i) {
        // Access all the vertex data
    }

   // Loop over output triangle (face) data
    for (int i = 0; i < m_F.rows(); ++i) {
        // Condition to decide if facet is inside or outside the solid B
        if (m_D.coeff(i)) {
            // The output face is outside the solid B
        } else {
            // The output face is inside the solid B
        }
    }

Fine result

Sometimes the trim result is fine. Like this one which is trimming a teapot model with a solid cylinder:

image

image

Bad result

But sometimes the trim result is NOT as expected:

image

image

image

As shown by the wire-frame view above, the intersection of teapot and cylinder is identified correctly. But for some reason, this loop is NOT able to detect triangles which are outside the cylinder:

   // Loop over output triangle (face) data
    for (int i = 0; i < m_F.rows(); ++i) {
        // Condition to decide if facet is inside or outside the solid B
        if (m_D.coeff(i)) {
            // Face is outside the solid B
        } else {
            // Face is inside the solid B
        }
    }

Does anybody know what I'm possibly missing?

1

There are 1 answers

0
Megidd On BEST ANSWER

Previously, I was using Qt3DExtras::QCylinderMesh as solid B (VB and FB). But it was NOT watertight. I replaced it with the following code which creates watertight cylinders.

Header:
    // Create a cylinder mesh which is exactly solid
    // without any open boundary
    // Down facing cylinder in Z direction with arguments:
    // r: radius
    // h: Height
    // ssteps: how many edges will create the base circle
    // sp: starting point
    static void cylinder(
            std::vector<QVector3D>& points
            , std::vector<std::array<int, 3>>& indices
            , const float r
            , const float h
            , const size_t ssteps = 45
            , const QVector3D &sp = QVector3D()
            );
Source:
void EditorUtils::cylinder(
        std::vector<QVector3D> &points
        , std::vector<std::array<int, 3>> &indices
        , const float r
        , const float h
        , const size_t ssteps
        , const QVector3D &sp
        )
{
    assert(ssteps > 0);

    auto PI = M_PI;

    auto steps = int(ssteps);
    points.reserve(2*ssteps);
    double a = 2*PI/steps;

    QVector3D jp = sp;
    QVector3D endp = {sp.x(), sp.y(), sp.z() + h};

    // Upper circle points
    for(int i = 0; i < steps; ++i) {
        double phi = i*a;
        double ex = endp.x() + r*std::cos(phi);
        double ey = endp.y() + r*std::sin(phi);
        points.emplace_back(ex, ey, endp.z());
    }

    // Lower circle points
    for(int i = 0; i < steps; ++i) {
        double phi = i*a;
        double x = jp.x() + r*std::cos(phi);
        double y = jp.y() + r*std::sin(phi);
        points.emplace_back(x, y, jp.z());
    }

    // Now create long triangles connecting upper and lower circles
    indices.reserve(2*ssteps);
    auto offs = steps;
    for(int i = 0; i < steps - 1; ++i) {
        indices.emplace_back(std::array<int, 3>{i, i + offs, offs + i + 1});
        indices.emplace_back(std::array<int, 3>{i, offs + i + 1, i + 1});
    }

    // Last triangle connecting the first and last vertices
    auto last = steps - 1;
    indices.emplace_back(std::array<int, 3>{0, last, offs});
    indices.emplace_back(std::array<int, 3>{last, offs + last, offs});

    // Try generating a watertight body.
    // So we create a triangle fan for the upper and lower
    // ending of the cylinder to close the geometry.
    points.emplace_back(jp); int ci = int(points.size() - 1);
    for(int i = 0; i < steps - 1; ++i)
        indices.emplace_back(std::array<int, 3>{i + offs + 1, i + offs, ci});

    indices.emplace_back(std::array<int, 3>{offs, steps + offs - 1, ci});

    points.emplace_back(endp); ci = int(points.size() - 1);
    for(int i = 0; i < steps - 1; ++i)
        indices.emplace_back(std::array<int, 3>{ci, i, i + 1});

    indices.emplace_back(std::array<int, 3>{steps - 1, 0, ci});

    return;
}

Now the holes are created properly:

image

image