123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- #include <iostream>
- #include <sstream> // std::stringstream
- #include <fstream>
- #include <vector>
- #include <string>
- 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 <point> sommets; // liste des sommets générés
- vector <int> 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<faces.size(); i+=4){
- char v=4;
- out.write(&v, sizeof(char));
- writeBinary(out, faces[i], true);
- writeBinary(out, faces[i+1], true);
- writeBinary(out, faces[i+2], true);
- writeBinary(out, faces[i+3], true);
- // écriture au format ascii
- // out << "4 ";
- // out << faces[i] << " ";
- // out << faces[i+1] << " ";
- // out << faces[i+2] << " ";
- // out << faces[i+3] << endl;
- }
- out.close();
-
- }// toply
- // décodage des arguments - à ce stade :
- // -l niveau de subdivision (level)
- // -s taille du cune centré à l'origine (size)
- bool parse_args(int argc, char *argv[], options &opt){
- // valeurs par défaut
- opt.niveau = 2;
- opt.taille = 20.0;
- if(argc==1) return true;
- if(argc%2!=1){
- cerr << "nb arguments incompatibles" << endl;
- return false;
- }
- for(int i=1; i<argc; i+=2){
- if(string(argv[i])=="-l"){// niveau de recursivité
- opt.niveau = stoi(string(argv[i+1]));
- continue;
- }
- if(string(argv[i])=="-s"){// taille du cube
- opt.taille = stof(string(argv[i+1]));
- continue;
- }
- cerr << "option inconnue : " << argv[i] << endl;
- return false;
- }// for
- return true;
- }
- // écriture binaire d'un nombre réel au format :
- // - little endian si littleEndian vaut true
- // - big endian sinon
- void writeBinary(ofstream & out, float v, bool littleEndian){
- unsigned char byte[sizeof(float)];
- if(littleEndian)
- for(int i=0; i<sizeof(float); i++)
- byte[i] = *((unsigned char*)&v +i);
- else // big endian
- for(int i=0; i<sizeof(float); i++)
- byte[i] = *((unsigned char*)&v+(sizeof(float)-1-i));
-
- out.write((char*)byte, sizeof(float));
-
- }
- // écriture binaire d'un nombre entier au format :
- // - little endian si littleEndian vaut true
- // - big endian sinon
- void writeBinary(ofstream & out, int v, bool littleEndian){
- unsigned char byte[sizeof(int)];
- out.write((char*)&v, sizeof(int));
- return;
- if(littleEndian)
- for(int i=0; i<sizeof(int); i++)
- byte[i] = (unsigned char)(v>>(i*8));
- else // big endian
- for(int i=0; i<sizeof(int); i++)
- byte[i] = (unsigned char)(v>>((sizeof(int)-1-i)*8));
-
- out.write((char*)byte, sizeof(int));
- }
- void usage(const string &exe){
- cout << "usage : " << exe << " [-l <subdivision level>] [-s <cube size>]" << endl;
- }
|