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
    +关注

    关注

    4317

    文章

    23013

    浏览量

    396375
收藏 人收藏

    评论

    相关推荐

    了解双面和多层pcb的优缺点

    在现代电子设备的设计和制造中,印刷电路PCB)是不可或缺的组件。PCB不仅提供了电子元件的物理支撑,还实现了电子元件之间的电气连接或电绝缘。随着技术的发展,
    的头像 发表于 11-04 13:57 124次阅读

    中低频pcb与高频pcb区别

    随着电子技术的飞速发展,对PCB的性能要求也越来越高。在不同的应用场景中,如通信、雷达、卫星等,高频信号的处理变得越来越重要。 中低频PCB 中低频
    的头像 发表于 11-04 13:48 169次阅读

    pcb没有工艺怎么贴片

    PCB没有工艺时,进行贴片加工需要特别注意以下几点,以确保贴片过程的顺利进行和最终产品的质量。 一、了解工艺的作用 工艺PCB
    的头像 发表于 08-15 09:45 730次阅读

    PCB设计与PCB的紧密关系

    一站式PCBA智造厂家今天为大家讲讲PCB设计与PCB有什么关系?PCB设计与PCB的关
    的头像 发表于 08-12 10:04 441次阅读

    PCB如何收费?pcb收费标准

    一站式PCBA智造厂家今天为大家讲讲PCB加工费是如何收取的?PCB收费方法和价格因素。PCB
    的头像 发表于 08-07 09:24 938次阅读

    OTG充电芯片如何实现充电与数据传输并行?

    OTG充电芯片实现充电与数据传输并行的功能,主要依赖于其内部的设计和与USB Type-C接口标准的结合。
    的头像 发表于 07-14 10:35 512次阅读

    PCB天线设计原理解析

    PCB(Printed Circuit Board)天线是一种基于印刷电路的无线通信设备,广泛应用于无线通信领域。本文将介绍PCB天线的设计原理,包括天线的基本概念、设计要素和常见的PCB
    的头像 发表于 04-03 11:00 2322次阅读
    <b class='flag-5'>PCB</b>天线设计原理<b class='flag-5'>解析</b>

    PCBA为什么要设计工艺?设计工艺有什么好处吗?

    PCBA设计师们在设计线路的时候,往往会预留工艺。这么做得到原因大家知道是为什么吗?设计工艺有什么好处吗?今天给大家讲解一下PCBA为什么要设计工艺
    的头像 发表于 03-22 11:45 1298次阅读

    PCB基础知识详细解析

    的,故被称为“印刷”电路PCB,即在已经有电子产品实物和电路板实物的前提下,利用反向研发技术手段对电路进行逆向解析,将原有产品的
    的头像 发表于 03-03 17:02 536次阅读

    HDI与普通pcb有哪些不同

    HDI与普通pcb有哪些不同
    的头像 发表于 03-01 10:51 1374次阅读

    详解PCB过程

    作者:深圳市清宝电子 来源:网络 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。   PCB的技术实现过程简单来说,就是先将要抄的电路
    的头像 发表于 02-27 11:03 581次阅读

    很好的实现PCB板边倒圆角

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

    PCB高速设计信号完整性五个经验分享

    隔离一块PCB上的元器件有各种各样的值(edge rates)和各种噪声差异。对改善SI直接的方式就是依据器件的值和灵敏度,通过PCB
    发表于 01-02 15:47 745次阅读
    <b class='flag-5'>PCB</b>高速设计信号完整性五个经验分享

    PCB生产过程:为什么PCB内外层蚀刻方法不一样

    如果单板或拼板的尺寸不合适,PCB生产过程中,就会产生很多的原料废PCB厂会把之些废的价格都加到你的板子上,这样你的
    发表于 12-25 10:19 1481次阅读
    <b class='flag-5'>PCB</b>生产过程:为什么<b class='flag-5'>PCB</b>内外层蚀刻方法不一样

    浅谈PCB工艺的宽度设定标准

    由于工艺会消耗更多的PCB板材,会增加PCB的整体成本,因此在设计PCB工艺时,需要平衡经济和可**性。针对一些特殊形状的
    发表于 11-30 15:45 946次阅读