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

    关注

    4372

    文章

    23550

    浏览量

    411935
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    PCB全流程解析:从拆解到测试,技术要点全揭秘!

    一站式PCBA加工厂家今天为大家讲讲PCB的完整流程是什么?PCB的完整流程与技术要点。PCB
    的头像 发表于 07-26 16:22 ?456次阅读

    PCBA加工必知!工艺预留的原因、方式与重要性全解析

    一站式PCBA加工厂家今天为大家讲讲PCBA加工中为什么要预留工艺?预留工艺的方式及重要性。在PCBA加工过程中,预留工艺是一个至关重要的环节。许多客户在设计电路时可能会忽略这
    的头像 发表于 06-24 09:15 ?240次阅读

    芯片内嵌式PCB封装技术方案解析"七部曲" | 第二曲:市场主流玩家与技术方案解读

    以下完整内容发表在「SysPro电力电子技术」知识星球-《芯片内嵌式PCB封装技术方案全面解析的七部曲》系列文章-SysPro原创文章,仅用于SysPro内部使用-本篇为节选,完整内容会在知识星球
    的头像 发表于 06-13 06:48 ?702次阅读
    芯片内嵌式<b class='flag-5'>PCB</b>封装技术<b class='flag-5'>方案</b><b class='flag-5'>解析</b>&amp;quot;七部曲&amp;quot; | 第二曲:市场主流玩家与技术<b class='flag-5'>方案</b>解读

    一文读懂:单层、多层、特殊材质 PCB 加工方式全解析

    一站式PCBA加工厂家今天为大家讲讲单层、多层及特殊材质PCB的加工方式有哪些?单层、多层及特殊材质PCB加工方式。在电子产品制造过程中,PCB
    的头像 发表于 05-06 08:59 ?350次阅读

    PCBA设计工艺:提升生产效率与精度的关键

    缘的尺寸、形状、过孔、切割方式等多方面的考虑。虽然在许多设计中,板材的内部结构可能会得到更多的关注,但工艺的设计同样是至关重要的,因为它直接影响到整个PCB的制造、组装、性能以及可靠性。 什么是PCBA设计工艺? PCBA设
    的头像 发表于 04-23 09:24 ?309次阅读

    反激的PSR与SSR控制技术解析及优劣

    率比原和副绕组的交叉调整率更容易实现,同时副调节还可以采用不同的技术来优化调节性能。比如,在变压器中使用升级绕组或加权反馈技术。 2 PSR与SSR技术
    发表于 03-27 13:51

    PCB芯片加固方案

    PCB芯片加固方案PCB芯片加固工艺是确保电子设备性能和可靠性的重要环节。以下是一些常见的PCB
    的头像 发表于 03-06 15:37 ?606次阅读
    <b class='flag-5'>PCB</b><b class='flag-5'>板</b>芯片加固<b class='flag-5'>方案</b>

    深度解析:双面PCB与单面PCB的制造差异

    一站式PCBA智造厂家今天为大家讲讲双面PCB与单面PCB制造工艺有什么差异?双面PCB
    的头像 发表于 02-05 10:00 ?822次阅读

    PCB为什么绿色居多?

    PCB
    扬兴科技
    发布于 :2025年01月16日 18:14:47

    必看!PCB几层设计的决定要素全解析

    一站式PCBA智造厂家今天为大家讲讲PCB几层的决定因素是什么?PCB设计成几层的决定因素。PCB作为电子产品中的关键组成部分,其层数设
    的头像 发表于 12-14 11:38 ?843次阅读

    PCB厚度对信号传输的影响

    PCB的厚度对其信号传输性能有着显著的影响。以下是详细分析: 1、信号传输速度 PCB的厚度会影响信号传输的速度。一般来说,较薄的PCB
    的头像 发表于 12-06 17:24 ?1301次阅读

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

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

    中低频pcb与高频pcb区别

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

    什么是pcb的作用

    在电子技术飞速发展的今天,PCB已经成为电子产品不可或缺的一部分。它不仅承载着电子元器件,还负责连接这些元器件,确保电路的正常工作。 1. PCB的基本作用
    的头像 发表于 11-04 13:45 ?1879次阅读

    精科睿科普 pcb板材全解析

    PCB
    雨後陽光
    发布于 :2024年09月27日 10:40:40