{"version":3,"file":"STLLoader.cjs","sources":["../../src/loaders/STLLoader.js"],"sourcesContent":["import {\n  BufferAttribute,\n  BufferGeometry,\n  FileLoader,\n  Float32BufferAttribute,\n  Loader,\n  LoaderUtils,\n  Vector3,\n} from 'three'\nimport { decodeText } from '../_polyfill/LoaderUtils'\n\n/**\n * Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs.\n *\n * Supports both binary and ASCII encoded files, with automatic detection of type.\n *\n * The loader returns a non-indexed buffer geometry.\n *\n * Limitations:\n *  Binary decoding supports \"Magics\" color format (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL).\n *  There is perhaps some question as to how valid it is to always assume little-endian-ness.\n *  ASCII decoding assumes file is UTF-8.\n *\n * Usage:\n *  const loader = new STLLoader();\n *  loader.load( './models/stl/slotted_disk.stl', function ( geometry ) {\n *    scene.add( new THREE.Mesh( geometry ) );\n *  });\n *\n * For binary STLs geometry might contain colors for vertices. To use it:\n *  // use the same code to load STL as above\n *  if (geometry.hasColors) {\n *    material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: true });\n *  } else { .... }\n *  const mesh = new THREE.Mesh( geometry, material );\n *\n * For ASCII STLs containing multiple solids, each solid is assigned to a different group.\n * Groups can be used to assign a different color by defining an array of materials with the same length of\n * geometry.groups and passing it to the Mesh constructor:\n *\n * const mesh = new THREE.Mesh( geometry, material );\n *\n * For example:\n *\n *  const materials = [];\n *  const nGeometryGroups = geometry.groups.length;\n *\n *  const colorMap = ...; // Some logic to index colors.\n *\n *  for (let i = 0; i < nGeometryGroups; i++) {\n *\n *\t\tconst material = new THREE.MeshPhongMaterial({\n *\t\t\tcolor: colorMap[i],\n *\t\t\twireframe: false\n *\t\t});\n *\n *  }\n *\n *  materials.push(material);\n *  const mesh = new THREE.Mesh(geometry, materials);\n */\n\nclass STLLoader extends Loader {\n  constructor(manager) {\n    super(manager)\n  }\n\n  load(url, onLoad, onProgress, onError) {\n    const scope = this\n\n    const loader = new FileLoader(this.manager)\n    loader.setPath(this.path)\n    loader.setResponseType('arraybuffer')\n    loader.setRequestHeader(this.requestHeader)\n    loader.setWithCredentials(this.withCredentials)\n\n    loader.load(\n      url,\n      function (text) {\n        try {\n          onLoad(scope.parse(text))\n        } catch (e) {\n          if (onError) {\n            onError(e)\n          } else {\n            console.error(e)\n          }\n\n          scope.manager.itemError(url)\n        }\n      },\n      onProgress,\n      onError,\n    )\n  }\n\n  parse(data) {\n    function isBinary(data) {\n      const reader = new DataView(data)\n      const face_size = (32 / 8) * 3 + (32 / 8) * 3 * 3 + 16 / 8\n      const n_faces = reader.getUint32(80, true)\n      const expect = 80 + 32 / 8 + n_faces * face_size\n\n      if (expect === reader.byteLength) {\n        return true\n      }\n\n      // An ASCII STL data must begin with 'solid ' as the first six bytes.\n      // However, ASCII STLs lacking the SPACE after the 'd' are known to be\n      // plentiful.  So, check the first 5 bytes for 'solid'.\n\n      // Several encodings, such as UTF-8, precede the text with up to 5 bytes:\n      // https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding\n      // Search for \"solid\" to start anywhere after those prefixes.\n\n      // US-ASCII ordinal values for 's', 'o', 'l', 'i', 'd'\n\n      const solid = [115, 111, 108, 105, 100]\n\n      for (let off = 0; off < 5; off++) {\n        // If \"solid\" text is matched to the current offset, declare it to be an ASCII STL.\n\n        if (matchDataViewAt(solid, reader, off)) return false\n      }\n\n      // Couldn't find \"solid\" text at the beginning; it is binary STL.\n\n      return true\n    }\n\n    function matchDataViewAt(query, reader, offset) {\n      // Check if each byte in query matches the corresponding byte from the current offset\n\n      for (let i = 0, il = query.length; i < il; i++) {\n        if (query[i] !== reader.getUint8(offset + i, false)) return false\n      }\n\n      return true\n    }\n\n    function parseBinary(data) {\n      const reader = new DataView(data)\n      const faces = reader.getUint32(80, true)\n\n      let r,\n        g,\n        b,\n        hasColors = false,\n        colors\n      let defaultR, defaultG, defaultB, alpha\n\n      // process STL header\n      // check for default color in header (\"COLOR=rgba\" sequence).\n\n      for (let index = 0; index < 80 - 10; index++) {\n        if (\n          reader.getUint32(index, false) == 0x434f4c4f /*COLO*/ &&\n          reader.getUint8(index + 4) == 0x52 /*'R'*/ &&\n          reader.getUint8(index + 5) == 0x3d /*'='*/\n        ) {\n          hasColors = true\n          colors = new Float32Array(faces * 3 * 3)\n\n          defaultR = reader.getUint8(index + 6) / 255\n          defaultG = reader.getUint8(index + 7) / 255\n          defaultB = reader.getUint8(index + 8) / 255\n          alpha = reader.getUint8(index + 9) / 255\n        }\n      }\n\n      const dataOffset = 84\n      const faceLength = 12 * 4 + 2\n\n      const geometry = new BufferGeometry()\n\n      const vertices = new Float32Array(faces * 3 * 3)\n      const normals = new Float32Array(faces * 3 * 3)\n\n      for (let face = 0; face < faces; face++) {\n        const start = dataOffset + face * faceLength\n        const normalX = reader.getFloat32(start, true)\n        const normalY = reader.getFloat32(start + 4, true)\n        const normalZ = reader.getFloat32(start + 8, true)\n\n        if (hasColors) {\n          const packedColor = reader.getUint16(start + 48, true)\n\n          if ((packedColor & 0x8000) === 0) {\n            // facet has its own unique color\n\n            r = (packedColor & 0x1f) / 31\n            g = ((packedColor >> 5) & 0x1f) / 31\n            b = ((packedColor >> 10) & 0x1f) / 31\n          } else {\n            r = defaultR\n            g = defaultG\n            b = defaultB\n          }\n        }\n\n        for (let i = 1; i <= 3; i++) {\n          const vertexstart = start + i * 12\n          const componentIdx = face * 3 * 3 + (i - 1) * 3\n\n          vertices[componentIdx] = reader.getFloat32(vertexstart, true)\n          vertices[componentIdx + 1] = reader.getFloat32(vertexstart + 4, true)\n          vertices[componentIdx + 2] = reader.getFloat32(vertexstart + 8, true)\n\n          normals[componentIdx] = normalX\n          normals[componentIdx + 1] = normalY\n          normals[componentIdx + 2] = normalZ\n\n          if (hasColors) {\n            colors[componentIdx] = r\n            colors[componentIdx + 1] = g\n            colors[componentIdx + 2] = b\n          }\n        }\n      }\n\n      geometry.setAttribute('position', new BufferAttribute(vertices, 3))\n      geometry.setAttribute('normal', new BufferAttribute(normals, 3))\n\n      if (hasColors) {\n        geometry.setAttribute('color', new BufferAttribute(colors, 3))\n        geometry.hasColors = true\n        geometry.alpha = alpha\n      }\n\n      return geometry\n    }\n\n    function parseASCII(data) {\n      const geometry = new BufferGeometry()\n      const patternSolid = /solid([\\s\\S]*?)endsolid/g\n      const patternFace = /facet([\\s\\S]*?)endfacet/g\n      let faceCounter = 0\n\n      const patternFloat = /[\\s]+([+-]?(?:\\d*)(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)/.source\n      const patternVertex = new RegExp('vertex' + patternFloat + patternFloat + patternFloat, 'g')\n      const patternNormal = new RegExp('normal' + patternFloat + patternFloat + patternFloat, 'g')\n\n      const vertices = []\n      const normals = []\n\n      const normal = new Vector3()\n\n      let result\n\n      let groupCount = 0\n      let startVertex = 0\n      let endVertex = 0\n\n      while ((result = patternSolid.exec(data)) !== null) {\n        startVertex = endVertex\n\n        const solid = result[0]\n\n        while ((result = patternFace.exec(solid)) !== null) {\n          let vertexCountPerFace = 0\n          let normalCountPerFace = 0\n\n          const text = result[0]\n\n          while ((result = patternNormal.exec(text)) !== null) {\n            normal.x = parseFloat(result[1])\n            normal.y = parseFloat(result[2])\n            normal.z = parseFloat(result[3])\n            normalCountPerFace++\n          }\n\n          while ((result = patternVertex.exec(text)) !== null) {\n            vertices.push(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]))\n            normals.push(normal.x, normal.y, normal.z)\n            vertexCountPerFace++\n            endVertex++\n          }\n\n          // every face have to own ONE valid normal\n\n          if (normalCountPerFace !== 1) {\n            console.error(\"THREE.STLLoader: Something isn't right with the normal of face number \" + faceCounter)\n          }\n\n          // each face have to own THREE valid vertices\n\n          if (vertexCountPerFace !== 3) {\n            console.error(\"THREE.STLLoader: Something isn't right with the vertices of face number \" + faceCounter)\n          }\n\n          faceCounter++\n        }\n\n        const start = startVertex\n        const count = endVertex - startVertex\n\n        geometry.addGroup(start, count, groupCount)\n        groupCount++\n      }\n\n      geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3))\n      geometry.setAttribute('normal', new Float32BufferAttribute(normals, 3))\n\n      return geometry\n    }\n\n    function ensureString(buffer) {\n      if (typeof buffer !== 'string') {\n        return decodeText(new Uint8Array(buffer))\n      }\n\n      return buffer\n    }\n\n    function ensureBinary(buffer) {\n      if (typeof buffer === 'string') {\n        const array_buffer = new Uint8Array(buffer.length)\n        for (let i = 0; i < buffer.length; i++) {\n          array_buffer[i] = buffer.charCodeAt(i) & 0xff // implicitly assumes little-endian\n        }\n\n        return array_buffer.buffer || array_buffer\n      } else {\n        return buffer\n      }\n    }\n\n    // start\n\n    const binData = ensureBinary(data)\n\n    return isBinary(binData) ? parseBinary(binData) : parseASCII(ensureString(data))\n  }\n}\n\nexport { STLLoader }\n"],"names":["Loader","FileLoader","data","BufferGeometry","BufferAttribute","Vector3","Float32BufferAttribute","decodeText"],"mappings":";;;;AA8DA,MAAM,kBAAkBA,MAAAA,OAAO;AAAA,EAC7B,YAAY,SAAS;AACnB,UAAM,OAAO;AAAA,EACd;AAAA,EAED,KAAK,KAAK,QAAQ,YAAY,SAAS;AACrC,UAAM,QAAQ;AAEd,UAAM,SAAS,IAAIC,iBAAW,KAAK,OAAO;AAC1C,WAAO,QAAQ,KAAK,IAAI;AACxB,WAAO,gBAAgB,aAAa;AACpC,WAAO,iBAAiB,KAAK,aAAa;AAC1C,WAAO,mBAAmB,KAAK,eAAe;AAE9C,WAAO;AAAA,MACL;AAAA,MACA,SAAU,MAAM;AACd,YAAI;AACF,iBAAO,MAAM,MAAM,IAAI,CAAC;AAAA,QACzB,SAAQ,GAAP;AACA,cAAI,SAAS;AACX,oBAAQ,CAAC;AAAA,UACrB,OAAiB;AACL,oBAAQ,MAAM,CAAC;AAAA,UAChB;AAED,gBAAM,QAAQ,UAAU,GAAG;AAAA,QAC5B;AAAA,MACF;AAAA,MACD;AAAA,MACA;AAAA,IACD;AAAA,EACF;AAAA,EAED,MAAM,MAAM;AACV,aAAS,SAASC,OAAM;AACtB,YAAM,SAAS,IAAI,SAASA,KAAI;AAChC,YAAM,YAAa,KAAK,IAAK,IAAK,KAAK,IAAK,IAAI,IAAI,KAAK;AACzD,YAAM,UAAU,OAAO,UAAU,IAAI,IAAI;AACzC,YAAM,SAAS,KAAK,KAAK,IAAI,UAAU;AAEvC,UAAI,WAAW,OAAO,YAAY;AAChC,eAAO;AAAA,MACR;AAYD,YAAM,QAAQ,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG;AAEtC,eAAS,MAAM,GAAG,MAAM,GAAG,OAAO;AAGhC,YAAI,gBAAgB,OAAO,QAAQ,GAAG;AAAG,iBAAO;AAAA,MACjD;AAID,aAAO;AAAA,IACR;AAED,aAAS,gBAAgB,OAAO,QAAQ,QAAQ;AAG9C,eAAS,IAAI,GAAG,KAAK,MAAM,QAAQ,IAAI,IAAI,KAAK;AAC9C,YAAI,MAAM,CAAC,MAAM,OAAO,SAAS,SAAS,GAAG,KAAK;AAAG,iBAAO;AAAA,MAC7D;AAED,aAAO;AAAA,IACR;AAED,aAAS,YAAYA,OAAM;AACzB,YAAM,SAAS,IAAI,SAASA,KAAI;AAChC,YAAM,QAAQ,OAAO,UAAU,IAAI,IAAI;AAEvC,UAAI,GACF,GACA,GACA,YAAY,OACZ;AACF,UAAI,UAAU,UAAU,UAAU;AAKlC,eAAS,QAAQ,GAAG,QAAQ,KAAK,IAAI,SAAS;AAC5C,YACE,OAAO,UAAU,OAAO,KAAK,KAAK,cAClC,OAAO,SAAS,QAAQ,CAAC,KAAK,MAC9B,OAAO,SAAS,QAAQ,CAAC,KAAK,IAC9B;AACA,sBAAY;AACZ,mBAAS,IAAI,aAAa,QAAQ,IAAI,CAAC;AAEvC,qBAAW,OAAO,SAAS,QAAQ,CAAC,IAAI;AACxC,qBAAW,OAAO,SAAS,QAAQ,CAAC,IAAI;AACxC,qBAAW,OAAO,SAAS,QAAQ,CAAC,IAAI;AACxC,kBAAQ,OAAO,SAAS,QAAQ,CAAC,IAAI;AAAA,QACtC;AAAA,MACF;AAED,YAAM,aAAa;AACnB,YAAM,aAAa,KAAK,IAAI;AAE5B,YAAM,WAAW,IAAIC,qBAAgB;AAErC,YAAM,WAAW,IAAI,aAAa,QAAQ,IAAI,CAAC;AAC/C,YAAM,UAAU,IAAI,aAAa,QAAQ,IAAI,CAAC;AAE9C,eAAS,OAAO,GAAG,OAAO,OAAO,QAAQ;AACvC,cAAM,QAAQ,aAAa,OAAO;AAClC,cAAM,UAAU,OAAO,WAAW,OAAO,IAAI;AAC7C,cAAM,UAAU,OAAO,WAAW,QAAQ,GAAG,IAAI;AACjD,cAAM,UAAU,OAAO,WAAW,QAAQ,GAAG,IAAI;AAEjD,YAAI,WAAW;AACb,gBAAM,cAAc,OAAO,UAAU,QAAQ,IAAI,IAAI;AAErD,eAAK,cAAc,WAAY,GAAG;AAGhC,iBAAK,cAAc,MAAQ;AAC3B,iBAAM,eAAe,IAAK,MAAQ;AAClC,iBAAM,eAAe,KAAM,MAAQ;AAAA,UAC/C,OAAiB;AACL,gBAAI;AACJ,gBAAI;AACJ,gBAAI;AAAA,UACL;AAAA,QACF;AAED,iBAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,gBAAM,cAAc,QAAQ,IAAI;AAChC,gBAAM,eAAe,OAAO,IAAI,KAAK,IAAI,KAAK;AAE9C,mBAAS,YAAY,IAAI,OAAO,WAAW,aAAa,IAAI;AAC5D,mBAAS,eAAe,CAAC,IAAI,OAAO,WAAW,cAAc,GAAG,IAAI;AACpE,mBAAS,eAAe,CAAC,IAAI,OAAO,WAAW,cAAc,GAAG,IAAI;AAEpE,kBAAQ,YAAY,IAAI;AACxB,kBAAQ,eAAe,CAAC,IAAI;AAC5B,kBAAQ,eAAe,CAAC,IAAI;AAE5B,cAAI,WAAW;AACb,mBAAO,YAAY,IAAI;AACvB,mBAAO,eAAe,CAAC,IAAI;AAC3B,mBAAO,eAAe,CAAC,IAAI;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AAED,eAAS,aAAa,YAAY,IAAIC,MAAAA,gBAAgB,UAAU,CAAC,CAAC;AAClE,eAAS,aAAa,UAAU,IAAIA,MAAAA,gBAAgB,SAAS,CAAC,CAAC;AAE/D,UAAI,WAAW;AACb,iBAAS,aAAa,SAAS,IAAIA,MAAAA,gBAAgB,QAAQ,CAAC,CAAC;AAC7D,iBAAS,YAAY;AACrB,iBAAS,QAAQ;AAAA,MAClB;AAED,aAAO;AAAA,IACR;AAED,aAAS,WAAWF,OAAM;AACxB,YAAM,WAAW,IAAIC,qBAAgB;AACrC,YAAM,eAAe;AACrB,YAAM,cAAc;AACpB,UAAI,cAAc;AAElB,YAAM,eAAe,iDAAiD;AACtE,YAAM,gBAAgB,IAAI,OAAO,WAAW,eAAe,eAAe,cAAc,GAAG;AAC3F,YAAM,gBAAgB,IAAI,OAAO,WAAW,eAAe,eAAe,cAAc,GAAG;AAE3F,YAAM,WAAW,CAAE;AACnB,YAAM,UAAU,CAAE;AAElB,YAAM,SAAS,IAAIE,cAAS;AAE5B,UAAI;AAEJ,UAAI,aAAa;AACjB,UAAI,cAAc;AAClB,UAAI,YAAY;AAEhB,cAAQ,SAAS,aAAa,KAAKH,KAAI,OAAO,MAAM;AAClD,sBAAc;AAEd,cAAM,QAAQ,OAAO,CAAC;AAEtB,gBAAQ,SAAS,YAAY,KAAK,KAAK,OAAO,MAAM;AAClD,cAAI,qBAAqB;AACzB,cAAI,qBAAqB;AAEzB,gBAAM,OAAO,OAAO,CAAC;AAErB,kBAAQ,SAAS,cAAc,KAAK,IAAI,OAAO,MAAM;AACnD,mBAAO,IAAI,WAAW,OAAO,CAAC,CAAC;AAC/B,mBAAO,IAAI,WAAW,OAAO,CAAC,CAAC;AAC/B,mBAAO,IAAI,WAAW,OAAO,CAAC,CAAC;AAC/B;AAAA,UACD;AAED,kBAAQ,SAAS,cAAc,KAAK,IAAI,OAAO,MAAM;AACnD,qBAAS,KAAK,WAAW,OAAO,CAAC,CAAC,GAAG,WAAW,OAAO,CAAC,CAAC,GAAG,WAAW,OAAO,CAAC,CAAC,CAAC;AACjF,oBAAQ,KAAK,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACzC;AACA;AAAA,UACD;AAID,cAAI,uBAAuB,GAAG;AAC5B,oBAAQ,MAAM,2EAA2E,WAAW;AAAA,UACrG;AAID,cAAI,uBAAuB,GAAG;AAC5B,oBAAQ,MAAM,6EAA6E,WAAW;AAAA,UACvG;AAED;AAAA,QACD;AAED,cAAM,QAAQ;AACd,cAAM,QAAQ,YAAY;AAE1B,iBAAS,SAAS,OAAO,OAAO,UAAU;AAC1C;AAAA,MACD;AAED,eAAS,aAAa,YAAY,IAAII,MAAAA,uBAAuB,UAAU,CAAC,CAAC;AACzE,eAAS,aAAa,UAAU,IAAIA,MAAAA,uBAAuB,SAAS,CAAC,CAAC;AAEtE,aAAO;AAAA,IACR;AAED,aAAS,aAAa,QAAQ;AAC5B,UAAI,OAAO,WAAW,UAAU;AAC9B,eAAOC,uBAAW,IAAI,WAAW,MAAM,CAAC;AAAA,MACzC;AAED,aAAO;AAAA,IACR;AAED,aAAS,aAAa,QAAQ;AAC5B,UAAI,OAAO,WAAW,UAAU;AAC9B,cAAM,eAAe,IAAI,WAAW,OAAO,MAAM;AACjD,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,uBAAa,CAAC,IAAI,OAAO,WAAW,CAAC,IAAI;AAAA,QAC1C;AAED,eAAO,aAAa,UAAU;AAAA,MACtC,OAAa;AACL,eAAO;AAAA,MACR;AAAA,IACF;AAID,UAAM,UAAU,aAAa,IAAI;AAEjC,WAAO,SAAS,OAAO,IAAI,YAAY,OAAO,IAAI,WAAW,aAAa,IAAI,CAAC;AAAA,EAChF;AACH;;"}