public override string ToString() { // for some reason the arc in version 5.99 needs start middle end // rather than start end angle like for fp_arc ... go figure // X1, Y1 = centre double Xs, Ys, Xm, Ym, Xe, Ye; Xs = Math.Round(X1 + Radius * Math.Cos(Radians(StartAngle)), Precision); Ys = Math.Round(Y1 + Radius * Math.Sin(Radians(StartAngle)), Precision); Xm = Math.Round(X1 + Radius * Math.Cos(Radians(StartAngle + (EndAngle - StartAngle) / 2)), Precision); Ym = Math.Round(Y1 + Radius * Math.Sin(Radians(StartAngle + (EndAngle - StartAngle) / 2)), Precision); Xe = Math.Round(X1 + Radius * Math.Cos(Radians(EndAngle)), Precision); Ye = Math.Round(Y1 + Radius * Math.Sin(Radians(EndAngle)), Precision); string netstr = (net == -1) ? "" : $"(net {net})"; if (Brd.IsCopperLayer(Layer)) { return($" (arc (start {Xs} {-Ys}) (mid {Xm} {-Ym}) (end {Xe} {-Ye}) (layer {Brd.GetLayer(Layer)}) {netstr} (width {Width}))\n"); } else { return($" (gr_arc (start {Math.Round(X1, Precision)} {Math.Round(-Y1, Precision)}) (end {Math.Round(Xs, Precision)} {Math.Round(-Ys, Precision)}) (angle {Math.Round(-(EndAngle - StartAngle), Precision)}) (layer {Brd.GetLayer(Layer)}) (width {Width}))\n"); } }
public override bool ProcessLine(byte[] line) { double StartAngle, EndAngle, Radius, Width; Layers Layer; double X1, Y1; Int16 Component; Int16 net; base.ProcessLine(); ArcStruct a = ByteArrayToStructure <ArcStruct>(line); Layer = (Layers)a.Layer; net = a.net; net++; Component = a.Component; X1 = Math.Round((double)a.X1 * 25.4 / 10000000 - originX, Precision); Y1 = Math.Round((double)a.Y1 * 25.4 / 10000000 - originY, Precision); Radius = Math.Round((double)a.Radius * 25.4 / 10000000, Precision); StartAngle = a.StartAngle; EndAngle = a.EndAngle; Width = (double)a.Width * 25.4 / 10000000; bool InComponent = Component != -1; double Angle; if (EndAngle < StartAngle) { EndAngle += 360; } Angle = (EndAngle - StartAngle); double X = X1 + Radius * Math.Cos(StartAngle * Math.PI / 180); double Y = Y1 + Radius * Math.Sin(StartAngle * Math.PI / 180); string layer = Brd.GetLayer(Layer); if (!InComponent) { if (net > 0 && Brd.IsCopperLayer(Layer)) { if (!Globals.PcbnewVersion) { // arcs with nets on copper layers allowed in 5.99 Arc Arc = new Arc(X1, Y1, StartAngle, EndAngle, Radius, Layer, Width, net); ArcsL.Add(Arc); } else { //arcs.Append($" (arc (start {Math.Round(X1, Precision)} {Math.Round(-Y1, Precision)}) (end {Math.Round(X, Precision)} {Math.Round(-Y, Precision)}) (angle {Math.Round(Angle, Precision)}) (layer {L}) (net {Net}) (width {Width}))\n"); // we have an arc/track on a copper layer and it has a net // these aren't supported by KiCad yet so generate a curve out of track segments // first normalise it so that the centre is at 0,0 // save the centre point double XC = X1; double YC = Y1; X = X - XC; Y = Y - YC; double radius = Math.Sqrt(X * X + Y * Y); // start angle in radians double start_angle = Arc.Radians(StartAngle); double end_angle = Arc.Radians(EndAngle); double X2 = Radius * Math.Cos(end_angle); double Y2 = Radius * Math.Sin(end_angle); X = Radius * Math.Cos(start_angle); Y = Radius * Math.Sin(start_angle); // generate arc segments at 5° increments for (double angle = start_angle; angle < end_angle; angle += 2 * Math.PI / 72) { X1 = Radius * Math.Cos(angle); Y1 = Radius * Math.Sin(angle); Line Line = new Line(XC + X, YC + Y, XC + X1, YC + Y1, layer, Width, net); LinesL.Add(Line); X = X1; Y = Y1; } // do last segment if (X != X2 || Y != Y2) { Line Line = new Line(X + XC, Y + YC, X2 + XC, Y2 + YC, layer, Width, net); LinesL.Add(Line); } } } else { // only add if not part of board outline if ((layer != "Edge.Cuts") || !Brd.CheckExistingArc(X1, Y1, X, Y, Angle)) { List <string> Layers = Brd.GetLayers(layer); foreach (var L in Layers) { Arc Arc = new Arc(X1, Y1, StartAngle, EndAngle, Radius, Brd.GetAltiumLayer(L), Width); ArcsL.Add(Arc); } } } } else { Arc Arc = new Arc(X1, Y1, StartAngle, EndAngle, Radius, Layer, Width); ModulesL[Component].Arcs.Add(Arc); } return(true); }
public override bool ProcessBinaryFile(byte[] data) { bool GenerateTxtFile = true; // set to true to generate text version of the file FileStream TextFile = null; StartTimer(); if (Binary_size == 0) { return(false); } if (GenerateTxtFile) { if (ExtractFiles) { TextFile = File.Open("Data.txt", FileMode.OpenOrCreate); } } try { using (MemoryStream ms = new MemoryStream(data)) { UInt32 pos = 0; uint size = (uint)ms.Length; BinaryReader br = new BinaryReader(ms, System.Text.Encoding.UTF8); ms.Seek(pos, SeekOrigin.Begin); List <UInt32> Starts = new List <UInt32>(); // look for record starts { Stopwatch timer = new Stopwatch(); timer.Start(); // signature is // byte 02 // int32 length // byte strlen = length - 1 // string strlen ascci chars // bytes 01 00 00 00 while (pos < size) { ms.Seek(pos, SeekOrigin.Begin); byte recordtype = br.ReadByte(); // should be 2 if (recordtype == 2) { // possible start UInt32 nextnamelength = br.ReadUInt32(); if (nextnamelength < 256) { uint l = br.ReadByte(); // string length if (l == nextnamelength - 1) { // everything ok so far // now check bytes in string are ASCII bool found = true; for (int i = 0; i < l; i++) { byte c = br.ReadByte(); if (c < 0x20 || c > 0x7F) { found = false; } } if (br.ReadByte() != 1) { found = false; } if (br.ReadByte() != 0) { found = false; } if (br.ReadByte() != 0) { found = false; } if (br.ReadByte() != 0) { found = false; } if (br.ReadByte() != 0) { found = false; } if (found) { // OutputString($"Found header at {pos:x08}"); Starts.Add(pos); } } } } pos = pos + 1; } } pos = 0; int index = -1; Int16 Component; byte[] r = br.ReadBytes(2); try { UInt32 Longest = 0; UInt32 len; // find the length of the logest pad record foreach (var p in Starts) { index++; if (index < Starts.Count - 1) { len = Starts[index + 1] - Starts[index]; } else { len = size - Starts[index]; } if (len > Longest) { Longest = len; } } index = -1; if (GenerateTxtFile && ExtractFiles) { AddText(TextFile, $"Altium Version {VersionString}\n"); // generate headers for .txt file string Header1 = "Pos "; for (int i = 0; i < Longest; i++) { Header1 += $"{(i / 100),-3:D2}"; } string Header2 = " "; for (int i = 0; i < Longest; i++) { Header2 += $"{(i % 100),-3:D2}"; } string Header3 = "--------------------"; for (int i = 0; i < Longest; i++) { Header3 += $"---"; } if (ExtractFiles) { AddText(TextFile, Header1 + "\n"); AddText(TextFile, Header2 + "\n"); AddText(TextFile, Header3 + "\n"); } } foreach (var p in Starts) { pos = p; //OutputString($"Processing pad record at {pos:x08}"); index++; base.ProcessLine(); ms.Seek(p, SeekOrigin.Begin); byte recordtype = br.ReadByte(); // should be 2 UInt32 next = br.ReadUInt32(); uint l = br.ReadByte(); // string length //pos = (uint)ms.Position; string name; if (l != 0) { name = new string(br.ReadChars((int)l)); } else { name = ""; } pos = (uint)ms.Position; // find out how many bytes to read if (index < Starts.Count - 1) { len = Starts[index + 1] - Starts[index]; } else { len = size - Starts[index]; } // we are now pointing to the pad record // Layers Layer; byte shape; bool plated; double X, Y, XSize, YSize, HoleSize; //, MIDXSize, MIDYSize, BottomXSize, BottomYSize; double Rotation = 0; double RRatio = 0; Int16 Net; Int16 JumperID; byte[] bytes = br.ReadBytes((int)len - 6); // get record after header stuff if (GenerateTxtFile) { if (p == 0) { r = bytes; // get reference bytes } StringBuilder text = new StringBuilder(""); int count = 0; int CompareLimit = Math.Min(r.Length, bytes.Length); foreach (var c in bytes) { if (count < CompareLimit && r[count] != bytes[count]) { text.Append($"|{c:X2}"); } else { text.Append($" {c:X2}"); } count++; } if (ExtractFiles) { AddText(TextFile, $"{pos:X8} " + $"{len - name.Length,4} {name,4} {text.ToString()}\n"); } } PadStruct pad = ByteArrayToStructure <PadStruct>(bytes); ms.Seek(pos + pad.Offset, SeekOrigin.Begin); int LayersSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(PadLayers)); byte[] layerbytes = br.ReadBytes(LayersSize); // get layers data PadLayers PadLayers = ByteArrayToStructure <PadLayers>(layerbytes); Layer = (Layers)pad.Layer; Net = pad.Net; Net++; string n = NetsL[Net].Name; Component = pad.Component; if (Component != -1 && Component != 0) { X = 0; } X = ToMM(pad.X) - originX; Y = ToMM(pad.Y) - originY; XSize = ToMM(pad.XSize); YSize = ToMM(pad.YSize); HoleSize = ToMM(pad.HoleSize); unsafe { shape = pad.TopShape; if (len > 160 && shape == 1) // TODO this can't be right { shape = PadLayers.PadShapes[0]; RRatio = (double)PadLayers.RRatios[0] / 200; } else { RRatio = 0; } } if (shape > 5) { shape = 5; } string[] shapes = { "circle", "circle", "rect", "octagonal", "oval", "roundrect" }; if (shapes[shape] == "circle" && XSize != YSize) { shape = 4; // oval pad } Rotation = pad.Rotation; plated = pad.Plated != 0; JumperID = pad.JumperID; bool InComponent = Component != -1; string type; if (Layer == Layers.Multi_Layer) { if (plated) { type = "thru_hole"; } else { type = "np_thru_hole"; // name = "\"\""; } if (HoleSize < 0.01) { OutputError($"Zero size hole through hole pad at {X} {Y}"); } } else { type = "smd"; } string layer = Brd.GetLayer(Layer); if (!Brd.IsCopperLayer(Layer)) { OutputError($"Pad on non copper layer = {Layer} at {X} {-Y}"); // TODO generate circular polygon instead continue; } if (layer == "Margin") // TODO sort this keepout layer malarky { layer = "Dwgs.User"; } if (type == "smd") { layer += layer == "F.Cu" ? " F.Mask F.Paste" : (layer == "B.Cu") ? " B.Mask B.Paste" : ""; } else { layer += " *.Mask"; } if (XSize < HoleSize | YSize < HoleSize) { XSize = YSize = HoleSize; } Pad Pad = new Pad(name, type, shapes[shape], X, Y, Rotation, XSize, YSize, HoleSize, layer, Net, RRatio) { Component = Component }; if (pad.UsePasteMaskRules == 1) { Pad.PasteMaskExpansion = GetRuleValue(Pad, "PasteMaskExpansion", "PasteMaskExpansion"); } else { Pad.PasteMaskExpansion = ToMM(pad.PasteMaskExpansion); } if (pad.UseSolderMaskRules == 1) { Pad.SolderMaskExpansion = GetRuleValue(Pad, "SolderMaskExpansion", "SolderMaskExpansion"); } else { Pad.SolderMaskExpansion = ToMM(pad.SolderMaskExpansion); } if (!InComponent) { PadsL.Add(Pad); // free pads not allowed (at present) in PcbNew so generate a single pad module Module M = new Module($"FreePad{ModulesL.Count}", X, Y, XSize, YSize, Pad); ModulesL.Add(M); } else { try { ModulesL[Component].Pads.Add(Pad); } catch (Exception Ex) { CheckThreadAbort(Ex, $"At position {pos} in Pads file"); } } } } catch (Exception Ex) { CheckThreadAbort(Ex); } if (GenerateTxtFile && TextFile != null) { TextFile.Close(); } } } catch (Exception Ex) { CheckThreadAbort(Ex); } return(true); }