PCB 铜皮(Surface)折线多边形扩大缩小实现(第一节)
继续铜皮多边形的相关的算法, 如何用代码实现多边形的扩大与缩小,这部份内容准备分为四节内容来讲解,
第一节,折线多边形的扩大缩小(不包含圆弧) 此篇讲第一节
第二节,带圆弧的多边形的扩大缩小
第三节,多边形扩大缩小----尖角处理
第四节,多边形扩大缩小----自相交处理
1.偏移点计算方法: (具体见贴的代码)
1.求出ABC三角形的角度【1】,即可求出BDP三角形角度【2】
2.通过偏移距离L与BDP角度【2】求出:点B到点D距离
3.求出ABC方位角位角
4.以点B为基准点,ABC方位角,点B到点D距离求出点D坐标
2.算法步骤:
1.获取多边形点数组 List<gSur_Point_list>
2.先检测多边形是顺时针,还是逆时针,这步必不可少,决定后面多边形计算是向内偏移还是向外偏移
这好比锣(铣)带的偏移算法,锣外形必须向外偏移,如果锣带是逆时针,那么它是Right补偿,那如果是顺时针那么它就是Left补偿;
3.遍历List<gSur_Point_list>,依次求出3点偏移后的的相交点(按上图偏移点计算方法实现)。
1.调用代码:
//获取层名为3的Surface数据 gLayer workLayerInfo = g.getFEATURES("3"); var PolyListUp= calc2.s_offset(workLayerInfo.Slist, 1); addCOM.line_poly(PolyListUp, 120); var PolyListDown = calc2.s_offset(workLayerInfo.Slist, 1); addCOM.line_poly(PolyListDown, 120); //获取Profile数据 var Profile = g.getFEATURES_Profile(); var ProfileUp = calc2.s_offset(Profile.sur_list, 1); addCOM.line_poly(ProfileUp, 120); var ProfileDown = calc2.s_offset(Profile.sur_list, -1); addCOM.line_poly(ProfileDown, 120);
2. 折线多边形扩大缩小实现函数
/// <summary> /// Surface偏移(扩大或缩小) /// </summary> /// <param name="gSur_Point_list"></param> /// <param name="offset_val">偏移数值(正值加大 负值缩小)</param> /// <returns></returns> public List<gSur_Point> s_offset(List<gSur_Point> gSur_Point_list, double offset_val) { bool isCCW = s_isCCW(gSur_Point_list); int count = gSur_Point_list.Count(); List<gSur_Point> Point_list = new List<gSur_Point>(); Point_list.Add(gSur_Point_list[0]); gPoint CurrentP = new gPoint(); for (int i = 1; i < count; i++) { int NextIndex = (count == i + 1) ? 1 : i + 1; CurrentP = l2l_OffsetIntersect(gSur_Point_list[i - 1].p, gSur_Point_list[i].p, gSur_Point_list[NextIndex].p, isCCW, offset_val); Point_list.Add(new gSur_Point(CurrentP, gSur_Point_list[i].type_point)); } gSur_Point_list[0].p = CurrentP; return Point_list; } /// <summary> /// Surface偏移(扩大或缩小) /// </summary> /// <param name="gS"></param> /// <param name="offset_val"></param> /// <returns></returns> public gS s_offset(gS gS, double offset_val) { gS SurfacePolyline = new gS(); SurfacePolyline.negative = gS.negative; SurfacePolyline.attribut = gS.attribut; foreach (var Polyline in gS.sur_group) { gSur_list sur_list = new gSur_list(); sur_list.is_ccw = Polyline.is_ccw; sur_list.is_hole = Polyline.is_hole; if (sur_list.is_hole) sur_list.sur_list = s_offset(Polyline.sur_list, -offset_val); else sur_list.sur_list = s_offset(Polyline.sur_list, offset_val); SurfacePolyline.sur_group.Add(sur_list); } return SurfacePolyline; } /// <summary> /// Surface偏移(扩大或缩小) /// </summary> /// <param name="gS_list"></param> /// <param name="offset_val"></param> /// <returns></returns> public List<gS> s_offset(List<gS> gS_list, double offset_val) { List<gS> surface_list = new List<gS>(); foreach (var item in gS_list) { surface_list.Add(s_offset(item, offset_val)); } return surface_list; } /// <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[i].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[i].p.y) * (gSur_Point_list[NextI].p.x - gSur_Point_list[i].p.x); } return d > 0; } /// <summary> /// /线段与线段偏移 求交点 /// </summary> /// <param name="ps"></param> /// <param name="pc"></param> /// <param name="pe"></param> /// <param name="ccw"></param> /// <param name="OffsetVal"></param> /// <returns></returns> public gPoint l2l_OffsetIntersect(gPoint ps, gPoint pc, gPoint pe, bool ccw, double OffsetVal) { double center_dirdction = 0; bool islg180deg = false; double pcAng = a_Angle(ps, pc, pe, ccw, ref center_dirdction, ref islg180deg);//交点圆心角 double pcSinVal = OffsetVal / (Math.Sin(pcAng * 0.5 * Math.PI / 180)); //交点增量 var IntersectP = p_val_ang(pc, pcSinVal, center_dirdction); return IntersectP; } /// <summary> /// 求弧Arc圆心角 3点 //后续改进 用叉积 与3P求角度求解 验证哪个效率高 /// </summary> /// <param name="ps"></param> /// <param name="pc"></param> /// <param name="pe"></param> /// <param name="ccw"></param> /// <param name="center_dirdction">中心方位角</param> /// <param name="islg180deg">3点组成的内角不超180度,超出计算按反方位角计算 当值为true时 ccw值则失效了 返回值确认与P1,P2关系</param> /// <returns></returns> public double a_Angle(gPoint ps, gPoint pc, gPoint pe, bool ccw, ref double center_dirdction, ref bool islg180deg) { double angle_s, angle_e, angle_sum; if (ccw) { angle_s = p_ang(pc, pe); angle_e = p_ang(pc, ps); } else { angle_s = p_ang(pc, ps); angle_e = p_ang(pc, pe); } if (angle_s == 360) { angle_s = 0; } if (angle_e >= angle_s) { angle_sum = 360 - (angle_e - angle_s); center_dirdction = (angle_s + angle_e) * 0.5 + 180; } else { angle_sum = angle_s - angle_e; center_dirdction = (angle_s + angle_e) * 0.5; } if (islg180deg) // { if (angle_sum > 180) { angle_sum = 360 - angle_sum; center_dirdction = p_ang_invert(center_dirdction); if (angle_e >= angle_s) islg180deg = !(angle_e >= angle_s); else islg180deg = (angle_e >= angle_s); } else { //islg180deg = (angle_e >= angle_s); //例1 PS 30 PE 330 true 例2 PS 80 PE 30 false if (angle_e >= angle_s) islg180deg = (angle_e >= angle_s); else islg180deg = !(angle_e >= angle_s); } } else { if (center_dirdction > 360) { center_dirdction = center_dirdction - 360; } } return angle_sum; } /// <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; } } /// <summary> /// 求反方位角 /// </summary> /// <param name="ang_direction"></param> /// <returns></returns> public double p_ang_invert(double ang_direction)//求反方位角 { if (ang_direction >= 180) return ang_direction - 180; else return ang_direction + 180; } /// <summary> /// 求增量坐标 /// </summary> /// <param name="ps">起点</param> /// <param name="val">增量值</param> /// <param name="ang_direction">角度</param> /// <returns></returns> public gPoint p_val_ang(gPoint ps, double val, double ang_direction) { gPoint pe; pe.x = ps.x + val * Math.Cos(ang_direction * Math.PI / 180); pe.y = ps.y + val * Math.Sin(ang_direction * Math.PI / 180); return pe; }
3.数据结构
/// <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> /// Surface 坐标泛型集类2 /// </summary> public class gSur_list { public List<gSur_Point> sur_list = new List<gSur_Point>(); /// <summary> /// 是否为空洞 /// </summary> public bool is_hole { get; set; } /// <summary> /// 是否逆时针 /// </summary> public bool is_ccw { get; set; } } /// <summary> /// Surface 坐标泛型集类3 /// </summary> public class gS { public List<gSur_list> sur_group = new List<gSur_list>(); /// <summary> /// 是否为负 polarity-- P N /// </summary> public bool negative { get; set; } public string attribut { 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; } } /// <summary> /// ARC 数据类型 /// </summary> public struct gA { public gA(double ps_x, double ps_y, double pc_x, double pc_y, double pe_x, double pe_y, double width_, bool ccw_) { this.ps = new gPoint(ps_x, ps_y); this.pc = new gPoint(pc_x, pc_y); this.pe = new gPoint(pe_x, pe_y); this.negative = false; this.ccw = ccw_; this.symbols = "r" + width_.ToString(); this.attribut = string.Empty; this.width = width_; } public gA(gPoint ps_, gPoint pc_, gPoint pe_, double width_, bool ccw_ = false) { this.ps = ps_; this.pc = pc_; this.pe = pe_; this.negative = false; this.ccw = ccw_; this.symbols = "r" + width_.ToString(); this.attribut = string.Empty; this.width = width_; } public gPoint ps; public gPoint pe; public gPoint pc; public bool negative;//polarity-- positive negative public bool ccw; //direction-- cw ccw public string symbols; public string attribut; public double width; public static gA operator +(gA arc1, gPoint move_p) { arc1.ps += move_p; arc1.pe += move_p; arc1.pc += move_p; return arc1; } public static gA operator +(gA arc1, gPP move_p) { arc1.ps += move_p.p; arc1.pe += move_p.p; arc1.pc += move_p.p; return arc1; } public static gA operator +(gA arc1, gP move_p) { arc1.ps += move_p.p; arc1.pe += move_p.p; arc1.pc += move_p.p; return arc1; } public static gA operator -(gA arc1, gPoint move_p) { arc1.ps -= move_p; arc1.pe -= move_p; arc1.pc -= move_p; return arc1; } public static gA operator -(gA arc1, gPP move_p) { arc1.ps -= move_p.p; arc1.pe -= move_p.p; arc1.pc -= move_p.p; return arc1; } public static gA operator -(gA arc1, gP move_p) { arc1.ps -= move_p.p; arc1.pe -= move_p.p; arc1.pc -= move_p.p; return arc1; } }
作者:pcbren 微信号:yadnfku QQ号: 254566449
博客地址:https://www.cnblogs.com/pcbren/
声明:本博客原创文字只代表本人工作中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未授权,贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。
如果大家感觉我的博文对大家有帮助,请推荐支持一把。