CGAL / cgal

The public CGAL repository, see the README below
https://github.com/CGAL/cgal#readme
Other
4.86k stars 1.38k forks source link

Error: assertion violation! by consecutive corefinement boolean operation #6481

Open FuzhangHe opened 2 years ago

FuzhangHe commented 2 years ago

Issue Details

Hi, I am trying to do corefine_and_compute_difference operation between two objects. The goal is not just one step, but about 5000 steps together. The workspiece("VB56.off") stands still, the tool ("Cylinder6.off") moves down in every step, and a new boolean operation should be done.

My problem is that, i can only do two steps successfully. In third step, it will got the error:

Unhandled exception at 0x00007FF893464F69 in corefinement_polyhedron_union.exe: Microsoft C++ exception: CGAL::Assertion_exception at memory location 0x000000723C8FD3D0.

---------- Message CMD ------ CGAL error: assertion violation! Expression: oxz_pqr != COLLINEAR File: C:\dev\vcpkg\installed\x64-windows\include\CGAL\predicates\kernel_ftC3.h Line: 190 Explanation: Refere to the bug-reporting instructions at https://www.cgal.org/bug_report.html

Source Code

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Aff_transformation_3.h>

#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polyhedron_items_with_id_3.h>
#include <CGAL/Polygon_mesh_processing/corefinement.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <CGAL/Polygon_mesh_processing/transform.h>

#include <fstream>
#include <iostream>

using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Vector_3 = typename Kernel::Vector_3;

using K = CGAL::Exact_predicates_inexact_constructions_kernel;
using Mesh = CGAL::Polyhedron_3<K, CGAL::Polyhedron_items_with_id_3>;
using Affine_transformation_3 = CGAL::Aff_transformation_3<Kernel>;

namespace PMP = CGAL::Polygon_mesh_processing;

int main(int argc, char* argv[])
{

    const std::string Tool = (argc > 1) ? argv[1] : CGAL::data_file_path("werkzeug/Cylinder6.off");
    const std::string Workpiece = (argc > 2) ? argv[2] : CGAL::data_file_path("werkzeug/VB56.off");

    Mesh mesh_Tool, meshWorkpiece;
    if (!PMP::IO::read_polygon_mesh(Tool, mesh_Tool) || !PMP::IO::read_polygon_mesh(Workpiece, meshWorkpiece))
    {
        std::cerr << "Invalid input." << std::endl;
        return 1;
    }

    for (int step = 1; step <= 2; step++) {
        PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(0, 0, -1)), mesh_Tool);
        PMP::corefine_and_compute_difference(meshWorkpiece, mesh_Tool, meshWorkpiece);
    }

    // output file
    std::cout << "Union was successfully computed\n";
    std::ofstream output("../../data/output/NewWorkpiece.off");
    output.precision(17);
    output << meshWorkpiece;
    return 0;

}

the code and file are in github uploaded: github

Environment

sloriot commented 2 years ago

You are having issues with rounding to double. Try using this example to workaround them: https://doc.cgal.org/latest/Polygon_mesh_processing/Polygon_mesh_processing_2corefinement_consecutive_bool_op_8cpp-example.html

If speed then becomes an issue some mesh cleaning operations must probably be done instead.

FuzhangHe commented 2 years ago

Now i have changed the code based on the example "corefinement_consecutive_bool_op.cpp". It can still only run two steps.

Source Code

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/corefinement.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <CGAL/Polygon_mesh_processing/transform.h>
#include <CGAL/Aff_transformation_3.h>
#include <fstream>
#include <iostream>

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Exact_predicates_exact_constructions_kernel EK;
typedef CGAL::Surface_mesh<K::Point_3> Mesh;
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef Mesh::Property_map<vertex_descriptor, EK::Point_3> Exact_point_map;

typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef typename Kernel::Vector_3 Vector_3;
typedef CGAL::Aff_transformation_3<Kernel> Affine_transformation_3;

namespace PMP = CGAL::Polygon_mesh_processing;
namespace params = PMP::parameters;

struct Exact_vertex_point_map
{
    // typedef for the property map
    typedef boost::property_traits<Exact_point_map>::value_type value_type;
    typedef boost::property_traits<Exact_point_map>::reference reference;
    typedef boost::property_traits<Exact_point_map>::key_type key_type;
    typedef boost::read_write_property_map_tag category;

