0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于PCB 板的边倒圆角实现方案解析

PCB线路板打样 来源:博客园 作者:pcbren 2021-03-02 14:11 次阅读

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 个小线段组成的尖角倒角会出错(要实现完美效果只有自己写倒角算法啦)

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

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

编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • pcb
    pcb
    +关注

    关注

    4213

    文章

    22442

    浏览量

    385203
收藏 人收藏

    评论

    相关推荐

    很好的实现PCB板边倒圆角

    PCB外形是直角时,通常工程制作外形(锣带)时,会将直角或尖角的地方倒成圆角,主要是为了防止PCB容易划伤板他扎伤人。
    发表于 01-15 15:37 844次阅读
    很好的<b class='flag-5'>实现</b><b class='flag-5'>PCB</b>板边<b class='flag-5'>倒圆角</b>

    ADAU1761可否实现录音从耳机放音的功能吗?

    嗨,想设计一款产品,采用mems数字麦克风采集音频信号,在通过ADAU1761将音频信号存储在spi-flash里面,通过无线蓝牙上传至手机,ADAU1761可否实现录音从耳机放音的功能吗?
    发表于 11-29 06:22

    PCB基础知识「详细版」

    电气连接的提供者。由于它是采用电子印刷术制作的,故被称为“印刷”电路。 二、PCB在各种电子设备中作用和功能   1.焊盘:提供集成电路等各种电子元器件固定、装配的机械支撑。    2.走线:实现
    发表于 11-22 13:21

    PCB工艺制程能力介绍及解析(下)

    PCB工艺制程能力介绍及解析(上)》。 图形转移 线宽公差 PCB加工十几道工序会,不可避免的会存在加工误差,PCB制造行业采用的标准通常是指标准的ISO、UL、等行业标准。华秋
    发表于 09-01 09:51

    PCB工艺制程能力介绍及解析(下)

    PCB工艺制程能力介绍及解析(上)》。 图形转移 线宽公差 PCB加工十几道工序会,不可避免的会存在加工误差,PCB制造行业采用的标准通常是指标准的ISO、UL、等行业标准。华秋
    的头像 发表于 08-31 15:54 1125次阅读
    <b class='flag-5'>PCB</b>工艺制程能力介绍及<b class='flag-5'>解析</b>(下)

    【硬件】PCB上的死铜:解析和影响

    ▼ 点击下方名片,关注公众号,获取更多精彩内容 ▼   在PCB的制造和设计过程中,可能会出现一种叫做"死铜"的问题。本文将解析死铜在PCB上的含义、成因、对电路性能的影响以及解决方法
    的头像 发表于 08-21 17:17 1681次阅读
    【硬件】<b class='flag-5'>PCB</b>上的死铜:<b class='flag-5'>解析</b>和影响

    汽车 PCB 与普通 PCB 的区别

    和传动装置等。安全系统必须实现高度的可靠性和安全性,以保证乘客的生命安全。这就需要汽车 PCB 能够承受极端的温度和湿度等极端工作环境,保证系统的正常运行。 方案介绍瑞芯微RK35
    发表于 06-25 14:23

    华秋亮相汽车电子研讨会,展出高可靠PCB

    管理能力。 目前,华秋 PCB 工艺基本可以满足各行各业的产品需求。熟练掌握填孔电镀、叠孔、金属包、半孔等 PCB 的生产制造技术,最小线宽可达 2.5 mil,最小线距达 3 m
    发表于 06-16 15:43

    华秋亮相汽车电子研讨会,展出智能座舱方案、高可靠PCB

    管理能力。 目前,华秋 PCB 工艺基本可以满足各行各业的产品需求。熟练掌握填孔电镀、叠孔、金属包、半孔等 PCB 的生产制造技术,最小线宽可达 2.5 mil,最小线距达 3 m
    发表于 06-16 15:10

    怎么对电路进行pcb

    本帖最后由 我爱方案网 于 2023-6-13 14:49 编辑 PCB的技术实现过程简单来说,就是先将要抄的电路
    发表于 06-13 14:47

    啥?PCB拼版对SMT组装有影响!

    PCB为什么要拼版? 拼版主要是为了满足 生产的需求 ,有些PCB太小,不满足做夹具的要求,所以需要拼在一起进行生产。 拼版也可以提高SMT贴片的 焊接效率 ,如只需要过一次SMT,即可完成多块
    发表于 06-13 09:57

    pcb 微波天线pcb 射频天线pcb 雷达天线pcb 毫米波天线pcb

    PCB
    鑫成尔电路板
    发布于 :2023年05月15日 14:16:35

    PCB的拼板设计介绍

    。拼板块数以拼板后尺寸符合6.2规定为宜。这种拼法刚度较好,利于波峰焊。图7(a)为典型的拼板,图7(b)适合于子分离后要求圆角的情况。   例2:PCB
    发表于 04-25 17:08

    PCB制造基本工艺及目前的制造水平

    使用的多层制造技术,它是用减成法制作电路层,通过层压一机械钻孔一化学沉铜一镀铜等工艺使各层电路实现互连,最后涂敷阻焊剂、喷锡、丝印字符完成多层PCB的制造。目前国内主要厂家的工艺水平如表3所列
    发表于 04-25 17:00

    常见PCB弓曲扭曲翘曲挠曲分析改善方案

    上,使凸面向上,对每一条,要用最够的力压住两个角以保证他们和基准面接触,用千分尺或者塞尺测出垂直方向的最大读数为R1 (四条都需要测量)  用千分尺测试PCB厚为R2  使用足够
    发表于 04-20 16:39