如何用代碼畫出一隻齒輪?
如題。求大神不吝賜教
卸腰。。有很多圖,請在wifi下觀看
齒輪的形狀是多種多樣的,我沒有畫漸開線齒輪(對不起各位機械大佬了),簡單畫一個好實現的思路;
1,把一個圓的邊緣均分分成若干點:
while (angular&<(2*Math.PI)+sportAngular){
PointF p = new PointF((float)( centerF.x+(diameter/2)*Math.cos(angular)),(float) (centerF.y+(diameter/2)*Math.sin(angular)));
breadthP.add(new BreadthP(p,angular));
angular+=breadth;
}

2,然後呢,把這些點用path連接起來:

有的同學肯定會說:你騙人,這東西和齒輪有jj關係;
別著急啊,想要畫出彎彎曲曲的圓周曲線,我們需要先做一道初中數學題來取用來做貝塞爾曲線的點:

已知O點坐標,日1,日2,x1,y1,x2,y2。求xq,yq的坐標值?
小明同學出色的完成了算術題:

求出貝塞爾點之後,我們的圖形變成這個樣子:

再將偶數點取負:

這一段的代碼實現:
我們將取點的密度提高一倍,中間再加個圓圈:for(int i =0;i&

這是不就像是個齒輪了?
再加上個角自增的線程:
Runnable runnable =new Runnable() {
@Override
public void run() {
angle+=(float) (Math.PI/100);
gear.setSportAngular(angle);
invalidate();
handler.postDelayed(this,5);
}
};
handler .postDelayed(runnable,0);


你以為這樣就ok了?那你也太小看我上班閑的程度了,接下來,我們再來點難度,不知道同學們有沒有聽說過一種九齒聯動的指尖陀螺:

國外超火的指尖陀螺,這次是9個齒輪聯動!_機械_科技_bilibili_嗶哩嗶哩
我們先根據規定陀螺轉心的位置,畫出9個齒輪的圓心:
/*
5 6 7
4 0 8
3 2 1
*/
private void setFixPoints() {
fixPoints .clear();
float d = (float) (diameter/Math.sqrt(2));
fixPoints.add(centerF);
for (int i =1 ;i&<9 ; i++ ){
float j = (i%2==0) ? d : diameter;
PointF p = new PointF((float) (centerF.x+ ( j*Math.cos(sportAngular+ Math.PI*i/4))),(float) (centerF.y+j*Math.sin(sportAngular+ Math.PI*i/4)));
fixPoints.add(p);
}
}
然後把它們畫出來:
再套上外殼,關於外殼的完成,其實也是貝塞爾曲線的一種應用,請參考我的另一篇回答: https://www.zhihu.com/question/37231903/answer/139438769double r = diameter/Math.sqrt(2);
for(int i =0;i&



再加上單獨齒輪旋轉的效果:


最後,再把touch事件寫好:
@Override
public boolean onTouchEvent(MotionEvent event){getTracker(event);
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startY = event.getY();
startX = event.getX();
float r = (float) (nineGearLinkage.getShell().getDiameter()/Math.sqrt(2)+nineGearLinkage.getShell().getR());
boolean a = Math.abs(centerF.x-startX)&boolean a1 = Math.abs(centerF.y-startY)& if(aa1){
isOut = false;
}else {
isOut = true;
}
dV = 0;
startThread();
sA = (float) Math.atan((startY-centerF.y)/(startX-centerF.x));
if(mTracker==null){
mTracker = VelocityTracker.obtain();
}else{
mTracker.clear();
}
mTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
X = event.getX();
Y = event.getY();
mA = (float) Math.atan((Y-centerF.y)/(X-centerF.x));if(isOut){
nineGearLinkage.setAngleV(0,mA-sA);
}else {
angle = mA-sA;
nineGearLinkage.setAngleV(angle ,0);
}invalidate();
mTracker.addMovement(event);
mTracker.computeCurrentVelocity(1000);break;
case MotionEvent.ACTION_UP:
float b = Math.abs(X-startX)&>Math.abs(Y-startY)? (startX-X): (Y-startY);
mV = (b&>0)? getSpeed(): -(getSpeed());
dV = mV;
cancelTracker();
startThread();break;
}
return true;
}


照例,我要把源碼放出來給各位同學參考:
wuyongxiang/Gear
從看見這個問題,到完成效果,我差不多花了15,6個小時,還不算我偷偷避開老闆的時間,各位同學你們看到這真的忍心不贊一下嗎?
工程上應用最多的是漸開線齒輪,圓弧齒輪應用比漸開線少,故本答案主要考慮漸開線齒輪的齒廓繪製。注意圖多。
先上最終效果:

淘寶上隨便找了個圖對比下輪廓(請自動忽略掉水印):

兩個齒輪(11齒和31齒):

放大看嚙合部分,看看嚙合得多麼完美:

1.首先推導漸開線方程
漸開線是一條與圓相切的直線在圓上滾動,直線上定點所形成的軌跡。

用MATLAB試試:
clear;clc;
rb=20
alphaK=0:0.01:1
thetaK=tan(alphaK)-alphaK
rK=rb./cos(alphaK)
polar(thetaK,rK)
alphaK從0到1,rb暫時取20。下面是繪圖效果:

可以看到漸開線已經出來了,不過是從0°開始畫,我們希望最後生成的齒廓在y軸正方向能夠剛好有一個齒在中間,並且左右對稱。所以需要加一點角度。
2. 計算4個圓的半徑
先不管上面說的角度。下面把4個圓算出來:
%塊1
clear;clc;
m=1;%模數
z=17;%齒數
ha=1;c=0.25;x=0;%齒頂高係數;頂隙係數;變位係數
alpha=deg2rad(20);%壓力角
r=z*m/2;%分度圓半徑
ra=r+(ha+x)*m;%齒頂圓半徑
rf=r-(ha+c-x)*m;%齒根圓半徑
rb=r*cos(alpha);%基圓半徑
circle(0,0,r,"black")
circle(0,0,rb,"black")
circle(0,0,ra,"r")
circle(0,0,rf,"b")
其中circle是一個自定義函數,用來畫圓的。circle.m如下:
function []=circle(x,y,r,cr)
rectangle("Position",[x-r,y-r,2*r,2*r],"Curvature",[1,1],"edgecolor",cr),axis equal
end
得到圖片(上面的缺口是截圖缺陷):

由外向內依次是齒頂圓,分度圓,基圓,齒根圓。從這裡開始的rb就不是第1節隨便取的20了,而是模數1,齒數17,不變位的標準齒輪的基圓半徑。
3.偏移漸開線
第1節的漸開線在x正方向,不爽。加90度轉到上面來:
%上接塊1
alphaK=0:0.01:1
thetaK=tan(alphaK)-alphaK+pi/2
rK=rb./cos(alphaK)
polar(thetaK,rK)

好了,這樣可以發現,在thetaK後面加上角度就可以旋轉漸開線的起點。
但是齒輪有齒有溝,怎麼把齒放在中間?下圖P1點是現在漸開線上的點,P2點是旋轉後的點。

寫代碼:
%上接塊1
alphaK=0:0.01:1
p=pi*m;%齒距
s=p/2+2*x*m*tan(alpha);%齒厚
theta1=tan(acos(rb/r))-acos(rb/r);
theta2=s/(2*r);
thetaK=tan(alphaK)-alphaK+pi/2-theta1-theta2
rK=rb./cos(alphaK)
polar(thetaK,rK)
這時可以看到漸開線起點已經偏移到位了。

但上面那截還有點多餘。漸開線的盡頭是齒頂圓,所以只要得到齒頂圓和漸開線的交點,讓漸開線畫到交點就行了。
回到漸開線方程。

回到上一段代碼,把alphaK改成:
alphaK=0:0.01:acos(rb/ra);
得到:

之後畫出齒頂圓的圓弧,再把之前的漸開線鏡像一下(轉為直角坐標,x取負,再轉回極坐標)。代碼略(最後會給出總代碼),得到圖:

紅線是齒頂圓,藍線是齒根圓。基圓比齒根圓大,中間有段過渡曲線。這個部分就非常麻煩了,因為根據齒輪加工方式的不同,這段曲線是刀具包絡形成的,在范成法加工時是擺線。建模上一般用圓弧和直線代替。
下面這個圖是參考文獻2里的,感受一下:

所以我就用圓弧和直線代替齒根輪廓了,一般建模也是這麼處理的。
從這裡開始符號換一換,theta-&>beta, theta1-&>beta1, theta2-&>beta2。另外把偏移角挪到最後來處理。
把單個齒形輪廓劃分為8段。

1,2,3我們已經得到。4是一條指向圓心的直線,6是齒根圓弧,5是4和6之間的圓角並且與4和6都是相切的關係。
5是一條弧線,圓心不在極坐標軸原點,在直角坐標下要好算坐標一些。先編寫函數arc求弧線的點:
function [x y]=arc(Ox,Oy,r,angle1,angle2,all_step)%逆時針
t=angle1:(angle2-angle1)/all_step:angle2;
x=r.*cos(t)+Ox;
y=r.*sin(t)+Oy;
end
Ox, Oy, r 是圓心坐標和半徑;angle1, angle2是弧線開始和結束的角;all_step是取點的數量。
設弧線5的半徑是rb-rf的一半(這個是我個人設置的,因為嚴格的齒根輪廓在成型法加工時是刀具輪廓,在范成法加工時是擺線,這裡的齒根輪廓僅作建模及示意使用[註:這句話有誤,詳見最後])。下面推導弧線5的圓心及始末角:

綜合以上,得出一個齒形的代碼:
%代碼A
clear;clc;
m=1;%模數
z=17;%齒數
ha=1;c=0.25;x=0;%齒頂高係數;頂隙係數;變位係數
alpha=deg2rad(20);%壓力角
r=z*m/2;%分度圓半徑
ra=r+(ha+x)*m;%齒頂圓半徑
rf=r-(ha+c-x)*m;%齒根圓半徑
rb=r*cos(alpha);%基圓半徑
%circle(0,0,r,"black")
%circle(0,0,rb,"black")
%circle(0,0,ra,"r")
%circle(0,0,rf,"b")
hold on;
axis equal;
p=pi*m;%齒距
s=p/2+2*x*m*tan(alpha);%齒厚
beta1=involute(acos(rb/r))
beta2=s/(2*r)
beta=beta1+beta2;
%第1段 漸開線
alphaK=0:0.01:acos(rb/ra);
thetaK1=involute(alphaK)-beta;%自定義函數
rK1=rb./cos(alphaK);
%第2段 齒頂圓
thetaba=involute(acos(rb/ra))
thetaa=beta-thetaba
theta2=-thetaa:0.01:thetaa;
rou2=ra*ones(1,length(theta2));
%第3段 漸開線 = 漸開線1鏡像
[x,y]=pol2cart(thetaK1,rK1);
y=-y;
[theta3,rou3]=cart2pol(x,y);
theta3=fliplr(theta3)%倒序排列
rou3=fliplr(rou3)%倒序排列
%第4段 直線
rr=(rb-rf)/2;
t_start=beta;
t_end=t_start;
r_end=sqrt((rr+rf)^2-rr^2);
theta4=[t_start t_end];
rou4=[rb r_end];
%倒數第1段 直線=直線4鏡像
[x_1 y_1]=pol2cart(theta4,rou4);
y_1=-y_1;
[theta_1 rou_1]=cart2pol(x_1,y_1);
%第5段 圓角
HE=rr;OH=rf+rr;
gama=asin(HE/OH);
epsilon=pi/2-gama-beta;
Hx=OH*sin(epsilon);
Hy=OH*cos(epsilon);
angle1=pi+gama+beta;
angle2=angle1+(pi/2-gama);
[x5 y5]=arc(Hx,Hy,rr,angle1,angle2,10);%自定義函數
[theta5 rou5]=cart2pol(x5,y5);
theta5=fliplr(theta5)%倒序排列
rou5=fliplr(rou5)%倒序排列
%倒數第2段 圓角 = 圓角5鏡像
x_2=x5;y_2=-y5;
[theta_2 rou_2]=cart2pol(x_2,y_2);
%第6段 齒根圓弧
phi=2*pi/z-2*beta-2*gama;
theta6=beta+gama:0.01:beta+gama+phi;
rou6=rf*ones(1,length(theta6));
theta=[theta_2 theta_1 thetaK1 theta2 theta3 theta4 theta5 theta6];%
rou=[rou_2 rou_1 rK1 rou2 rou3 rou4 rou5 rou6];%
start=pi/2;
theta=theta+start;%
polar(theta,rou)%單個齒形曲線
如圖:

用一個for語句作圓周陣列:
%上接代碼A
%本節為代碼B
theta_all=[];rou_all=[];
for i=0:(z-1)
temp_theta=theta+2*pi/z*i;
temp_rou=rou;
theta_all=[theta_all temp_theta];
rou_all=[rou_all temp_rou];
end
polar(theta_all,rou_all);
得到1個齒輪:

加齒輪也很簡單:
%上接代碼B
[gear1x gear1y]=pol2cart(theta_all,rou_all);
gear2x=gear1x;
gear2y=gear1y+2*r;
plot(gear2x,gear2y);
因為齒輪以y軸對稱,所以直接在y軸方向偏移中心距就可以了。

把前面的代碼包裝成函數,就可以生成其他齒數、模數、變位係數等參數的齒輪了。
比如下面這個:

大齒輪15齒,變位係數-0.3。小齒輪5齒,變位係數0.3。當然這個圖只作為演示,沒有驗算根切條件……我好像說得太多了。就這樣結束吧。
MATLAB代碼還是很直觀的,改一改就可以用C, JAVA等其他語言來畫了。
另外,上面的圓角部分沒有驗算圓角存在條件,齒數較大及較小時會出現圓角失真,這種情況手動設置下圓角半徑就行了。另外,變位係數較大時兩個漸開線會相交,這種情況需要求交點並省略掉齒頂圓弧,我懶得處理這部分代碼了。
動畫我懶得做了(MATLAB可以做動畫)。
另外,忽略我醜陋的公式圖,因為懶得輸公式,直接照了照片。
源碼已傳GitHub: tomwillow/DrawGearContour
參考文獻
[1] 謝進, 萬朝燕, 杜立傑. [M]機械原理. 北京: 高等教育出版社. 2004.
[2] 李濱城, 徐超. [M]機械原理MATLAB輔助分析. 北京: 化學工業出版社. 2011.
對根切感興趣的可以看這個問題及回答:pengcheng:齒輪少於17個齒就不能轉嗎?
pengcheng:一道關於齒輪設計(非標準齒輪)的問題?『
更新:
評論區 @zmztx 指出:
關於「所以我就用圓弧和直線代替齒根輪廓了,一般建模也是這麼處理的。」
用一根直線代替齒根輪廓,很不合理。齒根過渡曲線的幾何意義是避免嚙合中的干涉。用圓角還說的過去,用直線就說不過去了。為了避免干涉,則在漸開線與過渡曲線切點(沒有根切),因為你只用一根直線,為了避開嚙合的齒輪齒頂,直線要向入體方向極度撇進去,那麼齒根將變得很難看;如果不撇進去,必然出現干涉。另外,「嚴格的齒根輪廓在范成法加工時是擺線」,正確的是,在用齒條刀具(滾齒刀)做范成方式加工齒坯時,過渡曲線為等距延伸漸開線。在用齒輪刀具(插齒刀)做范成方式加工齒坯時,過渡曲線為等距延伸外擺線。
大家注意我的齒根輪廓僅為示意,不是實際情況。齒輪裡面確實門道太多了,上學時書上就沒怎麼講齒根輪廓怎麼回事,兩句話就帶過了。上面pengcheng的答案講得非常好,非常透徹。
請大家關注下 @pengcheng ,這是一個專業的齒輪工程師,我僅僅是本科畢業而已,不要再贊我了,只是做了點科普的小工作,拋磚引玉而已,圖還這麼粗糙。大家去看看 @pengcheng 的答案,這才是知乎之寶。
高贊答主這個是在Android上面實現的,可移植性不強,這類代碼還是用JS實現更加喜聞樂見一點。
那麼就要推薦Javascript裡面著名的可視化工具包D3(Data-Driven Documents)啦,這個強大的工具包可以畫出這種

這種

還有這種

的精美數據可視化。
然後有人藉助D3.js的框架畫了個行星齒輪組的演示:
Epicyclic Gearing

可以畫出這樣的齒輪組,看起來很酷炫是不是?而且還會動呢。
雖然是放在了D3.js的gallery里,但其實每一個齒輪都是通過如下的源生JS代碼定義的:
function gear(d) {
var n = d.teeth,
r2 = Math.abs(d.radius),
r0 = r2 - 8,
r1 = r2 + 8,
r3 = d.annulus ? (r3 = r0, r0 = r1, r1 = r3, r2 + 20) : 20,
da = Math.PI / n,
a0 = -Math.PI / 2 + (d.annulus ? Math.PI / n : 0),
i = -1,
path = ["M", r0 * Math.cos(a0), ",", r0 * Math.sin(a0)];
while (++i &< n) path.push(
"A", r0, ",", r0, " 0 0,1 ", r0 * Math.cos(a0 += da), ",", r0 * Math.sin(a0),
"L", r2 * Math.cos(a0), ",", r2 * Math.sin(a0),
"L", r1 * Math.cos(a0 += da / 3), ",", r1 * Math.sin(a0),
"A", r1, ",", r1, " 0 0,1 ", r1 * Math.cos(a0 += da / 3), ",", r1 * Math.sin(a0),
"L", r2 * Math.cos(a0 += da / 3), ",", r2 * Math.sin(a0),
"L", r0 * Math.cos(a0), ",", r0 * Math.sin(a0));
path.push("M0,", -r3, "A", r3, ",", r3, " 0 0,0 0,", r3, "A", r3, ",", r3, " 0 0,0 0,", -r3, "Z");
return path.join("");
}
然後通過D3.js的API就可以把齒輪生成出來
var width = 960,
height = 500,
radius = 120,
x = Math.sin(2 * Math.PI / 3),
y = Math.cos(2 * Math.PI / 3);
var offset = 0,
speed = 4,
start = Date.now();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(.55)")
.append("g");
var frame = svg.append("g")
.datum({radius: Infinity});
frame.append("g")
.attr("class", "planet")
.attr("transform", "translate(0,-" + radius + ")")
.datum({teeth: 32, radius: -radius * 2})
.append("path")
.attr("d", gear);
通過改改參數,就可以得到不同尺寸的形態的齒輪

大家也能看出來,其實這個齒輪並不是按照機械上的漸開線或者外擺線齒形來設計的。但是其實修改起來也不難,我沒時間弄了,大家可以自己試試。JS的好處是,只要把下面一段代碼保存到一個.html文件里就可以在瀏覽器里愉快地調試了。
&
&
&
&
&
&
var width = 960,
height = 500,
radius = 70,
x = Math.sin(2 * Math.PI / 3),
y = Math.cos(2 * Math.PI / 3);
var offset = 0,
speed = 4,
start = Date.now();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")scale(.55)")
.append("g");
var frame = svg.append("g")
.datum({radius: Infinity});
frame.append("g")
.attr("class", "planet")
.attr("transform", "translate(0,-" + radius + ")")
.datum({teeth: 20, radius: -radius * 2})
.append("path")
.attr("d", gear);
function gear(d) {
var n = d.teeth,
r2 = Math.abs(d.radius),
r0 = r2 - 8,
r1 = r2 + 8,
r3 = d.annulus ? (r3 = r0, r0 = r1, r1 = r3, r2 + 20) : 20,
da = Math.PI / n,
a0 = -Math.PI / 2 + (d.annulus ? Math.PI / n : 0),
i = -1,
path = ["M", r0 * Math.cos(a0), ",", r0 * Math.sin(a0)];
while (++i &< n) path.push(
"A", r0, ",", r0, " 0 0,1 ", r0 * Math.cos(a0 += da), ",", r0 * Math.sin(a0),
"L", r2 * Math.cos(a0), ",", r2 * Math.sin(a0),
"L", r1 * Math.cos(a0 += da / 3), ",", r1 * Math.sin(a0),
"A", r1, ",", r1, " 0 0,1 ", r1 * Math.cos(a0 += da / 3), ",", r1 * Math.sin(a0),
"L", r2 * Math.cos(a0 += da / 3), ",", r2 * Math.sin(a0),
"L", r0 * Math.cos(a0), ",", r0 * Math.sin(a0));
path.push("M0,", -r3, "A", r3, ",", r3, " 0 0,0 0,", r3, "A", r3, ",", r3, " 0 0,0 0,", -r3, "Z");
return path.join("");
}
d3.timer(function() {
var angle = (Date.now() - start) * speed,
transform = function(d) { return "rotate(" + angle / d.radius + ")"; };
frame.selectAll("path").attr("transform", transform);
frame.attr("transform", transform); // frame of reference
});
&
看大神花式炫技,想說畫個齒輪沒有那麼難- -。都有sin展成曲線了,也有漸開線公式推導,我想說,漸開線不就是直線展成曲線嗎- -(更正!直線是漸開線的一個特例,但是漸開線不是直線直接展成的,直接展成的是阿基米德螺線,,?^?,,怎麼畫漸開線後面有提,唉唉唉你們記得往後看看啊(? ???ω??? ?)
不啰嗦了,上代碼!
先畫個sin試試手:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0,10,1000)
y = np.sin(x)
plt.plot(x, y)
plt.show()