    // exterior references
    Exact_point_map exact_point_map;
    Mesh* tm_ptr;
    // Converters
    CGAL::Cartesian_converter<K, EK> to_exact;
    CGAL::Cartesian_converter<EK, K> to_input;
    Exact_vertex_point_map()
        : tm_ptr(nullptr)
    {}
    Exact_vertex_point_map(const Exact_point_map& ep, Mesh& tm)
        : exact_point_map(ep)
        , tm_ptr(&tm)
    {
        for (Mesh::Vertex_index v : vertices(tm))
            exact_point_map[v] = to_exact(tm.point(v));
    }
    friend
        reference get(const Exact_vertex_point_map& map, key_type k)
    {
        CGAL_precondition(map.tm_ptr != nullptr);
        return map.exact_point_map[k];
    }
    friend
        void put(const Exact_vertex_point_map& map, key_type k, const EK::Point_3& p)
    {
        CGAL_precondition(map.tm_ptr != nullptr);
        map.exact_point_map[k] = p;
        // create the input point from the exact one
        map.tm_ptr->point(k) = map.to_input(p);
    }
};
int main(int argc, char* argv[])
{
    const std::string filename1 = (argc > 1) ? argv[1] : CGAL::data_file_path("werkzeug/VB56.off");
    const std::string filename2 = (argc > 2) ? argv[2] : CGAL::data_file_path("werkzeug/Cylinder6.off");
    Mesh mesh1, mesh2;
    if (!PMP::IO::read_polygon_mesh(filename1, mesh1) || !PMP::IO::read_polygon_mesh(filename2, mesh2))
    {
        std::cerr << "Invalid input." << std::endl;
        return 1;
    }
for (int step = 1; step <= 2; step++) {
    // Transformation
    PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(0, 0, -1)), mesh2);

    // Boolean Operation
    Exact_point_map mesh1_exact_points =
        mesh1.add_property_map<vertex_descriptor, EK::Point_3>("v:exact_point").first;
    Exact_point_map mesh2_exact_points =
        mesh2.add_property_map<vertex_descriptor, EK::Point_3>("v:exact_point").first;
    Exact_vertex_point_map mesh1_vpm(mesh1_exact_points, mesh1);
    Exact_vertex_point_map mesh2_vpm(mesh2_exact_points, mesh2);

    PMP::corefine_and_compute_difference(mesh1,
        mesh2,
        mesh1,
        params::vertex_point_map(mesh1_vpm),
        params::vertex_point_map(mesh2_vpm),
        params::vertex_point_map(mesh1_vpm));
}
std::cout << "Intersection and union were successfully computed\n";
CGAL::IO::write_polygon_mesh("../../data/output/NewWorkpiece.off", mesh1, CGAL::parameters::stream_precision(17));
CGAL::IO::write_polygon_mesh("../../data/output/NewWerkzeug.off", mesh2, CGAL::parameters::stream_precision(17));
return 0;

}

sloriot commented 2 years ago

Since you are really only updating mesh1, define mesh1_vpm outside of the loop (otherwise exact points will get overridden). For mesh_2, I suggest to copy it at the beginning of the loop to avoid refining it. So define mesh_2 outside of the loop and copy it to mesh_2_for_loop before doing the affine transformation (keep track of the number of translations of course).

FuzhangHe commented 2 years ago

As you suggested , i put the mesh1_vpm outsideof the loop, and now i got the error :

Severity    Code    Description Project File    Line    Suppression State
Error   C2338   (std::is_same<typename boost::property_traits<VPM1>::value_type, typename boost::property_traits<VPM2>::value_type>::value) corefinement_consecutive_bool_op_Version    C:\dev\vcpkg\installed\x64-windows\include\CGAL\Polygon_mesh_processing\corefinement.h  207 
Error   C2338   (std::is_same<typename boost::property_traits<VertexPointMap1>::value_type, typename boost::property_traits<VertexPointMap2>::value_type>::value)   corefinement_consecutive_bool_op_Version    C:\dev\vcpkg\installed\x64-windows\include\CGAL\Polygon_mesh_processing\internal\Corefinement\intersection_nodes.h  333 

Source Code

Exact_point_map mesh1_exact_points =
    mesh1.add_property_map<vertex_descriptor, EK::Point_3>("v:exact_point").first;
Exact_vertex_point_map mesh1_vpm(mesh1_exact_points, mesh1);

// todo: copy mesh 
// mesh_copy;

