一.为什么 连孔加除毛刺孔

原因是 PCB板材中含有玻璃纤维, 毛刺产生位置在于2个孔相交位置,由于此处钻刀受力不均导致纤维切削不断形成毛刺 ,为了解决这个问题:在钻完2个连孔后,在相交处再钻一个孔,并钻进去一点(常规进去1-2mil),这样就可以将纤维毛刺去除

PCB同行业毛刺问题处理办法 钻孔孔内毛刺问题分析改善报告

二.如何判断除毛刺孔是加1个还是2个呢?

在PCB行业工程加除毛刺孔是加1个孔还是2个孔,没有太明确的定义,只要满足毛刺去除即可.

我们先看下面这个示例(采用此加1个除毛刺孔,会呈现此效果,2边削切宽度不一样)为了防止此切削宽度不一致现象,所以需采用增加2个除毛刺孔。

这边测试后得出一个判断条件(但不一定适合所有工厂),加1个除毛刺孔条件需满足: (1.槽半径小于三分之二大圆半径时,增加1个毛刺孔   2.槽宽>=0.8mm,增加1个毛刺孔),否则需加2个毛刺孔

三.连孔加除毛刺孔实现原理

除毛刺孔,这里列举几个关键参数,如下图所示(因为求解的参数太多,画图不好呈现,具体请看下方的代码)

1.加1 个孔

2.加2个孔

四.C#简易代码实现:

1.加除毛刺孔代码

  1. #region 加除毛刺孔 mcdrl
  2. gLayer glayer = g.getFEATURES($"{"drl"}", g.STEP, g.JOB, "mm", true);
  3. gP hole = glayer.Plist[];
  4. gL line = glayer.Llist[];
  5. gA arc = calc2.p_2A(hole);
  6. List<gP> gpList = calc2.l2a_IntersectHole(line, arc,1.3,0.076);
  7. addCOM.pad(gpList);
  8. #endregion

