基于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() - 1;
int n = gsur_point_list.count();
for (int i = 0; i 《n; i++)
{
int indexpre = (i - 1) % sum;
if (indexpre == -1) indexpre = sum - 1;
int indexcurrent = i % sum;
int indexnext = (i + 1) % sum;
if (gsur_point_list[indexpre].type_point》 0) continue;
if (gsur_point_list[indexcurrent].type_point》 0) continue;
var multival = multi(gsur_point_list[indexpre].p, gsur_point_list[indexcurrent].p, gsur_point_list[indexnext].p);
if ((isccw && multival》 0) || (!isccw && multival 《0))
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() - 1;
n = pointlist.count();
for (int i = 0; i 《n; i++)
{
int indexpre = (i - 1) % sum;
if (indexpre == -1) indexpre = sum - 1;
int indexcurrent = i % sum;
int indexnext = (i + 1) % sum;
var multival = multi(pointlist[indexpre].p, pointlist[indexcurrent].p, pointlist[indexnext].p);
if ((isccw && multival》 0) || (!isccw && multival 《0))
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() - 1;
int n = gsur_point_list.count();
for (int i = 0; i 《n; i++)
{
int indexpre = (i - 1) % sum;
if (indexpre == -1) indexpre = sum - 1;
int indexcurrent = i % sum;
int indexnext = (i + 1) % sum;
if (gsur_point_list[indexpre].type_point》 0) continue;
if (gsur_point_list[indexcurrent].type_point》 0) continue;
var multival = multi(gsur_point_list[indexpre].p, gsur_point_list[indexcurrent].p, gsur_point_list[indexnext].p);
if ((isccw && multival》 0) || (!isccw && multival 《0))
{
l1:
if (stackpoint.count》 1)
{
var top1point = stackpoint.pop();
var top2point = stackpoint.peek();
multival = multi(top2point.p, top1point.p, gsur_point_list[indexcurrent].p);
if ((isccw && multival》 0) || (!isccw && multival 《0))
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 - 1);
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[0]);
stack《gsur_point》 stackpoint = new stack《gsur_point》();
var isccw = true;
int sum = gsur_point_list.count() - 1;
int n = gsur_point_list.count();
for (int i = 0; i 《n; i++)
{
int indexpre = (i - 1) % sum;
if (indexpre == -1) indexpre = sum - 1;
int indexcurrent = i % sum;
int indexnext = (i + 1) % sum;
var multival = multi(gsur_point_list[indexpre].p, gsur_point_list[indexcurrent].p, gsur_point_list[indexnext].p);
if (isccw && multival》 0)
{
l1:
if (stackpoint.count》 1)
{
var top1point = stackpoint.pop();
var top2point = stackpoint.peek();
multival = multi(top2point.p, top1point.p, gsur_point_list[indexcurrent].p);
if (isccw && multival》 0)
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; } = 0;
/// 《summary》
/// 值
/// 《/summary》
public double value { get; set; } = 0;
/// 《summary》
/// 角度
/// 《/summary》
public double angle { get; set; } = 0;
/// 《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 = 0;
int n = gsur_point_list.count() - 1;
for (int i = 0; i 《n; i++)
{
if (gsur_point_list.type_point》 0) continue;
int nexti = i + 1 + (gsur_point_list[i + 1].type_point》 0 ? 1 : 0);
d += -0.5 * (gsur_point_list[nexti].p.y + gsur_point_list.p.y) * (gsur_point_list[nexti].p.x - gsur_point_list.p.x);
}
return d》 0;
}
/// 《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 * 180;
// 象限角 转方位角 计算所属象限 并求得方位角
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 + 180;
}
else if (!(pe.x》= ps.x) && !(pe.y》= ps.y)) //↙ 第三象限
{
return a_ang + 180;
}
else if (pe.x》= ps.x && !(pe.y》= ps.y)) // ↘ 第四象限
{
return a_ang + 360;
}
else
{
return a_ang;
}
}
view code
三。 板边凸点倒圆角方法
方法一。 也最简单的倒角方法, 我们将 pcb 板边凸点找出来后, 可以直接借助 genesis 倒角功能就可以实现了
当然但偶尔会报错的, 且当 n 个小线段组成的尖角倒角会出错(要实现完美效果只有自己写倒角算法啦)
方法二: 自己写倒角算法, 这个算法和加内角孔算法类似 (这里只是介绍简单的倒角) 考虑特殊的需要扩展
四。 凸点加倒圆角实现效果


传统技术市场地位稳固 生物识别仍待“腾飞”
泵浦功率和泵浦光半径对热透镜焦距的数值模拟
华为荣耀8青春版定位于时尚人群,你会选择吗?
后照明时代整合持续,喜忧参半
JetBrains推出新的C/C++ IDE:CLion Nova
基于PCB 板的边倒圆角实现方案解析
5G是怎样颠覆教育行业的
随着车市的发展和优胜劣汰,新能源车1.0时代的乱象将会减少
高精度SF6气体定量检漏仪的功能特点
token经济你理解正确了吗
11月国内手机市场出货量2958.4万部,5G手机占比提升至68.1%
iQOOPro5G用户到手之后对它的评价如何呢?
处在SaaS黄金赛道,三家新型SaaS企业Q3表现如何
如何将Notes邮件存档迁移至MicrosoftExchange邮箱呢
人工智能做菜?索尼AI发布“美食旗舰”项目
大众汽车和意法半导体合作研发下一代汽车芯片
低端单片机如何驱动高分辨率彩屏
什么是5G 深度解析5G
如今各行各业都已应用上激光对射探测器
台积电用10nm生产A11 联发科又该头疼了!