// Taken from: // https://doc.cgal.org/latest/Surface_mesher/Surface_mesher_2mesh_an_implicit_function_8cpp-example.html // https://doc.cgal.org/latest/Surface_mesher/index.html // https://doc.cgal.org/latest/Mesh_3/index.html #include #include #include #ifdef CGAL_FACETS_IN_COMPLEX_2_TO_TRIANGLE_MESH_H #include #else // NixOS currently has CGAL 4.11, not 4.12. I guess 4.12 is needed // for this. The #ifdef is unnecessary, but the header and call for // below are deprecated. #include #endif #include #include #include #include #include #include #include #include #include // Triangulation typedef CGAL::Surface_mesh_default_triangulation_3 Tr; typedef CGAL::Complex_2_in_triangulation_3 C2t3; // Domain? typedef Tr::Geom_traits GT; typedef GT::Sphere_3 Sphere_3; typedef GT::Point_3 Point_3; typedef GT::Vector_3 Vector_3; typedef GT::FT FT; typedef FT (*Function)(Point_3); typedef CGAL::Implicit_surface_3 Surface_3; // how does this differ from CGAL::Implicit_mesh_domain_3? typedef CGAL::Polyhedron_3 Polyhedron; FT sphere_function(Point_3 p) { Point_3 p2(p.x() + 0.1 * cos(p.x() * 20), p.y(), p.z() + 0.1 * sin(p.z() * 4)); const FT x2=p2.x()*p2.x(), y2=p2.y()*p2.y(), z2=p2.z()*p2.z(); return x2+y2+z2-1; } Vector_3 sphere_gradient(Point_3 p) { float A = 0.1; float B = 0.1; float F1 = 20; float F2 = 4; return Vector_3(2*(A*cos(p.x()*F1) + p.x())*(1 - A*F1*sin(p.x()*F1)), 2*p.y(), 2*(B*sin(p.z()*F2) + p.z())*(1 + B*F2*cos(p.z()*F2))); } FT spiral_function(Point_3 p) { float outer = 2.0; float inner = 0.4; // 0.9 float freq = 20; // 10 float phase = M_PI; // 3 * M_PI / 2; float thresh = 0.3; const FT d1 = p.y()*outer - inner * sin(p.x()*freq + phase); const FT d2 = p.z()*outer - inner * cos(p.x()*freq + phase); return std::max(sqrt(d1*d1 + d2*d2) - thresh, p.x()*p.x() + p.y()*p.y() + p.z()*p.z() - 1.9*1.9); } Vector_3 spiral_gradient(Point_3 p) { float outer = 2.0; float inner = 0.4; float freq = 20; float phase = M_PI; float thresh = 0.3; // "block([%1,%2,%3,%4,%5,%6],%1:P+x*F,%2:cos(%1),%3:z*O-I*%2,%4:sin(%1),%5:y*O-I*%4,%6:1/sqrt(%5^2+%3^2),[((2*F*I*%3*%4-2*F*I*%2*%5)*%6)/2,O*%5*%6,O*%3*%6])" float v1 = phase + p.x() * freq; float v2 = cos(v1); float v3 = p.z() * outer - inner * v2; float v4 = sin(v1); float v5 = p.y() * outer - inner * v4; float v6 = 1.0 / sqrt(v5*v5 + v3*v3); return Vector_3(((2*freq*inner*v3*v4-2*freq*inner*v2*v5)*v6)/2, outer * v5 * v6, outer * v3 * v6); } int main() { Tr tr; // 3D-Delaunay triangulation C2t3 c2t3 (tr); // 2D-complex in 3D-Delaunay triangulation FT bounding_sphere_rad = 2.0; // defining the surface Surface_3 surface(spiral_function, // pointer to function Sphere_3(CGAL::ORIGIN, bounding_sphere_rad*bounding_sphere_rad)); // bounding sphere std::string fname("spiral_thing4.obj"); float angular_bound = 30; float radius_bound = 0.02; float distance_bound = 0.02; // Note that "2." above is the *squared* radius of the bounding sphere! // defining meshing criteria CGAL::Surface_mesh_default_criteria_3 criteria( angular_bound, radius_bound, distance_bound); std::cout << "angular bound = " << angular_bound << ", " << "radius bound = " << radius_bound << ", " << "distance bound = " << distance_bound << std::endl; std::cout << "Making surface mesh..." << std::endl; // meshing surface CGAL::make_surface_mesh(c2t3, surface, criteria, CGAL::Manifold_tag()); std::cout << "Vertices: " << tr.number_of_vertices() << std::endl; // This didn't work on some calls instead of 'poly': //CGAL::Surface_mesh sm; Polyhedron poly; std::cout << "Turning facets to triangle mesh..." << std::endl; #ifdef CGAL_FACETS_IN_COMPLEX_2_TO_TRIANGLE_MESH_H CGAL::facets_in_complex_2_to_triangle_mesh(c2t3, poly); #else CGAL::output_surface_facets_to_polyhedron(c2t3, poly); #endif FT err = 0.0; FT inf = std::numeric_limits::infinity(); for (Polyhedron::Point_iterator it = poly.points_begin(); it != poly.points_end(); ++it) { FT rate = 2e-6; FT f0 = abs(spiral_function(*it)); FT f; for (int i = 0; i < 100; ++i) { f = spiral_function(*it); Vector_3 grad(spiral_gradient(*it)); *it -= grad * rate * (f > 0 ? 1 : -1); /* std::cout << "Iter " << i << ": " << "F(" << it->x() << "," << it->y() << "," << it->z() << ")=" << f << ", F'=" << grad << std::endl; */ } //FT diff = (abs(f) - abs(f0)) / f0; /* std::cout << "F(" << it->x() << "," << it->y() << "," << it->z() << "): " << f0 << " to " << f << std::endl; */ err += f * f; } err = sqrt(err); std::cout << "RMS isosurface distance: " << err << std::endl; std::cout << "Mesh vertices: " << poly.size_of_vertices() << ", " << "facets: " << poly.size_of_facets() << std::endl; std::cout << "Writing to " << fname << "..." << std::endl; std::ofstream ofs(fname); CGAL::print_polyhedron_wavefront(ofs, poly); }