2.计算函数

  1. /// <summary>
  2. /// 求线段与弧2个交点
  3. /// </summary>
  4. /// <param name="L1"></param>
  5. /// <param name="L2"></param>
  6. /// <param name="HoleScale">当加1个孔时 是开口宽度1.3倍</param>
  7. /// <param name="CutInner">切入板内0.05mm</param>
  8. /// <returns></returns>
  9. public List<gP> l2a_IntersectHole(gL l, gA a, double HoleScale = 1.3, double CutInner = 0.05)
  10. {
  11. List<gP> gpList = new List<gP>();
  12. double Lwidth = l.width * 0.001;
  13. gL lineL, lineR;
  14. l_offset(l, Lwidth * 0.5, out lineL, out lineR);
  15. gPoint gpL = new gPoint();
  16. gPoint gpR = new gPoint();
  17. int isIntersectL = , isIntersectR = ;
  18. double A_Radius = p2p_di(a.pc, a.ps);
  19. gL l1 = l2a_Intersect(lineL, a, ref gpL, ref isIntersectL);
  20. gL l2 = l2a_Intersect(lineR, a, ref gpR, ref isIntersectR);
  21. gL gpL1 = new gL(l1.ps, l2.ps, );
  22. double gpL1di = l_Length(gpL1);
  23. gL gpL2 = new gL(l1.pe, l2.pe, );
  24. double gpL2di = l_Length(gpL2);
  25. if (isIntersectL + isIntersectR < )
  26. gpL1di = ;
  27. //钻1个孔条件
  28. if (gpL1di < A_Radius * 0.667 && gpL1di >= 0.8) //当小于Slot槽宽要小于0.667倍大圆半径,且Slot槽需大于0.8
  29. {
  30. if (p2p_di(lineL.ps, a.pc) >= A_Radius && p2p_di(lineR.ps, a.pc) >= A_Radius)
  31. {
  32. double Hole_Radius = ((int)(Math.Ceiling(((gpL1di + CutInner) * HoleScale * ) / )) * ) * 0.0005;
  33. gP gpL1P = l2a_CentereExtend(gpL1, a, Hole_Radius - CutInner);
  34. gpList.Add(new gP(gpL1P.p, (Hole_Radius) * ));
  35. }
  36. if (p2p_di(lineL.pe, a.pc) >= A_Radius && p2p_di(lineR.pe, a.pc) >= A_Radius)
  37. {
  38. double Hole_Radius = ((int)(Math.Ceiling(((gpL2di + CutInner) * HoleScale * ) / )) * ) * 0.0005;
  39. gP gpL2P = l2a_CentereExtend(gpL2, a, Hole_Radius - CutInner);
  40. gpList.Add(new gP(gpL2P.p, (Hole_Radius) * ));
  41. }
  42. }
  43. else //钻2个孔
  44. {
  45. double Radius = (isIntersectL + isIntersectR < ) ? Lwidth * 0.5 : gpL1di * 0.5;
  46. double multiLval = multi(lineL.ps, lineL.pe, a.pc);
  47. double multiRval = multi(lineR.ps, lineR.pe, a.pc);
  48. bool isSameSide = (multiLval >= && multiRval >= ) || (multiLval <= && multiRval <= );
  49. int line1L_Position = , line1R_Position = ; ;
  50. if (isSameSide)
  51. {
  52. if (Math.Abs(multiLval) > Math.Abs(multiRval))
  53. line1R_Position = ;
  54. else
  55. line1L_Position = ;
  56. }
  57. if (isIntersectL == )
  58. {
  59. gL_di line1L = l2a__Round(lineL, a, 0.05, 0.5, , line1L_Position);
  60. if (line1L.isIntersect)
  61. {
  62. gPoint pointLP1 = p_val_ang(line1L.pc, Radius - CutInner, line1L.ang_direction);
  63. gpList.Add(new gP(pointLP1, Radius * ));
  64. }
  65. gL_di line1R = l2a__Round(lineL, a, 0.05, 0.5, , line1L_Position);
  66. if (line1R.isIntersect)
  67. {
  68. gPoint pointLP2 = p_val_ang(line1R.pc, Radius - CutInner, line1R.ang_direction);
  69. gpList.Add(new gP(pointLP2, Radius * ));
  70. }
  71. }
  72. if (isIntersectR == )
  73. {
  74. gL_di line2L = l2a__Round(lineR, a, 0.05, 0.5, , line1R_Position);
  75. if (line2L.isIntersect)
  76. {
  77. gPoint pointRP3 = p_val_ang(line2L.pc, Radius - CutInner, line2L.ang_direction);
  78. gpList.Add(new gP(pointRP3, Radius * ));
  79. }
  80. gL_di line2R = l2a__Round(lineR, a, 0.05, 0.5, , line1R_Position);
  81. if (line2R.isIntersect)
  82. {
  83. gPoint pointRP4 = p_val_ang(line2R.pc, Radius - CutInner, line2R.ang_direction);
  84. gpList.Add(new gP(pointRP4, Radius * ));
  85. }
  86. }
  87. }
  88. return gpList;
  89. }
  90. /// <summary>
  91. /// 线Line偏移 out 左与右偏移线Line
  92. /// </summary>
  93. /// <param name="l"></param>
  94. /// <param name="offset_val">偏移数值</param>
  95. /// <param name="left_l">out 左偏移线L</param>
  96. /// <param name="rithg_l">out 右偏移线L</param>
  97. public void l_offset(gL l, double offset_val, out gL left_l, out gL rithg_l)
  98. {
  99. left_l = l;
  100. rithg_l = l;
  101. double angle_ = p_ang(l.ps, l.pe);
  102. left_l.ps = p_val_ang(l.ps, offset_val, angle_ + );
  103. left_l.pe = p_val_ang(l.pe, offset_val, angle_ + );
  104. rithg_l.ps = p_val_ang(l.ps, offset_val, angle_ - );
  105. rithg_l.pe = p_val_ang(l.pe, offset_val, angle_ - );
  106. }
  107. /// <summary>
  108. /// 返回两点之间欧氏距离
  109. /// </summary>
  110. /// <param name="p1"></param>
  111. /// <param name="p2"></param>
  112. /// <returns></returns>
  113. public double p2p_di(gPoint p1, gPoint p2)
  114. {
  115. return Math.Sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
  116. }
  117.  
  118. /// <summary>
  119. /// 求线段与弧2个交点
  120. /// </summary>
  121. /// <param name="l"></param>
  122. /// <param name="a"></param>
  123. /// <param name="gp">垂足</param>
  124. /// <param name="isIntersectType">1本身相交 0本身不相交 (相对于圆而言)</param>
  125. /// <returns></returns>
  126. public gL l2a_Intersect(gL l, gA a, ref gPoint gp, ref int isIntersectType)
  127. {
  128. gp = p2l_toP(a.pc, l);
  129. double pc2gpDi = p2p_di(gp, a.pc);
  130. double Radius = p2p_di(a.pc, a.ps);
  131. isIntersectType = Radius >= pc2gpDi ? : ;
  132. double val = Math.Sqrt(Math.Pow(Radius, ) - Math.Pow(pc2gpDi, ));
  133. double ang = p_ang(gp, l.ps);
  134. bool isIsNaN = false;
  135. if (double.IsNaN(ang))
  136. {
  137. isIsNaN = true;
  138. ang = p_ang(gp, l.pe);
  139. }
  140. gPoint leftP = p_val_ang(gp, val, ang);
  141. gPoint rightP = p_val_ang(gp, val, ang - );
  142. if (isIsNaN)
  143. return new gL(rightP, leftP, );
  144. else
  145. return new gL(leftP, rightP, );
  146. }
  147. /// <summary>
  148. /// 求线Line长度
  149. /// </summary>
  150. /// <param name="l"></param>
  151. /// <param name="is_calc_width"></param>
  152. /// <returns></returns>
  153. public double l_Length(gL l, bool is_calc_width = false)
  154. {
  155. if (is_calc_width)
  156. return Math.Sqrt((l.ps.x - l.pe.x) * (l.ps.x - l.pe.x) + (l.ps.y - l.pe.y) * (l.ps.y - l.pe.y)) + l.width / ;
  157. else
  158. return Math.Sqrt((l.ps.x - l.pe.x) * (l.ps.x - l.pe.x) + (l.ps.y - l.pe.y) * (l.ps.y - l.pe.y));
  159. }
  160. /// <summary>
  161. /// 求叉积 判断【点P与线L】位置关系【小于0】在右边 【大于0】在左边 【等于0】共线
  162. /// </summary>
  163. /// <param name="ps"></param>
  164. /// <param name="pe"></param>
  165. /// <param name="p"></param>
  166. /// <returns>【小于0】在右边 【大于0】在左边 【等于0】共线</returns>
  167. public double multi(gPoint ps, gPoint pe, gPoint p)
  168. {
  169. return ((ps.x - p.x) * (pe.y - p.y) - (pe.x - p.x) * (ps.y - p.y));
  170. }
  171. /// <summary>
  172. /// 求线段与弧段倒圆角 //2个交点时处理 相交时检测最近点所有位置 孔大于开口处理 孔小于开口处理
  173. /// </summary>
  174. /// <param name="l"></param>
  175. /// <param name="a"></param>
  176. /// <param name="Radius">内角孔 半径 </param>
  177. /// <param name="tolerance">连接位公差 暂先忽略</param>
  178. /// <param name="l2aType">【0】 自动选取最近点 【1】左(垂足点到PC) 【2】右(垂足点到PC) </param>
  179. /// <param name="l2aPosition">【0】 自动选取最长线段为夹角 【1】圆内,近芯 【2】圆外,近芯 【3】圆外,远芯 【4】圆内,远芯 </param>
  180. /// <returns></returns>
  181. public gL_di l2a__Round(gL l, gA a, double Radius, double tolerance = 0.5, int l2aTypeLR = , int l2aPosition = )
  182. {
  183. gL_di gldi = new gL_di();
  184. d1 calc1 = new d1();
  185. gPoint gp = p2l_toP(a.pc, l);
  186. double ang = p_ang(gp, a.pc);
  187. double aRdi = p2p_di(a.pc, a.ps);
  188. double gp2pcDi = p2p_di(gp, a.pc);
  189. gPoint gpMin = new gPoint(); //由于会产生2个交点,取最近一个交点
  190. double val = ; //弦长 的一半
  191. bool isDisjoint = false;
  192. if (aRdi > gp2pcDi) //线在弧内
  193. {
  194. //求交点
  195. val = Math.Sqrt(Math.Pow(p2p_di(a.pc, a.ps), ) - Math.Pow(p2p_di(gp, a.pc), ));
  196. gPoint leftP = p_val_ang(gp, val, ang + );
  197. gPoint rightP = p_val_ang(gp, val, ang - );
  198. //sxi 2018-9-11 此判断通地最近距离判断最近交点 不太准确,后续修正
  199. if (l2aTypeLR == )
  200. gpMin = leftP;
  201. else if (l2aTypeLR == )
  202. gpMin = rightP;
  203. else
  204. {
  205. if ((p2p_di(leftP, a.ps) + p2p_di(leftP, a.pe) > p2p_di(rightP, a.ps) + p2p_di(rightP, a.pe)))
  206. {
  207. gpMin = rightP;
  208. l2aTypeLR = ;
  209. }
  210. else
  211. {
  212. gpMin = leftP;
  213. l2aTypeLR = ;
  214. }
  215. }
  216. }
  217. else//线在弧外
  218. {
  219. isDisjoint = true;
  220. gpMin = gp;
  221. if (multi(gp, a.pc, l.ps) + multi(gp, a.pc, l.pe) > )
  222. {
  223. l2aTypeLR = ;
  224. }
  225. else
  226. {
  227. l2aTypeLR = ;
  228. }
  229. }
  230.  
  231. gldi.pc = gpMin;
  232. int Lindex = p2p_di_minP(gpMin, l.ps, l.pe);
  233. int Aindex = p2p_di_minP(gpMin, a.ps, a.pe);
  234. if (Lindex == )
  235. {
  236. gldi.p1 = l.ps;
  237. gldi.p1_Ptype = Ptype.ps;
  238. }
  239. else if (Lindex == )
  240. {
  241. gldi.p1 = l.pe;
  242. gldi.p1_Ptype = Ptype.pe;
  243. }
  244. if (Aindex == )
  245. {
  246. gldi.p2 = a.ps;
  247. gldi.p2_Ptype = Ptype.ps;
  248. }
  249. else if (Aindex == )
  250. {
  251. gldi.p2 = a.pe;
  252. gldi.p2_Ptype = Ptype.pe;
  253. }
  254. if (l2aPosition == )
  255. l2aPosition = ;
  256.  
  257. //求弧
  258. if (!isDisjoint) //线在弧内
  259. {
  260. if (l2aPosition == ) // 左上↖
  261. val = Math.Sqrt(Math.Pow(p2p_di(a.pc, a.ps) - Radius, ) - Math.Pow(p2p_di(gp, a.pc) - Radius, ));
  262. else if (l2aPosition == ) //右上↗
  263. val = Math.Sqrt(Math.Pow(p2p_di(a.pc, a.ps) + Radius, ) - Math.Pow(p2p_di(gp, a.pc) - Radius, ));
  264. else if (l2aPosition == ) //右下↘
  265. val = Math.Sqrt(Math.Pow(p2p_di(a.pc, a.ps) + Radius, ) - Math.Pow(p2p_di(gp, a.pc) + Radius, ));
  266. else if (l2aPosition == ) //左下↙
  267. val = Math.Sqrt(Math.Pow(p2p_di(a.pc, a.ps) - Radius, ) - Math.Pow(p2p_di(gp, a.pc) + Radius, ));
  268. }
  269. else
  270. {
  271. val = Math.Sqrt(Math.Pow(p2p_di(a.pc, a.ps) + Radius, ) - Math.Pow(p2p_di(gp, a.pc) - Radius, ));
  272. l2aPosition = ;
  273. }
  274.  
  275. double angTB = ang;
  276. gL gl;
  277. if ((l2aPosition == ) || (l2aPosition == )) //线外
  278. {
  279. angTB = p_ang_invert(ang);
  280. gl = p_val_angL(gp, Radius, angTB, val * );
  281. gPoint gpTemp = gl.ps;
  282. gl.ps = gl.pe;
  283. gl.pe = gpTemp;
  284. }
  285. else
  286. {
  287. gl = p_val_angL(gp, Radius, angTB, val * );
  288. }
  289.  
  290. gPoint gpPc = (l2aTypeLR == ) ? gl.pe : gl.ps;
  291. double angL = p_ang(a.pc, gpPc);
  292. if ((l2aPosition == ) || (l2aPosition == ) || isDisjoint) //圆外
  293. {
  294. angL = p_ang_invert(angL);
  295. }
  296. gA ga = new gA();
  297. ga.pc = gpPc;
  298. if (l2aTypeLR == ) //右
  299. {
  300. gPoint maxP = multi(gp, a.pc, l.ps) < multi(gp, a.pc, l.pe) ? l.ps : l.pe;
  301. double lineRdi = p2p_di(a.pc, maxP);
  302. gldi.isIntersect = lineRdi > aRdi; //不包含线在圆外检测判断
  303.  
  304. if (((l2aPosition == ) || (l2aPosition == )) && !isDisjoint)
  305. {
  306. ga.ps = p_val_ang(gpPc, Radius, angL);//弧切点
  307. ga.pe = p_val_ang(gp, val, ang - );//线切点
  308. }
  309. else
  310. {
  311. ga.ps = p_val_ang(gp, val, ang - );//线切点
  312. ga.pe = p_val_ang(gpPc, Radius, angL);//弧切点
  313. }
  314. }
  315. else if (l2aTypeLR == )//左
  316. {
  317. gPoint maxP = multi(gp, a.pc, l.ps) > multi(gp, a.pc, l.pe) ? l.ps : l.pe;
  318. double lineRdi = p2p_di(a.pc, maxP);
  319. gldi.isIntersect = lineRdi > aRdi;//不包含线在圆外检测判断
  320. if (((l2aPosition == ) || (l2aPosition == )) && !isDisjoint)
  321. {
  322. ga.ps = p_val_ang(gp, val, ang + ); //线切点
  323. ga.pe = p_val_ang(gpPc, Radius, angL);//弧切点
  324. }
  325. else
  326. {
  327. ga.ps = p_val_ang(gpPc, Radius, angL);//弧切点
  328. ga.pe = p_val_ang(gp, val, ang + ); //线切点
  329. }
  330. }
  331. gldi.a = ga;
  332. gldi.State = ; ; //线段 目前仅支持:线在弧内,弧段与线间距不检测
  333. return gldi;
  334. }
  335. /// <summary>
  336. /// 求增量坐标
  337. /// </summary>
  338. /// <param name="ps">起点</param>
  339. /// <param name="val">增量值</param>
  340. /// <param name="ang_direction">角度</param>
  341. /// <returns></returns>
  342. public gPoint p_val_ang(gPoint ps, double val, double ang_direction)
  343. {
  344. gPoint pe;
  345. pe.x = ps.x + val * Math.Cos(ang_direction * Math.PI / );
  346. pe.y = ps.y + val * Math.Sin(ang_direction * Math.PI / );
  347. return pe;
  348. }
  349. /// <summary>
  350. /// 弦长不变,更新新圆半径,并求出新圆中心点
  351. /// </summary>
  352. /// <param name="l">弦长</param>
  353. /// <param name="a">圆弧</param>
  354. /// <param name="Cval">新圆半径</param>
  355. /// <returns></returns>
  356. public gP l2a_CentereExtend(gL l, gA a, double Cval)
  357. {
  358. double gpdi = l_Length(l);
  359. gPoint gpcenter = l_centerP(l);
  360. double gpang = p_ang(gpcenter, a.pc);
  361. double A_Radius = p2p_di(a.pc, a.ps);
  362. double Bval = (gpdi * 0.5);
  363. double Aval = Math.Sqrt(Cval * Cval - Bval * Bval);
  364. gPoint gpPoint = p_val_ang(gpcenter, Aval, gpang);
  365. return new gP(gpPoint, Cval * );
  366. }