不能再簡單,那就展成一下吧!
r = 3
w = 10
x = np.linspace(0,10,1000)
y = np.sin(w*x)+r
ax1 = plt.subplot(111, projection="polar")
ax1.plot(x, y)
plt.show()

初具形態了呢!興奮地搓搓手,開始畫齒條:
看看看!是不是很像sin函數呢?(人家明明是cos好嗎!!) 我已經等不及了,展成一下: ax1 = plt.subplot(111, projection="polar") 嚙合一下: plt.figure(figsize=(6,6)) 為啥要多加0.25?沒想明白,不過嚙合效果倒是挺好的~(原來這個是阿基米德螺線齒輪啊,難怪。不過下面的肯定是漸開線齒輪!!) 聽說有人算不了根切(的齒輪輪廓,感謝 @Tom Willow 指出語法錯誤)?這怎能難倒我! 先畫個齒條: plt.xlim(-20, 20) 轉一下試試看: plt.figure(figsize=(6,6)) 為什麼要轉一下呢?當然是模擬齒輪成形啦~ racks = [] plt.figure(figsize=(6,6)) 加工好啦!!!來求一下輪廓吧! racks = [] 太完美啦~完全沒有根切(17齒,目測orz)~ 看看5齒根切是什麼樣的~ 哎呀我的媽,不能看,溜了溜了~ 留個讚唄,嘻嘻~ 根據評論要求畫個內齒輪: 代碼就不放了,一樣樣的。32齒照樣畫噢~圖為16齒和32齒嚙合。但是16齒對17齒就不行了,如下所示: 不過9齒對17齒好像又可以: 依稀可以看清9齒的樣子,貌似還都可以接受呢~最後來一個5齒對10齒: 逃了掏了,寫簡歷去了~~ 晚上做數學題的時候,看到這個問題,覺得挺有趣。 @祥子 巨巨辛苦了,看了巨巨的答案,我有了另一個想法,這不sin函數曲線繞圓一周嘛!來,我們把圖中圓看似一條直線(想像成地平線),以圓邊這條線為x軸,做sin或cos函數,繞圓轉一圈,即為一個齒輪的形狀。因為自己不是機械專業的,不懂這個齒輪需不需要滿足什麼曲線方程以減少齒輪與齒輪之間轉動的損耗之類的。 如圖,(做題累了,寫的好醜= =)角θ為轉動的弧度,x=弧長=r·θ,y=sinx+r (圖中漏掉r),所以路徑上點P((sin(rθ)+r)cosθ, (sin(rθ)+r)sinθ),坐標出來了。寫代碼吧 附上JS canvas實現的代碼: OK,以下是效果圖: 一個小齒輪搞定了,剩下的怎麼讓他轉動,怎麼做九齒輪,相信你可以自己發揮的。(??????) ? 20分鐘搞定,雖然沒有十幾小時,但是..也好想要一個贊贊~ 完。 /* * 以上是原答案 * 下面是補充 */ 在調參數的時候,出現下面不完美的圖形: 仔細想想得到: sin函數因為美觀需要,要變得長一些,於是我們加了個參數d,即構成sin(dx),於是sin函數周期變成了2πd,圓的周長為2πr,可得2πr/2πd需要為整數,這樣才是整數個sin函數周期,才不會出現上圖所示尷尬圖形,即 r=nd,n為整數。 好了,參數關係有了,評論區 @Petra 說:你的齒輪沒有軸啊~ 畫圓啊,so easy,請看: 代碼如下: Github完整源碼:itibbers/zhihu-gear,歡迎分享與交流~ 有空再接著補充和擴展。 Peace. 來個Mathematica的漸開線齒輪作法 Wolfram Demonstrations Project 代碼太長了就不放了 再來個收集了各種漸開線齒輪系統的網站 Gear Inventions and Artwork 其中也收集了用Mathematica作圖的代碼 雖然跑題了還是要說MMA大法好 歪個樓。 去年有陣子迷上了用一個div元素畫畫,畫過一個齒輪的,代碼在這裡:yiting007/singleDiv 畫齒輪,首先要弄清楚齒輪是怎麼工作的。當然,如果只是做個動畫,在視覺上過得去就行了。以下說的是能正確工作的齒輪 齒輪工作,是一對齒輪對滾,也就是兩個齒輪。這兩個齒輪的輪齒輪廓線要滿足一定條件,即曲線必須是共軛。因此,齒輪的輪廓可以是各種曲線,但他們應該符合共軛的條件 在機械中最常用的齒廓是漸開線曲線的。但是要注意,齒廓的漸開線部分,是輪齒對滾(專業術語叫嚙合)中相互接觸的那部分曲線。還有一部分曲線叫做過渡曲線,這部分不參與對滾。可是沒有這部分,齒輪的輪齒在對滾時也許會被咬死(卡死),專業名詞叫做干涉。當然為了不咬死就把這部分過渡曲線加大,這會導致輪齒折斷。 根據以上介紹,應該知道了和齒輪對滾有關係的齒廓曲線是兩部分:漸開線段和過渡曲線段。漸開線段的曲線方程就是漸開線;過渡曲線部分則要看是怎麼加工的,正常情況下是等距延伸漸開線或者等距延伸擺線(統稱旋輪線)。 對於學機械的來說,畫齒輪一般用3D/CAD軟體。先畫出對稱輪齒的一半齒廓,然後鏡像出對稱的另外一半,再陣列。再拉伸。一個或者一對齒輪就出來了。他們真正是可以對滾,並且確保不出現干涉、不出現不合理的嚙合(比如重合度過小就會出現轉動不均勻,時轉時停)。齒廓曲線是由四段組成:齒頂圓、漸開線段、過渡曲線段、齒根圓。這其中的漸開線段、過渡曲線段難度要大。 在開始畫齒輪齒廓前,需要知道這樣一些參數:齒數、模數(齒輪傳動的專用概念,下面的都是)、壓力角、齒頂高係數、頂隙係數、加工刀具的圓角、變位係數。這幾個確定後,齒廓曲線就確定了(嚴格說,是漸開線圓柱直齒輪)。一個齒輪的參數不下幾十個,其他的都是由這幾個基本參數計算出來的。 還要了解齒廓是怎麼生成的。齒輪加工最常見的是范成法(在專用機床上用刀具轉出來的)。簡單原理是:兩個圓做無滑動滾動。對於插齒刀是兩個節圓,對於滾齒刀是節線(滾齒刀的)在齒坯分度圓(這個概念要清楚)做無滑動滾動。而齒廓則是由刀具的切削刃一點點形成的。這就是所謂的范成法。 畫齒廓曲線(計算齒廓曲線坐標)的思路不止一種:有的是用統一的滾動角,將漸開線和過渡曲線一次畫出來。這種方法典型的是用法線法,可以不涉及漸開線方程。於是在不出現根切的情況下,齒廓曲線是連續且光滑;有的是分別畫出漸開線部分和過渡曲線部分,再設法將他們拼在一起,效果是一樣的。這種思路一般是用漸開線方程,但過渡曲線方程往往也是用法線法推導出來的。至於發生了根切,則只有用數值方法來處理了。再有就是近似方法,上面帖子中似乎大多數是用的近似方法,或者只要求視覺像就行了。 假如你看完上面的內容,覺得麻煩。那麼真正繪製出準確的齒廓曲線,則要比這麻煩十倍,幾十倍。 還要提醒,即便是關於齒輪的經典著作,公式幾乎沒有全對的,要不就是腳標錯了,要麼是字母錯了。千萬要仔細。否則,你的曲線總也不對。就算你自己統統推導一遍,最後一檢查,也有錯誤。 無意中看到這個問題,正好這段時間花了2個月業餘時間研究齒輪,用AS3寫了一個齒輪機構設計的playground,發上來顯擺一下:(話說dead language + AIR還是很好用,暫時找不到替代) 漸開線齒輪,齒數(N) 壓力角(Pa) 模(M) 可調,精確齦合。 本來想學習各位答主的專業精神來解釋下過程,在腦中仔細回想了一下還是放棄了……(研究兩個月,能通俗易懂的解釋寫成文章估計兩個月都不止。真的寫了,估計能仔細研究的人也是非常非常少的),放幾張研究過程收集的有用資料如下,諸位如果真有興趣深入研究,可以留言,本人盡量解答。 齒輪漸開線繪製流程通俗解釋:(重要程度 5星) Circle Involute -- from Wolfram MathWorld 齒輪參數圖示:(重要程度 4星) 齒輪參數計算公式:(重要程度 2星) 也許未來某天心血來潮把代碼放到github上 什麼?怎麼畫在笛卡爾坐標系? 漸開線齒輪更新了。畫了一下午天都黑了。(百度百科上的漸開線的函數是錯的。)齒廓是由點構成的,沒有現成的曲線方法可以調用。 不是很完美,在計算過程中有好多取整的運算。最後存在累積誤差。齒數與模數設置小的時候不是很明顯,齒數多的時候齒輪就看到缺陷了。比如: 截屏額操作會觸發repaint()方法,所以圖片一閃一閃的。代碼太多了,裡面還涉及一些機械基礎的知識,就不貼了。(反正也沒人看)。 --------分割線-------- 看見你們的齒輪都可以動,我重新用java寫了個可以動的齒輪。(python中tkinter的沒找到怎麼畫函數曲線,理論上來說用小烏龜可以畫漸開線齒輪,但太煩了,我想用java試一下,意外發現齒輪可以動了) //gif圖好難弄啊,還要下截屏軟體; java代碼如下: int m = 15; //齒輪模數 g.setColor(color.blue);//這邊怎麼有一個連接?? ----------------以下為原答案------------- 剛用python寫了一個直齒圓柱齒輪的畫法,有一點不標準。明天補個漸開線齒輪。 我本來就是學機械的畫齒輪還是很簡單的。齒輪的齒頂齒根其實都是圓弧。兩側面是漸開線的。我暫時用直線畫了一個。 root = Tk() canvas.create_arc( xf= df/2*math.cos(math.radians(360/z*(i+0.5)))+400 canvas.pack() Iconfont-阿里巴巴矢量圖標庫 && &
& 唉, 樓上一堆公式, 我這切圖仔真心看不懂呀, 要是頁面上整個齒輪用 JS 也太重(low)了. 來, 47行的純 CSS 齒輪, 還會轉哦 .gear-rotate { 需要齒輪咬合? 來, 56行 CSS .two-gears-rotate:before, .two-gears-rotate:after { 好吧, 我是抄自這兒的 one-div.com 這個網站只用一個 div 用純 CSS 來實現各種圖形效果 這種大顯身手的機會,也可以交給processsing來!雖是小眾軟體,但是術業有專攻! 在processing里,畫齒輪最有意思的是可以把齒輪當成自製的封閉圖形來看待和編寫代碼。 畫齒輪的思路: beginShape(); + 一個for循環畫齒輪的輪廓線條 + endShape(CLOSE);即是一個齒輪! 運行效果1: processing代碼1: void setup(){ 可以觀察到,程序中,齒輪的齒數和齒輪的半徑是可以通過參數很快改變的。 運行效果2: 先靜態將齒數、半徑不相等,但齒大小相同的兩個齒輪調至嚙合。 processing代碼2: 運行效果3: processing代碼3: translate(125,height/2); 加入動態效果,速度可以通過參數theta1、theta2進行調節。 這個程序還可以加入很多齒輪的細節,用processing這樣編寫代碼會比較簡約,數學關係也比較鮮明。processing是C和Java的結合產物,而且processing開源,如果想用其他編程語言,實現這種繪製封閉圖形的思想方法,可以查看、參考一下processing相關函數的內部代碼。 LOGO語言? 說句題外話,我很久之前就碰到過一個大四的畢設就是類似的玩意兒,他用的安卓,拿出了手機給我看了這麼一個適應屏幕的齒輪,用來做遊戲的 坐標,杭州下沙區 ※高斯模糊的原理是什麼,怎樣在界面中實現?def rack(x, a=20, m=1):
x = x % (np.pi*m)
k = np.tan((90-a)/180*np.pi)
tr = np.array([np.pi/4-1/k, np.pi/4+1.25/k, np.pi*3/4-1.25/k, np.pi*3/4+1/k])*m
y = []
for xi in x.flat:
if xi&

m = 1
z = 17
r = z*m/2
x = np.linspace(0,2*np.pi,1000)
y = rack(x*r)+r
ax1.plot(x, y)
plt.show()

m = 1
z = 17
r = z*m/2
theta = np.linspace(0,2*np.pi,1000)
rho = rack(theta*r)+r
x = rho*np.cos(theta)
y = rho*np.sin(theta)
plt.xlim((-3, 3))
plt.ylim((-3, 3))
plt.plot(x+r+0.25, y)
plt.plot(x-r, y)
plt.show()

m = 1
z = 17
r = z*m/2
x = np.linspace(-10, 10, 1000)
y = -rack(x)+r
plt.ylim(-20, 20)
plt.plot(x, y)
plt.show()

phi = np.pi/3
xr = x*np.cos(phi)-y*np.sin(phi)
yr = x*np.sin(phi)+y*np.cos(phi)
plt.xlim(-20, 20)
plt.ylim(-20, 20)
plt.plot(xr, yr)
plt.show()

m = 1
z = 17
r = z*m/2
x = np.linspace(-2*np.pi*r, 0, 1000)
y = -rack(x)+r
for phi in np.arange(0, 2*np.pi, np.pi/100):
x += np.pi/100*r
xr = x*np.cos(phi)-y*np.sin(phi)
yr = x*np.sin(phi)+y*np.cos(phi)
racks.append((xr.copy(), yr.copy()))
plt.xlim(-20, 20)
plt.ylim(-20, 20)
for rk in racks:
plt.plot(rk[0], rk[1])
plt.show()

m = 1
z = 17
r = z*m/2
x = np.linspace(-2*np.pi*r, 0, 1000)
y = -rack(x)+r
contour = np.array([2*r for i in range(1000)])
for phi in np.arange(0, 2*np.pi, np.pi/100):
x += np.pi/100*r
xr = x*np.cos(phi)-y*np.sin(phi)
yr = x*np.sin(phi)+y*np.cos(phi)
racks.append((xr.copy(), yr.copy()))
d = np.sqrt(xr**2+yr**2)
theta = (np.arctan(yr/xr)+np.pi*(xr&<=0))*(xr!=0)+((np.pi/2)*(yr&>0)+(np.pi/2)*yr&<=0)*(xr==0)
theta[theta&<0] += 2*np.pi
idx = theta/2/np.pi*1000//1
for i, j in enumerate(idx):
j = int(j)
contour[j] = min(contour[j], d[i])
ax1 = plt.subplot(111, projection="polar")
ax1.plot(np.arange(0, 2*np.pi, np.pi/500), contour)
plt.show()







&
&
&
&
&
&
&
&
&
&




function gear(c, x, y, r){
var a = 1/r; // 步長,可固定值
var A = 6; // 振幅A
var d = 4; // 拉長sin函數
c.beginPath();
for (var i = 0; i &< 2 * Math.PI; i+=a) {
// P( (sin(ri)+r)cos(i), (sin(ri)+r)sin(i))
c.lineTo(x + ( A * Math.sin(r * i / d) + r ) * Math.cos(i), y + ( A * Math.sin(r * i / d) + r ) * Math.sin(i));
}
c.closePath();
c.stroke();
// 畫齒輪內圓
c.beginPath();
c.arc(x, y, r/2, 0, 2*Math.PI);
c.stroke();
}









確定只是齒輪?齒輪有函數的呀…
極坐標系下的
r=齒輪半徑+齒的深度*sin(齒的數量*t)
比如
r=10+sin(20t)
的圖像就是個有個20個齒的齒輪,半徑為10,齒的深度為1,雖然不是真正的齒輪,但已經很像了,用在遊戲里足夠了
如圖:
不用謝…

坐標轉換呀!
我真的不是抖機靈
找設計給你出個svg 除非特殊需求
否則自己動手寫繪製代碼完全是對進度的浪費
人家AI軟體滑鼠點點劃劃幾分鐘的功夫
你要連寫帶算好幾個鐘頭
完全是以己之短搏人之長...






import java.awt.*;
import javax.swing.*;
public class RRun extends JFrame implements Runnable {
static int i = 300; //起始偏移量
static int j = 300;
static double x = 100;
static double y = 0;
int r=100;//旋轉半徑
static int bq=0;
static int jiaodu=0;
static double hudu = 0;//弧度
static double jiaov = 1;//角速度
public RRun() {
this.setSize(800, 700);
this.setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
int z =30; //齒數
int d =m*z ;//分度圓
double da=d+2*m; //齒頂圓
double df=d-2.5*m; //齒根圓
// g.setStroke(new BasicStroke(1f));
// g.drawOval(i -d/2, j-d/2, d, d);
// g.drawArc(i -(int)df/2,i-(int)df/2,(int)df,(int)df,jiaodu,180);
// g.fillOval(i+(int) x-10, j + (int) y-10, 20, 20);
for(int i1=0;i1&
#畫齒輪
import math
if __name__ == "__main__":
from tkinter import *
root.title("Canvas")
canvas = Canvas(root,width = 900,height = 900,bg = "yellow")
x = 400#圓心坐標
y = 400
m = 15 #齒輪模數
z =30 #齒數
d =m*z
da=d+2*m #齒頂圓
df=d-2.5*m #齒根圓
for i in range(1,z+1):
canvas.create_arc(
(x-da/2,y-da/2,x+da/2,y+da/2),
style = ARC, #指定樣式
start = 360/z*i, #指定起始角度
extent = 360/z-8 #指定角度偏移量
)
(x-df/2,y-df/2,x+df/2,y+df/2),
style = ARC, #指定樣式
start = 360/z*(i+0.5), #指定起始角度
extent = 360/z-8 #指定角度偏移量
)
yf= df/2*math.sin(math.radians(360/z*(i+0.5)))+400
xa= da/2*math.cos(math.radians(360/z*i))+400
ya= da/2*math.sin(math.radians(360/z*i))+400
xa0= da/2*math.cos(math.radians(360/z*(i+1)-360/z+8))+400
ya0= da/2*math.sin(math.radians(360/z*(i+1)-360/z+8))+400
xf1= df/2*math.cos(math.radians(360/z*(i+0.5)-360/z+8))+400
yf1= df/2*math.sin(math.radians(360/z*(i+0.5)-360/z+8))+400
canvas.create_line(xf1,yf1,xa,ya)
canvas.create_line(xf,yf,xa0,ya0)
root.mainloop()

&
&
&
&
ios嘛? 可以用貝賽爾曲線~
這個問題...雖然是問用代碼畫...但是畫的是齒輪
標題沒一個跟機械相關....
都以為齒輪是尖頂或圓頂是吧....
不理解齒廓線方程畫個蛋蛋
普通設計用到齒輪 ME是拖庫畫的
只有搞傳動跟摩擦的才會研究齒廓線構型
又是計算機萬能系列...真替機械心疼

@-webkit-keyframes gear-rotate {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(180deg); }
}
@-moz-keyframes gear-rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(180deg); }
}
@keyframes gear-rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(180deg); }
}
width: 2em;
height: 2em;
background: #2C2C2C;
position: relative;
border-radius: 1em;
-webkit-animation: 1s gear-rotate steps(10) infinite;
-moz-animation: 1s gear-rotate steps(10) infinite;
animation: 1s gear-rotate steps(10) infinite;
}
.gear-rotate::before {
width: 2.8em;
height: 2.8em;
background: -webkit-linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),-webkit-linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),-webkit-linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
background: -moz-linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),-moz-linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),-moz-linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
background: -o-linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),-o-linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),-o-linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
background: -ms-linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),-ms-linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),-ms-linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
background: linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
position: absolute;
content:"";
top: -.4em;
left: -.4em;
border-radius:1.4em;
}
.gear-rotate::after {
width: 1em;
height: 1em;
background: #EEEEEE;
position: absolute;
content:"";
top: .5em;
left: .5em;
border-radius: .5em;
}

