Wrong inexact intersection between 3D triangles (CGAL) - c++

I'm having a really weird bug when trying to intersect two triangles inside a 3D space while using the CGAL::Exact_predicates_inexact_constructions_kernel kernel. Essentially, I have two triangles that should not intersect. The function CGAL::do_intersect returns always false when testing them, but the function CGAL::intersection builds an intersection, depending on the order of the vertices of the triangles.
The bug disappears when I use the CGAL::Exact_predicates_exact_constructions_kernel kernel, but I can't afford to use it in the real case scenario.
Below is a minimal code with the bug. Triangles B and C are equal (up to a permutation of the vertices), and should return the same intersection with Triangle A.
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Intersections.h>
#include <iostream>
#include <vector>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point_3;
typedef Kernel::Triangle_3 Triangle_3;
int main(int argc, char *argv[])
{
std::vector<Point_3> APoints(3);
std::vector<Point_3> BPoints(3);
APoints[0] = Point_3(2, 2, 0.9423616295572568);
APoints[1] = Point_3(0.9685134704003172, 2, 0.9678422992674797);
APoints[2] = Point_3(2, 1.124710354419025, 1.068692504586136);
BPoints[0] = Point_3(2.5, 2.5, 1.442361629557257);
BPoints[1] = Point_3(1.588259113885977, 2.5, 0.5);
BPoints[2] = Point_3(2.5, 1.624710354419025, 1.568692504586136);
Triangle_3 TriangleA(APoints[0],APoints[1],APoints[2]);
Triangle_3 TriangleB(BPoints[0],BPoints[1],BPoints[2]);
Triangle_3 TriangleC(BPoints[2],BPoints[1],BPoints[0]);
std::cout.precision(16);
std::cout << " - Tried to intersect: " << std::endl;
std::cout << " - Triangle (A) " << " : "
<< "(" << TriangleA.vertex(0) << ") "
<< "(" << TriangleA.vertex(1) << ") "
<< "(" << TriangleA.vertex(2) << ") " << std::endl;
std::cout << " - Triangle (B) " << " : "
<< "(" << TriangleB.vertex(0) << ") "
<< "(" << TriangleB.vertex(1) << ") "
<< "(" << TriangleB.vertex(2) << ") " << std::endl;
std::cout << " - Triangle (C) " << " : "
<< "(" << TriangleC.vertex(0) << ") "
<< "(" << TriangleC.vertex(1) << ") "
<< "(" << TriangleC.vertex(2) << ") " << std::endl;
if( TriangleB.vertex(0)==TriangleC.vertex(2) &&
TriangleB.vertex(1)==TriangleC.vertex(1) &&
TriangleB.vertex(2)==TriangleC.vertex(0))
{
std::cout << " - Triangles (B) and (C) have the same vertices " << std::endl;
}
bool bIntersectAB = CGAL::do_intersect(TriangleA,TriangleB);
bool bIntersectAC = CGAL::do_intersect(TriangleA,TriangleC);
bool bIntersectInexactAB = CGAL::intersection(TriangleA,TriangleB);
bool bIntersectInexactAC = CGAL::intersection(TriangleA,TriangleC);
if(bIntersectAB)
{
std::cout << " --> A and B are intersecting (exact) ..." << std::endl;
}
if(bIntersectAC)
{
std::cout << " --> A and C are intersecting (exact) ..." << std::endl;
}
if(bIntersectInexactAB)
{
std::cout << " --> A and B are intersecting (inexact) ..." << std::endl;
}
if(bIntersectInexactAC)
{
std::cout << " --> A and C are intersecting (inexact) ..." << std::endl;
}
return 0;
}
Here's the output ...
- Tried to intersect:
- Triangle (A) : (2 2 0.9423616295572568) (0.9685134704003172 2 0.9678422992674797) (2 1.124710354419025 1.068692504586136)
- Triangle (B) : (2.5 2.5 1.442361629557257) (1.588259113885977 2.5 0.5) (2.5 1.624710354419025 1.568692504586136)
- Triangle (C) : (2.5 1.624710354419025 1.568692504586136) (1.588259113885977 2.5 0.5) (2.5 2.5 1.442361629557257)
- Triangles (B) and (C) have the same vertices
--> A and C are intersecting (inexact) ...
... and a figure with the two triangles (A: vertices 1, 2, 3 ; B: vertices 11,12,13) and the "intersection" (segment 21 - 22), found using a similar version of this program.
What could be wrong? I'm using CGAL 4.6.1 on OS X 10.10.5 (Yosemite). Thanks in advance!