3.Point,PAD;Line;Arc数据结构

  1. /// <summary>
  2. /// Line 数据类型
  3. /// </summary>
  4. public struct gL
  5. {
  6. public gL(double ps_x, double ps_y, double pe_x, double pe_y, double width_)
  7. {
  8. this.ps = new gPoint(ps_x, ps_y);
  9. this.pe = new gPoint(pe_x, pe_y);
  10. this.negative = false;
  11. this.symbols = "r";
  12. this.attribut = string.Empty;
  13. this.width = width_;
  14. }
  15. public gL(gPoint ps_, gPoint pe_, double width_)
  16. {
  17. this.ps = ps_;
  18. this.pe = pe_;
  19. this.negative = false;
  20. this.symbols = "r";
  21. this.attribut = string.Empty;
  22. this.width = width_;
  23. }
  24. public gL(gPoint ps_, gPoint pe_, string symbols_, double width_)
  25. {
  26. this.ps = ps_;
  27. this.pe = pe_;
  28. this.negative = false;
  29. this.symbols = symbols_;
  30. this.attribut = string.Empty;
  31. this.width = width_;
  32. }
  33. public gPoint ps;
  34. public gPoint pe;
  35. public bool negative;//polarity-- positive negative
  36. public string symbols;
  37. public string attribut;
  38. public double width;
  39. public static gL operator +(gL l1, gPoint move_p)
  40. {
  41. l1.ps += move_p;
  42. l1.pe += move_p;
  43. return l1;
  44. }
  45. public static gL operator +(gL l1, gP move_p)
  46. {
  47. l1.ps += move_p.p;
  48. l1.pe += move_p.p;
  49. return l1;
  50. }
  51. public static gL operator -(gL l1, gPoint move_p)
  52. {
  53. l1.ps -= move_p;
  54. l1.pe -= move_p;
  55. return l1;
  56. }
  57. public static gL operator -(gL l1, gP move_p)
  58. {
  59. l1.ps -= move_p.p;
  60. l1.pe -= move_p.p;
  61. return l1;
  62. }
  63. }
  64. /// <summary>
  65. /// ARC 数据类型
  66. /// </summary>
  67. public struct gA
  68. {
  69. public gA(double ps_x, double ps_y, double pc_x, double pc_y, double pe_x, double pe_y, double width_, bool ccw_)
  70. {
  71. this.ps = new gPoint(ps_x, ps_y);
  72. this.pc = new gPoint(pc_x, pc_y);
  73. this.pe = new gPoint(pe_x, pe_y);
  74. this.negative = false;
  75. this.ccw = ccw_;
  76. this.symbols = "r";
  77. this.attribut = string.Empty;
  78. this.width = width_;
  79. }
  80. public gA(gPoint ps_, gPoint pc_, gPoint pe_, double width_, bool ccw_ = false)
  81. {
  82. this.ps = ps_;
  83. this.pc = pc_;
  84. this.pe = pe_;
  85. this.negative = false;
  86. this.ccw = ccw_;
  87. this.symbols = "r";
  88. this.attribut = string.Empty;
  89. this.width = width_;
  90. }
  91. public gPoint ps;
  92. public gPoint pe;
  93. public gPoint pc;
  94. public bool negative;//polarity-- positive negative
  95. public bool ccw; //direction-- cw ccw
  96. public string symbols;
  97. public string attribut;
  98. public double width;
  99. public static gA operator +(gA arc1, gPoint move_p)
  100. {
  101. arc1.ps += move_p;
  102. arc1.pe += move_p;
  103. arc1.pc += move_p;
  104. return arc1;
  105. }
  106. public static gA operator +(gA arc1, gP move_p)
  107. {
  108. arc1.ps += move_p.p;
  109. arc1.pe += move_p.p;
  110. arc1.pc += move_p.p;
  111. return arc1;
  112. }
  113. public static gA operator -(gA arc1, gPoint move_p)
  114. {
  115. arc1.ps -= move_p;
  116. arc1.pe -= move_p;
  117. arc1.pc -= move_p;
  118. return arc1;
  119. }
  120. public static gA operator -(gA arc1, gP move_p)
  121. {
  122. arc1.ps -= move_p.p;
  123. arc1.pe -= move_p.p;
  124. arc1.pc -= move_p.p;
  125. return arc1;
  126. }
  127. }
  128. /// <summary>
  129. /// PAD 数据类型
  130. /// </summary>
  131. public struct gP
  132. {
  133. public gP(double x_val, double y_val, double width_)
  134. {
  135. this.p = new gPoint(x_val, y_val);
  136. this.negative = false;
  137. this.angle = ;
  138. this.mirror = false;
  139. this.symbols = "r";
  140. this.attribut = string.Empty;
  141. this.width = width_;
  142. }
  143. public gPoint p;
  144. public bool negative;//polarity-- positive negative
  145. public double angle;
  146. public bool mirror;
  147. public string symbols;
  148. public string attribut;
  149. public double width;
  150. public static gP operator +(gP p1, gP p2)
  151. {
  152. p1.p += p2.p;
  153. return p1;
  154. }
  155. public static gP operator -(gP p1, gP p2)
  156. {
  157. p1.p -= p2.p;
  158. return p1;
  159. }
  160. }
  161. /// <summary>
  162. /// 点 数据类型 (XY)
  163. /// </summary>
  164. public struct gPoint
  165. {
  166. public gPoint(gPoint p_)
  167. {
  168. this.x = p_.x;
  169. this.y = p_.y;
  170. }
  171. public gPoint(double x_val, double y_val)
  172. {
  173. this.x = x_val;
  174. this.y = y_val;
  175. }
  176. public double x;
  177. public double y;
  178. public static gPoint operator +(gPoint p1, gPoint p2)
  179. {
  180. p1.x += p2.x;
  181. p1.y += p2.y;
  182. return p1;
  183. }
  184. public static gPoint operator -(gPoint p1, gPoint p2)
  185. {
  186. p1.x -= p2.x;
  187. p1.y -= p2.y;
  188. return p1;
  189. }
  190. }

