gencubesierpinski.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include <iostream>
  2. #include <sstream> // std::stringstream
  3. #include <fstream>
  4. #include <vector>
  5. #include <string>
  6. using namespace std;
  7. // génération d'un fichier ply contenant un modèle d'un(e) cube (éponge)
  8. // de sierpinski, au format ply.
  9. // compilation : g++ -std=c++11 -o gcs gencubesierpinski.cpp
  10. // syntaxe : ./gcs -l niveau-de-subdivision -s taille_du_cube
  11. // représentation des option pour la génération
  12. struct options {
  13. int niveau; // niveau de subdivision 1 = pas de subdivision)
  14. int taille; // taille du cube, qui est centré à l'origine
  15. };
  16. // représentation d'un point 3D, avec sa normale
  17. struct point {
  18. float x, y, z;
  19. float nx, ny, nz;
  20. point(float x, float y, float z,
  21. float nx, float ny, float nz) :
  22. x(x), y(y), z(z), nx(nx), ny(ny), nz(nz){
  23. }
  24. };
  25. // varibales globales
  26. vector <point> sommets; // liste des sommets générés
  27. vector <int> faces; // liste des faces générées
  28. // prédéfinition des fonctions
  29. void toPly(const string & filename);
  30. bool parse_args(int argc, char *argv[], options &opt);
  31. void writeBinary(ofstream & out, float v, bool littleEndian);
  32. void writeBinary(ofstream & out, int v, bool littleEndian);
  33. void usage(const string &exe);
  34. // ajout d'une face à laliste des faces
  35. // la face est donnée par les indices de ses 4 sommets successifs
  36. // dans la liste des sommets
  37. inline void add_face(int i, int j, int k, int l){
  38. faces.push_back(i);
  39. faces.push_back(j);
  40. faces.push_back(k);
  41. faces.push_back(l);
  42. }
  43. // génération d'un cube
  44. // (x,y,z) représente les coordonnées du coin ayant le plus "petit"
  45. // d représente la taille du cube
  46. // n représente le niveau de subdivision restant à accomplir
  47. // (si n = 1, plus de subdivisions)
  48. // la subdivisin est faite en découpant le cube en 3 selon chaque axe
  49. // et en supprimant la partie centrale.
  50. void Cube(float x, float y,float z, float d, int n) {
  51. if (--n>0) { // subdivision
  52. d /= 3;
  53. float xa=x+d,ya=y+d,za=z+d,xb=x+d+d,yb=y+d+d,zb=z+d+d;
  54. Cube(x, y, z, d, n); Cube(xa, y, z,d, n); Cube(x, ya, z,d, n); Cube(xb, y, z, d, n);
  55. Cube(x,yb,z ,d,n); Cube(xb,ya,z ,d,n); Cube(xa,yb,z ,d,n); Cube(xb,yb,z ,d,n);
  56. Cube(x,y ,za,d,n); Cube(xb,y ,za,d,n); Cube(x ,yb,za,d,n); Cube(xb,yb,za,d,n);
  57. Cube(x,y ,zb,d,n); Cube(xa,y ,zb,d,n); Cube(x ,ya,zb,d,n); Cube(xb,y ,zb,d,n);
  58. Cube(x,yb,zb,d,n); Cube(xb,ya,zb,d,n); Cube(xa,yb,zb,d,n); Cube(xb,yb,zb,d,n);
  59. } else { // enregistrement mémoire de chaque face
  60. int isdeb = sommets.size();
  61. // face inférieure
  62. sommets.push_back(point(x,y,z,0,-1,0));
  63. sommets.push_back(point(x+d,y,z,0,-1,0));
  64. sommets.push_back(point(x+d,y,z+d,0,-1,0));
  65. sommets.push_back(point(x,y,z+d,0,-1,0));
  66. add_face(isdeb, isdeb+1, isdeb+2, isdeb+3);
  67. // face supérieure
  68. isdeb += 4;
  69. sommets.push_back(point(x,y+d,z,0,1,0));
  70. sommets.push_back(point(x+d,y+d,z,0,1,0));
  71. sommets.push_back(point(x+d,y+d,z+d,0,1,0));
  72. sommets.push_back(point(x,y+d,z+d,0,1,0));
  73. add_face(isdeb, isdeb+1, isdeb+2, isdeb+3);
  74. // face droite
  75. isdeb += 4;
  76. sommets.push_back(point(x+d,y+d,z,1,0,0));
  77. sommets.push_back(point(x+d,y+d,z+d,1,0,0));
  78. sommets.push_back(point(x+d,y,z+d,1,0,0));
  79. sommets.push_back(point(x+d,y,z,1,0,0));
  80. add_face(isdeb, isdeb+1, isdeb+2, isdeb+3);
  81. // face gauche
  82. isdeb += 4;
  83. sommets.push_back(point(x,y+d,z,-1,0,0));
  84. sommets.push_back(point(x,y+d,z+d,-1,0,0));
  85. sommets.push_back(point(x,y,z+d,-1,0,0));
  86. sommets.push_back(point(x,y,z,-1,0,0));
  87. add_face(isdeb, isdeb+1, isdeb+2, isdeb+3);
  88. // face avant
  89. isdeb += 4;
  90. sommets.push_back(point(x,y+d,z+d,0,0,1));
  91. sommets.push_back(point(x+d,y+d,z+d,0,0,1));
  92. sommets.push_back(point(x+d,y,z+d,0,0,1));
  93. sommets.push_back(point(x,y,z+d,0,0,1));
  94. add_face(isdeb, isdeb+1, isdeb+2, isdeb+3);
  95. // face arrière
  96. isdeb += 4;
  97. sommets.push_back(point(x,y+d,z,0,0,-1));
  98. sommets.push_back(point(x+d,y+d,z,0,0,-1));
  99. sommets.push_back(point(x+d,y,z,0,0,-1));
  100. sommets.push_back(point(x,y,z,0,0,-1));
  101. add_face(isdeb, isdeb+1, isdeb+2, isdeb+3);
  102. }
  103. }// Cube
  104. // génération et sauvegarde de l'éponge
  105. void eponge(options opt) {
  106. Cube(-opt.taille/2.0, -opt.taille/2.0, -opt.taille/2.0, opt.taille, opt.niveau);
  107. stringstream filename;
  108. filename << "eponge_" << opt.niveau << ".ply";
  109. toPly(filename.str());
  110. }
  111. int main(int argc, char* argv[]){
  112. options opt;
  113. if(!parse_args(argc, argv, opt)){
  114. usage(argv[0]);
  115. return 0;
  116. }
  117. eponge(opt);
  118. cout << "nombre de sommets générés : " << sommets.size() << endl;
  119. cout << "nombre de faces générées : " << faces.size()/4 << endl;
  120. return 1;
  121. }
  122. // sauvegarde au format ply binaire
  123. void toPly(const string & filename){
  124. ofstream out(filename,ios::binary);
  125. if(!out.is_open()){
  126. cerr << "erreur d'ouverture de " << filename << endl;
  127. return;
  128. }
  129. // écriture de l'entête
  130. out << "ply" << endl;
  131. // out << "format ascii 1.0" << endl;
  132. out << "format binary_little_endian 1.0" << endl;
  133. out << "comment cube/eponge de sierpinski" << endl;
  134. out << "element vertex " << sommets.size() << endl;
  135. out << "property float x" << endl;
  136. out << "property float y" << endl;
  137. out << "property float z" << endl;
  138. out << "property float nx" << endl;
  139. out << "property float ny" << endl;
  140. out << "property float nz" << endl;
  141. out << "element face " << faces.size()/4 << endl;
  142. out << "property list uchar int vertex_indices" << endl;
  143. out << "end_header" << endl;
  144. // écriture des sommets au format binaire little endian
  145. for(int i=0; i< sommets.size(); i++){
  146. writeBinary(out, sommets[i].x, true);// little endian
  147. writeBinary(out, sommets[i].y, true);
  148. writeBinary(out, sommets[i].z, true);
  149. writeBinary(out, sommets[i].nx, true);
  150. writeBinary(out, sommets[i].ny, true);
  151. writeBinary(out, sommets[i].nz, true);
  152. // écriture au format ascii
  153. // out << sommets[i].x << " ";
  154. // out << sommets[i].y << " ";
  155. // out << sommets[i].z << " ";
  156. // out << sommets[i].nx << " ";
  157. // out << sommets[i].ny << " ";
  158. // out << sommets[i].nz << endl;
  159. }
  160. // écriture des faces au format binaire little endian
  161. for(int i=0; i<faces.size(); i+=4){
  162. char v=4;
  163. out.write(&v, sizeof(char));
  164. writeBinary(out, faces[i], true);
  165. writeBinary(out, faces[i+1], true);
  166. writeBinary(out, faces[i+2], true);
  167. writeBinary(out, faces[i+3], true);
  168. // écriture au format ascii
  169. // out << "4 ";
  170. // out << faces[i] << " ";
  171. // out << faces[i+1] << " ";
  172. // out << faces[i+2] << " ";
  173. // out << faces[i+3] << endl;
  174. }
  175. out.close();
  176. }// toply
  177. // décodage des arguments - à ce stade :
  178. // -l niveau de subdivision (level)
  179. // -s taille du cune centré à l'origine (size)
  180. bool parse_args(int argc, char *argv[], options &opt){
  181. // valeurs par défaut
  182. opt.niveau = 2;
  183. opt.taille = 20.0;
  184. if(argc==1) return true;
  185. if(argc%2!=1){
  186. cerr << "nb arguments incompatibles" << endl;
  187. return false;
  188. }
  189. for(int i=1; i<argc; i+=2){
  190. if(string(argv[i])=="-l"){// niveau de recursivité
  191. opt.niveau = stoi(string(argv[i+1]));
  192. continue;
  193. }
  194. if(string(argv[i])=="-s"){// taille du cube
  195. opt.taille = stof(string(argv[i+1]));
  196. continue;
  197. }
  198. cerr << "option inconnue : " << argv[i] << endl;
  199. return false;
  200. }// for
  201. return true;
  202. }
  203. // écriture binaire d'un nombre réel au format :
  204. // - little endian si littleEndian vaut true
  205. // - big endian sinon
  206. void writeBinary(ofstream & out, float v, bool littleEndian){
  207. unsigned char byte[sizeof(float)];
  208. if(littleEndian)
  209. for(int i=0; i<sizeof(float); i++)
  210. byte[i] = *((unsigned char*)&v +i);
  211. else // big endian
  212. for(int i=0; i<sizeof(float); i++)
  213. byte[i] = *((unsigned char*)&v+(sizeof(float)-1-i));
  214. out.write((char*)byte, sizeof(float));
  215. }
  216. // écriture binaire d'un nombre entier au format :
  217. // - little endian si littleEndian vaut true
  218. // - big endian sinon
  219. void writeBinary(ofstream & out, int v, bool littleEndian){
  220. unsigned char byte[sizeof(int)];
  221. out.write((char*)&v, sizeof(int));
  222. return;
  223. if(littleEndian)
  224. for(int i=0; i<sizeof(int); i++)
  225. byte[i] = (unsigned char)(v>>(i*8));
  226. else // big endian
  227. for(int i=0; i<sizeof(int); i++)
  228. byte[i] = (unsigned char)(v>>((sizeof(int)-1-i)*8));
  229. out.write((char*)byte, sizeof(int));
  230. }
  231. void usage(const string &exe){
  232. cout << "usage : " << exe << " [-l <subdivision level>] [-s <cube size>]" << endl;
  233. }