I've also sent this question to CGAL's mailing list, and the developers answered that this behaviour is not a bug, although
it is unfortunate. intersection is a generic function, implemented the same way for all CGAL kernels, and it uses one step that is not always handled correctly by inexact kernels - hence the intersection error. According to this thread at CGAL's GitHub page,
In order to keep using a kernel with inexact constructions, I usually advice to first call the do_intersect predicate and then call the intersection function using EPECK on primitives converted on the fly using CGAL::Cartesian_converter. You'll have to convert the output using another CGAL::Cartesian_converter. The call to do_intersect is not mandatory, it usually depends on your setting.

Related

Out of bounds index returns correct values from vector created in chibi scheme

I've embedded chibi scheme into my C++ application and am trying to create a float vector with a size of 3 in scheme, and then get the individual values of that vector back into my c++ program, however when I attempt to do so I only get the correct results if I use indexes beyond the size of the vector. As you can see below I verify the size of the vector.
test.scm
(define (test-vec in-a in-b)
(let ((vec (vector (* 3.1 in-a) (* 4.1 in-b) 5.0)))
(display "From Scheme: ")
(display vec)
(display "\n")
vec))
test.cpp
#include <iostream>
#include <chibi/eval.h>
int is_defined(sexp ctx, const char *sym)
{
sexp_gc_var1(ret);
sexp_gc_preserve1(ctx, ret);
ret = sexp_eval_string(ctx, sym, -1, NULL);
int defined = sexp_procedurep(ret);
sexp_gc_release1(ctx);
return defined;
}
int main()
{
float returnA, returnB, returnC, returnD, returnE, returnF;
sexp_scheme_init();
sexp ctx = sexp_make_eval_context(NULL, NULL, NULL, 0, 0);
sexp_load_standard_env(ctx, NULL, SEXP_SEVEN);
sexp_load_standard_ports(ctx, NULL, stdin, stdout, stderr, 1);
// Load the scheme file and create temp variables to pass the values to chibi
sexp_gc_var6(inAVal, inASym, inBVal, inBSym, returnedVector, filePath);
sexp_gc_preserve6(ctx, inAVal, inASym, inBVal, inBSym, returnedVector, filePath);
filePath = sexp_c_string(ctx, "test.scm", -1);
sexp_load(ctx, filePath, NULL);
// Ensure our procedure is defined
if(is_defined(ctx, "test-vec"))
std::cout << "test-vec is defined" << std::endl;
// Create the values and create the symbols
inAVal = sexp_make_flonum(ctx, 1.0);
inASym = sexp_intern(ctx, "a", -1);
inBVal = sexp_make_flonum(ctx, 2.0);
inBSym = sexp_intern(ctx, "b", -1);
// Bind the values to the symbols and pass them to chibi
sexp_env_define(ctx, sexp_context_env(ctx), inASym, inAVal);
sexp_env_define(ctx, sexp_context_env(ctx), inBSym, inBVal);
// Evaluate the expression and store the result
returnedVector = sexp_eval_string(ctx, "(test-vec a b)", -1, NULL);
std::cout << "Vector size: " << sexp_vector_length(returnedVector) << std::endl;
// I would expect this to return the expected results?
returnA = sexp_flonum_value(sexp_vector_ref(returnedVector, 0));
returnB = sexp_flonum_value(sexp_vector_ref(returnedVector, 1));
returnC = sexp_flonum_value(sexp_vector_ref(returnedVector, 2));
std::cout << "Vector[0] = " << returnA << "\nVector[1] = " << returnB << "\nVector[2] = " << returnC << std::endl << std::endl;
// If I index outside of the range of the vector, it gives me the correct results?
returnD = sexp_flonum_value(sexp_vector_ref(returnedVector, 0));
returnE = sexp_flonum_value(sexp_vector_ref(returnedVector, 3));
returnF = sexp_flonum_value(sexp_vector_ref(returnedVector, 4));
std::cout << "Vector[0] = " << returnD << "\nVector[3] = " << returnE << "\nVector[4] = " << returnF << std::endl;
sexp_gc_release6(ctx);
}
Which gives me the output:
test-vec is defined
From Scheme: #(3.1 8.2 5.0)
Vector size: 3
Vector[0] = 3.1
Vector[1] = 3.1
Vector[2] = 8.2
Vector[0] = 3.1
Vector[3] = 8.2
Vector[4] = 5
How come indexing beyond the length of the vector is giving me the correct values?
Figured out the issue. It's because sexp_vector_ref(vec, i) evaluates to
#define sexp_vector_ref(x,i) (sexp_vector_data(x)[sexp_unbox_fixnum(i)])
and sexp_unbox_fixnum(i) evaluates to
#define sexp_unbox_fixnum(n) (((sexp_sint_t)((sexp_uint_t)(n) & ~SEXP_FIXNUM_TAG))/(sexp_sint_t)((sexp_sint_t)1<<SEXP_FIXNUM_BITS))
Which when we just pass in straight integers
std::cout << "Unboxed fixnums: " <<
sexp_unbox_fixnum(0) << " " <<
sexp_unbox_fixnum(1) << " " <<
sexp_unbox_fixnum(2) << " " <<
sexp_unbox_fixnum(3) << " " <<
sexp_unbox_fixnum(4) << std::endl;
gives us the output
Unboxed fixnums: 0 0 1 1 2
However if we first convert them into the proper types that chibi expects, like so
std::cout << "Fixnum: " <<
sexp_unbox_fixnum(sexp_make_fixnum(0)) << " " <<
sexp_unbox_fixnum(sexp_make_fixnum(1)) << " " <<
sexp_unbox_fixnum(sexp_make_fixnum(2)) << " " <<
sexp_unbox_fixnum(sexp_make_fixnum(3)) << " " <<
sexp_unbox_fixnum(sexp_make_fixnum(4)) << std::endl;
we get the proper output
Fixnum: 0 1 2 3 4
Solution: Use the correct types when indexing

