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

 

三.折线多边形扩大缩小实现效果

     

 

posted @ 2019-05-27 01:20  pcbren  阅读(1702)  评论(0编辑  收藏  举报