這里講解一下用net解析PCB圖形繪制實現方法
一.解析PCB圖形繪制實現
解析PCB圖形,說簡單也非常簡單,先說一下,PCB Gerber圖形由:點,線,弧,銅皮,文字 5類元素組成,通常簡寫為:P,L,A,S,T五類,這幾類元素的難易程度,剛好是按這個順序排列的(個人實際應用這么認為的)。即然是5類就得建立5種元素的數據結構存儲它吧,
PAD結構
/// <summary> /// PAD 數據類型 /// </summary> public struct gP { public gPoint p; public bool negative;//polarity-- positive negative public int angle; public bool mirror; public string symbols; public string attribut; public double width; }
線結構
/// <summary> /// Line 數據類型 /// </summary> public struct gL { public gPoint ps; public gPoint pe; public bool negative;//polarity-- positive negative public string symbols; public string attribut; public double width; }
弧結構
/// <summary> /// ARC 數據類型 /// </summary> public struct gA { 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; }
銅皮結構
/// <summary> /// Surface 坐標泛型集類1 /// </summary> public struct gSur_Point { public gPoint p; /// <summary> /// 0為折點 1為順時針 2為逆時針 /// </summary> public byte type_point; } /// <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; } }
文字結構
看這個結構比Surface銅皮結構還簡單呀,為什么文字結構更復雜了,這里只是實現最普通的字體結構,實際復雜程度遠大於Surface,需要解析到所用到的字體庫中的的坐標,而且字體存在各式各樣的,有二維碼,點陣字,有條碼,要想保證和Genesis所顯示一致,這里需要下點功夫。
/// <summary> /// Text 文本數據類型 簡易型 更復雜的需要擴展 /// </summary> public struct gT { public gPoint ps; public string font; public bool negative;//polarity-- positive negative public int angle; public bool mirror; public double x_size; public double y_size; public double width; public string Text; public string attribut; }
那么為什么symbols不算一類呢,因為symbols也是由這5類基礎元素組合而成的,繪制時檢索symbols中所含元素集合,再將Symbols集合遍歷一個一個的元素繪制到畫板上來的。
Gerber數據存儲到這個結構中后.那用Graphics類,遍歷元素集合,依次繪制元素就好了;下面說一下遇到的問題解決方法
二.繪制Gerber圖形遇到的幾個問題解決方法
1.同一層圖形的元素是存在先后順序的,不能按元素類別分類集合,如List<P>,List<L>,這樣是錯誤的
若元素要按先后順序保存,那么這里可以選擇用ArrayList集合存儲數據
2.繪制圓形焊盤時,對於Genesis而言它是一個點坐標,在net中是沒有直接繪制點方法.
那么對應net中是用FillEllipse方法繪制就可以了
3.繪制焊盤有很多種symbols,包含標准symbols和非標准symbols(自定義的),如何判斷一個symbols是標准symbols還是非標准symbols呢
在解析ODB++或Gerber前,提前將自定義symbols名存儲為自定義symbols字典集合中,繪制時優先檢測symbols名是否存在自定義字典集合中,如果存在,則解析自定義symbosl繪制,如果不存在,則通過標准symbosl名命名規則匹配,不考慮校率用正則也可以的,如:r200,rect200x300,oval200x300,donut_r300x200等,匹配到標准symbols后通過建立各種標准symbols繪制模版,找到對應的symbols模版再繪制。
4.如繪制:donut_r300x200這個symbols時,是繪制300這個實心圓,再繪制黑色背景實現圓環效果呢,
其實這樣繪制就是錯誤的,需采用:GraphicsPath類繪制,再用Region類差集裁減掉不需要多余部份圖形。
5.在Gerber圖形中一條弧直徑只有0.1毫米,轉為像素為0,繪制會出錯,
要這里需加以判斷,0像素時直接跳出不繪
6.在Gerber圖形中一條線段,線段間距只有0.1毫米, 轉為像素為0時,但線寬為5毫米,轉為像不為2像素,
那這是繪呢,還是不繪呢,由於長度像素是0,但線的寬度達到了2個像素,那么就這條線就按一個點來繪制
7.在Gerber中Surface銅皮中存在空洞時,不能用FillPolygon方法繪制,
需采用:GraphicsPath類繪制,再用Region類差集裁減掉不需要多余部份圖形
8.在Gerber中Surface銅皮存在弧節點時,不能用FillPolygon方法繪制,這結構它不支持弧節點,
如果一定要要用FillPolygon可以將弧轉為多個節點來繪制多邊形,當然另一種方法用GraphicsPath類中增Arc結點來完成弧的繪制
9.Gerber中如果字體引用了shx字體如何解析呢
這里就需要熟悉shx的數據結構了才行了,不然一點辦法也沒有
點擊進去: https://wenku.baidu.com/view/0f7d49c4aa00b52acfc7cab3.html 這是解析方法,解析后再轉為坐標數據就可以了
10.如果是:canned_57,standard等字體如何解析呢
這是Genesis自帶字體,文件一般存放在:C:\genesis\fw\lib\fonts,這是明文坐標很好解決,直接解析就好了。
三.5類元素基本數據結構
這是基本的不全面,可以擴展並改進的

