Files
linuxcncWebWASM/scripts/generate_rtcp_beginner_figures.py

104 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Original diagrams for the beginner's work-coordinate handbook."""
import shutil
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import font_manager
from matplotlib.patches import Rectangle, Polygon
import numpy as np
ROOT=Path(__file__).resolve().parents[1]
OUT=ROOT/'docs/teaching/rtcp-beginners/assets';OUT.mkdir(parents=True,exist_ok=True)
font_manager.fontManager.addfont('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc')
plt.rcParams.update({'font.family':'Noto Sans CJK JP','font.size':14,'axes.unicode_minus':False})
BLUE,TEAL,RED,GRAY,INK='#2563b8','#00877b','#d45549','#8a969f','#23303a'
for name in ['machine-ac','machine-bc','hierarchy','identity-no-follow','tcp-follow','rotated-direction','bc-frame','pivot-offset','arc-chord','tool-length','orientation']:
shutil.copyfile(ROOT/f'docs/teaching/rtcp-five-axis/assets/{name}.png',OUT/f'{name}.png')
def save(fig,name):
fig.savefig(OUT/f'{name}.png',dpi=190,facecolor='white',bbox_inches='tight',pad_inches=.18);plt.close(fig)
def arrow(ax,start,end,color,label='',dx=0,dy=0):
ax.annotate('',end,start,arrowprops={'arrowstyle':'-|>','lw':2,'color':color})
if label:ax.text(end[0]+dx,end[1]+dy,label,color=color,fontsize=14)
fig,ax=plt.subplots(figsize=(8,4.2));ax.set(xlim=(-8,55),ylim=(-8,38),aspect='equal');ax.axis('off')
for x in range(0,51,10):ax.plot([x,x],[0,30],c='#dce6ec',lw=1);ax.text(x,-4,str(x),ha='center',fontsize=12,color=GRAY)
for y in range(0,31,10):ax.plot([0,50],[y,y],c='#dce6ec',lw=1);ax.text(-4,y,str(y),va='center',fontsize=12,color=GRAY)
arrow(ax,(0,0),(54,0),BLUE,'X',-1,-5);arrow(ax,(0,0),(0,36),BLUE,'Y',-5,-1)
ax.scatter([30],[20],s=90,color=RED);ax.plot([30,30,0],[0,20,20],ls='--',color=RED,lw=1.5)
ax.text(32,22,'P = (30, 20) mm',color=RED);ax.text(2,32,'先选原点,再沿指定方向量距离',fontsize=14,color=INK)
save(fig,'coordinate-grid')
fig,ax=plt.subplots(figsize=(8,4.4));ax.set(xlim=(-10,95),ylim=(-10,60),aspect='equal');ax.axis('off')
arrow(ax,(0,0),(90,0),BLUE,'X_M',-8,-7);arrow(ax,(0,0),(0,56),BLUE,'Y_M',-8,-2)
arrow(ax,(40,20),(79,20),TEAL,'X_W',0,-2);arrow(ax,(40,20),(40,54),TEAL,'Y_W',2,0)
ax.scatter([50],[35],s=95,color=RED);ax.text(54,38,'同一个点 P',color=RED)
ax.plot([50,50,40],[20,35,35],ls='--',color=TEAL);ax.text(43,24,'10',color=TEAL);ax.text(32,27,'15',color=TEAL)
ax.annotate('O_W 在 M 中为 (40,20)',(40,20),xytext=(23,6),fontsize=12,arrowprops={'arrowstyle':'->','color':GRAY})
ax.text(3,46,'P_M=(50,35)\nP_W=(10,15)',fontsize=15,color=INK)
save(fig,'same-point')
fig,axes=plt.subplots(1,2,figsize=(10,5))
for ax,c in zip(axes,[0,90]):
ax.set(xlim=(-55,85),ylim=(-28,95),aspect='equal');ax.axis('off')
arrow(ax,(0,0),(78,0),BLUE,'X_M',-5,-12);arrow(ax,(0,0),(0,85),BLUE,'Y_M',-18,-1)
rad=np.deg2rad(c);r=np.array([[np.cos(rad),-np.sin(rad)],[np.sin(rad),np.cos(rad)]])
o=r@np.array([40,20]);point=r@np.array([50,20]);x=r@np.array([25,0]);y=r@np.array([0,25])
poly=np.array([o+r@np.array(v) for v in [[-5,-5],[30,-5],[30,20],[-5,20]]]);ax.add_patch(Polygon(poly,fc='#e1f2ee',ec=TEAL,alpha=.65))
arrow(ax,o,o+x,TEAL,'X_W',2,0);arrow(ax,o,o+y,TEAL,'Y_W',2,0)
ax.scatter(*o,color=TEAL,s=70);ax.scatter(*point,color=RED,s=100,marker='*')
ax.text(-48,89,f'C = {c}°',color=INK,fontsize=17)
ax.text(-48,-23,f'O_M=({o[0]:.0f},{o[1]:.0f})\nP_M=({point[0]:.0f},{point[1]:.0f})',color=INK,fontsize=13)
label_position=(12,57) if c else (-45,67)
ax.annotate('P:X10,Y0',point,xytext=label_position,arrowprops={'arrowstyle':'->','color':RED},color=RED,fontsize=12)
fig.subplots_adjust(wspace=.15)
save(fig,'moving-origin')
fig,ax=plt.subplots(figsize=(8,4.5));ax.axis('off');ax.set(xlim=(-10,120),ylim=(-15,80),aspect='equal')
front=np.array([[10,15],[85,15],[85,38],[10,38]]);side=np.array([[85,15],[108,37],[108,60],[85,38]]);top=np.array([[10,38],[85,38],[108,60],[33,60]])
for poly,color in [(front,'#d4e3e8'),(side,'#b9cdd3'),(top,'#e5f2ef')]:ax.add_patch(Polygon(poly,fc=color,ec=GRAY))
origin=(10,38);arrow(ax,origin,(66,38),TEAL,'+X',0,-7);arrow(ax,origin,(33,60),TEAL,'+Y',-4,7);arrow(ax,origin,(10,72),TEAL,'+Z',2,0)
ax.scatter(*origin,color=RED,s=70);ax.annotate('示例:顶面左前角为零点',origin,xytext=(5,2),arrowprops={'arrowstyle':'->','color':RED},color=RED,fontsize=14)
ax.scatter([65],[48],color=BLUE,s=130,facecolors='none');ax.annotate('也可选孔中心\n必须与CAD/CAM约定一致',(65,48),xytext=(75,74),arrowprops={'arrowstyle':'->','color':BLUE},color=BLUE,fontsize=12)
save(fig,'datum-choice')
fig,ax=plt.subplots(figsize=(8,4.5));ax.axis('off');ax.set(xlim=(-20,110),ylim=(-20,85),aspect='equal')
o=np.array([15,8]);a=np.deg2rad(20);u=np.array([np.cos(a),np.sin(a)]);v=np.array([-np.sin(a),np.cos(a)])
pts=[o,o+u*75,o+v*45]
ax.plot([pts[1][0],o[0],pts[2][0]],[pts[1][1],o[1],pts[2][1]],color=TEAL,lw=2)
for p,label,dx,dy in zip(pts,['O:所选原点','P_x:确定 +X','P_y:确定 XY 面'],[-12,2,-10],[-12,0,6]):ax.scatter(*p,s=80,color=RED);ax.text(p[0]+dx,p[1]+dy,label,fontsize=13,color=INK)
arrow(ax,o,o+u*93,TEAL,'+X',0,0);arrow(ax,o,o+v*62,TEAL,'+Y',-5,3)
arrow(ax,(-8,-9),(100,-9),BLUE,'机床 X',-25,-8)
ax.text(48,64,'工件不能只靠“一个点”\n确定全部方向',color=INK,fontsize=15,ha='center')
save(fig,'orientation-measure')
fig,axes=plt.subplots(2,1,figsize=(8,3.6))
for ax,title,target in zip(axes,['当前位置 X=10,G90 X20','当前位置 X=10,G91 X20'],[20,30]):
ax.set(xlim=(-3,39),ylim=(-1,6));ax.axis('off');arrow(ax,(0,1),(37,1),BLUE)
for x in [0,10,20,30]:ax.plot([x,x],[.8,1.2],color=GRAY);ax.text(x,-.2,str(x),ha='center',fontsize=13)
ax.text(0,4,title,fontsize=15,color=INK);ax.scatter([10],[1],color=GRAY,s=70);ax.scatter([target],[1],color=RED,s=90)
arrow(ax,(10,2),(target,2),RED);ax.text((10+target)/2,2.8,f'实际移动 {target-10}',ha='center',color=RED,fontsize=12)
fig.subplots_adjust(hspace=.35);save(fig,'absolute-incremental')
fig,ax=plt.subplots(figsize=(8,4));ax.axis('off');ax.set(xlim=(0,10),ylim=(0,5))
rows=[('① 程序工件点 W','(10, 0, 5)',TEAL),('② 加 G54 零位偏置','+(40, 20, 10)',GRAY),('③ 运动学输入 K','(50, 20, 15)',BLUE),('④ C=90°,RTCP变换','(-20, 50, 15)',RED)]
for i,(label,value,color) in enumerate(rows):
y=4.15-i*1.06;ax.add_patch(Rectangle((.3,y-.34),9.3,.74,fc='#eef4f6',ec='none'))
ax.text(.55,y,label,color=color,fontsize=15,va='center');ax.text(6.1,y,value,color=color,fontsize=16,va='center')
if i<3:ax.text(5,y-.58,'↓',ha='center',va='center',color=GRAY)
save(fig,'offset-pipeline')
c=np.linspace(0,90,181);r=np.deg2rad(c);qx=50*np.cos(r)-20*np.sin(r);qy=50*np.sin(r)+20*np.cos(r)
fig,ax=plt.subplots(figsize=(8,4));ax.plot(c,qx,color=BLUE,lw=2.4,label='关节 X');ax.plot(c,qy,color=TEAL,lw=2.4,label='关节 Y');ax.plot(c,np.full_like(c,15),color=RED,lw=2.4,label='关节 Z')
ax.set(xlabel='C 角度(°)',ylabel='关节位置(mm)',xlim=(0,90));ax.grid(alpha=.2);ax.legend(loc='lower left',ncol=3,fontsize=12);ax.set_title('程序 X10 Y0 Z5 保持;关节由RTCP连续计算',fontsize=15,color=INK)
fig.tight_layout();save(fig,'continuous-joints')
fig,ax=plt.subplots(figsize=(6.7,4.1));ax.set(aspect='equal',xlim=(-3,14),ylim=(-3,14));ax.axis('off')
arrow(ax,(0,0),(13,0),BLUE,'X',0,-1);arrow(ax,(0,0),(0,13),BLUE,'Y',-1,0)
t=np.linspace(0,np.pi/2,100);ax.plot(10*np.cos(t),10*np.sin(t),color=TEAL,lw=3)
arrow(ax,(8.5,5.27),(7.8,6.25),TEAL);ax.scatter([10,0,0],[0,10,0],color=[RED,TEAL,GRAY],s=80)
ax.text(6.8,-1.8,'起点 (10,0)',color=RED,fontsize=13);ax.text(.8,10.5,'终点 (0,10)',color=TEAL,fontsize=13)
ax.text(2.8,3.5,'圆心 (0,0)\nI=-10,J=0',color=INK,fontsize=14)
ax.plot([10,0],[0,0],ls=':',color=GRAY,lw=2);save(fig,'arc-words')
print('Created 9 new diagrams and reused 11 verified original assets:',OUT)