如何用代碼畫出一隻齒輪?

如題。求大神不吝賜教


卸腰。。有很多圖,請在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); } }

然後把它們畫出來:

double r = diameter/Math.sqrt(2);
for(int i =0;i&

再套上外殼,關於外殼的完成,其實也是貝塞爾曲線的一種應用,請參考我的另一篇回答:

https://www.zhihu.com/question/37231903/answer/139438769

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

最後,再把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文件里就可以在瀏覽器里愉快地調試了。

&
&
&

body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}

form {
position: absolute;
top: 1em;
left: 1em;
}

path {
fill-rule: evenodd;
stroke: #333;
stroke-width: 2px;
}

.sun path {
fill: #6baed6;
}

.planet path {
fill: #9ecae1;
}

.annulus path {
fill: #c6dbef;
}

& &

& &