static GerberNet AddDrillHole(GerberImage image, DrillState drillState, GerberNet currentNet) { image.DrillStats.IncrementDrillCounter(drillState.CurrentTool); GerberNet newDrillNet = new GerberNet(image, currentNet, null, null); newDrillNet.BoundingBox = new BoundingBox(); newDrillNet.StartX = drillState.CurrentX; newDrillNet.StartY = drillState.CurrentY; if (drillState.Unit == GerberUnit.Millimeter) { newDrillNet.StartX /= 25.4; newDrillNet.StartY /= 25.4; newDrillNet.NetState.Unit = GerberUnit.Inch; } newDrillNet.StopX = newDrillNet.StartX - drillState.OriginX; newDrillNet.StopY = newDrillNet.StartY - drillState.OriginY; newDrillNet.Aperture = drillState.CurrentTool; newDrillNet.ApertureState = GerberApertureState.Flash; // Check if the aperture is set. if (image.ApertureArray[drillState.CurrentTool] == null) { return(newDrillNet); } newDrillNet.BoundingBox.Left = newDrillNet.StartX - image.ApertureArray[drillState.CurrentTool].Parameters[0] / 2; newDrillNet.BoundingBox.Right = newDrillNet.StartX + image.ApertureArray[drillState.CurrentTool].Parameters[0] / 2; newDrillNet.BoundingBox.Bottom = newDrillNet.StartY - image.ApertureArray[drillState.CurrentTool].Parameters[0] / 2; newDrillNet.BoundingBox.Top = newDrillNet.StartY + image.ApertureArray[drillState.CurrentTool].Parameters[0] / 2; image.ImageInfo.MinX = Math.Min(image.ImageInfo.MinX, (newDrillNet.StartX - image.ApertureArray[drillState.CurrentTool].Parameters[0] / 2)); image.ImageInfo.MinY = Math.Min(image.ImageInfo.MinY, (newDrillNet.StartY - image.ApertureArray[drillState.CurrentTool].Parameters[0] / 2)); image.ImageInfo.MaxX = Math.Max(image.ImageInfo.MaxX, (newDrillNet.StartX + image.ApertureArray[drillState.CurrentTool].Parameters[0] / 2)); image.ImageInfo.MaxY = Math.Max(image.ImageInfo.MaxY, (newDrillNet.StartY + image.ApertureArray[drillState.CurrentTool].Parameters[0] / 2)); return(newDrillNet); }
static void ParseCoordinate(GerberLineReader lineReader, char firstCharacter, GerberImage image, DrillState drillState) { if (drillState.CoordinateMode == DrillCoordinateMode.Absolute) { if (firstCharacter == 'X') { drillState.CurrentX = GetDoubleValue(lineReader, drillState.DataNumberFormat, image.Format.OmitZeros, drillState.DecimalPlaces); if (lineReader.Read() == 'Y') { drillState.CurrentY = GetDoubleValue(lineReader, drillState.DataNumberFormat, image.Format.OmitZeros, drillState.DecimalPlaces); } else { lineReader.Position--; } } else { drillState.CurrentY = GetDoubleValue(lineReader, drillState.DataNumberFormat, image.Format.OmitZeros, drillState.DecimalPlaces); } } else { if (firstCharacter == 'X') { drillState.CurrentX += GetDoubleValue(lineReader, drillState.DataNumberFormat, image.Format.OmitZeros, drillState.DecimalPlaces); if (lineReader.Read() == 'Y') { drillState.CurrentY += GetDoubleValue(lineReader, drillState.DataNumberFormat, image.Format.OmitZeros, drillState.DecimalPlaces); } } else { drillState.CurrentY += GetDoubleValue(lineReader, drillState.DataNumberFormat, image.Format.OmitZeros, drillState.DecimalPlaces); } } }
static int ParseTCode(GerberLineReader lineReader, string drillFileName, DrillState drillState, GerberImage image) { int drillNumber; double drillSize = 0.0; int length = 0; char nextCharacter; bool done = false; DrillFileStats stats = image.DrillStats; string line = String.Empty; string errorMessage = String.Empty; nextCharacter = lineReader.Read(); if (!Char.IsDigit(nextCharacter)) { if (nextCharacter == 'C') { lineReader.Position -= 2; line = lineReader.ReadLineToEnd(); if (line == "TCST") { errorMessage = "Tool change stop switch found."; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberNote, lineReader.LineNumber, drillFileName); } return(-1); } } lineReader.Position--; drillNumber = lineReader.GetIntegerValue(ref length); // T00 is a tool unload command. if (drillNumber == 0) { return(drillNumber); } if (drillNumber < ToolMin && drillNumber >= ToolMax) { errorMessage = String.Format(CultureInfo.CurrentCulture, "Drill number out of bounds:{0}.\n", drillNumber); stats.AddNewError(-1, errorMessage, GerberErrorType.GerberError, lineReader.LineNumber, drillFileName); } drillState.CurrentTool = drillNumber; // Tool definition following tool number. if (lineReader.Position > 0) { while (!done) { nextCharacter = lineReader.Read(); switch (nextCharacter) { case 'C': drillSize = GetDoubleValue(lineReader, drillState.HeaderNumberFormat, GerberOmitZero.OmitZerosTrailing, drillState.DecimalPlaces); if (drillState.Unit == GerberUnit.Millimeter) { drillSize /= 25.4; } else if (drillSize >= 4.0) { drillSize /= 1000.0; } if (drillSize <= 0 || drillSize >= 10000) { errorMessage = "Unreasonable drill size found."; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberError, lineReader.LineNumber, drillFileName); } else { // Allow a redefinition of a tool only if all parameters are the same. if (image.ApertureArray[drillNumber] != null) { if (image.ApertureArray[drillNumber].Parameters[0] != drillSize || image.ApertureArray[drillNumber].ApertureType != GerberApertureType.Circle || image.ApertureArray[drillNumber].ParameterCount != 1 || image.ApertureArray[drillNumber].Unit != GerberUnit.Inch) { errorMessage = String.Format(CultureInfo.CurrentCulture, "Found redefinition if drill {0}.\n", drillNumber); stats.AddNewError(-1, errorMessage, GerberErrorType.GerberError); } } else { image.ApertureArray[drillNumber] = new ApertureDefinition(); image.ApertureArray[drillNumber].Parameters[0] = drillSize; image.ApertureArray[drillNumber].ApertureType = GerberApertureType.Circle; image.ApertureArray[drillNumber].ParameterCount = 1; image.ApertureArray[drillNumber].Unit = GerberUnit.Inch; } } string drillUnit = (drillState.Unit == GerberUnit.Millimeter) ? "MM" : "INCH"; stats.AddToDrillList(drillNumber, (drillState.Unit == GerberUnit.Millimeter) ? drillSize * 25.4 : drillSize, drillUnit); break; case 'F': case 'S': lineReader.GetIntegerValue(ref length); break; default: lineReader.Position--; done = true; break; } } } return(drillNumber); }
static DrillMCode ParseMCode(GerberLineReader lineReader, DrillState drillState, GerberImage image) { DrillFileStats stats = image.DrillStats; DrillMCode result = DrillMCode.Unknown; int length = 0; string line = String.Empty; int value = lineReader.GetIntegerValue(ref length); switch (value) { case 0: stats.M00++; result = DrillMCode.End; break; case 1: stats.M01++; result = DrillMCode.EndPattern; break; case 18: stats.M18++; result = DrillMCode.TipCheck; break; case 25: stats.M25++; result = DrillMCode.BeginPattern; break; case 30: stats.M30++; result = DrillMCode.EndRewind; break; case 31: stats.M31++; result = DrillMCode.BeginPattern; break; case 45: stats.M45++; result = DrillMCode.LongMessage; break; case 47: stats.M47++; result = DrillMCode.Message; break; case 48: stats.M48++; result = DrillMCode.Header; break; case 71: stats.M71++; result = DrillMCode.Metric; break; case 72: stats.M72++; result = DrillMCode.Imperial; break; case 95: stats.M95++; result = DrillMCode.EndHeader; break; case 97: stats.M97++; result = DrillMCode.CannedText; break; case 98: stats.M98++; result = DrillMCode.CannedText; break; default: stats.MUnknown++; break; } return(result); }
private static List <GerberHIDAttribute> drillAttributeList = new List <GerberHIDAttribute>(); /* <---- NOT SURE IF WE NEED THIS.*/ public static GerberImage ParseDrillFile(string drillFileName, List <GerberHIDAttribute> attributeList, int numberOfAttributes, bool reload) { bool foundEOF = false; string errorMessage = String.Empty; DrillState drillState = new DrillState(); GerberImage image = new GerberImage("Excellon Drill File"); CreateDefaultAttributeList(); if (reload & attributeList != null) { image.ImageInfo.NumberOfAttribute = numberOfAttributes; image.ImageInfo.AttributeList = new List <GerberHIDAttribute>(); for (int i = 0; i < numberOfAttributes; i++) { GerberHIDAttribute attribute = new GerberHIDAttribute(attributeList[i]); image.ImageInfo.AttributeList.Add(attribute); } } else { // Load default attributes. image.ImageInfo.NumberOfAttribute = drillAttributeList.Count; image.ImageInfo.AttributeList = new List <GerberHIDAttribute>(); for (int i = 0; i < image.ImageInfo.NumberOfAttribute; i++) { GerberHIDAttribute attribute = new GerberHIDAttribute(drillAttributeList[i]); image.ImageInfo.AttributeList.Add(attribute); } } DrillAttributeMerge(image.ImageInfo.AttributeList, image.ImageInfo.NumberOfAttribute, attributeList, numberOfAttributes); image.FileType = GerberFileType.Drill; image.DrillStats = new DrillFileStats(); image.Format = new GerberFormat(); image.Format.OmitZeros = GerberOmitZero.OmitZerosUnspecified; if (image.ImageInfo.AttributeList[(int)HA.AutoDetect].DefaultValue.IntValue > 0) { drillState.AutoDetect = false; drillState.DataNumberFormat = DrillNumberFormat.UserDefined; drillState.DecimalPlaces = image.ImageInfo.AttributeList[(int)HA.Digits].DefaultValue.IntValue; if (image.ImageInfo.AttributeList[(int)HA.ZeroSuppression].DefaultValue.IntValue == (int)Units.Millimeters) { drillState.Unit = GerberUnit.Millimeter; } switch (image.ImageInfo.AttributeList[(int)HA.ZeroSuppression].DefaultValue.IntValue) { case (int)ZeroSuppression.Leading: image.Format.OmitZeros = GerberOmitZero.OmitZerosLeading; break; case (int)ZeroSuppression.Trailing: image.Format.OmitZeros = GerberOmitZero.OmitZerosTrailing; break; default: image.Format.OmitZeros = GerberOmitZero.OmitZerosExplicit; break; } } //Debug.WriteLine(String.Format("Starting to parse drill file {0}", drillFileName)); using (StreamReader drillFileStream = new StreamReader(drillFileName, Encoding.ASCII)) { GerberLineReader lineReader = new GerberLineReader(drillFileStream); foundEOF = ParseDrillSegment(drillFileName, lineReader, image, drillState); } if (!foundEOF) { errorMessage = String.Format(CultureInfo.CurrentCulture, "File {0} is missing Excellon Drill EOF code./n", drillFileName); image.DrillStats.AddNewError(-1, errorMessage, GerberErrorType.GerberError); } //Debug.WriteLine("... done parsing Excellon Drill file."); return(image); }
static bool ParseDrillSegment(string drillFileName, GerberLineReader lineReader, GerberImage image, DrillState drillState) { bool foundEOF = false; DrillFileStats stats = image.DrillStats; GerberNet currentNet = image.GerberNetList[0]; currentNet.Level = image.LevelList[0]; currentNet.NetState = image.NetStateList[0]; bool done = false; string line; string[] command; string errorMessage; char nextCharacter; while (!lineReader.EndOfFile && !foundEOF) { nextCharacter = lineReader.Read(); switch (nextCharacter) { case ';': // Comment. line = lineReader.ReadLineToEnd(); break; case 'D': lineReader.Position--; line = lineReader.ReadLineToEnd(); if (line.Substring(0, 6) == "DETECT") { stats.Detect = line.Substring(6, (line.Length - 7)); } else { errorMessage = String.Format(CultureInfo.CurrentCulture, "Undefined header line: {0}.\n", line); stats.AddNewError(-1, errorMessage, GerberErrorType.GerberNote, lineReader.LineNumber, drillFileName); } break; case 'F': lineReader.Position--; line = lineReader.ReadLineToEnd(); if (line != "FMAT,2") { errorMessage = String.Format(CultureInfo.CurrentCulture, "Undefined header line: {0}.\n", line); stats.AddNewError(-1, errorMessage, GerberErrorType.GerberNote, lineReader.LineNumber, drillFileName); } break; case 'G': DrillGCode gCode = ParseGCode(lineReader, image); switch (gCode) { case DrillGCode.Rout: errorMessage = "Rout Mode not supported.\n"; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberNote, lineReader.LineNumber, drillFileName); break; case DrillGCode.Drill: break; case DrillGCode.Slot: nextCharacter = lineReader.Read(); ParseCoordinate(lineReader, nextCharacter, image, drillState); currentNet.StopX = drillState.CurrentX; currentNet.StopY = drillState.CurrentY; if (drillState.Unit == GerberUnit.Millimeter) { currentNet.StopX /= 25.4; currentNet.StopY /= 25.4; } currentNet.ApertureState = GerberApertureState.On; break; case DrillGCode.Absolute: drillState.CoordinateMode = DrillCoordinateMode.Absolute; break; case DrillGCode.Incrementle: drillState.CoordinateMode = DrillCoordinateMode.Incremental; break; case DrillGCode.ZeroSet: nextCharacter = lineReader.Read(); ParseCoordinate(lineReader, nextCharacter, image, drillState); drillState.OriginX = drillState.CurrentX; drillState.OriginY = drillState.CurrentY; break; default: line = lineReader.ReadLineToEnd(); break; } break; case 'I': // Inch header. if (drillState.CurrentSection != DrillFileSection.Header) { break; } nextCharacter = lineReader.Read(); switch (nextCharacter) { // Inch case 'N': lineReader.Position -= 2; line = lineReader.ReadLineToEnd(); command = line.Split(','); if (command[0] == "INCH") { drillState.Unit = GerberUnit.Inch; } if (command.Length == 2) { if (command[1] == "TZ") { if (drillState.AutoDetect) { image.Format.OmitZeros = GerberOmitZero.OmitZerosLeading; drillState.HeaderNumberFormat = DrillNumberFormat.Format_00_0000; drillState.DecimalPlaces = 4; } } else if (command[1] == "LZ") { image.Format.OmitZeros = GerberOmitZero.OmitZerosTrailing; drillState.HeaderNumberFormat = DrillNumberFormat.Format_00_0000; drillState.DecimalPlaces = 4; } else { errorMessage = "Invalid zero suppression found after INCH.\n"; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberWarning, lineReader.LineNumber, drillFileName); } } else { // No TZ/LZ specified, use defaults. if (drillState.AutoDetect) { image.Format.OmitZeros = GerberOmitZero.OmitZerosLeading; drillState.HeaderNumberFormat = DrillNumberFormat.Format_00_0000; drillState.DecimalPlaces = 4; } } break; case 'C': lineReader.Position -= 2; line = lineReader.ReadLineToEnd(); command = line.Split(','); if (command.Length == 2) { if (command[1] == "ON") { drillState.CoordinateMode = DrillCoordinateMode.Incremental; } else if (command[1] == "OFF") { drillState.CoordinateMode = DrillCoordinateMode.Absolute; } else { errorMessage = "Invalid coordinate data found.\n"; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberWarning, lineReader.LineNumber, drillFileName); } } else { errorMessage = "Invalid data found.\n"; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberWarning, lineReader.LineNumber, drillFileName); } break; } break; case 'M': // M code or Metric nextCharacter = lineReader.Read(); if (!Char.IsDigit(nextCharacter)) // Not a M## command. { // Should be a metric command in header. // METRIC is only acceptable within the header section. // The syntax is METRIC[,{TZ|LZ}][,{000.000|000.00|0000.00}] ?????? if (drillState.CurrentSection != DrillFileSection.Header) { break; } done = true; lineReader.Position -= 2; // Point back to the start on the line. line = lineReader.ReadLineToEnd(); command = line.Split(','); if (command[0] == "METRIC") { drillState.Unit = GerberUnit.Millimeter; } if (command.Length > 1) { if (command[1] == "TZ") { if (drillState.AutoDetect) { image.Format.OmitZeros = GerberOmitZero.OmitZerosLeading; } done = false; } else if (command[1] == "LZ") { if (drillState.AutoDetect) { image.Format.OmitZeros = GerberOmitZero.OmitZerosTrailing; } done = false; } else { errorMessage = "Invalid zero suppression found after METRIC.\n"; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberWarning, lineReader.LineNumber, drillFileName); done = true; } // Number format may or may not be specified. if (!done && command.Length == 3) { if (drillState.AutoDetect) { drillState.HeaderNumberFormat = drillState.DataNumberFormat = DrillNumberFormat.Format_000_000; drillState.DecimalPlaces = 3; } if (command[2] == "0000.00") { drillState.DataNumberFormat = DrillNumberFormat.Format_0000_00; drillState.DecimalPlaces = 2; } else if (command[2] == "000.000") { drillState.DataNumberFormat = DrillNumberFormat.Format_000_000; drillState.DecimalPlaces = 3; } else if (command[2] == "000.00") { drillState.DataNumberFormat = DrillNumberFormat.Format_000_00; drillState.DecimalPlaces = 2; } else { errorMessage = "Invalid number format found after TZ/LZ.\n"; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberWarning, lineReader.LineNumber, drillFileName); } } } else { // No TZ/LZ or number format specified, use defaults. if (drillState.AutoDetect) { image.Format.OmitZeros = GerberOmitZero.OmitZerosLeading; drillState.HeaderNumberFormat = DrillNumberFormat.Format_000_000; drillState.DecimalPlaces = 3; } } } else if (Char.IsDigit(nextCharacter)) { // Must be an M## code. lineReader.Position--; DrillMCode mCode = ParseMCode(lineReader, drillState, image); switch (mCode) { case DrillMCode.Header: drillState.CurrentSection = DrillFileSection.Header; break; case DrillMCode.EndHeader: drillState.CurrentSection = DrillFileSection.Data; break; case DrillMCode.Metric: if (drillState.Unit == GerberUnit.Unspecified && drillState.CurrentSection != DrillFileSection.Header) { errorMessage = "M71 code found with no METRIC specification in header.\n"; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberError, lineReader.LineNumber, drillFileName); errorMessage = "Assuming all tool sizes are in millimeters.\n"; stats.AddNewError(-1, errorMessage, GerberErrorType.GerberWarning); for (int toolNumber = ToolMin; toolNumber < ToolMax; toolNumber++) { if (image.ApertureArray[toolNumber] != null) { double toolSize = image.ApertureArray[toolNumber].Parameters[0]; stats.ModifyDrillList(toolNumber, toolSize, "MM"); image.ApertureArray[toolNumber].Parameters[0] /= 25.4; } } } if (drillState.AutoDetect) { drillState.DataNumberFormat = drillState.BackupNumberFormat; drillState.Unit = GerberUnit.Millimeter; } break; case DrillMCode.Imperial: if (drillState.AutoDetect) { if (drillState.DataNumberFormat != DrillNumberFormat.Format_00_0000) { drillState.BackupNumberFormat = drillState.DataNumberFormat; // Save format definition for later. } drillState.DataNumberFormat = DrillNumberFormat.Format_00_0000; drillState.DecimalPlaces = 4; drillState.Unit = GerberUnit.Inch; } break; case DrillMCode.LongMessage: case DrillMCode.Message: case DrillMCode.CannedText: line = lineReader.ReadLineToEnd(); // message here. break; case DrillMCode.NotImplemented: case DrillMCode.EndPattern: case DrillMCode.TipCheck: break; case DrillMCode.End: line = lineReader.ReadLineToEnd(); break; case DrillMCode.EndRewind: // EOF. //done = true; foundEOF = true; break; default: stats.AddNewError(-1, "Undefined M code.", GerberErrorType.GerberError, lineReader.LineNumber, drillFileName); break; } } break; case 'R': if (drillState.CurrentSection == DrillFileSection.Header) { stats.AddNewError(-1, "R code not allowed in the header.", GerberErrorType.GerberError, lineReader.LineNumber, drillFileName); } else { double stepX = 0.0, stepY = 0.0; int length = 0; image.DrillStats.R++; double startX = drillState.CurrentX; double startY = drillState.CurrentY; int repeatcount = lineReader.GetIntegerValue(ref length); nextCharacter = lineReader.Read(); if (nextCharacter == 'X') { stepX = GetDoubleValue(lineReader, drillState.DataNumberFormat, image.Format.OmitZeros, drillState.DecimalPlaces); nextCharacter = lineReader.Read(); } if (nextCharacter == 'Y') { stepY = GetDoubleValue(lineReader, drillState.DataNumberFormat, image.Format.OmitZeros, drillState.DecimalPlaces); } else { lineReader.Position--; } for (int i = 1; i < repeatcount; i++) { drillState.CurrentX = startX + i * stepX; drillState.CurrentY = startY + i * stepY; currentNet = AddDrillHole(image, drillState, currentNet); } } break; case 'S': // Ignore spindle speed. lineReader.ReadLineToEnd(); break; case 'T': int tool = ParseTCode(lineReader, drillFileName, drillState, image); break; case 'X': case 'Y': // Hole coordinate found. Do some parsing. ParseCoordinate(lineReader, nextCharacter, image, drillState); // Add the new drill hole. currentNet = AddDrillHole(image, drillState, currentNet); break; case '%': drillState.CurrentSection = DrillFileSection.Data; break; // Ignore white space or null characters. case '\n': case '\r': case ' ': case '\t': case '\0': break; } } return(foundEOF); }