GeometryCollective / boundary-first-flattening

MIT License
768 stars 96 forks source link

Asymmetric result after flattening #89

Closed artemishenkov closed 1 year ago

artemishenkov commented 1 year ago

bff.zip Hello, I was trying to unfold mesh in file input_mesh.obj but I've got weird asymmetric result (left and right rectangle holes are the same in 3D mesh but different after flattening) (file output_result.obj).

My code(from bff console project):

void LoadModel(const std::string& inputPath, Model& model, std::vector<bool>& surfaceIsClosed)
{
    std::string error;
    if (MeshIO::read(inputPath, model, error)) {
        int nMeshes = model.size();
        surfaceIsClosed.resize(nMeshes, false);

        for (int i = 0; i < nMeshes; i++) {
            bff::Mesh& mesh = model[i];
            int nBoundaries = (int)mesh.boundaries.size();

            if (nBoundaries >= 1) {
                // mesh has boundaries
                int eulerPlusBoundaries = mesh.eulerCharacteristic() + nBoundaries;

                if (eulerPlusBoundaries == 2) {
                    // fill holes if mesh has more than 1 boundary
                    if (nBoundaries > 1) {
                        if (HoleFiller::fill(mesh)) {
                            // all holes were filled
                            surfaceIsClosed[i] = true;
                        }
                    }

                }
                else {
                    // mesh probably has holes and handles
                    HoleFiller::fill(mesh, true);
                    Generators::compute(mesh);
                }

            }
            else if (nBoundaries == 0) {
                if (mesh.eulerCharacteristic() == 2) {
                    // mesh is closed
                    surfaceIsClosed[i] = true;

                }
                else {
                    // mesh has handles
                    Generators::compute(mesh);
                }
            }
        }

    }
    else {
        std::cerr << "Unable to load file: " << inputPath << ". " << error << std::endl;
        exit(EXIT_FAILURE);
    }
}

void Flatten(Model& model, const std::vector<bool>& surfaceIsClosed, int nCones, bool flattenToDisk, bool mapToSphere)
{
    int nMeshes = model.size();
    for (int i = 0; i < nMeshes; i++) {
        bff::Mesh& mesh = model[i];
        BFF bff(mesh);

        if (nCones > 0) {
            std::vector<VertexIter> cones;
            DenseMatrix coneAngles(bff.data->iN);
            int S = std::min(nCones, (int)mesh.vertices.size() - bff.data->bN);

            if (ConePlacement::findConesAndPrescribeAngles(S, cones, coneAngles, bff.data, mesh)
                == ConePlacement::ErrorCode::ok) {
                if (!surfaceIsClosed[i] || cones.size() > 0) {
                    Cutter::cut(cones, mesh);
                    bff.flattenWithCones(coneAngles, true);
                }
            }

        }
        else {
            if (surfaceIsClosed[i]) {
                if (mapToSphere) {
                    bool res = bff.mapToSphere();
                    std::cout << res << std::endl;

                }
                else {
                    std::cerr << "Surface is closed. Either specify nCones or mapToSphere." << std::endl;
                    exit(EXIT_FAILURE);
                }

            }
            else {
                if (flattenToDisk) {
                    bff.flattenToDisk();

                }
                else {
                    DenseMatrix u(bff.data->bN);
                    bff.flatten(u, true);
                }
            }
        }
    }
}

void WriteModelUVs(const std::string& outputPath, Model& model, const std::vector<bool>& surfaceIsClosed, bool mapToSphere, bool normalizeUVs)
{
    int nMeshes = model.size();
    std::vector<bool> mappedToSphere(nMeshes, false);
    for (int i = 0; i < nMeshes; i++) {
        if (surfaceIsClosed[i]) {
            mappedToSphere[i] = mapToSphere;
        }
    }

    if (!MeshIO::write(outputPath, model, mappedToSphere, normalizeUVs)) {
        std::cerr << "Unable to write file: " << outputPath << std::endl;
        exit(EXIT_FAILURE);
    }
}
void BFFWrapper::Flat(string input, string output) {
    int nCones = 0;
    bool flattenToDisk = false;
    bool mapToSphere = false;
    bool normalizeUVs = true;
    Model model;
    std::vector<bool> surfaceIsClosed = {false};
    LoadModel(input, model, surfaceIsClosed);

    Flatten(model, surfaceIsClosed, nCones, flattenToDisk, mapToSphere);
    WriteModelUVs(output, model, surfaceIsClosed, mapToSphere, normalizeUVs);
}

I would appreciate any help, thank you.

rohan-sawhney commented 1 year ago

weird, it's likely a problem with the HoleFiller::fill(mesh), I'll investigate.

rohan-sawhney commented 1 year ago

Are you using the new-features branch?

rohan-sawhney commented 1 year ago

I've determined the root cause of the problem: the hole filling with this model introduces zero area triangles. This issue can likely be resolved using "mollification" (see section 4.5 in this paper), and I'm in the process of implementing it.

artemishenkov commented 1 year ago

@rohan-sawhney thank you for your quick response. So awesome to hear that you are working on it. I am using master branch should I switch to new-features?

rohan-sawhney commented 1 year ago

The issue isn't resolved yet on master or on new-features. I'll implement the fix on new-features, and then merge to master soon.

rohan-sawhney commented 1 year ago

@artemishenkov The new-features branch has a fix now, not yet merged into master. Screenshot 2023-05-11 at 3 26 53 PM

artemishenkov commented 1 year ago

Hi @rohan-sawhney that's awesome thank you for the super quick update. I will update my project soon!