zoukankan      html  css  js  c++  java
  • 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
    三.折线多边形扩大缩小实现效果

         

  • 相关阅读:
    HDU 5492 Find a path
    codeforce gym 100548H The Problem to Make You Happy
    Topcoder SRM 144 Lottery
    codeforce 165E Compatible Numbers
    codeforce gym 100307H Hack Protection
    区间DP总结
    UESTC 1321 柱爷的恋爱 (区间DP)
    HDU 4283 You Are the One (区间DP)
    HDU 2476 String painter (区间DP)
    UESTC 426 Food Delivery (区间DP)
  • 原文地址:https://www.cnblogs.com/pcbren/p/10928628.html
Copyright © 2011-2022 走看看