for (int step = 1; step <= 2; step++) {
    // Transformation
    PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(0, 0, -1)), mesh2);

    // Boolean Operation

    PMP::corefine_and_compute_difference(mesh1,
        mesh2,
        mesh1,
        params::vertex_point_map(mesh1_vpm),
        params::all_default(),
        params::vertex_point_map(mesh1_vpm));
}

Copy Mesh

Can you please also tell me how to copy mesh ? I am new in C++...

sloriot commented 2 years ago

You are missing mesh2_vpm

FuzhangHe commented 2 years ago

do you mean code like this ?

Exact_point_map mesh1_exact_points =
    mesh1.add_property_map<vertex_descriptor, EK::Point_3>("v:exact_point").first;
Exact_vertex_point_map mesh1_vpm(mesh1_exact_points, mesh1);

for (int step = 1; step <= 3; step++) {
    // todo: copy mesh 
    // mesh_copy;

    // Transformation
    PMP::transform(Affine_transformation_3(CGAL::Translation(), Vector_3(0, 0, -1)), mesh2);

    // Boolean Operation
    Exact_point_map mesh2_exact_points =
        mesh2.add_property_map<vertex_descriptor, EK::Point_3>("v:exact_point").first;
    Exact_vertex_point_map mesh2_vpm(mesh2_exact_points, mesh2);

    PMP::corefine_and_compute_difference(mesh1,
        mesh2,
        mesh1,
        params::vertex_point_map(mesh1_vpm),
        params::vertex_point_map(mesh2_vpm),
        params::vertex_point_map(mesh1_vpm));
}

but i still get the error assertion violation somehow.

sloriot commented 2 years ago

The following works for me but you then have the runtime issue I was mentioning earlier: https://gist.github.com/sloriot/b29acaa073765dde8d79e735893e74a5

FuzhangHe commented 2 years ago

Thank you for the code. As you said, it works but very slow.

It is slower than nef Boolean Operation. For the same model, it need 1316 seconds to calculate 30 steps with corefinement, but with nef3 only 300 seconds for 100 steps.

it gets slower and slower, because the workpiece is more and more complicate.

afabri commented 2 years ago

Hello, we had a closer look at what happens. Each time the cylinder moves down it produces a new layer of vertical faces. In the next iteration all these faces are cut again by edges of the cylinder which are not vertical. And this happens for each iteration for all layers so far produced. As only the head of the tool is cutting it is maybe a solution for you to make the cylinder only 2 * step_distance high. Then only the previous layer is concerned by an additional subdivision. Is that an option for you?

FuzhangHe commented 2 years ago

Hi, Afabri,

Thank you for take a closer look at this modell.

It is really intearsting, the cylinder after move down and before Corefinement Boolean Operation doesnot have so many vertices. Something strange has happend during the corefinement boolean operation.

I also want to simulate the tool deviation (deformation), that means the boolean operation is no more ideal. So it is not a good idea to cut the cylinder so short.

PS. in Nef Boolean Operation the cylinder doesnot get more vertices after boolean operation.

logan20083308 commented 2 years ago

Hi, Afabri,

Thank you for take a closer look at this modell.

It is really intearsting, the cylinder after move down and before Corefinement Boolean Operation doesnot have so many vertices. Something strange has happend during the corefinement boolean operation.

I also want to simulate the tool deviation (deformation), that means the boolean operation is no more ideal. So it is not a good idea to cut the cylinder so short.

PS. in Nef Boolean Operation the cylinder doesnot get more vertices after boolean operation.

Hello, blogger. I have the same problem as you. Boolean operation is very slow when i use [PMP::corefine_and_compute_difference]. I want to cut the rectangular workpiece with a cylindrical cutter. Do you have any good suggestions?

Hi, Afabri,

Thank you for take a closer look at this modell.

It is really intearsting, the cylinder after move down and before Corefinement Boolean Operation doesnot have so many vertices. Something strange has happend during the corefinement boolean operation.

I also want to simulate the tool deviation (deformation), that means the boolean operation is no more ideal. So it is not a good idea to cut the cylinder so short.

PS. in Nef Boolean Operation the cylinder doesnot get more vertices after boolean operation.

Hello, blogger. I have the same problem as you. Boolean operation is very slow when i use [PMP::corefine_and_compute_difference]. I want to cut the rectangular workpiece with a cylindrical cutter. Do you have any good suggestions?