/// <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> /// 精簡 PAD 數據類型 /// </summary> public struct gPP { public gPP(double x_val, double y_val, double width_) { this.p = new gPoint(x_val, y_val); this.symbols = "r"; this.width = width_; } public gPP(gPoint p_, double width_) { this.p = p_; this.symbols = "r"; this.width = width_; } public gPP(gPoint p_, string symbols_, double width_) { this.p = p_; this.symbols = symbols_; this.width = width_; } public gPoint p; public string symbols; public double width; public static gPP operator +(gPP p1, gPP p2) { p1.p += p2.p; return p1; } public static gPP operator +(gPP p1, gPoint p2) { p1.p += p2; return p1; } public static gPP operator -(gPP p1, gPP p2) { p1.p -= p2.p; return p1; } public static gPP operator -(gPP p1, gPoint p2) { p1.p -= p2; return p1; } } /// <summary> /// PAD 數據類型 /// </summary> public struct gP { public gP(double x_val, double y_val, double width_) { this.p = new gPoint(x_val, y_val); this.negative = false; this.angle = 0; this.mirror = false; this.symbols = "r"; this.attribut = string.Empty; this.width = width_; } public gP(gPoint p_, double width_) { this.p = p_; this.negative = false; this.angle = 0; this.mirror = false; this.symbols = "r"; this.attribut = string.Empty; this.width = width_; } public gP(gPoint p_, string symbols_, double width_) { this.p = p_; this.negative = false; this.angle = 0; this.mirror = false; this.symbols = symbols_; this.attribut = string.Empty; this.width = width_; } public gPoint p; public bool negative;//polarity-- positive negative public int angle; public bool mirror; public string symbols; public string attribut; public double width; public static gP operator +(gP p1, gP p2) { p1.p += p2.p; return p1; } public static gP operator +(gP p1, gPP p2) { p1.p += p2.p; return p1; } public static gP operator +(gP p1, gPoint p2) { p1.p += p2; return p1; } public static gP operator -(gP p1, gP p2) { p1.p -= p2.p; return p1; } public static gP operator -(gP p1, gPP p2) { p1.p -= p2.p; return p1; } public static gP operator -(gP p1, gPoint p2) { p1.p -= p2; return p1; } } /// <summary> /// Line 數據類型 /// </summary> public struct gL { public gL(double ps_x, double ps_y, double pe_x, double pe_y, double width_) { this.ps = new gPoint(ps_x, ps_y); this.pe = new gPoint(pe_x, pe_y); this.negative = false; this.symbols = "r" + width_.ToString(); this.attribut = string.Empty; this.width = width_; } public gL(gPoint ps_, gPoint pe_, double width_) { this.ps = ps_; this.pe = pe_; this.negative = false; this.symbols = "r" + width_.ToString(); this.attribut = string.Empty; this.width = width_; } public gL(gPoint ps_, gPoint pe_, string symbols_, double width_) { this.ps = ps_; this.pe = pe_; this.negative = false; this.symbols = symbols_; this.attribut = string.Empty; this.width = width_; } public gPoint ps; public gPoint pe; public bool negative;//polarity-- positive negative public string symbols; public string attribut; public double width; public static gL operator +(gL l1, gPoint move_p) { l1.ps += move_p; l1.pe += move_p; return l1; } public static gL operator +(gL l1, gPP move_p) { l1.ps += move_p.p; l1.pe += move_p.p; return l1; } public static gL operator +(gL l1, gP move_p) { l1.ps += move_p.p; l1.pe += move_p.p; return l1; } public static gL operator -(gL l1, gPoint move_p) { l1.ps -= move_p; l1.pe -= move_p; return l1; } public static gL operator -(gL l1, gPP move_p) { l1.ps -= move_p.p; l1.pe -= move_p.p; return l1; } public static gL operator -(gL l1, gP move_p) { l1.ps -= move_p.p; l1.pe -= move_p.p; return l1; } } /// <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; } } /// <summary> /// Text 文本數據類型 簡易型 更復雜的需要擴展 /// </summary> public struct gT { public gPoint ps; public string font; public bool negative;//polarity-- positive negative public int angle; public bool mirror; public double x_size; public double y_size; public double width; public string Text; public string attribut; } /// <summary> /// Surface 坐標泛型集類1 /// </summary> public struct 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; } /// <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> /// 整層Layer坐標泛型集類 /// </summary> public class gLayer //坐標 { public List<gP> Plist = new List<gP>(); public List<gL> Llist = new List<gL>(); public List<gA> Alist = new List<gA>(); public List<gT> Tlist = new List<gT>(); public List<gS> Slist = new List<gS>(); }
四.net實現效果圖:
小結:
.NET圖形繪制效率真是個一大問題,圖形小繪制還感覺不明顯,當元素數量大於20W時繪制時間超長,有時內存爆掉,,但同時打開Genesis卻不爆,不管是編程語言,數據結構存儲,解析算法上都要更高超,不得不佩服Frontline太有實力。看來只能用NET在圖形上只能玩點小玩意了,注定玩不了大了。