How to access to the informations related to the facets of a convex hull in a dD triangulation? - cgal

I am rewriting codes that were using the class CGAL::Convex_hull_d, that is now deprecated. My need is to compute dynamically the convex hull of a set of points, and next to access to a a point and the normal of each facet.
The way to traverse the facets of a convex hull obtained by a triangulation is perfectly clear in the documentation, the problem is next to access to the informations related to the facets.
For the three-dimensional case, I have used the class CGAL::Delaunay_triangulation_3. After inserting points in the triangulation (called T), it is possible to obtain the convex hull using the CGAL::Surface_mesh class and the function CGAL::convex_hull_3_to_face_graph. Next, we can use facet iterators to traverse the facets, and next vertex iterators to access to the vertices of a facet. There is also a direct access to the normal to a facet using the function CGAL::Polygon_mesh_processing::compute_face_normal. This is described by the following portion of code.
Surface_mesh chull;
CGAL::convex_hull_3_to_face_graph(T,chull);
Surface_mesh::Face_range mesFaces = chull.faces();
Surface_mesh::Face_range::iterator debut,fin;
CGAL::Vertex_around_face_iterator<Surface_mesh> vbegin,vend;
debut = mesFaces.begin();
fin = mesFaces.end();
while(debut != fin)
{
Vector_3 p = CGAL::Polygon_mesh::compute_face_normal(*debut,chull);
std::cout << "Normal to the facet: (" << p[0] << "," << p[1] << "," << p[2] << ")" << std:endl;
boost::tie(vbegin,vend) = vertices_around_face(chull.halfedge(*debut),chull);
Point_3 po = chull.point(*vbegin);
std::cout << "One point of the facet: (" << po[0] << "," << po[1] << "," << po[2] << ")" << std:endl;
debut++;
}
However, the classes CGAL::Delaunay_Triangulation_3 and CGAL::Surface_mesh class cannot be used to compute the convex hull of a set of points with 4 dimensions. I have therefore considered the (recommended) use of dD Triangulation (in particular, the class CGAL::Triangulation). To traverse the facets of the convex hull is not a problem as a two full examples are given in the documention. Below, the first one is given.
{ int i=0;
typedef Triangulation::Full_cell_iterator Full_cell_iterator;
typedef Triangulation::Facet Facet;
for( Full_cell_iterator cit = t.full_cells_begin();cit != t.full_cells_end(); ++cit )
{
if( ! t.is_infinite(cit) )
continue;
Facet ft(cit, cit->index(t.infinite_vertex()));
++i;// |ft| is a facet of the convex hull
}
std::cout << "There are " << i << " facets on the convex hull."<< std::endl;
}
Here, the Facet ft is created but not used, the facets are only counted. I have not found a way to access to any information related to the facet in the documentation. My need would be the same as for the three-dimensional case.

Related

[cgal]; 3D Delaunay Triangulation

I'm trying to do a 3D Delaunay Triangulation and I need to obtain the circumcenters of this triangulation. I've done it this way:
typedef CGAL::Delaunay_triangulation_3<K, Tds> Triangulation;
// Construct the triangulation in parallel
Triangulation T(V.begin(), V.end());
assert(T.is_valid());
centros.open("centros.txt");
//With this I would obtain the circumcenters of the triangulation?:
for (Triangulation::Finite_cells_iterator it = T.finite_cells_begin(); it != T.finite_cells_end(); it++)
{
cout << it->circumcenter() << " / " << T.dual(it) << endl;
}
However, I obtain centers way too far from my initial points, so I'm doubting if this is the correct way of obtainint the circumcenters of the spheres. Any help? Thanks.
Note that the circumcenter is not necessarily inside the tetrahedron. This is especially true if you have some elements that are well shaped.
See the following 2D Delaunay Triangulation of 4 points and the corresponding circumcircles:

Numpy vs Eigen vs Xtensor Linear Algebra Benchmark Oddity

