[cgal]; 3D Delaunay Triangulation - cgal

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:

Related

Constrained Delaunay with Info

I have this setup:
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef CGAL::Triangulation_vertex_base_with_info_2<FIntPoint, K> Vb;
typedef CGAL::Constrained_triangulation_face_base_2<K> Fb;
typedef CGAL::Triangulation_data_structure_2<Vb, Fb> Tds;
typedef CGAL::Exact_predicates_tag Itag;
typedef CGAL::Constrained_Delaunay_triangulation_2<K, Tds, Itag> Delaunay;
typedef Delaunay::Point Point;
typedef Delaunay::Vertex_handle VertexHandle;
FIntPoint is a struct with 2 integers.
My vertices belong to border triangles of 2 separate terrain-like 3D meshes. I triangulate these vertices in 2D to connect these meshes. The info I need for each vertex is (1) which mesh it belongs to and (2) its vertex index within that mesh, so that I know where this vertex came from after triangulation, as more information is tied to these indices.
In this illustration, you can see the 2 meshes and their border triangles. I want to stitch these together:
This is basically how I insert points, simplified:
Delaunay Triangulation;
for (...)
{
// Insert a triangle from one of my meshes
VertexHandle vh1 = Triangulation.insert(Point(a.Y, a.Z));
vh1->info() = FIntPoint(iA, iM);
VertexHandle vh2 = Triangulation.insert(Point(b.Y, b.Z));
vh2->info() = FIntPoint(iB, iM);
VertexHandle vh3 = Triangulation.insert(Point(c.Y, c.Z));
vh3->info() = FIntPoint(iC, iM);
// Add constraints to keep this triangle exactly how it was in the origin mesh
Triangulation.insert_constraint(vh1, vh2);
Triangulation.insert_constraint(vh2, vh3);
Triangulation.insert_constraint(vh3, vh1);
}
My problem now is that when I try to retrieve the info, it is missing/incorrect. I get values outside of the range I'm inserting them.
This happens only with the constraints. When I comment out the lines with insert_constraint, it works as expected.
for (auto itFace = Triangulation.finite_faces_begin(); itFace != Triangulation.finite_faces_end(); itFace++)
{
// Retrieve vertex info
auto& a = itFace->vertex(0)->info();
auto& b = itFace->vertex(1)->info();
auto& c = itFace->vertex(2)->info();
// ...
}
What am I doing wrong with the constraints?
Additionally, I want to limit the length of edges. I haven't attempted so add this limitation in my code yet, because I wanted to fix the described problem first. If you could provide an answer that includes a maximum edge length, that would be very helpful too.
Any help is appreciated. I've been sitting on this problem for a long time.

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.

Custom Delaunay Refinement with CGAL Delaunay3D

I want to perform a custom refinement strategy in a tetrahedral mesh.My input is a point cloud and I have tetrahedralized it using Delaunay 3D routine available in CGAL. The points have scalar values associated with it. Now I want to refine the tetrahedral mesh with this following strategy:
1. Get the maximum value among the vertices of each tetrahedra.
2. Get the value at the point that is going to be inserted (May be barycentre, weighted centroid or circumcenter).
3. If the difference is large enough add this point.
Any idea how to do this effectively? Note: I do not require 0-1 dimensional feature preservation.
I have already tried the above strategy. Let me show what I have done so far.
// Assume T is Delaunay_3D triangulation CGAL mesh and I have an oracle f that tells me what is the value at the point that is going to be inserted if conditions are met.
bool updated = true;
int it = 0;
while (updated)
{
updated = false;
std::vector<std::pair<Point, unsigned> > point_to_be_inserted;
for (auto cit = T.finite_cells_begin(); cit != T.finite_cells_end(); cit++)
{
Cell_handle c = cit;
Point v = Maximum valued vertex
Point q = Point that is going to be inserted
double val_at_new_pt = oracle(q, &pts, var);
double ratio = std::abs(max_val - val_at_new_pt) / max_val;
if (ratio > threshold) {
point_to_be_inserted.emplace_back(std::make_pair(q, new_pt_ind));
updated = true;
}
}
if (updated)
{
std::cout << "Total pts inserted in it: " << it << " " << point_to_be_inserted.size() << std::endl;
T.insert(point_to_be_inserted.begin(), point_to_be_inserted.end())
}
}
The problem is it is quite slow (each time iterating through all the cells). I am not finding any effective strategy to do the refinement locally. I tried using a queue but the cell_handles are getting messed up after I perform one iteration of refinement. I cannot have a map that tells me whether the tetrahedra is refined or not because each time after insertion of new points cell_handles are getting created. Any help will be appreciated. Thanks in advance.

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

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.

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.