I'm trying to build a triangulation (or mesh) of 2D figure. But it fails for some figures, because bad triangles are produced. These triangles are built by points which lie at the one line. I identify these triangles by the area.
Does anybody know how to fix it?
my code:
#include <iostream>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Triangulation_conformer_2.h>
#include <CGAL/Delaunay_mesher_2.h>
#include <CGAL/Delaunay_mesh_face_base_2.h>
#include <CGAL/Delaunay_mesh_size_criteria_2.h>
#include <CGAL/Constrained_triangulation_plus_2.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Triangulation_vertex_base_2<K> Vb;
typedef CGAL::Delaunay_mesh_face_base_2<K> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb, Fb> Tds;
typedef CGAL::Constrained_Delaunay_triangulation_2<K, Tds, CGAL::Exact_predicates_tag> CDT;
typedef CGAL::Constrained_triangulation_plus_2<CDT> CDT_plus;
typedef CGAL::Delaunay_mesh_size_criteria_2<CDT_plus> Criteria;
typedef CGAL::Delaunay_mesher_2<CDT_plus, Criteria> Mesher;
typedef CDT::Vertex_handle Vertex_handle;
typedef CDT::Point Point;
void some_function()
{
CDT_plus cdt;
Point hp[6];
hp[0] = Point(0.500000091410, 0.486455788882);
hp[1] = Point(-0.334032111870, 0.486455788837);
hp[2] = Point(-0.500000091424, 0.120965046601);
hp[3] = Point(-0.500000091430, 0.008971885303);
hp[4] = Point(0.482938375290, -0.486030074474);
hp[5] = Point(0.500000091434, -0.448457168454);
for (int i = 0; i < 6; ++i)
{
cdt.insert_constraint(hp[i], hp[i + 1 < 6 ? i + 1 : 0]);
}
Mesher mesher(cdt, Criteria(0.125, 0.3));
int i = 0;
mesher.refine_mesh();
for (CDT::Finite_faces_iterator it = mesher.triangulation().finite_faces_begin(); it != mesher.triangulation().finite_faces_end(); it++)
{
CDT::Triangle trr = cdt.triangle(it);
if (trr.area()< 1e-12)
{
cout << "i am very saaad" << endl;
}
}
}
Related
I have the following code, which matches the example for 90%. I want to "flatten" the 3D model via parameterization. But the input and output do not have the same scale.
The question I have, how can we remain the same scale of the scaling. In the image below you can find the input and the output:
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Surface_mesh_parameterization/IO/File_off.h>
//#include <CGAL/Surface_mesh_parameterization/Circular_border_parameterizer_3.h>
//#include <CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h>
//#include <CGAL/Surface_mesh_parameterization/Square_border_parameterizer_3.h>
//#include <CGAL/Surface_mesh_parameterization/Barycentric_mapping_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Two_vertices_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/LSCM_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/Surface_mesh_parameterization/parameterize.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Kernel::Point_3> SurfaceMesh;
typedef boost::graph_traits<SurfaceMesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<SurfaceMesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<SurfaceMesh>::face_descriptor face_descriptor;
namespace SMP = CGAL::Surface_mesh_parameterization;
int main(int argc, char** argv)
{
std::ifstream in((argc > 1) ? argv[1] : "C:/Users/Niels/Desktop/CGAL/flatten.off");
if (!in) {
std::cerr << "Problem loading the input data" << std::endl;
return EXIT_FAILURE;
}
SurfaceMesh sm;
in >> sm;
// A halfedge on the border
halfedge_descriptor bhd = CGAL::Polygon_mesh_processing::longest_border(sm).first;
// The 2D points of the uv parametrisation will be written into this map
typedef SurfaceMesh::Property_map<vertex_descriptor, Point_2> UV_pmap;
UV_pmap uv_map = sm.add_property_map<vertex_descriptor, Point_2>("v:uv").first;
typedef SMP::Two_vertices_parameterizer_3<SurfaceMesh> Border_parameterizer;
typedef SMP::LSCM_parameterizer_3<SurfaceMesh, Border_parameterizer> Parameterizer;
SMP::Error_code err = SMP::parameterize(sm, Parameterizer(), bhd, uv_map);
if (err != SMP::OK) {
std::cerr << "Error: " << SMP::get_error_message(err) << std::endl;
return EXIT_FAILURE;
}
std::ofstream out("result.off");
SMP::IO::output_uvmap_to_off(sm, bhd, uv_map, out);
return EXIT_SUCCESS;
}
Update, but this runs infinite:
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Surface_mesh_parameterization/IO/File_off.h>
//#include <CGAL/Surface_mesh_parameterization/Circular_border_parameterizer_3.h>
//#include <CGAL/Surface_mesh_parameterization/Discrete_authalic_parameterizer_3.h>
//#include <CGAL/Surface_mesh_parameterization/Square_border_parameterizer_3.h>
//#include <CGAL/Surface_mesh_parameterization/Barycentric_mapping_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Two_vertices_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/LSCM_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/Error_code.h>
#include <CGAL/Surface_mesh_parameterization/parameterize.h>
#include <CGAL/Polygon_mesh_processing/measure.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_2 Point_2;
typedef Kernel::Point_3 Point_3;
typedef CGAL::Surface_mesh<Kernel::Point_3> SurfaceMesh;
typedef boost::graph_traits<SurfaceMesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<SurfaceMesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<SurfaceMesh>::face_descriptor face_descriptor;
namespace SMP = CGAL::Surface_mesh_parameterization;
#include <CGAL/Surface_mesh_parameterization/ARAP_parameterizer_3.h>
int main(int argc, char** argv)
{
std::ifstream in((argc > 1) ? argv[1] : "FlatteningObject.off");
if (!in) {
std::cerr << "Problem loading the input data" << std::endl;
return EXIT_FAILURE;
}
SurfaceMesh sm;
in >> sm;
// A halfedge on the border
halfedge_descriptor bhd = CGAL::Polygon_mesh_processing::longest_border(sm).first;
// The 2D points of the uv parametrisation will be written into this map
typedef SurfaceMesh::Property_map<vertex_descriptor, Point_2> UV_pmap;
UV_pmap uv_map = sm.add_property_map<vertex_descriptor, Point_2>("v:uv").first;
typedef SMP::Two_vertices_parameterizer_3<SurfaceMesh> Border_parameterizer;
typedef SMP::LSCM_parameterizer_3<SurfaceMesh, Border_parameterizer> Parameterizer;
SMP::Error_code err = SMP::parameterize(
sm,
SMP::ARAP_parameterizer_3<SurfaceMesh, Border_parameterizer>(
Border_parameterizer(),
CGAL::Eigen_solver_traits<Eigen::SparseLU<CGAL::Eigen_sparse_matrix<double>::EigenType> >(),
1000,
50
),
bhd,
uv_map);
if (err != SMP::OK) {
std::cerr << "Error: " << SMP::get_error_message(err) << std::endl;
return EXIT_FAILURE;
}
std::ofstream out("result.off");
SMP::IO::output_uvmap_to_off(sm, bhd, uv_map, out);
return EXIT_SUCCESS;
}
I have had some success with using the ARAP method instead. The default 50 iterations was not actually enough and produced a crossed over mesh. Bumping up the iterations to 500 worked.
SMP::Error_code err = SMP::parameterize(
in,
SMP::ARAP_parameterizer_3<geometry::Mesh, Border_parameterizer>(
Border_parameterizer(),
CGAL::Eigen_solver_traits<Eigen::SparseLU<CGAL::Eigen_sparse_matrix<double>::EigenType> >(),
1000,
500),
bhd,
uv_map);
...Using commit bec70a6d52
I reconstruct a 3D surface mesh using the advancing front surface reconstruction and would like to refine it. How can I achieve this?
This is part of the code used for surface reconstruction with refinement by passing through a file:
#include <CGAL/Advancing_front_surface_reconstruction.h>
#include <CGAL/compute_average_spacing.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Triangulation_data_structure_3.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Polygon_mesh_processing/refine.h>
#include <CGAL/Polygon_mesh_processing/fair.h>
typedef CGAL::Advancing_front_surface_reconstruction<> Reconstruction;
typedef Reconstruction::Triangulation_3 Triangulation_3;
typedef Reconstruction::Triangulation_data_structure_2 TDS_2;
typedef Reconstruction::Outlier_range Outlier_range;
typedef Reconstruction::Boundary_range Boundary_range;
typedef Reconstruction::Vertex_on_boundary_range Vertex_on_boundary_range;
typedef Reconstruction::Vertex_handle Vertex_handle;
typedef CGAL::Polyhedron_3<CGALMesher::Kernel> Polyhedron;
typedef CGAL::Surface_mesh<CGALMesher::Point> Mesh;
typedef CGAL::cpp11::array<std::size_t,3> Facet;
struct Construct {
Mesh& mesh;
template<typename PointIterator>
Construct(Mesh& mesh, PointIterator b, PointIterator e) : mesh(mesh) {
for (; b != e; ++b) {
boost::graph_traits<Mesh>::vertex_descriptor v;
v = add_vertex(mesh);
mesh.point(v) = *b;
}
}
Construct& operator=(const Facet f) {
typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Mesh>::vertices_size_type size_type;
mesh.add_face(vertex_descriptor(static_cast<size_type>(f[0])),
vertex_descriptor(static_cast<size_type>(f[1])),
vertex_descriptor(static_cast<size_type>(f[2])));
return *this;
}
Construct&
operator*() {
return *this;
}
Construct&
operator++() {
return *this;
}
Construct operator++(int) {
return *this;
}
};
void CGALMesher::AdvancingFrontMesher(std::vector<Point>& points) {
Mesh m;
Construct construct(m,points.begin(),points.end());
CGAL::advancing_front_surface_reconstruction(points.begin(), points.end(), construct);
std::ofstream mesh_off("mesh.off");
mesh_off << m;
mesh_off.close();
std::ifstream input("mesh.off");
Polyhedron poly;
if ( !input || !(input >> poly) || poly.empty() ) {
std::cerr << "Not a valid off file." << std::endl;
}
input.close();
std::vector<Polyhedron::Facet_handle> new_facets;
std::vector<Polyhedron::Vertex_handle> new_vertices;
CGAL::Polygon_mesh_processing::refine(poly,
faces(poly),
std::back_inserter(new_facets),
std::back_inserter(new_vertices),
CGAL::Polygon_mesh_processing::parameters::density_control_factor(3));
std::ofstream refined_off("refined.off");
refined_off << poly;
refined_off.close();
std::cout << "Refinement added " << new_vertices.size() << " vertices." << std::endl;
}
Once you extracted a polyhedral surface out of the reconstruction algorithm, you can use the refine() function from the polygon mesh processing package. There is also the possibility to use the fair().
More drastically, you can use remeshing algorithm like this one. In CGAL 4.8, there will also be the function isotropic_remeshing() that is already available in the master branch.
I'm getting an error saying no matching function for call to 'getline' involving the getline(tokenizer, " "); Im not sure how to fix this, Ive tried including some other headers but I just keep coming up with more errors.
#include <iostream>
#include <fstream>
#include <cstring>
#include <sstream>
#include <string>
using namespace std;
char encrypt(char character, int offset);
int main(int argc, char *argv[]) {
ifstream inputFile;
string str;
string token;
bool debug = true;
int lineLength = 0, offset;
inputFile.open(argv[1]);
if (inputFile.fail())
cout << "File failed to open. \n";
istringstream tokenizer(str);
getline(tokenizer, " ");
offset = token.length();
while (getline(inputFile, str)){
lineLength = str.length();
for (int i = 0; i < lineLength; i++)
str.at(i) = encrypt(str.at(i), offset);
cout << str << endl;
}
inputFile.close();
return(0);
}
I found a phenomenon, CGAL AABB tree Constructor function is very very slow for std::vector.
Here is a minimal test code:
Point a(1.0, 0.0, 0.0);
Point b(0.0, 1.0, 0.0);
Point c(0.0, 0.0, 1.0);
std::vector<Triangle> triangles;
for (size_t I=0;I<245000;I++)
{
triangles.push_back(Triangle(a,b,c));
}
// constructs AABB tree
MyTree tree(triangles.begin(),triangles.end());
245000 Primitive, not built, run much slower. I find source:
template<typename Tr>
template<typename ConstPrimitiveIterator, typename ... T>
void AABB_tree<Tr>::insert(ConstPrimitiveIterator first,
ConstPrimitiveIterator beyond,
T ... t)
{
set_shared_data(t...);
while(first != beyond)
{
m_primitives.push_back(Primitive(first,t...));
++first;
}
m_need_build = true;
}
I suspect vector push_back function will reallocate memory, but I'm not sure is the reason, So I tried this code:
template<typename Tr>
template<typename ConstPrimitiveIterator, typename ... T>
void AABB_tree<Tr>::insert(ConstPrimitiveIterator first,
ConstPrimitiveIterator beyond,
T ... t)
{
set_shared_data(t...);
m_primitives.assign(beyond-first,first);//pre allcate promitives
size_t Index = 0;
while(first != beyond)
{
m_primitives[Index] = Primitive(first,t...);
++first;
++Index;
}
m_need_build = true;
}
The problem solves! I need more advices, and I think this needs to be updated to CGAL source?
==================14-9-18 update ===============
I make an simple test:
#include <iostream>
#include <list>
#include "boost/timer/timer.hpp"
#include <CGAL/Simple_cartesian.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_triangle_primitive.h>
#include <CGAL/Polyhedron_3.h>
typedef CGAL::Simple_cartesian<double> K;
typedef K::FT FT;
typedef K::Ray_3 Ray;
typedef K::Line_3 Line;
typedef K::Point_3 Point;
typedef K::Triangle_3 Triangle;
typedef std::vector<Triangle>::iterator Iterator;
typedef CGAL::AABB_triangle_primitive<K, Iterator> Primitive;
typedef CGAL::AABB_traits<K, Primitive> AABB_triangle_traits;
typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
int main()
{
Point a(1.0, 0.0, 0.0);
Point b(0.0, 1.0, 0.0);
Point c(0.0, 0.0, 1.0);
std::vector<Triangle> triangles;
for (size_t I=0;I<245000;I++)
{
triangles.push_back(Triangle(a,b,c));
}
#define TIMER_SECOND boost::timer::nanosecond_type(1000000000LL)
auto first = triangles.begin();
auto beyond = triangles.end();
boost::timer::cpu_timer CountTimer;
//Test 1
std::vector<Primitive> TestV1;
CountTimer.start();
while(first != beyond)
{
TestV1.push_back(Primitive(first));
++first;
}
std::cout << "Test1 Time:" << CountTimer.elapsed().wall << std::endl;
//Test 2
first = triangles.begin();
beyond = triangles.end();
std::vector<Primitive> TestV2;
CountTimer.start();
TestV2.reserve(std::distance(first,beyond));
while(first != beyond)
{
TestV2.push_back(Primitive(first));
++first;
}
std::cout << "Test2 Time:" << CountTimer.elapsed().wall << std::endl;
system("pause");
return EXIT_SUCCESS;
}
in release mode:
Test1 Time:3426459
Test2 Time:926136
in debug mode:
Test1 Time:503719044580
Test2 Time:224280791
I am trying to use the boost::multi_index_container with the boost::serialization. However when I use Pointer to objects as elements and a non_unique order, I get a memory access violation loading the serialized container. I find it interesting that the error doesn't occur for unique ordering or using objects instead of pointers as container elements.
Can somebody tell me if there is a problem with my code or if this is a bug in the boost library?
Here is a minimal example that produces the described error:
#include <boost/multi_index_container.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/set.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <fstream>
using namespace std;
using namespace boost::multi_index;
struct element {
friend class boost::serialization::access;
std::string member1;
element( int num ) { member1 = boost::lexical_cast<string>( num ); }
element() {}
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & member1;
}
};
int main( int argc, const char *argv[] )
{
typedef multi_index_container<element *, indexed_by<ordered_non_unique<member<element, std::string, &element::member1>>>> TestSet;
TestSet myset;
srand( time (NULL ));
for (int i = 0; i < 20; i++) {
myset.insert(new element(rand()));
}
// Write set
ofstream os("test.bin");
boost::archive::binary_oarchive boa(os);
boa << myset;
os.close();
// Read set
TestSet newset;
ifstream is("test.bin");
boost::archive::binary_iarchive bia(is);
bia >> newset;
return 0;
}
ofstream os("test.bin"); should be:
ofstream os("test.bin", ios::binary);
Also:
ifstream is("test.bin"); should be: ifstream is("test.bin", ios::binary);