weird glm::mat2x4 assignment behaviour - c++

I am trying to load freetype chars, stuff them into a texture as subimages and then render them instanced.
While most of it seems to work, right now I have a problem with storing the texture coordinates into a glm::mat2x4 matrix.
As can be seen below each character has a struct with information I right now deem necessary, including a matrix called face, which should store the texture coordinates.
But when it comes to assigning the coordinates, after leaving the loop in which it takes place, suddenly all the values go crazy, without any (wanted/ intended) operation taking place from my side.
After creating the texture atlas with freetype and putting all my structs into the map, I assign the width and height of my texture aw & ah to a storage class called c_atlas.
I calculate the texture coordinates in the loop shown below, make the glm::mat2x4 a 0.0f matrix and then stuff them into it. Couting them into the console gives the values I want.
After leaving the for loop I start another one, browsing over the matrix and cout them into the console, which gives me more or less random values in the range of e^-23 to e^32.
All of this happens in namespace foo and is called in a constructor of a class in the same namespace (sth. like this:)
foo::class::constructor()
{
call_function();
}
int main()
{
foo::class c;
c.call_function();
}
I crafted a minimum working example, but unfortunatly I am not able to replicate the error.
So I have the following loop running (a part of call_function():
namespace foo
{
namespace alphabet
{
const char path_arial[] = "res/font/consola.ttf";
class character
{
public:
glm::vec2 advance;
glm::vec2 bearing;
glm::vec2 size;
glm::vec2 offset;
glm::mat2x4 face;
};
std::map<char, character> char_map;
FT_Library m_ftlib;
FT_Face m_ftface;
GLuint m_VBO, m_VAO;
}
c_atlas ascii;
}
void foo::call_function()
{
//creating all the charactur structs with freetype and store them in the char_map
std::ofstream f("atlas_data.csv", std::ios::openmode::_S_app);
f << "letter;topleft.x;topleft.y;topright.x;topright.y;bottomright.x;bottomright.y;bottomleft.x;bottomleft.y" << std::endl;
for(auto c : alphabet::char_map)
{
std::cout << "b4: " << c.second.offset.x;
c.second.offset /= glm::vec2(aw,ah);
std::cout << "\nafter: " << c.second.offset.x << std::endl;
glm::vec2 ts = c.second.size/glm::vec2(aw,ah);
//couts the right values
uint16_t n = 0;
c.second.face = glm::mat2x4(0.0f);
for(uint16_t i = 0; i < 4; ++i)
{
std::cout << c.first << " at init:\n";
std::cout << c.second.face[0][i] << "\n";
std::cout << c.second.face[1][i] << std::endl;
}
//couts the right values
c.second.face[0][n++] = c.second.offset.x;
c.second.face[0][n++] = c.second.offset.y;
c.second.face[0][n++] = c.second.offset.x+ts.x;
c.second.face[0][n++] = c.second.offset.y;
n = 0;
c.second.face[1][n++]= c.second.offset.x+ts.x;
c.second.face[1][n++] = c.second.offset.y+ts.y;
c.second.face[1][n++] = c.second.offset.x;
c.second.face[1][n++]= c.second.offset.y+ts.y;
for(uint16_t i = 0; i < 4; ++i)
{
std::cout << c.first << " assigned:\n";
std::cout << c.second.face[0][i] << "\n";
std::cout << c.second.face[1][i] << std::endl;
}
//still couts the right values
f << (char)c.first << ";" << c.second.face[0].x << ";" << c.second.face[0].y << ";" << c.second.face[0].z << ";" << c.second.face[0].w << ";" << c.second.face[1].x << ";" << c.second.face[1].y << ";" << c.second.face[1].z << ";" << c.second.face[1].w << std::endl;
//the file also have the right values
}
f.close();
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//yet here all the values totally off track, i.e. e^32 or e^-23 (while they should all be between 0.01f - 1.0f)
for(auto i : alphabet::char_map)
{
std::cout << "\ntopleft:\n";
std::cout << "X: " << i.second.face[0].x << " | " << "Y: " << i.second.face[0].x;
std::cout << "\ntopright:\n";
std::cout << "X: " << i.second.face[0].z << " | " << "Y: " << i.second.face[0].w;
std::cout << "\nbotleft:\n";
std::cout << "X: " << i.second.face[1].x << " | " << "Y: " << i.second.face[1].x;
std::cout << "\nbotright:\n";
std::cout << "X: " << i.second.face[1].z << " | " << "Y: " << i.second.face[1].w;
}
}
my mwe:
#include <iostream>
#include <string>
#include "glm/glm.hpp"
#include "GL/gl.h"
#include <map>
struct bin
{
glm::mat2x4 mat;
};
int main( int argc, char *argv[] )
{
std::map<char, bin> bucket;
uint16_t r = 0;
for(uint16_t n = 0; n < 7; ++n)
{
glm::vec4 v = glm::vec4(0.12128f, 0.12412f, 0.15532f, 0.23453f);
bin b;
r = 0;
b.mat[0][r++] = v.x;
b.mat[0][r++] = v.y;
b.mat[0][r++] = v.z;
b.mat[0][r++] = v.w;
r = 0;
b.mat[1][r++] = v.x;
b.mat[1][r++] = v.y;
b.mat[1][r++] = v.z;
b.mat[1][r++] = v.w;
bucket[n] = b;
}
for(auto it : bucket)
{
r = 0;
std::cout << "0:\t" << it.second.mat[0][0] << "\t" << it.second.mat[0][1] << "\t" << it.second.mat[0][2] << "\t" << it.second.mat[0][3] << "\n";
r = 0;
std::cout << "1:\t" << it.second.mat[1][0] << "\t" << it.second.mat[1][1] << "\t" << it.second.mat[1][2] << "\t" << it.second.mat[1][3] << std::endl;
}
return 0;
}
Right now I am totally lost, especially as my mwe works fine.
I am clueless what goes wrong after leaving the for-loop, so thanks for any thought on that!
Indeed, I could just rewrite that section and hope it would work - as my mwe does. But I would like to find out/ get help on finding out what exactly happens between the "assign" for loop and the "retrieve" for loop. Any ideas on that?

I made it work for me now:
Appartenly assigning the values this way:
for(auto c : alphabet::char_map)
{
c.second.face[0][n++] = c.second.offset.x;
//and so on
}
Did not work properly (for whatever reason..)
Changing this into a for(uint16_t i = 32; i < 128; ++i) worked for me. Also it was just the assigning loop, the auto-iterating ofer the map elsewhere works just fine.

Related

C++//STL to OBJ Converter: How can i make my program run faster

I am creating an "STL to OBJ" format converter. The program contains a header file that reads the data from an STL file. and the main program takes that data and writes it to a new OBJ file.
everything works great but with large files the program takes so long. I know exactly which part makes the program slow and I can't find any alternative of it. It is in the part "// Create Array for the Faces" exactly in the For-Loop.
First I want to explain a bit about STL and OBJ files. In general, any 3D image in the STL format is created from a large number of triangles and each triangle has 3 vertices (each vertex has 3 points: x, y and z). But there are many repeated vertices because the triangles are connected to each other. But in the OBJ format, 2 parts are responsible for it: one is "List of Vertices" and here vertices are sorted one after another without repetition. the second part is "List of Faces" and it is the Numbers of Index of the vertices.
this is my main code:
#include "Header.h"
using namespace std;
string inputFile = "Fidgit.stl"; //Import einen STL-Datei (1.6MB)
string outputFile = "Fidgit1.obj"; //Export einen OBJ-Datei (1.1MB)
int main(int argc, char** argv)
{
auto t0 = std::chrono::system_clock::now();
std::cout << "Lesen der STL-Datei" << std::endl;
std::vector<float> coords, normals;
std::vector<unsigned int> tris, solids;
stl_reader::ReadStlFile(inputFile.c_str(), coords, normals, tris, solids);
const size_t numTris = tris.size() / 3;
std::cout << " Numbers of Triangels: " << numTris << std::endl;
auto t1 = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
std::cout << " duration: " << elapsed.count() << " ms" << std::endl;
std::cout << "writing OBJ-File" << std::endl;
std::ofstream fileOBJ(outputFile.c_str(), std::ios::out);
std::cout << " Erstelle Liste der Punkte" << std::endl;
fileOBJ << "# Object name:" << std::endl;
fileOBJ << outputFile << std::endl;
fileOBJ << std::endl;
fileOBJ << "# Begin list of vertices" << std::endl;
vector<string> AllVertex;
std::ifstream inFile(outputFile.c_str(), std::ios::in);
////////////////////////////////////////////////////////////////////////////
// Find Vertiecs coordinates and write into OBJ file
for (size_t itri = 0; itri < numTris; ++itri) {
for (size_t icorner = 0; icorner < 3; ++icorner) {
float* c = &coords[3 * tris[3 * itri + icorner]];
std::string VerStr = "v " + to_string(c[2]) + " " + to_string(c[1]) + " " + to_string(c[0]) ;
AllVertex.push_back(VerStr);
}
}
// here is a vertices containing the vertices coordinates read from the STL file.
// But there are many repeated vectors that we don't need in obj format,
// so they have to be removed by next step
vector <string> OldSTLVertex = AllVertex;
//Copy of STL vectors before removing the repeated vertices
// to be able to find the faces indexes
sort(AllteVertex.begin(), AllVertex.end());
auto last = unique(AllVertex.begin(), AllVertex.end());
AllVertex.erase(last, AllVertex.end());
vector <string> OBJVertex = AllVertex;
// here are the vectors without repetitions
// ready to be able to save the vector coordinates in the created obj file:
for (auto ind : OBJVertex)
{
fileOBJ << ind << endl;
}
fileOBJ << "# End list of vertices" << std::endl;
fileOBJ << std::endl;
auto t2 = std::chrono::system_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
std::cout << " duration: " << elapsed.count() << " ms" << std::endl;
//////////////////////////////////////////////////////////////////////////////
// Create Arry for the Faces
std::cout << " Create list of faces (triangles)" << std::endl;
vector <int> OBJFaces(numTris * 3);
fileOBJ << "# Begin list of faces" << std::endl;
int iCounter = 0;
int iPercent = 0;
int vcounter = 0;
// the point here is: which index in OBJVertiecs[] hat jeder vertiec in OldSTLVertex[]
for (int i = 0; i < OldSTLVertex.size(); i++) // in my example OldSTLVertex.size() have 99030 elements
{
bool bFound = false;
int vertexIndex = 0;
while (!bFound) // for (size_t vertexIndex = 0; vertexIndex < OBJVertex.size(); ++vertexIndex)
{
if (OldSTLVertex[i] == OBJVertex[vertexIndex]) // OBJVertex have 16523 elements
{
bFound = true;
OBJFaces[vcounter] = vertexIndex;
vcounter++;
}
vertexIndex++;
}
iCounter++;
if (iCounter % (OldSTLVertex.size() / 100) == 0) // every time 10% are done
{
iPercent = iPercent + 1;
auto t3 = std::chrono::system_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(t3 - t2);
std::cout << " " << iPercent << "% done in " << elapsed.count() << " ms" << std::endl;
}
}
/////////////////////////////////////////////////////////////////////////////
// Write faces into OBJ file
unsigned count = 0;
for (auto ind : OBJFaces)
{
if (count++ % 3 == 0) fileOBJ << "f ";
fileOBJ << ind + 1 << " ";
if (count % 3 == 0) fileOBJ << std::endl;
}
fileOBJ << "# End list of faces" << std::endl;
fileOBJ << std::endl;
auto t4 = std::chrono::system_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(t4 - t0);
std::cout << "OBJ file written in " << elapsed.count() << " ms." << std::endl;
return 0;
}
Your current code first maps all vertices in the STL to the OBJ string format of the vertex index they reference, then uses std::unique to reduce this list, then uses an O(n) lookup on each vertex to find the original index. This is O(n*m) and is very expensive if both n and m are large.
Instead, you can do the following:
Walk the elements of tris, and for each referenced vertex idx use a std::map<std::tuple<float, float, float>, unsigned int> to deduplicate them.
If it is not present, you push the coord triple to a vector obj_coords and overwrite tris[idx] with its new index.
If it was present you simply overwrite tris[idx] with the existing index.
When rendering the vectors you can almost dump obj_coords as-is.
When rendering the faces, you simply follow the indirection in coords
So, in summary:
using Coord = std::tuple<float, float, float>;
std::map<Coord, int> coordToIndex;
std::vector<Coord> obj_coords;
for (auto &idx : tris) {
const Coord c = { coords[3*idx+0], coords[3*idx+1], coords[3*idx+2] };
if (auto it = coordToIndex.find(c); it != coordToIndex.end()) {
// We saw this vertex before
idx = it->second;
} else {
// New vertex.
obj_coords.push_back(c);
idx = obj_coords.size()-1;
coordToIndex[c] = idx; // Also create an entry in coordToIndex
}
}
Then, generating vertexes is simple: (not sure why you swapped z and x though)
for (const auto& coord : obj_coords) {
fileOBJ << "v " << std::get<2>(coord) << " " << std::get<1>(coord) << " " << std::get<0>(coord) << "\n";
}
And finally, the faces:
for (int tri = 0; tri < tris.size(); tri += 3) {
fileOBJ << "f " << tris[tri+0] << " " << tris[tri+1] << " " << tris[tri+2] << "\n"
}
You may have noticed I use "\n" instead of std::endl. This is because std::endl implies std::flush, which tries to ensure that data is written to disk. Calling this is as often as you will is wasteful.
Instead, you can just flush once manually, or trust that the destructor will do it for you:
fileOBJ << std::flush;

C++ accessing class array pointer in a pointer to a structure

I am new to C++ and I really need some help on this. I am trying to create a structure to interface with the GSL Monte-Carlo algorithms (a fact that is really not important for this example). I have searched all of the C++ tutorials, the stackoverflow posts and the GSL documentation with no luck. I am using the armadillo package for matrix manipulation; it is very robust. I am unable to use a dynamic array within the structure, as per the documentation, so I am trying to find a way to make my structure variable *M point to the values in my array *L[]. I am sure that this would be better with a vector but 1) the rest of the code (in bad form) uses pointers already, and 2) I am looking at this as a learning experience. I am surprised that the addresses for *M and *L[] are not the same in my code. I am also, less importantly, surprised that my std::cout prints a different number of spaces for each line. The code exits before printing the last std::cout as shown in the output below.
Thanks for your help!
#include "pch.h"
#include "stdio.h"
#include "complex"
#include "new"
#include "armadillo"
using namespace arma;
class Link
{
public:
arma::Mat<cx_double>::fixed<3, 3>* dir[4]; // pointer to directional SU(3) matrices
Link(); // default constructor
};
Link::Link() // default constructor - all directional matrices are the identity
{
for (size_t hcount = 0; hcount < 4; hcount++)
{
dir[hcount] = new arma::Mat<cx_double>::fixed<3, 3>{ fill::eye }; // create directional matrix in direction hcount
}
}
struct Param
{
Link* M;
};
int main()
{
const int size = 10;
Param* Parameters = new Param{ NULL };
Link* L[size];
arma::Mat<cx_double>::fixed<3, 3> One{ fill::eye };
for (size_t hcount = 0; hcount < 10; hcount++)
{
L[hcount] = new Link();
*L[hcount]->dir[1] = *L[hcount]->dir[1] + hcount * One; // Make each array element #1 unique
}
Parameters->M = L[0];
std::cout << "&L = " << &L << std::endl;
std::cout << "&Parameters->M = " << &Parameters->M << std::endl; // surprised that addresses are not the same
std::cout << std::endl;
std::cout << "&L[0] = " << &L[0] << std::endl;
std::cout << "&Parameters->M[0] = " << &Parameters->M[0] << std::endl;
std::cout << std::endl;
std::cout << "&L[5] = " << &L[5] << std::endl;
std::cout << "&Parameters->M[5] = " << &Parameters->M[5] << std::endl;
std::cout << std::endl;
std::cout << "&L[5]->dir[1] = " << &L[5]->dir[1] << std::endl;
std::cout << "&Parameters->M[5].dir[1] = " << &Parameters->M[5].dir[1] << std::endl;
std::cout << std::endl;
std::cout << "*L[5]->dir[1] = " << *L[5]->dir[1] << std::endl; // This works
std::cout << "*Parameters->M[5].dir[1] = " << *Parameters->M[5].dir[1] << std::endl; // This does not
std::cout << std::endl;
}
OUTPUT
&L = 0024F7CC
&Parameters->M = 004EEFD8
&L[0] = 0024F7CC
&Parameters->M[0] = 004E0578
&L[5] = 0024F7E0
&Parameters->M[5] = 004E05C8
&L[5]->dir[1] = 004E50C4
&Parameters->M[5].dir[1] = 004E05CC
*L[5]->dir[1] = (+6.000e+00,+0.000e+00) (0,0) (0,0)
(0,0) (+6.000e+00,+0.000e+00) (0,0)
(0,0) (0,0) (+6.000e+00,+0.000e+00)
*Parameters->M[5].dir[1] =
&L is the adress of L, so it's the adress of the pointer to the first element not the adress of the first elemenr itself. Same for & Parameters->M. That is the adress of thd the Member M from Parameters. You want to compare L[0] with Parameters->M except when M should not point to the element that L[0] refers to but to the start of the array itself, then you want to compare it with L. But then you also have to change the assignment.
I find it a bit weird that you use an array of pointers. Just use an array of Links.

