stlSerializer.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import { Mesh } from "babylonjs/Meshes/mesh";
  2. import { VertexBuffer } from "babylonjs/Meshes/buffer";
  3. import { Vector3 } from "babylonjs/Maths/math";
  4. /**
  5. * Class for generating STL data from a Babylon scene.
  6. */
  7. export class STLExport {
  8. /**
  9. * Exports the geometry of a Mesh array in .STL file format (ASCII)
  10. * @param meshes list defines the mesh to serialize
  11. * @param download triggers the automatic download of the file.
  12. * @param fileName changes the downloads fileName.
  13. * @param binary changes the STL to a binary type.
  14. * @returns the STL as UTF8 string
  15. */
  16. public static CreateSTL(meshes: Mesh[], download:boolean=true, fileName:string='STL_Mesh', binary:boolean=false): any {
  17. let data;
  18. let multiMesh = false;
  19. if(meshes.length>1){multiMesh=true;}
  20. if(!binary){
  21. data = 'solid exportedMesh\r\n';
  22. for(let i=0; i<meshes.length; i++){
  23. let mesh = meshes[i];
  24. mesh.bakeCurrentTransformIntoVertices();
  25. let vertices = mesh.getVerticesData(VertexBuffer.PositionKind) || [];
  26. let indices = mesh.getIndices() || [];
  27. for (let i = 0; i < indices.length; i += 3) {
  28. let id = [indices[i] * 3, indices[i + 1] * 3, indices[i + 2] * 3];
  29. let v = [
  30. new Vector3(vertices[id[0]], vertices[id[0] + 1], vertices[id[0] + 2]),
  31. new Vector3(vertices[id[1]], vertices[id[1] + 1], vertices[id[1] + 2]),
  32. new Vector3(vertices[id[2]], vertices[id[2] + 1], vertices[id[2] + 2])
  33. ];
  34. let p1p2 = v[0].subtract(v[1]);
  35. let p3p2 = v[2].subtract(v[1]);
  36. let n = (Vector3.Cross(p1p2, p3p2)).normalize();
  37. data += 'facet normal ' + n.x + ' ' + n.y + ' ' + n.z + '\r\n';
  38. data += '\touter loop\r\n';
  39. data += '\t\tvertex ' + v[0].x + ' ' + v[0].y + ' ' + v[0].z + '\r\n';
  40. data += '\t\tvertex ' + v[1].x + ' ' + v[1].y + ' ' + v[1].z + '\r\n';
  41. data += '\t\tvertex ' + v[2].x + ' ' + v[2].y + ' ' + v[2].z + '\r\n';
  42. data += '\tendloop\r\n';
  43. data += 'endfacet\r\n';
  44. }
  45. }
  46. data += 'endsolid exportedMesh';
  47. }else{
  48. //Adapted from https://gist.github.com/paulkaplan/6d5f0ab2c7e8fdc68a61
  49. //get faceCount
  50. let faceCount = 0;
  51. for(let i=0; i<meshes.length; i++){
  52. let mesh = meshes[i];
  53. faceCount += mesh.getIndices().length;
  54. }
  55. let isLittleEndian = true;
  56. let bufferSize = 84 + (50 * faceCount);
  57. let buffer = new ArrayBuffer(bufferSize);
  58. data = new DataView(buffer);
  59. let offset = 0;
  60. let writeVector = function(dataview:any, offset:number, vector:Vector3, isLittleEndian:boolean){
  61. offset = writeFloat(dataview, offset, vector.x, isLittleEndian);
  62. offset = writeFloat(dataview, offset, vector.y, isLittleEndian);
  63. return writeFloat(dataview, offset, vector.z, isLittleEndian);
  64. };
  65. let writeFloat = function(dataview:any, offset:number, value:number, isLittleEndian:boolean) {
  66. dataview.setFloat32(offset, value, isLittleEndian);
  67. return offset + 4;
  68. };
  69. //Allow later for binary Messages to be passed in the header for now offset by 80.
  70. offset += 80;
  71. data.setUint32(offset, faceCount, isLittleEndian);
  72. offset += 4;
  73. for(let i=0; i<meshes.length; i++){
  74. let mesh = meshes[i];
  75. mesh.bakeCurrentTransformIntoVertices();
  76. let vertices = mesh.getVerticesData(VertexBuffer.PositionKind) || [];
  77. let indices = mesh.getIndices() || [];
  78. for (let i = 0; i < indices.length; i += 3) {
  79. let id = [indices[i] * 3, indices[i + 1] * 3, indices[i + 2] * 3];
  80. let v = [
  81. new Vector3(vertices[id[0]], vertices[id[0] + 1], vertices[id[0] + 2]),
  82. new Vector3(vertices[id[1]], vertices[id[1] + 1], vertices[id[1] + 2]),
  83. new Vector3(vertices[id[2]], vertices[id[2] + 1], vertices[id[2] + 2])
  84. ];
  85. let p1p2 = v[0].subtract(v[1]);
  86. let p3p2 = v[2].subtract(v[1]);
  87. let n = (Vector3.Cross(p1p2, p3p2)).normalize();
  88. offset = writeVector(data, offset, n, isLittleEndian);
  89. offset = writeVector(data, offset, v[0], isLittleEndian);
  90. offset = writeVector(data, offset, v[1], isLittleEndian);
  91. offset = writeVector(data, offset, v[2], isLittleEndian);
  92. offset += 2;
  93. }
  94. }
  95. }
  96. if (download) {
  97. let a = document.createElement('a');
  98. let blob = new Blob([data], {'type': 'application/octet-stream'});
  99. a.href = window.URL.createObjectURL(blob);
  100. if (!fileName) {
  101. fileName = "STL_Mesh";
  102. }
  103. a.download = fileName + ".stl";
  104. a.click();
  105. }
  106. /*if(binary){
  107. return String.fromCharCode.apply(null, new Uint16Array(data));
  108. }*/
  109. return data;
  110. }
  111. }