@-webkit-keyframes two-gears-rotate-top {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(-180deg); }
}
@-moz-keyframes two-gears-rotate-top {
0% { transform: rotate(0deg); }
100% { transform: rotate(-180deg); }
}
@keyframes two-gears-rotate-top {
0% { transform: rotate(0deg); }
100% { transform: rotate(-180deg); }
}
@-webkit-keyframes two-gears-rotate-bottom {
0% { -webkit-transform: rotate(30deg); }
100% { -webkit-transform: rotate(210deg); }
}
@-moz-keyframes two-gears-rotate-bottom {
0% { transform: rotate(30deg); }
100% { transform: rotate(210deg); }
}
@keyframes two-gears-rotate-bottom {
0% { transform: rotate(30deg); }
100% { transform: rotate(210deg); }
}
width: 2em;
height: 2em;
content:"";
display:block;
background: -webkit-radial-gradient(center, #EEE 25%, #2C2C2C 25%, #2C2C2C 55%, transparent 55%), -webkit-linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),-webkit-linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),-webkit-linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
background: -moz-radial-gradient(center, #EEE 25%, #2C2C2C 25%, #2C2C2C 55%, transparent 55%), -moz-linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),-moz-linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),-moz-linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
background: -o-radial-gradient(center, #EEE 25%, #2C2C2C 25%, #2C2C2C 55%, transparent 55%), -o-linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),-o-linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),-o-linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
background: -ms-radial-gradient(center, #EEE 25%, #2C2C2C 25%, #2C2C2C 55%, transparent 55%), -ms-linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),-ms-linear-gradient(60deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),-ms-linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
background: radial-gradient(center, #EEE 25%, #2C2C2C 25%, #2C2C2C 55%, transparent 55%), linear-gradient(0deg,transparent 39%,#2C2C2C 39%,#2C2C2C 61%, transparent 61%),linear-gradient(50deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%),linear-gradient(120deg,transparent 42%,#2C2C2C 42%,#2C2C2C 58%, transparent 58%);
border-radius: 1em;
font-size: 0.5em;
position: absolute;
}
.two-gears-rotate {
font-size:20px;
width: 2em;
height: 2em;
position: relative;
}
.two-gears-rotate:before {
-webkit-animation: 1s two-gears-rotate-top steps(20) infinite;
-moz-animation: 1s two-gears-rotate-top steps(20) infinite;
animation: 1s two-gears-rotate-top steps(20) infinite;
}
.two-gears-rotate:after {
top: 1.8em;
-webkit-animation: 1s two-gears-rotate-bottom steps(20) infinite;
-moz-animation: 1s two-gears-rotate-bottom steps(20) infinite;
animation: 1s two-gears-rotate-bottom steps(20) infinite;
}


int n=18;
float R=70,r=60,theta,delta=2*PI/n,space=delta/3;
size(400,200);
smooth();
noStroke();
}
void draw(){
background(0,150,255);
translate(width/2,height/2);
fill(255);
beginShape();
for(int i=0;i&
int n1=10,n2=16;
float R1=50,r1=38,theta,delta1=2*PI/n1,space1=delta1/3;
float R2=80,r2=68, delta2=2*PI/n2,space2=delta2/3;
void setup(){
size(400,200);
smooth();
noStroke();
}
void draw(){
background(0,150,255);
translate(125,height/2);
fill(255);
beginShape();
for(int i=0;i&

float n1=10,n2=16;
float R1=50,r1=38,theta1,delta1=2*PI/n1,space1=delta1/3;
float R2=80,r2=68,theta2,delta2=2*PI/n2,space2=delta2/3;
void setup(){
size(400,200);
smooth();
noStroke();
//frameRate(50);
}
void draw(){
background(0,150,255);
fill(255);
beginShape();
for(int i=0;i&
難道已經全都忘記了autolisp語言么?機械的大佬吶?
推薦閱讀:
※用漢語能開發出計算機軟、硬體嗎?
※什麼是函數式編程思維?
※王小波的計算機水平到底有多好?
※epoll 或者 kqueue 的原理是什麼?
