• 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点偏移后的的相交点(按上图偏移点计算方法实现)。

    二.铜皮Surface折线多边形扩大缩小代码

        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;
            }
    View Code

       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;
            }
        }
    View Code
    三.折线多边形扩大缩小实现效果

         

  • 相关阅读:
    【LeetCode 41】缺失的第一个正数
    【LeetCode 38】报数
    Scrum立会报告+燃尽图 04
    Scrum立会报告+燃尽图 03
    Scrum立会报告+燃尽图 02
    20191017-2 alpha week 2/2 Scrum立会报告+燃尽图 01
    作业要求20191010-9 alpha week 1/2 Scrum立会报告+燃尽图 07
    20191010-8 alpha week 1/2 Scrum立会报告+燃尽图 06
    Alpha阶段贡献分配规则
    选题 Scrum立会报告+燃尽图 05
  • 原文地址:https://www.cnblogs.com/pcbren/p/10928628.html
Copyright © 2020-2023  润新知