I recently was trying to compare different python and C++ matrix libraries against each other for their linear algebra performance in order to see which one(s) to use in an upcoming project. While there are multiple types of linear algebra operations, I have chosen to focus mainly on matrix inversion, as it seems to be the one giving strange results. I have written the following code below for the comparison, but am thinking I must be doing something wrong.
C++ Code
#include <iostream>
#include "eigen/Eigen/Dense"
#include <xtensor/xarray.hpp>
#include <xtensor/xio.hpp>
#include <xtensor/xview.hpp>
#include <xtensor/xrandom.hpp>
#include <xtensor-blas/xlinalg.hpp> //-lblas -llapack for cblas, -llapack -L OpenBLAS/OpenBLAS_Install/lib -l:libopenblas.a -pthread for openblas
//including accurate timer
#include <chrono>
//including vector array
#include <vector>
void basicMatrixComparisonEigen(std::vector<int> dims, int numrepeats = 1000);
void basicMatrixComparisonXtensor(std::vector<int> dims, int numrepeats = 1000);
int main()
{
std::vector<int> sizings{1, 10, 100, 1000, 10000, 100000};
basicMatrixComparisonEigen(sizings, 2);
basicMatrixComparisonXtensor(sizings,2);
return 0;
}
void basicMatrixComparisonEigen(std::vector<int> dims, int numrepeats)
{
std::chrono::high_resolution_clock::time_point t1;
std::chrono::high_resolution_clock::time_point t2;
using time = std::chrono::high_resolution_clock;
std::cout << "Timing Eigen: " << std::endl;
for (auto &dim : dims)
{
std::cout << "Scale Factor: " << dim << std::endl;
try
{
//Linear Operations
auto l = Eigen::MatrixXd::Random(dim, dim);
//Eigen Matrix inversion
t1 = time::now();
for (int i = 0; i < numrepeats; i++)
{
Eigen::MatrixXd pinv = l.completeOrthogonalDecomposition().pseudoInverse();
//note this does not come out to be identity. The inverse is wrong.
//std::cout<<l*pinv<<std::endl;
}
t2 = time::now();
std::cout << "Eigen Matrix inversion took: " << std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1).count() * 1000 / (double)numrepeats << " milliseconds." << std::endl;
std::cout << "\n\n\n";
}
catch (const std::exception &e)
{
std::cout << "Error: '" << e.what() << "'\n";
}
}
}
void basicMatrixComparisonXtensor(std::vector<int> dims, int numrepeats)
{
std::chrono::high_resolution_clock::time_point t1;
std::chrono::high_resolution_clock::time_point t2;
using time = std::chrono::high_resolution_clock;
std::cout << "Timing Xtensor: " << std::endl;
for (auto &dim : dims)
{
std::cout << "Scale Factor: " << dim << std::endl;
try
{
//Linear Operations
auto l = xt::random::randn<double>({dim, dim});
//Xtensor Matrix inversion
t1 = time::now();
for (int i = 0; i < numrepeats; i++)
{
auto inverse = xt::linalg::pinv(l);
//something is wrong here. The inverse is not actually the inverse when you multiply it out.
//std::cout << xt::linalg::dot(inverse,l) << std::endl;
}
t2 = time::now();
std::cout << "Xtensor Matrix inversion took: " << std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1).count() * 1000 / (double)numrepeats << " milliseconds." << std::endl;
std::cout << "\n\n\n";
}
catch (const std::exception &e)
{
std::cout << "Error: '" << e.what() << "'\n";
}
}
}
This is compiled with:
g++ cpp_library.cpp -O2 -llapack -L OpenBLAS/OpenBLAS_Install/lib -l:libopenblas.a -pthread -march=native -o benchmark.exe
for OpenBLAS, and
g++ cpp_library.cpp -O2 -lblas -llapack -march=native -o benchmark.exe
for cBLAS.
g++ version 9.3.0.
And for Python 3:
import numpy as np
from datetime import datetime as dt
#import timeit
start=dt.now()
l=np.random.rand(1000,1000)
for i in range(2):
result=np.linalg.inv(l)
end=dt.now()
print("Completed in: "+str((end-start)/2))
#print(np.matmul(l,result))
#print(np.dot(l,result))
#Timeit also gives similar results
I will focus on the largest decade that runs in a reasonable amount of time on my computer: 1000x1000. I know that only 2 runs introduces a bit of variance, but I've run it with more and the results are roughly the same as below:
Eigen 3.3.9: 196.804 milliseconds
Xtensor/Xtensor-blas w/ OpenBlas: 378.156 milliseconds
Numpy 1.17.4: 172.582 milliseconds
Is this a reasonable result to expect? Why are the C++ libraries slower than Numpy? All 3 packages are using some sort of Lapack/BLAS backend, yet there is a significant difference between the 3. Particularly, Xtensor will pin my CPU to 100% usage with OpenBlas' threads, yet still manage to have worse performance.
I'm wondering if the C++ libraries are actually performing the inverse/pseudoinverse of the matrix, and if this is what is causing these results. In the commented sections of the C++ test code, I have noted that when I sanity-checked the results from both Eigen and Xtensor, the resulting matrix product between the matrix and its inverse was not even close to the identity matrix. I tried with smaller matrices (10x10) thinking it might be a precision error, but the problem remained. In another test, I test for rank, and these matrices are full rank. To be sure I wasn't going crazy, I tried with inv() instead of pinv() in both cases, and the results are the same. Am I using the wrong functions for this linear algebra benchmark, or is this Numpy twisting the knife on 2 disfunctional low level libraries?
EDIT:
Thank you everyone for your interest in this problem. I think I have figured out the issue. I suspect Eigen and Xtensor have lazy evaluation and this actually is causing errors downstream, and outputting random matrices instead of the inversed matrices. I was able to correct the strange numerical inversion failure with the following replacements in the code:
auto temp = Eigen::MatrixXd::Random(dim, dim);
Eigen::MatrixXd l(dim,dim);
l=temp;
and
auto temp = xt::random::randn<double>({dim, dim});
xt::xarray<double> l =temp;
However, the timings didn't change much:
Eigen 3.3.9: 201.386 milliseconds
Xtensor/Xtensor-blas w/ OpenBlas: 337.299 milliseconds.
Numpy 1.17.4: (from before) 172.582 milliseconds
Actually, a little strangely, adding -O3 and -ffast-math actually slowed down the code a little. -march=native had the biggest performance increase for me when I tried it. Also, OpenBLAS is 2-3X faster than CBLAS for these problems.
Firstly, you are not computing same things.
To compute inverse of l matrix, use l.inverse() for Eigen and xt::linalg::inv() for xtensor
When you link Blas to Eigen or xtensor, these operations are automatically dispatched to the your choosen Blas.
I tried replacing the inverse functions, replaced auto with MatrixXd and xt::xtensor to avoid lazy evaluation, linked openblas to Eigen, xtensor and numpy and compiled with only -O3 flag, the following are the results on my Macbook pro M1:
Eigen-3.3.9 (with openblas) - ~ 38 ms
Eigen-3.3.9 (without openblas) - ~ 85 ms
xtensor-master (with openblas) - ~41 ms
Numpy- 1.21.2 (with openblas) - ~35 ms.

