#include #include // std::stringstream #include #include #include using namespace std; // génération d'un fichier ply contenant un modèle d'un(e) cube (éponge) // de sierpinski, au format ply. // compilation : g++ -std=c++11 -o gcs gencubesierpinski.cpp // syntaxe : ./gcs -l niveau-de-subdivision -s taille_du_cube // représentation des option pour la génération struct options { int niveau; // niveau de subdivision 1 = pas de subdivision) int taille; // taille du cube, qui est centré à l'origine }; // représentation d'un point 3D, avec sa normale struct point { float x, y, z; float nx, ny, nz; point(float x, float y, float z, float nx, float ny, float nz) : x(x), y(y), z(z), nx(nx), ny(ny), nz(nz){ } }; // varibales globales vector sommets; // liste des sommets générés vector faces; // liste des faces générées // prédéfinition des fonctions void toPly(const string & filename); bool parse_args(int argc, char *argv[], options &opt); void writeBinary(ofstream & out, float v, bool littleEndian); void writeBinary(ofstream & out, int v, bool littleEndian); void usage(const string &exe); // ajout d'une face à laliste des faces // la face est donnée par les indices de ses 4 sommets successifs // dans la liste des sommets inline void add_face(int i, int j, int k, int l){ faces.push_back(i); faces.push_back(j); faces.push_back(k); faces.push_back(l); } // génération d'un cube // (x,y,z) représente les coordonnées du coin ayant le plus "petit" // d représente la taille du cube // n représente le niveau de subdivision restant à accomplir // (si n = 1, plus de subdivisions) // la subdivisin est faite en découpant le cube en 3 selon chaque axe // et en supprimant la partie centrale. void Cube(float x, float y,float z, float d, int n) { if (--n>0) { // subdivision d /= 3; float xa=x+d,ya=y+d,za=z+d,xb=x+d+d,yb=y+d+d,zb=z+d+d; Cube(x, y, z, d, n); Cube(xa, y, z,d, n); Cube(x, ya, z,d, n); Cube(xb, y, z, d, n); Cube(x,yb,z ,d,n); Cube(xb,ya,z ,d,n); Cube(xa,yb,z ,d,n); Cube(xb,yb,z ,d,n); Cube(x,y ,za,d,n); Cube(xb,y ,za,d,n); Cube(x ,yb,za,d,n); Cube(xb,yb,za,d,n); Cube(x,y ,zb,d,n); Cube(xa,y ,zb,d,n); Cube(x ,ya,zb,d,n); Cube(xb,y ,zb,d,n); Cube(x,yb,zb,d,n); Cube(xb,ya,zb,d,n); Cube(xa,yb,zb,d,n); Cube(xb,yb,zb,d,n); } else { // enregistrement mémoire de chaque face int isdeb = sommets.size(); // face inférieure sommets.push_back(point(x,y,z,0,-1,0)); sommets.push_back(point(x+d,y,z,0,-1,0)); sommets.push_back(point(x+d,y,z+d,0,-1,0)); sommets.push_back(point(x,y,z+d,0,-1,0)); add_face(isdeb, isdeb+1, isdeb+2, isdeb+3); // face supérieure isdeb += 4; sommets.push_back(point(x,y+d,z,0,1,0)); sommets.push_back(point(x+d,y+d,z,0,1,0)); sommets.push_back(point(x+d,y+d,z+d,0,1,0)); sommets.push_back(point(x,y+d,z+d,0,1,0)); add_face(isdeb, isdeb+1, isdeb+2, isdeb+3); // face droite isdeb += 4; sommets.push_back(point(x+d,y+d,z,1,0,0)); sommets.push_back(point(x+d,y+d,z+d,1,0,0)); sommets.push_back(point(x+d,y,z+d,1,0,0)); sommets.push_back(point(x+d,y,z,1,0,0)); add_face(isdeb, isdeb+1, isdeb+2, isdeb+3); // face gauche isdeb += 4; sommets.push_back(point(x,y+d,z,-1,0,0)); sommets.push_back(point(x,y+d,z+d,-1,0,0)); sommets.push_back(point(x,y,z+d,-1,0,0)); sommets.push_back(point(x,y,z,-1,0,0)); add_face(isdeb, isdeb+1, isdeb+2, isdeb+3); // face avant isdeb += 4; sommets.push_back(point(x,y+d,z+d,0,0,1)); sommets.push_back(point(x+d,y+d,z+d,0,0,1)); sommets.push_back(point(x+d,y,z+d,0,0,1)); sommets.push_back(point(x,y,z+d,0,0,1)); add_face(isdeb, isdeb+1, isdeb+2, isdeb+3); // face arrière isdeb += 4; sommets.push_back(point(x,y+d,z,0,0,-1)); sommets.push_back(point(x+d,y+d,z,0,0,-1)); sommets.push_back(point(x+d,y,z,0,0,-1)); sommets.push_back(point(x,y,z,0,0,-1)); add_face(isdeb, isdeb+1, isdeb+2, isdeb+3); } }// Cube // génération et sauvegarde de l'éponge void eponge(options opt) { Cube(-opt.taille/2.0, -opt.taille/2.0, -opt.taille/2.0, opt.taille, opt.niveau); stringstream filename; filename << "eponge_" << opt.niveau << ".ply"; toPly(filename.str()); } int main(int argc, char* argv[]){ options opt; if(!parse_args(argc, argv, opt)){ usage(argv[0]); return 0; } eponge(opt); cout << "nombre de sommets générés : " << sommets.size() << endl; cout << "nombre de faces générées : " << faces.size()/4 << endl; return 1; } // sauvegarde au format ply binaire void toPly(const string & filename){ ofstream out(filename,ios::binary); if(!out.is_open()){ cerr << "erreur d'ouverture de " << filename << endl; return; } // écriture de l'entête out << "ply" << endl; // out << "format ascii 1.0" << endl; out << "format binary_little_endian 1.0" << endl; out << "comment cube/eponge de sierpinski" << endl; out << "element vertex " << sommets.size() << endl; out << "property float x" << endl; out << "property float y" << endl; out << "property float z" << endl; out << "property float nx" << endl; out << "property float ny" << endl; out << "property float nz" << endl; out << "element face " << faces.size()/4 << endl; out << "property list uchar int vertex_indices" << endl; out << "end_header" << endl; // écriture des sommets au format binaire little endian for(int i=0; i< sommets.size(); i++){ writeBinary(out, sommets[i].x, true);// little endian writeBinary(out, sommets[i].y, true); writeBinary(out, sommets[i].z, true); writeBinary(out, sommets[i].nx, true); writeBinary(out, sommets[i].ny, true); writeBinary(out, sommets[i].nz, true); // écriture au format ascii // out << sommets[i].x << " "; // out << sommets[i].y << " "; // out << sommets[i].z << " "; // out << sommets[i].nx << " "; // out << sommets[i].ny << " "; // out << sommets[i].nz << endl; } // écriture des faces au format binaire little endian for(int i=0; i>(i*8)); else // big endian for(int i=0; i>((sizeof(int)-1-i)*8)); out.write((char*)byte, sizeof(int)); } void usage(const string &exe){ cout << "usage : " << exe << " [-l ] [-s ]" << endl; }