当PCB外形是直角时,通常工程制作外形(锣带)时,会将直角或尖角的地方倒成圆角,主要是为了防止PCB容易划伤板他扎伤人

所以当客户没有特殊要求时,PCB外形是直角一般会默认倒角0.5mm圆角(如下图所示)

 一.PCB板边倒圆角点分析

原PCB外形  如下图图示:看了这个PCB外形,产生有2个问题点.

1.外形中哪些点需倒圆角?

2.如何怎么倒圆角?

1.外形中哪些点需倒圆角?

看下图: PCB外形倒圆角的点,刚好就是我们凸包需求出的点,接下来我们将玩转凸包了,只要求出凸包,那么就可以实现PCB板边倒圆角啦。

求凸包的算法:我们可以借鉴算法导论中的查找凸包的算法(加以改进得到新的求凸包方法,详见【方法一】与【方法二】)

2.如何怎么倒圆角?

在下面有说明倒角方法.

 二. 求凸点

方法一求凸点:【采用多轮遍历,一遍一遍将凹点踢除,剩于的即是凸点】

方法一求凸点:  代码

        /// <summary>
/// 求最大多边形最大凸包1 【采用多轮遍历将凹点踢除,剩于的即是凸点】
/// </summary>
/// <param name="gSur_Point_list"></param>
/// <returns></returns>
public List<gSur_Point> s_convex_polyon1(List<gSur_Point> gSur_Point_list)
{
add addCOM = new add();
bool isOK = true;
List<gSur_Point> PointList = new List<gSur_Point>();
var isCCW = s_isCCW(gSur_Point_list);
int sum = gSur_Point_list.Count() - ;
int n = gSur_Point_list.Count();
for (int i = ; i < n; i++)
{
int IndexPre = (i - ) % sum;
if (IndexPre == -) IndexPre = sum - ;
int IndexCurrent = i % sum;
int IndexNext = (i + ) % sum;
if (gSur_Point_list[IndexPre].type_point > ) continue;
if (gSur_Point_list[IndexCurrent].type_point > ) continue;
var multiVal = multi(gSur_Point_list[IndexPre].p, gSur_Point_list[IndexCurrent].p, gSur_Point_list[IndexNext].p);
if ((isCCW && multiVal > ) || (!isCCW && multiVal < ))
PointList.Add(gSur_Point_list[IndexCurrent]);
else
isOK = false;
}
List<gSur_Point> Point2List = new List<gSur_Point>(PointList);
while (!isOK)
{
isOK = true;
PointList.Clear();
PointList.AddRange(Point2List);
Point2List.Clear();
sum = PointList.Count() - ;
n = PointList.Count();
for (int i = ; i < n; i++)
{
int IndexPre = (i - ) % sum;
if (IndexPre == -) IndexPre = sum - ;
int IndexCurrent = i % sum;
int IndexNext = (i + ) % sum;
var multiVal = multi(PointList[IndexPre].p, PointList[IndexCurrent].p, PointList[IndexNext].p);
if ((isCCW && multiVal > ) || (!isCCW && multiVal < ))
Point2List.Add(PointList[IndexCurrent]);
else
isOK = false;
}
}
return Point2List;
}

方法二求凸包:【采用一边遍历找出凸点并加入队列,并同时将队列中的凸点队列中找出凹点踢除】

方法二求凸包代码:

        /// <summary>
/// 求最大多边形最大凸包2 【采用一边遍历找出凸点并加入队列,并同时将队列中的凸点队列中找出凹点踢除】
/// </summary>
/// <param name="gSur_Point_list"></param>
/// <returns></returns>
public List<gSur_Point> s_convex_polyon2(List<gSur_Point> gSur_Point_list)
{
Stack<gSur_Point> StackPoint = new Stack<gSur_Point>();
var isCCW = s_isCCW(gSur_Point_list);
int sum = gSur_Point_list.Count() - ;
int n = gSur_Point_list.Count();
for (int i = ; i < n; i++)
{
int IndexPre = (i - ) % sum;
if (IndexPre == -) IndexPre = sum - ;
int IndexCurrent = i % sum;
int IndexNext = (i + ) % sum;
if (gSur_Point_list[IndexPre].type_point > ) continue;
if (gSur_Point_list[IndexCurrent].type_point > ) continue;
var multiVal = multi(gSur_Point_list[IndexPre].p, gSur_Point_list[IndexCurrent].p, gSur_Point_list[IndexNext].p);
if ((isCCW && multiVal > ) || (!isCCW && multiVal < ))
{
L1:
if (StackPoint.Count > )
{
var Top1Point = StackPoint.Pop();
var Top2Point = StackPoint.Peek();
multiVal = multi(Top2Point.p, Top1Point.p, gSur_Point_list[IndexCurrent].p);
if ((isCCW && multiVal > ) || (!isCCW && multiVal < ))
StackPoint.Push(Top1Point);
else
goto L1;
}
StackPoint.Push(gSur_Point_list[IndexCurrent]);
}
}
return StackPoint.Reverse().ToList();
}