CGAL hole filling with color

I need to implement a 3D hole filling using CGAL library that support color.
is there any possibility to do it without CGAL library modification? I need to fill the hole with an average color of the hole's edge.
Regards, Ali
....
int main(int argc, char* argv[])
{
const char* filename = (argc > 1) ? argv[1] : "data/mech-holes-shark.off";
Mesh mesh;
OpenMesh::IO::read_mesh(mesh, filename);
// Incrementally fill the holes
unsigned int nb_holes = 0;
BOOST_FOREACH(halfedge_descriptor h, halfedges(mesh))
{
if(CGAL::is_border(h,mesh))
{
std::vector<face_descriptor> patch_facets;
std::vector<vertex_descriptor> patch_vertices;
bool success = CGAL::cpp11::get<0>(
CGAL::Polygon_mesh_processing::triangulate_refine_and_fair_hole(
mesh,
h,
std::back_inserter(patch_facets),
std::back_inserter(patch_vertices),
CGAL::Polygon_mesh_processing::parameters::vertex_point_map(get(CGAL::vertex_point, mesh)).
geom_traits(Kernel())) );
CGAL_assertion(CGAL::is_valid_polygon_mesh(mesh));
std::cout << "* FILL HOLE NUMBER " << ++nb_holes << std::endl;
std::cout << " Number of facets in constructed patch: " << patch_facets.size() << std::endl;
std::cout << " Number of vertices in constructed patch: " << patch_vertices.size() << std::endl;
std::cout << " Is fairing successful: " << success << std::endl;
}
}
CGAL_assertion(CGAL::is_valid_polygon_mesh(mesh));
OpenMesh::IO::write_mesh(mesh, "filled_OM.off");
return 0;
}
If you use CGAL::Surface_mesh as Mesh, you can use dynamic property maps to define attributes for your simplices, which allows for example to define colors per face. The "standard" syntax for this is
mesh.add_property_map<face_descriptor, CGAL::Color >("f:color")
I think. There are examples in the documentation of Surface_mesh.

Point Set Shape Detection: save planar shapes to file