How to ignore certain input lines in C++?

Okay so a little background this code is supposed to read through a file containing DNA and calculate the number of nucleotides A, C, T, G and print them out and also do some other slight calculations. My code runs fine for most files except for files that contain lines that start with # and + in the file. I need to skip those lines in order to get an accurate number. So my question is how to skip or ignore these lines in my calculations.
My code is
#include <iostream>
#include <stream>
#include <string>
#include <vector>
#include <map>
int main(int argc, char** argv) {
// Ignore how the above argc and argv are used here
auto arguments = std::vector<std::string>(argv, argv + argc);
// "arguments" box has what you wrote on the right side after &&
if (arguments.size() != 2) {
// ensure you wrote a file name after "./a.out"
std::cout << "Please give a file name as argument\n";
return 1;
}
auto file = std::fstream(arguments[1]);
if (!file) {
// ensure the file name you gave is from the available files
std::cout << "Cannot open " << arguments[1] << "\n";
return 1;
}
auto counts = std::map<char,int>({{'G',0.0},{'A',0.0},{'C',0.0},{'T',0.0}});
// Just a test loop to print all lines from the file
for (auto dna = std::string(); std::getline(file, dna); ) {
//std::cout << dna << "\n";
for (auto nucleotide:dna) {
counts[nucleotide]=counts[nucleotide] + 1;
}
}
double total = counts['A'] + counts['T'] + counts['G'] + counts['C'];
double GC = (counts['G'] + counts['C'])*100/total;
double AT = (counts['A'] + counts['T'])*100/total;
double ratio = AT/GC;
auto classification = "";
if ( 40.0 < GC < 60.0) {
classification = "moderate GC content";
}
if (60 <= GC) {
classification = "high GC content";
}
if (GC <= 40.0) {
classification = "low GC content";
}
std::cout << "GC-content: " << GC << "\n";
std::cout << "AT-content: " << AT << "\n";
std::cout << "G count: " << counts['G'] << "\n";
std::cout << "C count: " << counts['C'] << "\n";
std::cout << "A count: " << counts['A'] << "\n";
std::cout << "T count: " << counts['T'] << "\n";
std::cout << "Total count: " << total << "\n";
std::cout << "AT/GC Ratio: " << ratio << "\n";
std::cout << "GC Classification: " << classification << "\n";
}
The file that is giving me trouble is this which is like this
#ERR034677.1 HWI-EAS349_0046:7:1:2144:972#0 length=76
NGATGATAAACAAGAGGGTAAAAAGAAAAAAGCTACAGACATTTCTGCTAATCTATTATTTTGTTCCTTTTTTTTT
+ERR034677.1 HWI-EAS349_0046:7:1:2144:972#0 length=76
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
If anyone can help me with this. I will be very grateful. I only need a hint or an idea of the concept I am missing so I can make my code compatible with all files. Thanks in advance
Your actual problem seems to be the standard case of "input is not always clean syntax".
The solution is always "do not expect clean syntax".
First read whole lines into a buffer.
Then check for syntax.
Skip broken syntax.
Scan clean syntax from buffer.

