bool ParseExcellon(List <string> lines, double drillscaler, ProgressLog log) { log.PushActivity("Parse Excellon"); Tools.Clear(); bool headerdone = false; int currentline = 0; ExcellonTool CurrentTool = null; GerberNumberFormat GNF = new GerberNumberFormat(); GNF.DigitsBefore = 3; GNF.DigitsAfter = 3; GNF.OmitLeading = true; double Scaler = 1.0f; bool FormatSpecified = false; bool NumberSpecHad = false; double LastX = 0; double LastY = 0; while (currentline < lines.Count) { switch (lines[currentline]) { // case "M70": GNF.Multiplier = 25.4; break; // inch mode case "INCH": if (Gerber.ExtremelyVerbose) { log.AddString("Out of header INCH found!"); } GNF.SetImperialMode(); break; // inch mode case "METRIC": if (Gerber.ExtremelyVerbose) { log.AddString("Out of header METRIC found!"); } GNF.SetMetricMode(); break; case "M72": if (Gerber.ExtremelyVerbose) { log.AddString("Out of header M72 found!"); } GNF.SetImperialMode(); break; // inch mode case "M71": if (Gerber.ExtremelyVerbose) { log.AddString("Out of header M71 found!"); } GNF.SetMetricMode(); break; // metric mode } if (lines[currentline] == "M48") { //Console.WriteLine("Excellon header starts at line {0}", currentline); currentline++; while ((lines[currentline] != "%" && lines[currentline] != "M95")) { headerdone = true; //double InchMult = 1;// 0.010; switch (lines[currentline]) { // case "M70": GNF.Multiplier = 25.4; break; // inch mode case "INCH": GNF.SetImperialMode(); //Scaler = 0.01; break; // inch mode case "METRIC": GNF.SetMetricMode(); break; case "M72": //GNF.Multiplier = 25.4 * InchMult; GNF.SetImperialMode(); // Scaler = 0.01; break; // inch mode case "M71": //GNF.Multiplier = 1.0; GNF.SetMetricMode(); break; // metric mode default: { var S = lines[currentline].Split(','); if (S[0].IndexOf("INCH") == 0 || S[0].IndexOf("METRIC") == 0) { if (S[0].IndexOf("INCH") == 0) { GNF.SetImperialMode(); } else { GNF.SetMetricMode(); } if (S.Count() > 1) { for (int i = 1; i < S.Count(); i++) { if (S[i][0] == '0') { log.AddString(String.Format("Number spec reading!: {0}", S[i])); var A = S[i].Split('.'); if (A.Length == 2) { GNF.DigitsBefore = A[0].Length; GNF.DigitsAfter = A[1].Length; NumberSpecHad = true; } } if (S[i] == "LZ") { GNF.OmitLeading = false; } if (S[i] == "TZ") { GNF.OmitLeading = true; } } } } else { if (lines[currentline][0] == ';') { if (Gerber.ShowProgress) { log.AddString(lines[currentline]); } if (lines[currentline].Contains(";FILE_FORMAT=")) { var N = lines[currentline].Substring(13).Split(':'); GNF.DigitsBefore = int.Parse(N[0]); GNF.DigitsAfter = int.Parse(N[1]); FormatSpecified = true; } } else { GCodeCommand GCC = new GCodeCommand(); GCC.Decode(lines[currentline], GNF); if (GCC.charcommands.Count > 0) { switch (GCC.charcommands[0]) { case 'T': { ExcellonTool ET = new ExcellonTool(); ET.ID = (int)GCC.numbercommands[0]; ET.Radius = GNF.ScaleFileToMM(GCC.GetNumber('C')) / 2.0f; Tools[ET.ID] = ET; } break; } } } } } break; } currentline++; } // Console.WriteLine("Excellon header stops at line {0}", currentline); if (FormatSpecified == false && NumberSpecHad == false) { if (GNF.CurrentNumberScale == GerberNumberFormat.NumberScale.Imperial) { // GNF.OmitLeading = true; GNF.DigitsBefore = 2; GNF.DigitsAfter = 4; } else { GNF.DigitsAfter = 3; GNF.DigitsBefore = 3; } } } else { if (headerdone) { GCodeCommand GCC = new GCodeCommand(); GCC.Decode(lines[currentline], GNF); if (GCC.charcommands.Count > 0) { switch (GCC.charcommands[0]) { case 'T': if ((int)GCC.numbercommands[0] > 0) { CurrentTool = Tools[(int)GCC.numbercommands[0]]; } else { CurrentTool = null; } break; case 'M': default: { GerberSplitter GS = new GerberSplitter(); GS.Split(GCC.originalline, GNF, true); if (GS.Has("G") && GS.Get("G") == 85 && (GS.Has("X") || GS.Has("Y"))) { GerberListSplitter GLS = new GerberListSplitter(); GLS.Split(GCC.originalline, GNF, true); double x1 = LastX; double y1 = LastY; if (GLS.HasBefore("G", "X")) { x1 = GNF.ScaleFileToMM(GLS.GetBefore("G", "X") * Scaler); LastX = x1; } if (GLS.HasBefore("G", "Y")) { y1 = GNF.ScaleFileToMM(GLS.GetBefore("G", "Y") * Scaler); LastY = y1; } double x2 = LastX; double y2 = LastY; if (GLS.HasAfter("G", "X")) { x2 = GNF.ScaleFileToMM(GLS.GetAfter("G", "X") * Scaler); LastX = x2; } if (GLS.HasAfter("G", "Y")) { y2 = GNF.ScaleFileToMM(GLS.GetAfter("G", "Y") * Scaler); LastY = y2; } CurrentTool.Slots.Add(new ExcellonTool.SlotInfo() { Start = new PointD(x1 * drillscaler, y1 * drillscaler), End = new PointD(x2 * drillscaler, y2 * drillscaler) }); LastX = x2; LastY = y2; } else if (GS.Has("G") && GS.Get("G") == 00 && (GS.Has("X") || GS.Has("Y"))) { GerberListSplitter GLS = new GerberListSplitter(); GLS.Split(GCC.originalline, GNF, true); double x1 = LastX; double y1 = LastY; if (GLS.HasAfter("G", "X")) { x1 = GNF.ScaleFileToMM(GLS.GetAfter("G", "X") * Scaler); LastX = x1; } if (GLS.HasAfter("G", "Y")) { y1 = GNF.ScaleFileToMM(GLS.GetAfter("G", "Y") * Scaler); LastY = y1; } } else if (GS.Has("G") && GS.Get("G") == 01 && (GS.Has("X") || GS.Has("Y"))) { GerberListSplitter GLS = new GerberListSplitter(); GLS.Split(GCC.originalline, GNF, true); double x1 = LastX; double y1 = LastY; double x2 = LastX; double y2 = LastY; if (GLS.HasAfter("G", "X")) { x2 = GNF.ScaleFileToMM(GLS.GetAfter("G", "X") * Scaler); LastX = x2; } if (GLS.HasAfter("G", "Y")) { y2 = GNF.ScaleFileToMM(GLS.GetAfter("G", "Y") * Scaler); LastY = y2; } CurrentTool.Slots.Add(new ExcellonTool.SlotInfo() { Start = new PointD(x1 * drillscaler, y1 * drillscaler), End = new PointD(x2 * drillscaler, y2 * drillscaler) }); LastX = x2; LastY = y2; } else { if (GS.Has("X") || GS.Has("Y")) { double X = LastX; if (GS.Has("X")) { X = GNF.ScaleFileToMM(GS.Get("X") * Scaler); } double Y = LastY; if (GS.Has("Y")) { Y = GNF.ScaleFileToMM(GS.Get("Y") * Scaler); } CurrentTool.Drills.Add(new PointD(X * drillscaler, Y * drillscaler)); LastX = X; LastY = Y; } } } break; } } } } currentline++; } log.PopActivity(); return(headerdone); }
/// <summary> /// /// </summary> /// <param name="lines"></param> /// <param name="drillscaler"></param> /// <param name="log"></param> /// <param name="radiusAdjust">半径修正系数,用于实现电镀孔厚度,单位mm</param> /// <returns></returns> bool ParseExcellon(List <string> lines, double drillscaler, ProgressLog log, double radiusScaler = 1.0f) { var LogID = log.PushActivity("Parse Excellon"); Tools.Clear(); bool headerdone = false; int currentline = 0; ExcellonTool CurrentTool = null; GerberNumberFormat GNF = new GerberNumberFormat(); GNF.DigitsBefore = 3; GNF.DigitsAfter = 3; GNF.OmitLeading = true; double Scaler = 1.0f; bool FormatSpecified = false; bool NumberSpecHad = false; double LastX = 0; double LastY = 0; CutterCompensation Compensation = CutterCompensation.None; List <PointD> PathCompensation = new List <PointD>(); bool WarnIntersections = true; while (currentline < lines.Count) { switch (lines[currentline]) { // case "M70": GNF.Multiplier = 25.4; break; // inch mode case "INCH": if (Gerber.ExtremelyVerbose) { log.AddString("Out of header INCH found!"); } GNF.SetImperialMode(); break; // inch mode case "METRIC": if (Gerber.ExtremelyVerbose) { log.AddString("Out of header METRIC found!"); } GNF.SetMetricMode(); break; case "M72": if (Gerber.ExtremelyVerbose) { log.AddString("Out of header M72 found!"); } GNF.SetImperialMode(); break; // inch mode case "M71": if (Gerber.ExtremelyVerbose) { log.AddString("Out of header M71 found!"); } GNF.SetMetricMode(); break; // metric mode } if (lines[currentline] == "M48") { //Console.WriteLine("Excellon header starts at line {0}", currentline); currentline++; while ((lines[currentline] != "%" && lines[currentline] != "M95")) { headerdone = true; //double InchMult = 1;// 0.010; switch (lines[currentline]) { // case "M70": GNF.Multiplier = 25.4; break; // inch mode case "INCH": GNF.SetImperialMode(); //Scaler = 0.01; break; // inch mode case "METRIC": GNF.SetMetricMode(); break; case "M72": //GNF.Multiplier = 25.4 * InchMult; GNF.SetImperialMode(); // Scaler = 0.01; break; // inch mode case "M71": //GNF.Multiplier = 1.0; GNF.SetMetricMode(); break; // metric mode default: { var S = lines[currentline].Split(','); if (S[0].IndexOf("INCH") == 0 || S[0].IndexOf("METRIC") == 0) { if (S[0].IndexOf("INCH") == 0) { GNF.SetImperialMode(); } else { GNF.SetMetricMode(); } if (S.Count() > 1) { for (int i = 1; i < S.Count(); i++) { if (S[i][0] == '0') { log.AddString(String.Format("Number spec reading!: {0}", S[i])); var A = S[i].Split('.'); if (A.Length == 2) { GNF.DigitsBefore = A[0].Length; GNF.DigitsAfter = A[1].Length; NumberSpecHad = true; } } if (S[i] == "LZ") { GNF.OmitLeading = false; } if (S[i] == "TZ") { GNF.OmitLeading = true; } } } } else { if (lines[currentline][0] == ';') { if (Gerber.ShowProgress) { log.AddString(lines[currentline]); } if (lines[currentline].Contains(";FILE_FORMAT=")) { var N = lines[currentline].Substring(13).Split(':'); GNF.DigitsBefore = int.Parse(N[0]); GNF.DigitsAfter = int.Parse(N[1]); FormatSpecified = true; } } else { GCodeCommand GCC = new GCodeCommand(); GCC.Decode(lines[currentline], GNF); if (GCC.charcommands.Count > 0) { switch (GCC.charcommands[0]) { case 'T': { ExcellonTool ET = new ExcellonTool(); ET.ID = (int)GCC.numbercommands[0]; ET.Radius = GNF.ScaleFileToMM(GCC.GetNumber('C')) / 2.0f * radiusScaler; Tools[ET.ID] = ET; } break; } } } } } break; } currentline++; } // Console.WriteLine("Excellon header stops at line {0}", currentline); if (FormatSpecified == false && NumberSpecHad == false) { if (GNF.CurrentNumberScale == GerberNumberFormat.NumberScale.Imperial) { // GNF.OmitLeading = true; GNF.DigitsBefore = 2; GNF.DigitsAfter = 4; } else { GNF.DigitsAfter = 3; GNF.DigitsBefore = 3; } } } else { if (headerdone) { GCodeCommand GCC = new GCodeCommand(); GCC.Decode(lines[currentline], GNF); if (GCC.charcommands.Count > 0) { switch (GCC.charcommands[0]) { case 'T': if ((int)GCC.numbercommands[0] > 0) { CurrentTool = Tools[(int)GCC.numbercommands[0]]; } else { CurrentTool = null; } break; case 'M': default: { GerberSplitter GS = new GerberSplitter(); GS.Split(GCC.originalline, GNF, true); if (GS.Has("G") && GS.Get("G") == 85 && (GS.Has("X") || GS.Has("Y"))) { GerberListSplitter GLS = new GerberListSplitter(); GLS.Split(GCC.originalline, GNF, true); double x1 = LastX; double y1 = LastY; if (GLS.HasBefore("G", "X")) { x1 = GNF.ScaleFileToMM(GLS.GetBefore("G", "X") * Scaler); LastX = x1; } if (GLS.HasBefore("G", "Y")) { y1 = GNF.ScaleFileToMM(GLS.GetBefore("G", "Y") * Scaler); LastY = y1; } double x2 = LastX; double y2 = LastY; if (GLS.HasAfter("G", "X")) { x2 = GNF.ScaleFileToMM(GLS.GetAfter("G", "X") * Scaler); LastX = x2; } if (GLS.HasAfter("G", "Y")) { y2 = GNF.ScaleFileToMM(GLS.GetAfter("G", "Y") * Scaler); LastY = y2; } CurrentTool.Slots.Add(new ExcellonTool.SlotInfo() { Start = new PointD(x1 * drillscaler, y1 * drillscaler), End = new PointD(x2 * drillscaler, y2 * drillscaler) }); LastX = x2; LastY = y2; } else if (GS.Has("G") && GS.Get("G") == 00 && (GS.Has("X") || GS.Has("Y"))) { GerberListSplitter GLS = new GerberListSplitter(); GLS.Split(GCC.originalline, GNF, true); double x1 = LastX; double y1 = LastY; if (GLS.HasAfter("G", "X")) { x1 = GNF.ScaleFileToMM(GLS.GetAfter("G", "X") * Scaler); LastX = x1; } if (GLS.HasAfter("G", "Y")) { y1 = GNF.ScaleFileToMM(GLS.GetAfter("G", "Y") * Scaler); LastY = y1; } /* cancel cutter compensation */ Compensation = CutterCompensation.None; PathCompensation.Clear(); } else if (GS.Has("G") && GS.Get("G") == 01 && (GS.Has("X") || GS.Has("Y"))) { GerberListSplitter GLS = new GerberListSplitter(); GLS.Split(GCC.originalline, GNF, true); double x1 = LastX; double y1 = LastY; double x2 = LastX; double y2 = LastY; if (GLS.HasAfter("G", "X")) { x2 = GNF.ScaleFileToMM(GLS.GetAfter("G", "X") * Scaler); LastX = x2; } if (GLS.HasAfter("G", "Y")) { y2 = GNF.ScaleFileToMM(GLS.GetAfter("G", "Y") * Scaler); LastY = y2; } if (Compensation == CutterCompensation.None) { CurrentTool.Slots.Add(new ExcellonTool.SlotInfo() { Start = new PointD(x1 * drillscaler, y1 * drillscaler), End = new PointD(x2 * drillscaler, y2 * drillscaler) }); } else { PathCompensation.Add(new PointD(x2 * drillscaler, y2 * drillscaler)); } LastX = x2; LastY = y2; } else if (GS.Has("G") && GS.Get("G") == 40) /* cutter compensation off */ { var comp = CutCompensation(PathCompensation, Compensation, CurrentTool.Radius * drillscaler); if (WarnIntersections) { /* warn about path intersections */ for (int i = 0; i < comp.Count - 1; i++) { for (int j = i + 2; j < comp.Count - 1; j++) { var intersection = Helpers.SegmentSegmentIntersect(comp[i], comp[i + 1], comp[j], comp[j + 1]); if (intersection != null) { log.AddString("Path with intersections found on cut compensation! Inspect output for accuracy!"); WarnIntersections = false; break; } } if (!WarnIntersections) { break; } } } /* create line segments from set of points */ var array = comp.Zip(comp.Skip(1), Tuple.Create); CurrentTool.Slots.AddRange(array.Select(i => new ExcellonTool.SlotInfo() { Start = i.Item1, End = i.Item2 })); Compensation = CutterCompensation.None; PathCompensation.Clear(); } else if (GS.Has("G") && GS.Get("G") == 41) /* cutter compensation left: offset of the cutter radius is to the LEFT of contouring direction */ { if (Compensation != CutterCompensation.None) { log.AddString("Unterminated cutter compensation block found! Inspect output for accuracy!"); } Compensation = CutterCompensation.Left; PathCompensation.Clear(); PathCompensation.Add(new PointD(LastX * drillscaler, LastY * drillscaler)); } else if (GS.Has("G") && GS.Get("G") == 42) /* cutter compensation right: offset of the cutter radius is to the RIGHT of contouring direction */ { if (Compensation != CutterCompensation.None) { log.AddString("Unterminated cutter compensation block found! Inspect output for accuracy!"); } Compensation = CutterCompensation.Right; PathCompensation.Clear(); PathCompensation.Add(new PointD(LastX * drillscaler, LastY * drillscaler)); } else { //Deal with the repeat code if (GS.Has("R") && (GS.Has("X") || GS.Has("Y"))) { double repeatX = 0; double repeatY = 0; if (GS.Has("X")) { repeatX = GNF.ScaleFileToMM(GS.Get("X") * Scaler); } if (GS.Has("Y")) { repeatY = GNF.ScaleFileToMM(GS.Get("Y") * Scaler); } for (int repeatIndex = 1; repeatIndex <= GS.Get("R"); repeatIndex++) { double X = LastX; if (GS.Has("X")) { X += repeatX; } double Y = LastY; if (GS.Has("Y")) { Y += repeatY; } CurrentTool.Drills.Add(new PointD(X * drillscaler, Y * drillscaler)); LastX = X; LastY = Y; } } else if (GS.Has("X") || GS.Has("Y")) { double X = LastX; if (GS.Has("X")) { X = GNF.ScaleFileToMM(GS.Get("X") * Scaler); } double Y = LastY; if (GS.Has("Y")) { Y = GNF.ScaleFileToMM(GS.Get("Y") * Scaler); } if (Compensation == CutterCompensation.None) { CurrentTool.Drills.Add(new PointD(X * drillscaler, Y * drillscaler)); } else { PathCompensation.Add(new PointD(X * drillscaler, Y * drillscaler)); } LastX = X; LastY = Y; } } } break; } } } } currentline++; } log.PopActivity(LogID); return(headerdone); }