方法三求凸包:按算法导论Graham扫描法 各节点按方位角+距离 逆时针排序  依次检查,当不属凸点于则弹出】

方法三求凸包代码

        /// <summary>
/// 求最大多边形最大凸包5 【按算法导论Graham扫描法 各节点按方位角+距离 逆时针排序 依次检查,当不属凸点于则弹出】
/// 由于把各点的排列顺序重新排序了,只支持折线节点(当存在弧节点时会出异常 !!!)
/// </summary>
/// <param name="gSur_Point_list"></param>
/// <returns></returns>
public List<gSur_Point> s_convex_polyon3(List<gSur_Point> gSur_Point_list)
{
var LeftBottomPoint = gSur_Point_list.OrderBy(tt => tt.p.y).ThenBy(tt => tt.p.x).FirstOrDefault();
gSur_Point_list.RemoveAt(gSur_Point_list.Count - );
gSur_Point_list.ForEach(tt =>
{
tt.Value = p2p_di(LeftBottomPoint.p, tt.p);
tt.Angle = p_ang(LeftBottomPoint.p, tt.p);
}
);
gSur_Point_list = gSur_Point_list.OrderBy(tt => tt.Angle).ThenBy(tt => tt.Value).ToList();
gSur_Point_list.Add(gSur_Point_list[]);
Stack<gSur_Point> StackPoint = new Stack<gSur_Point>();
var isCCW = true;
int sum = gSur_Point_list.Count() - ;
int n = gSur_Point_list.Count();
for (int i = ; i < n; i++)
{
int IndexPre = (i - ) % sum;
if (IndexPre == -) IndexPre = sum - ;
int IndexCurrent = i % sum;
int IndexNext = (i + ) % sum;
var multiVal = multi(gSur_Point_list[IndexPre].p, gSur_Point_list[IndexCurrent].p, gSur_Point_list[IndexNext].p);
if (isCCW && multiVal > )
{
L1:
if (StackPoint.Count > )
{
var Top1Point = StackPoint.Pop();
var Top2Point = StackPoint.Peek();
multiVal = multi(Top2Point.p, Top1Point.p, gSur_Point_list[IndexCurrent].p);
if (isCCW && multiVal > )
StackPoint.Push(Top1Point);
else
goto L1;
}
StackPoint.Push(gSur_Point_list[IndexCurrent]);
}
}
return StackPoint.Reverse().ToList();
}

公共方法与数据结构

    /// <summary>