C++ virtual inheritance with abstract class for basic implementation of some math functions

I have troubles with homework. The task is to implement files included in main.cpp so the program will work. main.cpp is the file we get from our teacher - we can't make any changes in it. At the end of it there is written a desired output. (note: there shouldn't be any overloaded operators).
This is what I did so far: https://wandbox.org/permlink/ffzkdaVoYK8Qovic
I can't get it to work properly. I don't know what I am doing wrong:
There must be some error with Differential. Teacher said that we don't need to use clone() method in it - so I didn't - but when I do, in constructor instead of setF, I'm getting segmentation fault. The same happens in function in(), when I'm trying to return the result according to the formula - and I don't get why it happens.
I get -5 instead of 5 (see output below main.cpp). Some math error? I can't spot it.
I have a feeling my class hierarchy is really bad. What should it be instead? (Guessing from the lecture there should be virtual inheritance, multiple inheritance and a solution to diamond problem - but well, that's just my guess.) I'm also getting some warnings when compiling and I didn't fix them because I think I just did the hierarchy wrong and if I fix it the problem will be gone.
In general, what can I fix in my code to make it better?
Here is main.cpp (it's also in the link to my solution):
#include "Fun.h"
#include "Elementary.h"
#include "Compound.h"
#include "Differential.h"
#include <iostream>
int main()
{
std::cout << "=====-===== 2 =====-=====" << std::endl;
Fun * lfun = Linear::create()->a(2.)->b(-1.); // This is ax + b = 2x-1
Fun * sfun = new Sinus;
std::cout << lfun->value(0.1) << " " << lfun->value(0) << std::endl;
std::cout << sfun->value(0.1) << " " << sfun->value(0) << std::endl;
std::cout << "=====-===== 2 =====-=====" << std::endl;
Fun * qbase = Quadratic::create()->a(1)->b(0.)->c(-4.);
Fun * qfun = qbase->clone(); // Cloning
std::cout << qbase->value(0.1) << " " << qbase->value(0) << std::endl;
std::cout << qfun->value(0.1) << " " << qfun->value(0) << std::endl;
delete qbase;
std::cout << qfun->value(0.1) << " " << qfun->value(0) << std::endl;
std::cout << "=====-===== 2 =====-=====" << std::endl;
Differential diff(0.01); // 0.01 is h
std::cout << "value of differential from lfun in 1.0 = " << diff.from(lfun)->in(1) << std::endl;
std::cout << "value of differential from qfun in 2.1 = " << diff.from(qfun)->in(2.1) << std::endl;
std::cout << "value of differential from sfun in 0.12 = " << diff.from(sfun)->in(0.12) << std::endl;
std::cout << "=====-===== 1 =====-=====" << std::endl;
Fun* comp = new Compound(lfun, qfun);
std::cout << "value of compound function " << comp->value(2) << std::endl; // Result from: qfun( lfun( 2 ) )
delete lfun;
delete qfun;
delete sfun;
std::cout << "=====-===== 1 =====-=====" << std::endl;
std::cout << "Compound func still works: " << comp->value(2) << std::endl;
delete comp;
}
/*********************************** OUTPUT ************************************
--------------------------------------------------------------------------------
=====-===== 2 =====-=====
-0.8 -1
0.0998334 0
=====-===== 2 =====-=====
-3.99 -4
-3.99 -4
-3.99 -4
=====-===== 2 =====-=====
value of differential from lfun in 1.0 = 2
value of differential from qfun in 2.1 = 4.2
value of differential from sfun in 0.12 = 0.992792
=====-===== 1 =====-=====
value of compound function 5
=====-===== 1 =====-=====
Compound func still works: 5
--------------------------------------------------------------------------------
*******************************************************************************/

Need my output to be in this form XXX.XXX c++

for example im getting an area of 6 for a triangle, i need my output to show 006.000
i know setprecision will do the trick for limiting the decimal places to three but how do i place zeros in front of my solutions?
this is what i have
CTriangle Sides(3,4,5);
cout << std::fixed << std::setprecision(3);
cout << "\n\n\t\tThe perimeter of this tringle is = " << Sides.Perimeter();
cout << "\n\n\t\tThe area of the triangle is = " << Sides.Area();
cout << "\n\n\t\tThe angle one is = " << Sides.Angleone();
cout << "\n\n\t\tThe angle two is = " << Sides.Angletwo();
cout << "\n\n\t\tThe angle three is = " << Sides.Anglethree();
cout << "\n\n\t\tThe altitude one of the triangle = " << Sides.Altitudeone();
cout << "\n\n\t\tThe altitude two of the triangle = " << Sides.Altitudetwo();
cout << "\n\n\t\tThe altitude three of the triangle = " << Sides.Altitudethree();
with the output being
The perimeter of this triangle is = 12.000
The area of the triangle is = 6.000
The angle one is = 90.000
The angle two is = 36.870
The angle three is = 53.130
The altitude one of the triangle = 2.400
The altitude two of the triangle = 6.667
The altitude three of the triangle = 3.750
but i need all the answers to be in this form XXX.XXX regardless of what my solutions are.(because the values will change)
any help is appreciated, thanks!
Use can use padding and filling manipulators:
std::setfill('0'); // is persistent
//...
cout << std::setw(7) << value; // required for each output
Using std::internal, std::fixed, std::setfill, std::setw and std::setprecision from iomanip and related headers, you can do:
std::cout << std::fixed << std::setfill('0') << std::internal << std::setprecision(3);
std::cout << std::setw(7);
std::cout << 12.34f << "\n";
and get the desired output. See it live on Coliru!
See "format": String and I/O Formatting (Modern C++)
The printf function can do that for you have a look at the docs:
http://www.cplusplus.com/reference/cstdio/printf/
Your case is somewhat unique because:
(these are not complete code snippets, apologies)
precision only applies to floating point formatting:
$ printf("%03.3f\n", 6)
> 6.000
And left padding only applies to integer formatting:
$ printf("%03.3d\n", 6)
> 006
Good luck hopefully you can take it from here

saving CGAL alpha shape surface mesh

I have never used CGAL and have got almost no C/C++ experience. But following
Google I have however managed to compile the example "Alpha_shapes_3"
(\CGAL-4.1-beta1\examples\Alpha_shapes_3) on a Windows 7 64bit machine using
visual studio 2010.
Now if we check the source code for the program "ex_alpha_shapes_3" we
notice that a data file called "bunny_1000" is red where the 3d point
cluster resides.
Now my question is how can I change the source code so that after the alpha
shape is computed for the given points, surface mesh of the alpha shape is
saved/wrote in an external file. It can be simply the list of polygons and
their respective 3D vertices. I guess these polygons will be defining the
surface mesh of the alpha shape. If I can do that I can see the output of
the alpha shape generation program in an external tool I am familiar with.
I know this is very straightforward but I could not figure this out with my
limited knowledge of CGAL.
I know you gueys have the code but I am pasting it again for completion.
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Alpha_shape_3.h>
#include <fstream>
#include <list>
#include <cassert>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Gt;
typedef CGAL::Alpha_shape_vertex_base_3<Gt> Vb;
typedef CGAL::Alpha_shape_cell_base_3<Gt> Fb;
typedef CGAL::Triangulation_data_structure_3<Vb,Fb> Tds;
typedef CGAL::Delaunay_triangulation_3<Gt,Tds> Triangulation_3;
typedef CGAL::Alpha_shape_3<Triangulation_3> Alpha_shape_3;
typedef Gt::Point_3 Point;
typedef Alpha_shape_3::Alpha_iterator Alpha_iterator;
int main()
{
std::list<Point> lp;
//read input
std::ifstream is("./data/bunny_1000");
int n;
is >> n;
std::cout << "Reading " << n << " points " << std::endl;
Point p;
for( ; n>0 ; n--) {
is >> p;
lp.push_back(p);
}
// compute alpha shape
Alpha_shape_3 as(lp.begin(),lp.end());
std::cout << "Alpha shape computed in REGULARIZED mode by default"
<< std::endl;
// find optimal alpha value
Alpha_iterator opt = as.find_optimal_alpha(1);
std::cout << "Optimal alpha value to get one connected component is "
<< *opt << std::endl;
as.set_alpha(*opt);
assert(as.number_of_solid_components() == 1);
return 0;
}
After searching a lot in the internet I found that probably we need to use something like
std::list<Facet> facets;
alpha_shape.get_alpha_shape_facets
(
std::back_inserter(facets),Alpha_shape::REGULAR
);
But I am still completely clueless how to use this in the above code!
As documented here, a facet is a pair (Cell_handle c,int i) defined as the facet in c opposite to the vertex of index i.
On this page, you have the description of how the vertex indices of a cell are.
In the following code sample, I added a small output that prints an OFF file on cout by duplicating the vertices. To do something clean, you can either use a std::map<Alpha_shape_3::Vertex_handle,int> to associate a unique index per vertex or add an info to the vertices like in those examples.
/// collect all regular facets
std::vector<Alpha_shape_3::Facet> facets;
as.get_alpha_shape_facets(std::back_inserter(facets), Alpha_shape_3::REGULAR);
std::stringstream pts;
std::stringstream ind;
std::size_t nbf=facets.size();
for (std::size_t i=0;i<nbf;++i)
{
//To have a consistent orientation of the facet, always consider an exterior cell
if ( as.classify( facets[i].first )!=Alpha_shape_3::EXTERIOR )
facets[i]=as.mirror_facet( facets[i] );
CGAL_assertion( as.classify( facets[i].first )==Alpha_shape_3::EXTERIOR );
int indices[3]={
(facets[i].second+1)%4,
(facets[i].second+2)%4,
(facets[i].second+3)%4,
};
/// according to the encoding of vertex indices, this is needed to get
/// a consistent orienation
if ( facets[i].second%2==0 ) std::swap(indices[0], indices[1]);
pts <<
facets[i].first->vertex(indices[0])->point() << "\n" <<
facets[i].first->vertex(indices[1])->point() << "\n" <<
facets[i].first->vertex(indices[2])->point() << "\n";
ind << "3 " << 3*i << " " << 3*i+1 << " " << 3*i+2 << "\n";
}
std::cout << "OFF "<< 3*nbf << " " << nbf << " 0\n";
std::cout << pts.str();
std::cout << ind.str();
Here is my code, which outputs vtk file for visualization in Paraview. Comparing with slorior's solutions, no duplicated points are saved in the file. But my code is just for the visualization, if you need to figure out the exterior or interior simplexes, you should modify the code to get these results.
void writevtk(Alpha_shape_3 &as, const std::string &asfile) {
// http://cgal-discuss.949826.n4.nabble.com/Help-with-filtration-and-filtration-with-alpha-values-td4659524.html#a4659549
std::cout << "Information of the Alpha_Complex:\n";
std::vector<Alpha_shape_3::Cell_handle> cells;
std::vector<Alpha_shape_3::Facet> facets;
std::vector<Alpha_shape_3::Edge> edges;
// tetrahedron = cell, they should be the interior, it is inside the 3D space
as.get_alpha_shape_cells(std::back_inserter(cells), Alpha_shape_3::INTERIOR);
// triangles
// for the visualiization, don't need regular because tetrahedron will show it
//as.get_alpha_shape_facets(std::back_inserter(facets), Alpha_shape_3::REGULAR);
as.get_alpha_shape_facets(std::back_inserter(facets), Alpha_shape_3::SINGULAR);
// edges
as.get_alpha_shape_edges(std::back_inserter(edges), Alpha_shape_3::SINGULAR);
std::cout << "The alpha-complex has : " << std::endl;
std::cout << cells.size() << " cells as tetrahedrons" << std::endl;
std::cout << facets.size() << " triangles" << std::endl;
std::cout << edges.size() << " edges" << std::endl;
size_t tetra_num, tri_num, edge_num;
tetra_num = cells.size();
tri_num = facets.size();
edge_num = edges.size();
// vertices: points <-> id
std::map<Point, size_t> points;
size_t index = 0;
// finite_.. is from DT class
for (auto v_it = as.finite_vertices_begin(); v_it != as.finite_vertices_end(); v_it++) {
points[v_it->point()] = index;
index++;
}
// write
std::ofstream of(asfile);
of << "# vtk DataFile Version 2.0\n\nASCII\nDATASET UNSTRUCTURED_GRID\n\n";
of << "POINTS " << index << " float\n";
for (auto v_it = as.finite_vertices_begin(); v_it != as.finite_vertices_end(); v_it++) {
of << v_it->point() << std::endl;
}
of << std::endl;
of << "CELLS " << tetra_num + tri_num + edge_num << " " << 5 * tetra_num + 4 * tri_num + 3 * edge_num << std::endl;
for (auto cell:cells) {
size_t v0 = points.find(cell->vertex(0)->point())->second;
size_t v1 = points.find(cell->vertex(1)->point())->second;
size_t v2 = points.find(cell->vertex(2)->point())->second;
size_t v3 = points.find(cell->vertex(3)->point())->second;
of << "4 " << v0 << " " << v1 << " " << v2 << " " << v3 << std::endl;
}
// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#ad6a20b45e66dfb690bfcdb8438e9fcae
for (auto tri_it = facets.begin(); tri_it != facets.end(); ++tri_it) {
of << "3 ";
auto tmp_tetra = tri_it->first;
for (int i = 0; i < 4; i++) {
if (i != tri_it->second) {
of << points.find(tmp_tetra->vertex(i)->point())->second << " ";
}
}
of << std::endl;
}
// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#af31db7673a6d7d28c0bb90a3115ac695
for (auto e : edges) {
of << "2 ";
auto tmp_tetra = e.get<0>();
int p1, p2;
p1 = e.get<1>();
p2 = e.get<2>();
of << points.find(tmp_tetra->vertex(p1)->point())->second << " "
<< points.find(tmp_tetra->vertex(p2)->point())->second << std::endl;
}
of << std::endl;
of << "CELL_TYPES " << tetra_num + tri_num + edge_num << std::endl;
for (int i = 0; i < tetra_num; i++) {
of << "10 ";
}
for (int i = 0; i < tri_num; i++) {
of << "5 ";
}
for (int i = 0; i < edge_num; i++) {
of << "3 ";
}
of << std::endl;
of.close();
}