Handing over std::vector to function with pointer

I have been searching on Google an in this forum for a while, but I could not find any answer or tip for my problem. Tutorials couldn't help me either...
I want to redistribute some points, stored in a vector p_org. (x-value is stored as double).
Therefore I have the function distribute, which is defined in maths.h
distribute_tanh(&p_org_temp,&p_new_temp,iz,spacing[0],spacing[1],l_rot[(kk+1)*iz-2],status);
The function distribute_tanh does look like this:
inline void distribute_tanh (std::vector<double> *p_org, std::vector<double> *p_new, const int n_points, double spacing_begin, double spacing_end, const double total_length, double status){
//if status == 0: FLAP, if status == 1: SLAT
std::cout << "spacing_begin: " << spacing_begin << " spacing_end: " << spacing_end << std::endl;
double s_begin = spacing_begin / total_length;
double s_end = spacing_end / total_length;
double A = sqrt(s_end/s_begin);
double B = 1 / (sqrt(s_end*s_begin)*n_points);
std::cout << "A: " << A << " B: " << B << std::endl;
std::vector<double> u (n_points);
std::vector<double> sn (n_points);
double dx;
double dy;
std::cout << "Control at the beginning: p_org: " << (p_org) << " p_new: " << (p_new) << " n_points: " << n_points << " s_begin: " << s_begin << " s_end: " << s_end << " total_length: " << total_length << std::endl;
//problem no. 1
for (int i=0;i<n_points;i++){
if (B > 1.001) {
if (B < 2.7829681) {
double Bq=B-1;
dy=sqrt(6*Bq)*(1-0.15*Bq+0.057321429*pow(Bq,2)-0.024907295*pow(Bq,3)+0.0077424461*pow(Bq,4)-0.0010794123*pow(Bq,5));
} else if (B > 2.7829681) {
double Bv=log(B);
double Bw=1/B-0.028527431;
dy=Bv+(1+1/Bv)*log(2*Bv)-0.02041793+0.24902722*Bw+1.9496443*pow(Bw,2)-2.6294547*pow(Bw,3)+8.56795911*pow(Bw,4);
}
u[i]=0.5+(tanh(dy*(i*(1.0/n_points)-0.5))/(2*tanh(dy/2)));
}
else if (B < 0.999) {
if (B < 0.26938972) {
dx=M_PI*(1-B+pow(B,2)-(1+(pow(M_PI,2))/6)*pow(B,3)+6.794732*pow(B,4)-13.205501*pow(B,5)+11.726095*pow(B,6));
} else if (B > 0.26938972) {
double Bq=1-B;
dx=sqrt(6*Bq)*(1+0.15*Bq+0.057321429*pow(Bq,2)+0.048774238*pow(Bq,3)-0.053337753*pow(Bq,4)+0.075845134*pow(Bq,5));
}
u[i]=0.5+(tan(dx*(i*(1.0/n_points)-0.5))/(2*tan(dx/2)));
}
else {
u[i]=i*(1.0/n_points)*(1+2*(B-1)*(i*(1.0/n_points)-0.5)*(1-i*(1.0/n_points)));
}
sn[i]=u[i]/(A+(1.0-A)*u[i]);
std::cout << "sn(i): " << sn[i] << std::endl;
std::cout << "p_org[n_points]: " << &p_org[n_points-1] << std::endl;
if(status==0){
//p_new[i]=p_org[0]+(total_length*sn[i]);
std::cout << "FLAP maths.h" << std::endl;
}
//Here is the problem no. 2
else if(status==1){
//p_new[i]=p_org[0]-(total_length*sn[i]);
std::cout << "SLAT maths.h" << std::endl;
}
//std::cout << "p_new in math: " << p_new << std::endl;
}
}
My problem is, that I am unable to access the value of p_org or p_new. At the beginning I would like to give out the value of p_org and p_new. If I try it with a *, the compiler is complaining: error: no operator "<<" matches these operands
operand types are: std::basic_ostream> << std::vector>
std::cout << "Control at the beginning: p_org: " << (*p_org) << " p_new: " << (*p_new) << " n_points: " << n_points << " s_begin: " << s_begin << " s_end: " << s_end << " total_length: " << total_length << std::endl;
If I leave the * off, I get the addresses of p_org and p_new.
At the end of the code I would like to write the new value to p_new. If I use * to access the value, the compiler is complaining, if I leave it off, its complaining too with the following message:
error: no operator "-" matches these operands
operand types are: std::vector<double, std::allocator<double>> - double
p_new[i]=p_org[0]-(total_length*sn[i]);
^
I tried to understand both problems, but until now I had no success.
Thanks for your advice.
Your issue with the compiler error can be cut down to a very simple program.
#include <vector>
void foo(std::vector<int>* pV)
{
pV[0] = 10; // error.
}
int main()
{
std::vector<int> v(10);
foo(&v);
}
The issue is that operator[] as done above works for objects and references, not pointers. Since pv is a pointer, you must dereference it first to obtain the object, and then apply [] to the dereferenced pointer.
void foo(std::vector<int>* pV)
{
(*pV)[0] = 10; // No error
}
The other form of calling operator[] can be also used, but is a bit more verbose:
void foo(std::vector<int>* pV)
{
pv->operator[](0) = 10; // No error
}
However, to alleviate having to do this, pass the vector by reference. Then the "normal" way of using operator[] can be used.
#include <vector>
void foo(std::vector<int>& pV)
{
pV[0] = 10; // No error.
}
int main()
{
std::vector<int> v(10);
foo(v);
}