/// Surface 坐标泛型集类1
/// </summary>
public class gSur_Point
{
public gSur_Point()
{ }
public gSur_Point(double x_val, double y_val, byte type_point_)
{
this.p.x = x_val;
this.p.y = y_val;
this.type_point = type_point_;
}
public gSur_Point(gPoint p, byte type_point_)
{
this.p = p;
this.type_point = type_point_;
}
public gPoint p;
/// <summary>
/// 0为折点 1为顺时针 2为逆时针
/// </summary>
public byte type_point { get; set; } = ;
/// <summary>
/// 值
/// </summary>
public double Value { get; set; } = ;
/// <summary>
/// 角度
/// </summary>
public double Angle { get; set; } = ;
/// <summary>
/// 标记
/// </summary>
public bool isFalg { get; set; }
}
/// <summary>
/// 点 数据类型 (XY)
/// </summary>
public struct gPoint
{
public gPoint(gPoint p_)
{
this.x = p_.x;
this.y = p_.y;
}
public gPoint(double x_val, double y_val)
{
this.x = x_val;
this.y = y_val;
}
public double x;
public double y;
public static gPoint operator +(gPoint p1, gPoint p2)
{
p1.x += p2.x;
p1.y += p2.y;
return p1;
}
public static gPoint operator -(gPoint p1, gPoint p2)
{
p1.x -= p2.x;
p1.y -= p2.y;
return p1;
}
public static gPoint operator +(gPoint p1, double val)
{
p1.x += val;
p1.y += val;
return p1;
}
public static bool operator ==(gPoint p1, gPoint p2)
{
return (p1.x == p2.x && p1.y == p2.y);
}
public static bool operator !=(gPoint p1, gPoint p2)
{
return !(p1.x == p2.x && p1.y == p2.y);
}
}
/// <summary>
/// 求叉积 判断【点P与线L】位置关系【小于0】在右边 【大于0】在左边 【等于0】共线
/// </summary>
/// <param name="ps"></param>
/// <param name="pe"></param>
/// <param name="p"></param>
/// <returns>【小于0】在右边 【大于0】在左边 【等于0】共线</returns>
public double multi(gPoint ps, gPoint pe, gPoint p)
{
return ((ps.x - p.x) * (pe.y - p.y) - (pe.x - p.x) * (ps.y - p.y));
}
/// <summary>
/// 检测 Surface是否逆时针
/// </summary>
/// <param name="gSur_Point_list"></param>
/// <returns></returns>
public bool s_isCCW(List<gSur_Point> gSur_Point_list)
{
double d = ;
int n = gSur_Point_list.Count() - ;
for (int i = ; i < n; i++)
{
if (gSur_Point_list[i].type_point > ) continue;
int NextI = i + + (gSur_Point_list[i + ].type_point > ? : );
d += -0.5 * (gSur_Point_list[NextI].p.y + gSur_Point_list[i].p.y) * (gSur_Point_list[NextI].p.x - gSur_Point_list[i].p.x);
}
return d > ;
}
/// <summary>
/// 返回两点之间欧氏距离
/// </summary>
/// <param name="p1"></param>
/// <param name="p2"></param>
/// <returns></returns>
public double p2p_di(gPoint p1, gPoint p2)
{
return Math.Sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
/// <summary>
/// 求方位角
/// </summary>
/// <param name="ps"></param>
/// <param name="pe"></param>
/// <returns></returns>
public double p_ang(gPoint ps, gPoint pe)
{
double a_ang = Math.Atan((pe.y - ps.y) / (pe.x - ps.x)) / Math.PI * ;
//象限角 转方位角 计算所属象限 并求得方位角
if (pe.x >= ps.x && pe.y >= ps.y) //↗ 第一象限
{
return a_ang;
}
else if (!(pe.x >= ps.x) && pe.y >= ps.y) // ↖ 第二象限
{
return a_ang + ;
}
else if (!(pe.x >= ps.x) && !(pe.y >= ps.y)) //↙ 第三象限
{
return a_ang + ;
}
else if (pe.x >= ps.x && !(pe.y >= ps.y)) // ↘ 第四象限
{
return a_ang + ;
}
else
{
return a_ang;
}
}
 三.板边凸点倒圆角方法

方法一.也最简单的倒角方法,我们将PCB板边凸点找出来后,可以直接借助genesis倒角功能就可以实现了

当然但偶尔会报错的, 且当N个小线段组成的尖角倒角会出错(要实现完美效果只有自己写倒角算法啦)

方法二:自己写倒角算法,这个算法和加内角孔算法类似(这里只是介绍简单的倒角)考虑特殊的需要扩展

可以参考这篇文章: https://www.cnblogs.com/pcbren/p/9665304.html

 四.凸点加倒圆角实现效果   

PCB 板边倒圆角的实现方法(基本算法一)的更多相关文章

  1. PCB板信号完整性分析的操作步骤及设置方法

    AD16的主要功能是画电路原理图和根据电路原理图设计PCB板.为了使设计的电路.画完的电路原理图,从电路原理上不存在错误,从电路逻辑上不存在混乱,AD16专门开发了电路原理图的仿真程序.这样可以把设计 ...

  2. PCB板可靠性测试方法择要

    在电子设备中PCB板是所有电子设备的核心,其的可靠性程度会直接影响了产品的耐用性和寿命.因此在我们实验室(上海摩尔实验室)的实际工作中遇到了越来越多的针对PCB板的可靠性的测试要求,现根据一些企业的内 ...

  3. Altium Designer 14(或者其他版本)里更改PCB板(图纸)大小

    1.在PCB板界面下方有一行不同颜色的图层选项,找到“Keep-Out Layer”,没看见的话点击右箭头即可找到.   2.在“Place”选项里面选择“line”,也就是添加线,把你所有元件用线条 ...

  4. PCB板蛇形走线有什么作用

    PCB板蛇形走线有什么作用  PCB上的不论什么一条走线在通过高频信号的情况下都会对该信号造成时延时,蛇形走线的主要作用是补偿"同一组相关"信号线中延时较小的部分,这些部分一般是没 ...

  5. 4个设计绝招教你减少PCB板电磁干扰

    电子设备的电子信号和处理器的频率不断提升,电子系统已是一个包含多种元器件和许多分系统的复杂设备.高密和高速会令系统的辐射加重,而低压和高灵敏度 会使系统的抗扰度降低. 因此,电磁干扰(EMI)实在是威 ...

  6. CH7511|LT7211|PS8625替代方案 CS5211 设计EDP转LVDS优势方案原理图+PCB板设计

    CH7511|LT7211|PS8625这三款都是专门用于设计EDP转LVDS转接板或者屏转换方案板,CH7511.LT7211.PS8625目前这几款都是出于缺货状态,台湾瑞奇达Capstone 新 ...

  7. 如何用TDR来测试PCB板的线路阻抗

    隔壁小王已经讲了TDR的原理以及如何确定TDR的分辨率.那么,我们要正确测量PCB板上的线路阻抗,还有哪些需要注意的地方呢? 1. 阻抗测试的行业标准 之前贴过好多张阻抗测试的图片,重新再贴一张给大家 ...

  8. PCB板的质量可接受性标准 IPC-A-600H 中文版下载

    对于电子行业的小伙伴来说,经常要找PCB板厂打板,总难免遇到跟板厂因PCB上的质量缺陷扯皮的时候,这是就要有一份公认PCB质量可接受性标准作为最终PCB产品的验收标准,即IPC-A-600标准规范. ...

  9. PCB板简易流程

    PCB布线规则设置 在进行布线之前一般要进行布线规则的设置,(因为元器件的封装已经画出了元件实际的轮廓大小,所以放置元件封装时,即使两个元件封装挨着也一般不会影响元件的实际安装,不过一般还是稍留一点距 ...

随机推荐

  1. Ackerman 函数

    先留个简介: 函数定义: 从定义可以看出是一个递归函数.阿克曼函数不仅值增长的非常快,而且递归深度很高. 一般用来测试编译其优化递归调用的能力.. 如果用一下代码简单实现的话,输入参数4,2程序就直接 ...

  2. 【Gerrit】Performance Cheat Sheet

    首先说下做这件事情的主因,组内有人说Project repo sync有点慢,废话不多说,直接上图. 相关官方文档参考链接: 我的数据: ~/review_site/logs# fgrep " ...

  3. 【Git】整合分支那些事儿

    对于scm这个岗位来说,基线升级应该是这个岗位需要的必备技能了,现在来说说我司进行高通代码基线升级时选择的方式方法,供大家参考,也供自己学习积累. git这个工具大家都并不陌生,但是对于不经常提交代码 ...

  4. HTML5离线缓存攻击测试

    本实验采用局域网模拟,通过修改本地HOSTS文件来模拟域名以及DNS欺骗.合法网站使用Linux CentOS7的apache服务器搭建,IP为192.168.1.113,HOSTS文件中加入192. ...

  5. 简单实用SQL脚本Part:查找SQL Server 自增ID值不连续记录

    原文:简单实用SQL脚本Part:查找SQL Server 自增ID值不连续记录 在很多的时候,我们会在数据库的表中设置一个字段:ID,这个ID是一个IDENTITY,也就是说这是一个自增ID.当并发 ...

  6. PHP的MIPS交叉编译(CC=mipsel-openwrt-linux-uclibc-gcc,LD=mipsel-openwrt-linux-uclibc-ld)

    物联网内存吃紧,跑JVM这种内存大户肯定吃不消.要跑还是跑C实现的服务,比如Nginx+PHP+SQLite.比如一些家用无线路由器,系统是Linux发行版OpenWrt,内存只有64MB到128MB ...

  7. MySQL半同步复制搭建

    默认情况下,MySQL 5.5/5.6/5.7和MariaDB 10.0/10.1的复制是异步的,异步复制可以提供最佳性能,主库把binlog日志发送给从库,这一动作就结束了,并不会验证从库是否接收完 ...

  8. Android零基础入门第53节:拖动条SeekBar和星级评分条RatingBar

    原文:Android零基础入门第53节:拖动条SeekBar和星级评分条RatingBar 前面两期都在学习ProgressBar的使用,关于自定义ProgressBar的内容后期会继续学习的,本期先 ...

  9. 12 寸 Retina MacBook 的大秘密: 可用移动电源充电

    苹果新款12寸Retina MacBook虽然只有一个USB-C接口,但这个接口的能力却十分强大.它不仅可以进行数据传输和视频输出,还能接收和输入电源.这也就是说,你可以使用移动电源对其进行充电,如果 ...

  10. 【查虫日志】快速判断一副灰度图像中是否只有黑色和白色值(即是否为二值图像)过程中bool变量的是是非非。

    二值图像我们在图像处理过程中是经常遇到的,有的时候我们在进行一个算法处理前,需要判断下一副图像的数据是否符合二值图的需求,这个时候我们可以写个简单的函数来做个判断,比如我写了一个很简单的的代码如下: ...