五.在Genesis或Incam中如何判断是否为连孔

判断2个孔是否为连孔,可以自己写算法实现啦,当然更多人还是会选择奥宝提供DrillChecklist分析出来的的结果来判断是否为连孔.因为你自己写的算法效率没有奥宝的效率高呀

六.实现效果

PCB genesis连孔加除毛刺孔(圆孔与槽孔)实现方法(二)的更多相关文章

  1. PCB genesis连孔加除毛刺孔(圆孔与圆孔)实现方法(一)

    一.为什么 连孔加除毛刺孔 原因是 PCB板材中含有玻璃纤维, 毛刺产生位置在于2个孔相交位置,由于此处钻刀受力不均导致纤维切削不断形成毛刺 ,为了解决这个问题:在钻完2个连孔后,在相交处再钻一个孔, ...

  2. PCB genesis连孔加除毛刺孔(槽孔与槽孔)实现方法(三)

    一.为什么 连孔加除毛刺孔 原因是 PCB板材中含有玻璃纤维, 毛刺产生位置在于2个孔相交位置,由于此处钻刀受力不均导致纤维切削不断形成毛刺 ,为了解决这个问题:在钻完2个连孔后,在相交处再钻一个孔, ...

  3. PCB genesis大孔加小孔(即卸力孔)实现方法

    一.为什么 大孔中要加小孔(即卸力孔) 这其实跟钻刀的排屑有关了,当钻刀越大孔,排屑量也越大(当然这也得跟转速,下刀速的参数有关系),通常当钻刀越大,转速越慢,下刀速也越慢(因为要保证它的排屑通畅). ...

  4. PCB genesis短槽加引导孔实现方法

    一.何为短槽 短槽通常定义:槽长小于2倍槽宽      如:槽长1.8mm,槽宽1.0mm 二.为什么要加短槽加引孔呢 短槽孔在钻孔时孔易偏斜导致槽长偏短, 当槽长宽比越小,则受力越不均匀,在钻第2个 ...

  5. PCB genesis自制孔点 Font字体实现方法

    一.先看genesis原有Font字体 在PCB工程CAM加孔点字体要求时,通常我们直接用Geneis软件给我们提供了2种孔点字体canned_57与canned_67,但此字体可能不能满足各个工厂个 ...

  6. PCB genesis孔符制作实现方法

    一.先看genesis原始孔符 孔符的作用:用于表示孔径的大小的一种代号, 当孔径检测时,可以按分孔图中的孔符对应的孔径尺寸对孔径检测. 在实际PCB行业通常不使用原始(图形)孔符,而使用字母孔符(如 ...

  7. PCB genesis加尾孔实现方法

    一.为什么增加尾孔呢 看一看下图在panel中增加尾孔的效果;如下图所示,主要有2点原因. 1.孔径大小测量 假设如果不增加尾孔,要检测孔径大小是否符合要求,那么QA检测会选择最后钻的孔进大小进行测量 ...

  8. PCB genesis 大孔扩孔(不用G84命令)实现方法

    PCB钻孔时,当钻刀>6.3mm时,超出钻孔范围,钻孔工序是没有这么大的钻刀,当这种情况,工程CAM会都采用G84命令用小孔扩孔的方式制作, 在这里介绍一种如果不用G84命令,用程序实现将大孔生 ...

  9. PCB Genesis SET拼板(圆形板拼板) 实现效果(二)

    越来发现Genesis采用Surface多边形数据结构的重要性了,当撑握了多边形缩放,交集, 差集,并集等算法, 想实现PCB拼板简直轻而易举了;当然借助多边形算法可以开发出更多的PCB实用的工具出来 ...

随机推荐

  1. Spring Security 介绍与Demo

    一.Spring Security 介绍 Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块的默认技术选型.我们仅需引入spring-boot-s ...

  2. 2019西安多校联训 Day1

    试题链接:http://www.accoders.com/contest.php?cid=1893  考试密码请私信;    T1 明明就是O(n)的模拟,强行打成二分QAQ 思路:判断收尾是否为1或 ...

  3. swift中使用对象归档进行数据本地

    对象归档是ios持久化中的其中一种,也是很常用的一种.现在来看看swift是如何实现的.实现要点1),必须实现NSCoding的协议 import UIKit let path=(NSSearchPa ...

  4. <SpringMvc>入门三 参数绑定

    1.get请求 <%--请求参数的绑定--%> <%--get请求参数--%> <a href="/param/testParam1?username=tom& ...

  5. js之条件判断

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. fillder抓取APP数据之小程序

    1.下载fillder ,fillder官网:https://www.telerik.com/fiddler 2.安装好后设置fillder: 工具—>选项,打开设置面板.选择HTTPS选项卡. ...

  7. Journals in Fluid Mechanics

    journal of fluid mechanics physics of fluids annual review of fluid mechanics

  8. 洛谷 4172 [WC2006]水管局长

    [题解] 我们把操作倒过来做,就变成了加边而不是删边.于是用LCT维护动态加边的最小生成树就好了.同样要注意把边权变为点权. #include<cstdio> #include<al ...

  9. HDU 1228 字符串到数字的转化

    一道水题,练练字符串的输入输出 #include <cstdio> #include <cstring> using namespace std; ] , s2[]; int ...

  10. HDU 1542 Atlantics 线段树+离散化扫描

    将 x 轴上的点进行离散化,扫描线沿着 y 轴向上扫描 每次添加一条边不断找到当前状态有效边的长度 , 根据这个长度和下一条边形成的高度差得到一块合法的矩形的面积 #include<iostre ...