Histogram Formatting

I am writing a program to create a horizontal histogram from an array of type double data. I was able to get the program to display the boundaries of each sub-interval along with the correct number of asterisks. However, the data is not formatted.
Here's the part of the program responsible for the output:
// endpoints == the boundaries of each sub-interval
// frequency == the number of values which occur in a given sub-interval
for (int i = 0; i < count - 1; i++)
{
cout << setprecision(2) << fixed;
cout << endPoints[i] << " to " << endPoints[i + 1] << ": ";
for (int j = frequency[i]; j > 0; j--)
{
cout << "*";
}
cout << " (" << frequency[i] << ")" << endl;
}
Here's what my output looks like:
0.00 to 3.90: *** (3)
3.90 to 7.80: * (1)
7.80 to 11.70: * (1)
11.70 to 15.60: (0)
15.60 to 19.50: ***** (5)
Here's what I would like it to look like:
00.00 to 04.00: *** (3)
04.00 to 08.00: * (1)
08.00 to 12.00: * (1)
12.00 to 16.00: (0)
16.00 to 20.00: ****** (6)
I've looked up C++ syntax and have found things like setw() and setprecision(). I tried to use both to format my histogram but have not been able to make it look like the model. I was hoping someone could tell me if I'm on the right track and, if so, how to implement setw() and/or setprecision() to properly format my histogram.
Assuming that all numbers are in the [0,100) interval, what you want is a chain of manipulators like:
#include <iostream>
#include <iomanip>
int main() {
std::cout
<< std::setfill('0') << std::setw(5)
<< std::setprecision(2) << std::fixed
<< 2.0
<< std::endl;
return 0;
}
Which will output:
02.00
This is for a single value, you can easily adapt it to suit your needs.
You could, for instance, turn this into an operator and use it like:
#include <iostream>
#include <iomanip>
class FixedDouble {
public:
FixedDouble(double v): value(v) {}
const double value;
}
std::ostream & operator<< (std::ostream & stream, const FixedDouble &number) {
stream
<< std::setfill('0') << std::setw(5)
<< std::setprecision(2) << std::fixed
<< number.value
<< std::endl;
return stream;
}
int main() {
//...
for (int i = 0; i < count - 1; i++) {
std::cout
<< FixedDouble(endPoints[i])
<< " to "
<< FixedDouble(endPoints[i + 1])
<< ": ";
}
for (int j = frequency[i]; j > 0; j--) {
std::cout << "*";
}
std::cout << " (" << frequency[i] << ")" << std::endl;
//...
}

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();
}