stlSerializer.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { Mesh } from "babylonjs/Meshes/mesh";
  2. import { VertexBuffer } from "babylonjs/Meshes/buffer";
  3. import { Vector3 } from "babylonjs/Maths/math.vector";
  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. * @param isLittleEndian toggle for binary type exporter.
  15. * @param doNotBakeTransform toggle if meshes transforms should be baked or not.
  16. * @returns the STL as UTF8 string
  17. */
  18. public static CreateSTL(meshes: Mesh[], download: boolean = true, fileName: string = 'stlmesh', binary: boolean = false, isLittleEndian: boolean = true, doNotBakeTransform: boolean = false): any {
  19. //Binary support adapted from https://gist.github.com/paulkaplan/6d5f0ab2c7e8fdc68a61
  20. let getFaceData = function(indices: any, vertices: any, i: number) {
  21. let id = [indices[i] * 3, indices[i + 1] * 3, indices[i + 2] * 3];
  22. let v = [
  23. new Vector3(vertices[id[0]], vertices[id[0] + 2], vertices[id[0] + 1]),
  24. new Vector3(vertices[id[1]], vertices[id[1] + 2], vertices[id[1] + 1]),
  25. new Vector3(vertices[id[2]], vertices[id[2] + 2], vertices[id[2] + 1])
  26. ];
  27. let p1p2 = v[0].subtract(v[1]);
  28. let p3p2 = v[2].subtract(v[1]);
  29. let n = (Vector3.Cross(p3p2, p1p2)).normalize();
  30. return {v, n};
  31. };
  32. let writeVector = function(dataview: any, offset: number, vector: Vector3, isLittleEndian: boolean) {
  33. offset = writeFloat(dataview, offset, vector.x, isLittleEndian);
  34. offset = writeFloat(dataview, offset, vector.y, isLittleEndian);
  35. return writeFloat(dataview, offset, vector.z, isLittleEndian);
  36. };
  37. let writeFloat = function(dataview: any, offset: number, value: number, isLittleEndian: boolean) {
  38. dataview.setFloat32(offset, value, isLittleEndian);
  39. return offset + 4;
  40. };
  41. let data;
  42. let faceCount = 0;
  43. let offset = 0;
  44. if (binary) {
  45. for (let i = 0; i < meshes.length; i++) {
  46. let mesh = meshes[i];
  47. let indices = mesh.getIndices();
  48. faceCount += indices ? indices.length / 3 : 0;
  49. }
  50. let bufferSize = 84 + (50 * faceCount);
  51. let buffer = new ArrayBuffer(bufferSize);
  52. data = new DataView(buffer);
  53. offset += 80;
  54. data.setUint32(offset, faceCount, isLittleEndian);
  55. offset += 4;
  56. } else {
  57. data = 'solid stlmesh\r\n';
  58. }
  59. for (let i = 0; i < meshes.length; i++) {
  60. let mesh = meshes[i];
  61. if (!doNotBakeTransform) {
  62. mesh.bakeCurrentTransformIntoVertices();
  63. }
  64. let vertices = mesh.getVerticesData(VertexBuffer.PositionKind) || [];
  65. let indices = mesh.getIndices() || [];
  66. for (let i = 0; i < indices.length; i += 3) {
  67. let fd = getFaceData(indices, vertices, i);
  68. if (binary) {
  69. offset = writeVector(data, offset, fd.n, isLittleEndian);
  70. offset = writeVector(data, offset, fd.v[0], isLittleEndian);
  71. offset = writeVector(data, offset, fd.v[1], isLittleEndian);
  72. offset = writeVector(data, offset, fd.v[2], isLittleEndian);
  73. offset += 2;
  74. } else {
  75. data += 'facet normal ' + fd.n.x + ' ' + fd.n.y + ' ' + fd.n.z + '\r\n';
  76. data += '\touter loop\r\n';
  77. data += '\t\tvertex ' + fd.v[0].x + ' ' + fd.v[0].y + ' ' + fd.v[0].z + '\r\n';
  78. data += '\t\tvertex ' + fd.v[1].x + ' ' + fd.v[1].y + ' ' + fd.v[1].z + '\r\n';
  79. data += '\t\tvertex ' + fd.v[2].x + ' ' + fd.v[2].y + ' ' + fd.v[2].z + '\r\n';
  80. data += '\tendloop\r\n';
  81. data += 'endfacet\r\n';
  82. }
  83. }
  84. }
  85. if (!binary) {
  86. data += 'endsolid stlmesh';
  87. }
  88. if (download) {
  89. let a = document.createElement('a');
  90. let blob = new Blob([data], {'type': 'application/octet-stream'});
  91. a.href = window.URL.createObjectURL(blob);
  92. a.download = fileName + ".stl";
  93. a.click();
  94. }
  95. return data;
  96. }
  97. }