Although I don't know how to write C++ I am trying to use CGAL for trying to derive building shapes from LiDAR point clouds using Point Set Shape Detection. Using the examples I can read points and normals from a file, whereupon CGAL detects shapes. The program is set to detect only planar shapes.
I would like to save the planar shapes to a file, so that I can use them in other software. But I was unable to find examples of how that can be achieved. The test program I use is based on the efficient_RANSAC_parameters.cpp code. It has a part when it iterates through all detected shapes. Could it be possible to add something there that will write the planar shapes to a file? I see the OFF format is a popular and simple way (in CGAL) to save polygons to a file, so that could be a good candidate file format.
A colleague who does know how to write C++ has helped me with this problem. He came up with the following:
while (it != shapes.end()) {
if (Plane* plane = dynamic_cast<Plane*>(it->get()))
{
std::cout << "PLANE_" << count++ << "[" << std::endl;
const std::vector<size_t> indices = it->get()->indices_of_assigned_points();
std::vector<size_t>::const_iterator iti = indices.begin();
while (iti != indices.end()) {
// Retrieves point
Point_with_normal pw = *(points.begin() + (*iti));
Kernel::Point_3 p = pw.first;
std::cout << "POINT[" << p.x() << "," << p.y() << "," << p.z() << "]" << std::endl;
// Proceeds with next point.
iti++;
}
std::cout << "]" << std::endl;
}
// Proceeds with next detected shape.
it++;
}
This block can replace loop in the efficient_RANSAC_parameters.cpp example. The output looks like this:
PLANE_0[
POINT[34.96,584.49,0.47]
POINT[34.97,585.24,0.54]
POINT[34.88,584.51,0.49]
POINT[34.98,584.75,0.49]
]
That gives me something to work with. In my case, I use sed to transform this output to SQL insert queries that allow me to transfer the data to a relational database for further processing.
In the example in the user manual you can see that once you have a plane shape object
if(Plane* plane = dynamic_cast<Plane*>(it->get())){..} you can obtain from the plane shape object a CGAL::Plane_3, from which you can obtain a point and a normal, or the coefficients of the plane.

How do I iterate through all the faces in a CGAL StraightSkeleton_2 / HalfedgeDS?

My goal is to take a polygon, find the straight skeleton, then turn each face into its own polygon.
I'm using the CGAL Create_straight_skeleton_2.cpp example as a starting point. I'm able to have it compute the skeleton and can iterate through the faces:
SsPtr iss = CGAL::create_interior_straight_skeleton_2(poly);
for( auto face = iss->faces_begin(); face != iss->faces_end(); ++face ) {
// How do I iterate through the vertexes?
}
But with a HalfedgeDSFace it looks like I can only call halfedge() for a HalfedgeDSHalfedge.
At that point I'm confused how to iterate through the vertexes in the face. Do I just treat it like a circular linked list and follow the next pointer until I get back to face->halfedge()?
Here's my first attempt at treating it like a circular linked list:
SsPtr iss = CGAL::create_interior_straight_skeleton_2(poly);
std::cout << "Faces:" << iss->size_of_faces() << std::endl;
for( auto face = iss->faces_begin(); face != iss->faces_end(); ++face ) {
std::cout << "Faces:" << iss->size_of_faces() << std::endl;
std::cout << "----" << std::endl;
do {
std::cout << edge->vertex()->point() << std::endl;
edge = edge->next();
} while (edge != face->halfedge());
}
But that seems to put an empty vertex in each face:
Faces:4
----
197.401 420.778
0 0
166.95 178.812
----
511.699 374.635
0 0
197.401 420.778
----
428.06 122.923
0 0
511.699 374.635
----
166.95 178.812
0 0
428.06 122.923
So the iteration is much as I'd expected:
// Each face
for( auto face = iss->faces_begin(); face != iss->faces_end(); ++face ) {
Ss::Halfedge_const_handle begin = face->halfedge();
Ss::Halfedge_const_handle edge = begin;
// Each vertex
do {
std::cout << edge->vertex()->point() << std::endl;
edge = edge->next();
} while (edge != begin);
}
The reason it wasn't working was the contour polygon I was using had a clockwise orientation. Once I reversed the order of the points I started getting valid data out of the faces.
For reference here's how you'd iterate over the vertexes in the contour:
// Pick a face and use the opposite edge to get on the contour.
Ss::Halfedge_const_handle begin = iss->faces_begin()->halfedge()->opposite();
Ss::Halfedge_const_handle edge = begin;
do {
std::cout << edge->vertex()->point() << std::endl;
// Iterate in the opposite direction.
edge = edge->prev();
} while (edge != begin);