歯車について勉強する2 の履歴(No.1)
更新歯車について勉強するシリーズ†
- 歯車について勉強する 歯車の形状についての基礎
- 歯車について勉強する2 仮想的なラックを使って歯車形状を切り出す
ラックを使って歯車を切り出す†
歯車について勉強する でやったようにインボリュート曲線やトロコイド曲線、歯先や歯底やフィレット用の円弧を繋げて歯車形状を作ろうとすると、特に歯元の形状をきれいに作るのがとても難しい。
実際の歯車が製作される際と同様に、仮想的な切削用のラックを想定して、ラックの歯形により切り出される歯車形状を計算すると実際の歯車と同様の自然な歯形を生成できるようだ。
参考: https://involutegearsoft.hatenablog.com/entry/involute-trochoid-draw-tool2
LANG: p5js_live var t;let e;const a=[];function s(t,e,s,h){let r=20*s+20,n=t.createSpan(e).position(20,r),i=t.createSpan(String(h.value));i.position(100,r);let l=t.createSlider(h.min,h.max,h.value,h.step);return l.position(150,r),l.size(300),l.elt.oninput=()=>i.html(String(l.value())),a.push(n,i,l),l}function h(t,e,s,r=0,n=!1){let i=100*r+20,l=20*s+20,o=t.createCheckbox();o.position(i,l),o.checked(n);let u=t.createSpan(e).position(i+20,l);return u.mouseClicked(()=>{o.checked(!o.checked()),o.elt.onchange&&o.elt.onchange()}),u.style("cursor","pointer "),a.push(u,o),o}class r{constructor(t,e){this.x=t,this.y=e}static polar(t,e){return new r(t*Math.cos(e),t*Math.sin(e))}angle(){return Math.atan2(this.y,this.x)}equal(t){return 1e-6>Math.abs(this.x-t.x)&&1e-6>Math.abs(this.y-t.y)}add(t){return new r(this.x+t.x,this.y+t.y)}sub(t){return new r(this.x-t.x,this.y-t.y)}mul(t){return new r(this.x*t,this.y*t)}rotate(t){let e=Math.cos(t),a=Math.sin(t);return new r(this.x*e-this.y*a,this.x*a+this.y*e)}addRotated(t,e){return this.add(e.rotate(t))}flipY(){return new r(this.x,-this.y)}flipX(){return new r(-this.x,this.y)}norm(){return Math.sqrt(this.x*this.x+this.y*this.y)}normalize(t=1){let e=this.norm()/t;return new r(this.x/e,this.y/e)}polar(){return[this.norm(),this.angle()]}inner(t){return this.x*t.x+this.y*t.y}outer(t){return this.x*t.y-this.y*t.x}}function n(t,e){return new r(t,e)}class i extends Array{constructor(t,...e){t instanceof r?(super(t,...e),this.option={}):(super(...e),this.option=t??{})}static circle(t,e=n(0,0),a={},s=100){let h=new i(a);for(let a=0;a<=s;a++){let r=2*Math.PI*a/s;h.push(n(t*Math.cos(r),t*Math.sin(r)).add(e))}return h}draw(t){if(void 0===this.option?.stroke?t.stroke("black"):t.stroke(this.option.stroke),void 0===this.option?.weight?t.strokeWeight(1):t.strokeWeight(this.option.weight),void 0===this.option?.dash?t.drawingContext.setLineDash([]):t.drawingContext.setLineDash(this.option.dash),void 0===this.option?.fill){t.noFill(),t.beginShape();for(let e=0;e<this.length;e++)t.vertex(this[e].x,this[e].y);t.endShape()}else{t.fill(this.option.fill),t.beginShape();for(let e=0;e<this.length;e++)t.vertex(this[e].x,this[e].y);t.endShape(t.CLOSE)}}apply(t,e=this.option){return new i(e,...this.filter(t=>t).map(t))}crossPoint(t){return l(this[0],this[1],t[0],t[1])}direction(t=0){return this[t].sub(this[t+1]).normalize()}}function l(t,e,a,s){let h=e.sub(t),r=s.sub(a),n=a.sub(t),i=h.outer(r);if(0==i)return;let l=n.outer(h)/i,o=n.outer(r)/i;if(!(l<0)&&!(l>1)&&!(o<0)&&!(o>1))return t.add(h.mul(o))}function o(t,e,a){let s=a.sub(e),h=t.sub(e);return Math.abs(s.outer(h)/s.norm())}function u(t,e,a,s=1e-6){for(;t+s<e;){let s=t+(e-t)/3,h=e-(e-t)/3;a(s)<a(h)?e=h:t=s}return(t+e)/2}const c={width:600,height:600,ox:0,oy:0};(t=p).setup=()=>{let{width:r,height:n}=c;c.ox=r/2,c.oy=n/2,t.createCanvas(r,n).style("position","relative"),e=function(t){let e=h(t,"ツールを非表示",27.5,0),r={m:s(t,"モジュール",0,{min:50,max:800,value:150,step:1}),z:s(t,"歯数",1,{min:4,max:100,value:6,step:1}),alpha:s(t,"圧力角",2,{min:10,max:32,value:20,step:1}),shift:s(t,"転位",3,{min:-.5,max:2,value:0,step:.05}),fillet:s(t,"フィレット",4,{min:0,max:.4,value:.4,step:.01}),backlash:s(t,"バックラッシュ",5,{min:0,max:2,value:0,step:.01}),theta:s(t,"回転角",6,{min:-90,max:90,value:0,step:.05}),play:h(t,"自動更新",7.5,0,!0),stop:!1};return a.forEach((t,e)=>{t.style("opacity","0.2"),t.mouseOver(()=>a.forEach(t=>t.style("opacity","1"))),t.mouseOut(()=>a.forEach(t=>t.style("opacity","0.2")))}),r.theta.mousePressed(()=>{r.stop=!0}),r.theta.mouseReleased(()=>{r.stop=!1}),e.elt.onchange=()=>{a.forEach((t,a)=>{a<2||(e.checked()?t.hide():t.show())})},{get m(){return Number(r.m.value())},get z(){return Number(r.z.value())},get alpha(){return Number(r.alpha.value())/180*Math.PI},get shift(){return Number(r.shift.value())*this.m},get theta(){return-(Number(r.theta.value())/180)*Math.PI},set theta(value){r.theta.value(-(180*value)/Math.PI),r.theta.elt.oninput()},get fillet(){return Number(r.fillet.value())*this.m},get mk(){return+this.m},get mf(){return 1.25*this.m},get rp(){return this.m*this.z/2},get rf(){return this.m*this.z/2-this.mf},get rk(){return this.m*this.z/2+this.mk},get backlash(){return Number(r.backlash.value())/100*2*Math.PI/this.z},get play(){return r.play.checked()&&!r.stop}}}(t)},t.draw=()=>{let a;let{ox:s,oy:h}=c;t.background(220);let{m:d,z:m,alpha:f,shift:y,theta:g,rp:w,rk:M,rf:k,backlash:x,play:b}=e,{sin:v,max:P,PI:I,cos:z,abs:G,min:S,ceil:R}=Math;if(b){let t=e.theta-.1*I/180;t<=-I/2&&(t=I/2),e.theta=t}let[E,N,C,B,q]=function(t){let e,{m:a,z:s,alpha:h,shift:r,theta:l,fillet:o,mf:u,mk:c,rp:d,rk:m}=t,f=[];o=function(t){let{m:e,alpha:a,fillet:s,mf:h,mk:r}=t;return Math.max(s=Math.min(s,(h-r)/(1-Math.sin(a)),(e*Math.PI/4-(e+h-r)*Math.tan(a))/Math.tan(Math.PI/4-a/2)),0)}(t);let y=Math.PI*a,g=new i({stroke:"Green",dash:[5,5],weight:1},n(-y-u*Math.tan(h),d+u+r),n(-y+c*Math.tan(h),d-c+r),n(-y/2-c*Math.tan(h),d-c+r),n(-y/2+u*Math.tan(h),d+u+r),n(-u*Math.tan(h),d+u+r),n(c*Math.tan(h),d-c+r),n(y/2-c*Math.tan(h),d-c+r),n(y/2+u*Math.tan(h),d+u+r),n(y-u*Math.tan(h),d+u+r),n(y+c*Math.tan(h),d-c+r),n(3*y/2-c*Math.tan(h),d-c+r),n(3*y/2+u*Math.tan(h),d+u+r));f.push(g);let w=new i({stroke:"Green",dash:[3,3],weight:2},n(-u*Math.tan(h),d+u+r),n(u*Math.tan(h),d-u+r));f.push(w);let M=new i({stroke:"Green",dash:[3,3],weight:2},n(u*Math.tan(h),d-u+r),n(a*Math.PI/4,d-u+r));f.push(M);let k=new i({stroke:"Green",dash:[10,6,4,6]},n(a*Math.PI/4,0),n(a*Math.PI/4,m+a+r));if(f.push(k),o>0){let t=w.direction().rotate(-Math.PI/2),a=w.apply(e=>e.add(t.mul(o))),s=M.apply(t=>t.add(n(0,o)));(e=a.crossPoint(s))||(e=a.crossPoint(k));let r=new i({stroke:"Green",dash:[3,3],weight:2});if(e){let t=h+Math.PI,a=3*Math.PI/2;for(let s=0;s<=20;s++){let h=t+(a-t)*s/20;r.push(n(e.x+o*Math.cos(h),e.y+o*Math.sin(h)))}f.push(r),w[1]=r[0],M[0]=r[r.length-1]}else e=w[1]}else{let t=w.crossPoint(k);t?(w[1]=t,M.splice(0),e=t):e=w[1]}f.push(i.circle(a/50,e,{stroke:"Green",fill:"Green"}));let x=new i({stroke:"Green",weight:2},n(c*Math.tan(h),d-c+r),n(a*Math.PI/4,d-c+r)),b=new i({stroke:"Green",weight:2},w[0],x[0]);return f.push(x,b),w[1].equal(x[0])?w.splice(0):w[0]=x[0],f.push(new i({stroke:"Green",dash:[10,10]},n(-a*Math.PI,d+r),n(a*Math.PI,d+r))),[f,b[0],b[1],e,o]}(e),L=[],O=(t,e)=>e.add(n(w*t,0)).rotate(t),Y=(t,e)=>e.rotate(t+I/2).add(n(w*(z(t)-t*v(t)),w*(v(t)+t*z(t))));E=E.map(t=>t.apply(t=>O(g,t)));let D=t=>{let e=O(t,N),a=O(t,C).sub(e),s=Y(t,N),h=Y(t,C).sub(s),r=s.outer(a)/h.outer(a);return[e.sub(a.mul(r)),r]},W,X,A=[];W=u(0,90-f,t=>G(D(t)[0].norm()-M-y)),D(W)[0].angle()>I*(1+1/m)/2-x&&(W=u(0,W,t=>G(D(t)[0].angle()-(I*(1+1/m)/2-x)))),X=u(0,-2*f,t=>D(t)[0].norm());let F=new i({stroke:"Red",weight:2});for(let t=0;t<100;t++){let e=W+(X-W)*t/100;F.push(D(e)[0]),A.push(e)}let j=new i({stroke:"Red",weight:2});if(F[0].angle()-I*(1+1/m)/2+x<-.001){let t=F[0].angle(),e=I*(1+1/m)/2-x;for(let a=0;a<=20;a++){let s=t+(e-t)*a/20;j.push(n((M+y)*z(s),(M+y)*v(s)))}}L.push(j);let H=new i({stroke:"Green",dash:[2,2]}),J,K,Q=[];for(J=0;;J-=.01){let t=B.add(n(w*J,0)).rotate(J);if(H.unshift(t),t.norm()>w+y+d/4)break}for(K=.01;;K+=.01){let t=B.add(n(w*K,0)).rotate(K);if(H.push(t),t.norm()>w+y+d/4)break}E.push(H);let T=new i({stroke:"Red",weight:2}),U=t=>{let e=O(t,B),a=Y(t,B).normalize(q),s=e.addRotated(-I/2,a),h=e.addRotated(I/2,a);return s.x+s.y<h.x+h.y?s:h},V=u(J,K,t=>U(t).norm());O(V,B).norm()>w&&([J,K]=[K,J]),K=V;let Z=!1,$=1,_=J;for(let t=0;t<=100;t+=$){let e=J+(K-J)*t/100,s=U(e);Z||s.norm()>C.norm()&&s.sub(C).angle()<I/2+f||(Z=!0,_=e,T.push(a),Q.push(e-(K-J)*$/100)),Z&&(T.push(s),Q.push(e));let h=O(e,B);if(t>0&&h.sub(O(V,B)).norm()<d/1e3){let t=-G(s.sub(O(V,B)).angle()),e=-I*(1+1/m)/2+x,a=R(G(e-t)/I*180);for(let s=1;s<=a;s++){let h=t+(e-t)*s/a;T.push(O(V,B).add(r.polar(q,h)))}break}t>0&&s.sub(a).norm()>d/100&&($/=2),a=s}J=_,(()=>{F=F.apply(t=>t),T=T.apply(t=>t);let[t,e,a]=function(t,e){let a=0,s=0;for(;a<t.length-1&&s<e.length-1;){if(t[a+1].y>e[s].y){a++;continue}if(t[a].y<e[s+1].y){s++;continue}let h=l(t[a],t[a+1],e[s],e[s+1]);if(h)return[h,a,s];t[a+1].y>e[s+1].y?a++:s++}return[]}(F,T);if(t)F.splice(e+1,1/0,t
),T.splice(0,a+1,t),X=A[e],J=Q[a];else{let[t,e,a,s]=function(t,e){let a=0,s=0,h=[1/0];for(;a<t.length-1&&s<e.length-1;){if(t[a+1].y>e[s].y){a++;continue}if(t[a].y<e[s+1].y){s++;continue}if(t[a].y<e[s].y){let r=o(t[a],e[s],e[s+1]);r<h[0]&&(h=[r,a,s,0])}else{let r=o(e[s],t[a],t[a+1]);r<h[0]&&(h=[r,a,s,1])}t[a+1].y>e[s+1].y?a++:s++}return h}(F,T);s?(F.splice(e+1,1/0,T[a]),T.splice(0,a)):(F.splice(e+1,1/0),T.splice(0,a+1,F[e])),X=A[e],J=Q[a]}})(),L.push(F),L.push(T);let tt=D(g)[0];X<=g&&g<=W&&E.push(i.circle(5,tt));let te=U(g);S(J,K)<=g&&g<=P(J,K)&&E.push(i.circle(5,te,{stroke:"Green"}));let ta=new i({stroke:"Red",weight:2});if(T.length>0){let t=T[T.length-1].angle(),e=T[T.length-1].norm();if(t-I*(1-1/m)/2+x>.001){let a=I*(1-1/m)/2-x;for(let s=0;s<20;s++){let h=t+(a-t)*s/20;ta.push(r.polar(e,h))}}}L.push(ta),E.push(new i({stroke:"Blue",dash:[10,6,3,6]},n(0,0),n(0,M+d+y)));let ts=new i({stroke:"Blue",dash:[10,10]}),th=new i({stroke:"Blue",dash:[10,10]}),tr=new i({stroke:"Blue",dash:[10,10]});for(let t=0;t<=100;t++){let e=I*t/100;tr.push(n(k*z(e),k*v(e))),ts.push(n(w*z(e),w*v(e))),y&&th.push(n*1w+y)*z(e),(w+y)*v(e)}E.push(ts,tr,th),E.push(new i({stroke:"Red",weight:1,dash:[10,6,3,6]},n(0,0),n*2M+d+y)*z(I*(1-1/m)/2),(M+d+y)*v(I*(1-1/m)/2)),E.push(new i({stroke:"Red",weight:1,dash:[10,6,3,6]},n(0,0),n*3M+d+y)*z(I*(1+1/m)/2),(M+d+y)*v(I*(1+1/m)/2)),(E=E.map(t=>t.apply(t=>t.flipY().add(n(s,h+w))))).forEach(e=>e.draw(t)),L.push(...L.map(t=>t.apply(t=>t.rotate(-I/m/2+x).flipX().rotate(I/m/2-x),{...t.option,weight:1,dash:[5,5]}))),L.push(...L.map(t=>t.apply(t=>t.rotate(2*I/m),{...t.option,weight:1,dash:[5,5]}))),(L=(L=(L=[...L,...L.map(t=>t.apply(t=>t.rotate(-4*I/m),{...t.option,weight:1,dash:[5,5]}))]).map(t=>t.apply(t=>t.rotate(x)))).map(t=>t.apply(t=>t.flipY().add(n(s,h+w))))).forEach(e=>e.draw(t))};
*1 w+y)*z(e),(w+y)*v(e
*2 M+d+y)*z(I*(1-1/m)/2),(M+d+y)*v(I*(1-1/m)/2
*3 M+d+y)*z(I*(1+1/m)/2),(M+d+y)*v(I*(1+1/m)/2