/
counterbugtech
/
KontrBugCAD
Обзор
Документация
Войти
/
counterbugtech
/
KontrBugCAD
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
js/generators/thread-generator.js
1 строка
8 KB
counterbugtech
версия 0.9.37
17 май 2026, 13:43
Верифицирован
17 май 2026, 13:43
31de57b
Код
Авторство
О чём код?
import*as THREE from"three";export class ThreadGenerator{constructor(e){if(!e)throw new Error("ManifoldWrapper обязателен для ThreadGenerator");this.wrapper=e,this.threadStandards={metric:{name:"Метрическая (ГОСТ 24705)",standards:{M3:{diameter:3,pitch:.5,minorDiameter:2.459,threadAngle:60,coilsGap:.15},M4:{diameter:4,pitch:.7,minorDiameter:3.242,threadAngle:60,coilsGap:.15},M5:{diameter:5,pitch:.8,minorDiameter:4.134,threadAngle:60,coilsGap:.15},M6:{diameter:6,pitch:1,minorDiameter:4.917,threadAngle:60,coilsGap:.15},M8:{diameter:8,pitch:1.25,minorDiameter:6.647,threadAngle:60,coilsGap:.15},M10:{diameter:10,pitch:1.5,minorDiameter:8.376,threadAngle:60,coilsGap:.15},M12:{diameter:12,pitch:1.75,minorDiameter:10.106,threadAngle:60,coilsGap:.15},M14:{diameter:14,pitch:2,minorDiameter:11.835,threadAngle:60,coilsGap:.15},M16:{diameter:16,pitch:2,minorDiameter:13.835,threadAngle:60,coilsGap:.15},M20:{diameter:20,pitch:2.5,minorDiameter:17.294,threadAngle:60,coilsGap:.15},M24:{diameter:24,pitch:3,minorDiameter:20.752,threadAngle:60,coilsGap:.15}}},inch:{name:"Дюймовая UNC/UNF",standards:{"1/4-20":{diameter:6.35,pitch:1.27,minorDiameter:5.08,threadAngle:60,coilsGap:.15},"5/16-18":{diameter:7.94,pitch:1.41,minorDiameter:6.48,threadAngle:60,coilsGap:.15},"3/8-16":{diameter:9.53,pitch:1.59,minorDiameter:7.94,threadAngle:60,coilsGap:.15},"1/2-13":{diameter:12.7,pitch:1.95,minorDiameter:10.92,threadAngle:60,coilsGap:.15},"3/4-10":{diameter:19.05,pitch:2.54,minorDiameter:16.41,threadAngle:60,coilsGap:.15},"1-8":{diameter:25.4,pitch:3.18,minorDiameter:22.23,threadAngle:60,coilsGap:.15}}},trapezoidal:{name:"Трапецеидальная (ГОСТ 24738)",standards:{"Tr8x1.5":{diameter:8,pitch:1.5,minorDiameter:6.5,threadAngle:30},Tr10x2:{diameter:10,pitch:2,minorDiameter:8,threadAngle:30},Tr12x3:{diameter:12,pitch:3,minorDiameter:9,threadAngle:30},Tr16x4:{diameter:16,pitch:4,minorDiameter:12,threadAngle:30},Tr20x4:{diameter:20,pitch:4,minorDiameter:16,threadAngle:30},Tr24x5:{diameter:24,pitch:5,minorDiameter:19,threadAngle:30}}},pipe:{name:"Трубная цилиндрическая (ГОСТ 6357)",standards:{"G1/8":{diameter:9.73,pitch:.907,minorDiameter:8.56,threadAngle:55},"G1/4":{diameter:13.16,pitch:1.337,minorDiameter:11.44,threadAngle:55},"G3/8":{diameter:16.66,pitch:1.337,minorDiameter:14.95,threadAngle:55},"G1/2":{diameter:20.96,pitch:1.814,minorDiameter:18.63,threadAngle:55},"G3/4":{diameter:26.44,pitch:1.814,minorDiameter:24.12,threadAngle:55},G1:{diameter:33.25,pitch:2.309,minorDiameter:30.29,threadAngle:55}}},custom:{name:"Произвольная",standards:{}}},this.defaultParams={type:"metric",standard:"M10",diameter:10,pitch:1.5,minorDiameter:8.376,threadAngle:60,length:30,direction:"right",threadType:"external",chamfer:!1,chamferAngle:45,quality:"medium",depthFactor:1,threadClearance:.05,coilsGap:0,leadInLength:1,leadOutLength:1,leadInStartFactor:0,leadOutStartFactor:0}}_getSegmentsCount(e){switch(e){case"high":return 16;case"medium":default:return 8;case"low":return 4}}_getsegmentsPerTurn(e){switch(e){case"high":return 128;case"medium":default:return 64;case"low":return 28}}_adjustRadii(e,t=!1){const r=e.diameter/2,a=e.minorDiameter/2,i=(e.threadClearance||0)*e.pitch;let n=r,h=a,o=a;return t?(n=r+i,h=a+i,o=a+i):(n=r-i,h=a-i,o=a-i),{majorRadius:n,minorRadius:h,shaftRadius:o}}generateThreadProfile(e,t,r){const a=[],i=t-r,n=e.pitch*(1-(e.coilsGap||0)),h=n/2,o=this._getSegmentsCount(e.quality);if("metric"===e.type||"inch"===e.type){const n=THREE.MathUtils.degToRad(e.threadAngle/2),s=i/Math.tan(n),d=.9*h,l=Math.min(s,d),c=h-l;a.push(new THREE.Vector2(r,-h));for(let e=1;e<=o;e++){const t=e/o;a.push(new THREE.Vector2(r+t*i,t*l-h))}a.push(new THREE.Vector2(t,-c)),a.push(new THREE.Vector2(t,c));for(let e=1;e<=o;e++){const r=e/o;a.push(new THREE.Vector2(t-r*i,c+r*l))}a.push(new THREE.Vector2(r,h))}else if("trapezoidal"===e.type){const s=THREE.MathUtils.degToRad(e.threadAngle/2);let d=n-2*(i*Math.tan(s));d<0&&(console.warn("Трапецеидальная резьба: недостаточно места для площадок, они будут нулевыми"),d=0);const l=d/2/2,c=-h+l,m=-l,p=l,u=h-l;a.push(new THREE.Vector2(r,c));for(let e=1;e<=o;e++){const t=e/o;a.push(new THREE.Vector2(r+t*i,c+t*(m-c)))}a.push(new THREE.Vector2(t,m)),a.push(new THREE.Vector2(t,p));for(let e=1;e<=o;e++){const r=e/o;a.push(new THREE.Vector2(t-r*i,p+r*(u-p)))}a.push(new THREE.Vector2(r,u))}else if("pipe"===e.type){const e=2*o;for(let t=0;t<=e;t++){const o=t/e,s=o*n-h,d=r+i*(.5-.5*Math.cos(2*Math.PI*o));a.push(new THREE.Vector2(d,s))}}else a.push(new THREE.Vector2(r,-h)),a.push(new THREE.Vector2(t,0)),a.push(new THREE.Vector2(r,h));return a}createHelicalMesh(e,t,r,a,i,n=0,h=0,o=0,s=0){const d=t/r,l=this._getsegmentsPerTurn(i)||32,c=Math.max(2,Math.ceil(d*l)+1),m=2*Math.PI/l*("right"===a?-1:1),p=r/l,u="left"===a,g=[...e];g.length>2&&Math.abs(g[0].x-g[g.length-1].x)<1e-6&&Math.abs(g[0].y-g[g.length-1].y)<1e-6&&g.pop();const T=g.length;if(T<3)throw new Error("Профиль резьбы должен содержать минимум 3 точки");const E=g[0].x,f=(g[0].y+g[g.length-1].y)/2,w=[],M=[],G=(e,t,r)=>(w.push(e,t,r),w.length/3-1);for(let e=0;e<c;e++){const r=e*m,a=e*p,i=Math.cos(r),d=Math.sin(r);let l=1;if(n>0){l=o+(1-o)*Math.min(1,a/n)}if(h>0){l*=s+(1-s)*Math.min(1,(t-a)/h)}for(const e of g){const t=E+(e.x-E)*l;G(t*i,a+e.y,t*d)}}for(let e=0;e<c-1;e++)for(let t=0;t<T;t++){const r=(t+1)%T,a=e*T+t,i=e*T+r,n=(e+1)*T+t,h=(e+1)*T+r;u?M.push(a,i,n,i,h,n):M.push(a,n,i,i,n,h)}const y=(c-1)*T,A=G(E,f,0),R=(c-1)*m,D=(c-1)*p+f,H=G(E*Math.cos(R),D,E*Math.sin(R));for(let e=0;e<T;e++){const t=(e+1)%T;u?M.push(A,0+t,0+e):M.push(A,0+e,0+t)}for(let e=0;e<T;e++){const t=(e+1)%T;u?M.push(H,y+e,y+t):M.push(H,y+t,y+e)}const x=new THREE.BufferGeometry;return x.setAttribute("position",new THREE.Float32BufferAttribute(w,3)),x.setIndex(M),x.computeVertexNormals(),x}createExternalThreadGeometry(e,t=!1){const{majorRadius:r,minorRadius:a,shaftRadius:i}=this._adjustRadii(e,t),n=this.generateThreadProfile(e,r,a),h=e.length-e.pitch,o=this.createHelicalMesh(n,h,e.pitch,e.direction,e.quality,e.leadInLength||0,e.leadOutLength||0,e.leadInStartFactor||0,e.leadOutStartFactor||0);o.translate(0,e.pitch/2,0);const s=this.wrapper.threeGeometryToManifold(o),d=new THREE.CylinderGeometry(1.001*i,1.001*i,e.length,96,1,!1);d.translate(0,e.length/2,0);const l=this.wrapper.threeGeometryToManifold(d);let c=this.wrapper.manifold.Manifold.union([l,s]);o.dispose(),s.delete(),d.dispose(),l.delete();const m=this.wrapper.manifoldToThreeGeometry(c);return c.delete(),m}createInternalThreadGeometry(e){const t={...e,threadType:"external",length:e.length+2*e.pitch,leadInStartFactor:1.5,leadOutStartFactor:1.5},r=this.createExternalThreadGeometry(t,!0),a=this.wrapper.threeGeometryToManifold(r),i=.7*e.diameter,n=new THREE.CylinderGeometry(i,i,e.length,96,1,!1);n.translate(0,e.length/2,0);const h=this.wrapper.threeGeometryToManifold(n);let o=this.wrapper.manifold.Manifold.difference(h,a);h.delete(),a.delete(),n.dispose(),r.dispose();const s=this.wrapper.manifoldToThreeGeometry(o);return o.delete(),s}createThread(e={}){const t={...this.defaultParams,...e};let r;const a=!0===t.forCutting;r="external"===t.threadType?this.createExternalThreadGeometry(t,a):this.createInternalThreadGeometry(t);const i=new THREE.MeshStandardMaterial({color:"external"===t.threadType?12632256:8421504,roughness:.5,metalness:"external"===t.threadType?.6:.3,flatShading:!0}),n=new THREE.Mesh(r,i);return n.castShadow=!0,n.receiveShadow=!0,n.position.y=0,n.userData={type:"thread",threadType:t.threadType,threadParams:t,name:`${"external"===t.threadType?"Наружная":"Внутренняя"} резьба ${t.standard||t.diameter+"мм"}`,createdAt:(new Date).toISOString()},n}}