|
@@ -0,0 +1,280 @@
|
|
|
+#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;
|
|
|
+}
|