Loading files
using GerberLibrary.Core.Primitives;
using System;
using System.Collections.Generic;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace GerberLibrary.Core
{
public enum PartOrderingStatus
{
Unknown,
Meta,
Unavailable,
Backorder,
Kippevoer,
MustBeOrdered,
InCart,
Ordered,
Stocked
}
public class StockDocument
{
public DateTime LastUpdated;
public List<StockPart> Parts = new List<StockPart>();
public static StockDocument Load(string filename)
{
XmlSerializer SettingsSerialize = new XmlSerializer(typeof(StockDocument));
FileStream ReadFileStream = null;
try
{
ReadFileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
// Load the object saved above by using the Deserialize function
StockDocument newset = (StockDocument)SettingsSerialize.Deserialize(ReadFileStream);
return newset;
}
catch (Exception)
{
return null;
}
}
public StockPart FindPart(string combinedname)
{
foreach (var a in Parts)
{
if (a.name == combinedname) return a;
}
return null;
}
public void Save(string filename)
{
XmlSerializer SerializerObj = new XmlSerializer(typeof(StockDocument));
TextWriter WriteFileStream = new StreamWriter(filename);
SerializerObj.Serialize(WriteFileStream, this);
WriteFileStream.Close();
}
}
public class StockPart
{
public int InStock = 0;
public int NeededForProduction = 0;
public string name;
public string MFGPartname;
public string MFG;
public string value;
public PartOrderingStatus status;
public string Stock;
public string Notes;
public bool IsPolarized;
public MountingType Mounting;
}
public class BoardContainer
{
public static int boardcount = 0;
public string Name = "";
[XmlIgnore]
public Rgba32 color = Color.LightGray;
// public Bitmap PrintableLabel = new Bitmap(256, 256);
public int BoardID;
public string BoardIDname = "";
public BoardContainer(string basename)
{
BoardID = boardcount;
boardcount++;
Name = basename;
if (BoardID > 0)
{
color = Helpers.RefractionNormalledMaxBrightnessAndSat((BoardID + 1) / 13.0f);
BuildBitmap();
char id = (char)((int)'A' + BoardID - 1);
BoardIDname += id;
}
else
{
BoardIDname = "X";
}
}
public BoardContainer()
{
}
void BuildBitmap()
{
}
/*
public void DrawLabel(GraphicsInterface graphics, Font font, Rectangle rectangle, bool darkedge = false, float fontangle = 0)
{
if (darkedge) graphics.FillRectangle(new SolidBrush(Color.FromRgb(30, 30, 30)), new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height));
graphics.FillRectangle(new SolidBrush(color), new Rectangle(rectangle.X + 2, rectangle.Y + 2, rectangle.Width - 4, rectangle.Height - 4));
var S = graphics.MeasureString(BoardIDname, font);
var store = graphics.Transform.Clone();
graphics.TranslateTransform(rectangle.X + (rectangle.Width) / 2, rectangle.Y + (rectangle.Height) / 2);
graphics.RotateTransform(fontangle);
graphics.DrawString(BoardIDname, font, Brushes.Black, new PointF(-S.Width / 2, -S.Height / 2 + 3));
graphics.Transform = store;
}
*/
}
public class PartListDisplayItem
{
public BOMEntry value;
public int theidx;
public PartListDisplayItem(int idx, BOMEntry value, StockPart P)
{
theidx = idx;
this.value = value;
Part = P;
}
public StockPart Part;
public List<BoardContainer> BoardsThisPartAppearsOn = new List<BoardContainer>();
public override string ToString()
{
return String.Format("{0}: {1} - {2} ({3})", theidx, value.RefDes.Count(), value.Combined(), value.PackageName);
}
public void FillBoardsFrom(List<BoardContainer> boards)
{
Dictionary<BoardContainer, bool> hadboards = new Dictionary<BoardContainer, bool>();
var refgroups = from i in value.RefDes group i by i.SourceBoard;
foreach (var g in refgroups)
{
var name = Path.GetFileNameWithoutExtension(g.Key);
var bc = (from i in boards where (i.Name + "_BOM" == name) select i).FirstOrDefault();
if (bc != null)
{
hadboards[bc] = true;
}
}
BoardsThisPartAppearsOn.Clear();
foreach (var a in hadboards.Keys) BoardsThisPartAppearsOn.Add(a);
}
}
public enum MountingType
{
SMD,
Throughhole,
Meta
}
public class BOMEntry
{
public string Name;
public string Desc;
public string Value;
public string Notes;
public string PackageName;
public string MfgPartNumber;
public string Mfg;
public string CombinedName;
public MountingType Mounting;
public class RefDesc
{
public string NameOnBoard;
public string SourceBoard;
public string OriginalName;
public double x;
public double y;
public double angle;
public BoardSide Side = BoardSide.Top;
public override string ToString()
{
return String.Format("{0} ({1},{2}) {3} - {4}", NameOnBoard, x, y, angle, Side);
}
}
public List<RefDesc> RefDes = new List<RefDesc>();
public bool Soldered = false;
internal string AddRef(string refdes, string source, BOMNumberSet set, double x, double y, double angle, BoardSide side)
{
if (set == null)
{
RefDes.Add(new RefDesc() { NameOnBoard = refdes, angle = angle, OriginalName = refdes, SourceBoard = source, x = x, y = y, Side = side });
return refdes;
}
string newref = set.GetNew(refdes);
RefDes.Add(new RefDesc() { NameOnBoard = newref, angle = angle, OriginalName = refdes, SourceBoard = source, x = x, y = y, Side = side });
return newref;
}
public void SetCombined(String c)
{
CombinedName = c;
}
public string Combined()
{
if (CombinedName != null)
{
return CombinedName;
}
// else
return (Name + "_" + PackageName + "_" + Value).Replace(' ', '_').Replace(',', '.');
}
public string DisplayLine()
{
return RefDes.Count() + " " + Name + " " + Value + " (" + PackageName + ")";
}
}
public enum DefaultPackages
{
Custom,
p0402,
p0603,
p0805,
QFN16_05,
QFN24_05,
QFN32_05,
QFP16_05,
QFP24_05,
QFP32_05,
QFP40_05,
QFP48_05,
SOIC8,
SOIC14,
SOIC16,
SOIC18,
DIP8,
DIP14,
DIP16,
DIP18,
DIP20,
DIP24,
M0101,
M0102,
M0103,
M0104,
M0105,
M0106
}
public enum Units
{
Ohm,
Farad,
Henry,
None,
Volt
}
public class PartLibrary
{
public static Dictionary<string, string> CreatePassivesMapping()
{
Dictionary<string, string> Res = new Dictionary<string, string>();
foreach (var R in Helpers.ResistorRanges)
{
foreach (var V in Helpers.E96)
{
string unit = Helpers.MakeNiceUnitString(V * R, Units.None).Replace(" ", "").Replace(',', '.');
string F = "R*_R0603_" + unit.ToUpper();
string F2 = "R*_R0603_" + unit.ToLower();
string F3 = "RES_0603_1%_0603_" + unit.ToUpper();
string F4 = "RES_0603_1%_0603_" + unit.ToLower();
string T = "RES_0603_1%_RES_0603_" + unit;
Res[F] = T;
Res[F2] = T;
Res[F3] = T;
Res[F4] = T;
}
foreach (var V in Helpers.E24)
{
string unit = Helpers.MakeNiceUnitString(V * R, Units.None).Replace(" ", "").Replace(',', '.');
string F = "R*_R0603_" + unit.ToUpper();
string F2 = "R*_R0603_" + unit.ToLower();
string F3 = "RES_0603_1%_0603_" + unit.ToUpper();
string F4 = "RES_0603_1%_0603_" + unit.ToLower();
string T = "RES_0603_1%_RES_0603_" + unit;
Res[F] = T;
Res[F2] = T;
Res[F3] = T;
Res[F4] = T;
}
foreach (var V in Helpers.E48)
{
string unit = Helpers.MakeNiceUnitString(V * R, Units.None).Replace(" ", "").Replace(',', '.');
string F = "R*_R0603_" + unit.ToUpper();
string F2 = "R*_R0603_" + unit.ToLower();
string F3 = "RES_0603_1%_0603_" + unit.ToUpper();
string F4 = "RES_0603_1%_0603_" + unit.ToLower();
string T = "RES_0603_1%_RES_0603_" + unit;
Res[F] = T;
Res[F2] = T;
Res[F3] = T;
Res[F4] = T;
}
}
foreach (var R in Helpers.CapacitorRanges)
{
foreach (var V in Helpers.E24)
{
string unit = Helpers.MakeNiceUnitString(V * R, Units.None).Replace(" ", "").Replace(',', '.');
string F = "C*_C0603_" + unit.ToUpper();
string F2 = "C*_C0603_" + unit.ToLower();
string F3 = "CAP_C0G_0603_50V_5%_0603_" + unit.ToUpper();
string F4 = "CAP_C0G_0603_50V_5%_0603_" + unit.ToLower();
string T;
if (V * R < 48e-9)
{
T = "CAP_C0G_0603_50V_5%_CAP_0603_" + unit;
}
else
{
T = "CAP_X7R_0603_25V_CAP_0603_" + unit;
}
Res[F] = T;
Res[F2] = T;
Res[F3] = T;
Res[F4] = T;
}
}
return Res;
}
}
public class BOMNumberSet
{
public Dictionary<string, int> prefixmap = new Dictionary<string, int>();
public string GetNew(string raw)
{
raw = raw.Split(':').Last();
string prefix = "";
int L = raw.Length - 1;
while (char.IsNumber(raw[L]) && L > 0)
{
L--;
}
prefix = raw.Substring(0, L + 1);
if (prefixmap.ContainsKey(prefix) == false)
{
prefixmap[prefix] = 0;
}
prefixmap[prefix] = prefixmap[prefix] + 1;
return prefix + prefixmap[prefix].ToString();
}
}
public class BOM
{
public List<BOM> SplitOverPolygons(List<Primitives.PolyLine> polygons)
{
List<BOM> Res = new List<BOM>();
List<BOMNumberSet> Ns = new List<BOMNumberSet>();
foreach (var p in polygons)
{
BOM SubBom = new BOM();
Res.Add(SubBom);
Ns.Add(new BOMNumberSet());
}
foreach (var packagepair in DeviceTree)
{
foreach (var devicevalue in packagepair.Value)
{
foreach (var n in devicevalue.Value.RefDes)
{
int i = 0;
int added = 0;
foreach (var p in polygons)
{
if (p.PointInPoly(new Primitives.PointD(n.x, n.y)))
{
OptionalOut<BOMEntry> bom = new OptionalOut<BOMEntry>();
Res[i].AddBOMItemInt(devicevalue.Value.PackageName, devicevalue.Value.Name, devicevalue.Value.Value, n.NameOnBoard, Ns[i], n.SourceBoard, n.x, n.y, n.angle, n.Side, bom);
bom.Result.SetCombined(devicevalue.Value.Combined());
added++;
}
i++;
}
if (added == 0)
{
Console.WriteLine("part skipped for some reason: {0}", n.NameOnBoard);
}
if (added > 1)
{
Console.WriteLine("part doublebooked for some reason: {0}", n.NameOnBoard);
}
}
}
}
return Res;
}
public void RemoveIgnored(List<string> toIgnore)
{
List<BOMEntry> ToRemove = new List<BOMEntry>();
foreach (var a in DeviceTree)
{
//Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
if (toIgnore.Contains(b.Value.PackageName) == true)
{
ToRemove.Add(b.Value);
}
}
}
foreach (var a in ToRemove)
{
RemoveEntry(a);
}
}
public Dictionary<string, Dictionary<string, BOMEntry>> DeviceTree = new Dictionary<string, Dictionary<string, BOMEntry>>();
public string AddBOMItemExt(string package, string device, string value, string refdes, BOMNumberSet set, string SourceBoard, double x, double y, double angle, BoardSide side = BoardSide.Top)
{
string ID = GetID(package, device, refdes);
return AddBOMItemInt(package, device, value, refdes, set, SourceBoard, x, y, angle, side);
}
public class OptionalOut<Type>
{
public Type Result { get; set; }
}
string AddBOMItemInt(string package, string device, string value, string refdes, BOMNumberSet set, string SourceBoard, double x, double y, double angle, BoardSide side = BoardSide.Top, OptionalOut<BOMEntry> bom = null)
{
string ID = GetID(package, device, refdes);
if (DeviceTree.ContainsKey(ID) == false) DeviceTree[ID] = new Dictionary<string, BOMEntry>();
if (DeviceTree[ID].ContainsKey(value) == false) DeviceTree[ID][value] = new BOMEntry() { Name = device, Value = value, PackageName = package };
BOMEntry BE = DeviceTree[ID][value];
if (bom != null) { bom.Result = BE; };
return BE.AddRef(refdes, SourceBoard, set, x, y, angle, side);
}
private string GetID(string package, string device, string refdes)
{
string ID = package + device;
if (refdes == device) ID = package;
return ID;
}
public void Translate(double x, double y)
{
foreach (var a in DeviceTree)
{
foreach (var b in a.Value)
{
foreach (var c in b.Value.RefDes)
{
c.x += x;
c.y += y;
}
}
}
}
public void WriteRefDesGerber(string outputbasename)
{
FontSet fnt = FontSet.Load("Font.xml");
GerberArtWriter Top = new GerberArtWriter();
GerberArtWriter Bottom = new GerberArtWriter();
int polyid = 0;
foreach (var a in DeviceTree)
{
foreach (var b in a.Value)
{
foreach (var c in b.Value.RefDes)
{
GerberArtWriter dest = (c.Side == BoardSide.Top) ? Top : Bottom;
float CX = (float)Math.Cos((c.angle * Math.PI*2.0)/360.0);
float SX = (float)Math.Sin((c.angle * Math.PI * 2.0) / 360.0);
dest.DrawString(new Primitives.PointD(c.x + CX, c.y + SX), fnt, c.NameOnBoard, 1, 0.02, StringAlign.CenterLeft, (c.Side == BoardSide.Top) ? false : true, c.angle);
PolyLine CrossA = new PolyLine(polyid++);
PolyLine CrossB = new PolyLine(polyid++);
CrossA.Add(c.x - 0.5, c.y - 0.5);
CrossA.Add(c.x + 0.5, c.y + 0.5);
CrossB.Add(c.x - 0.5, c.y + 0.5);
CrossB.Add(c.x + 0.5, c.y - 0.5);
dest.AddPolyLine(CrossA, 0.1);
dest.AddPolyLine(CrossB, 0.1);
}
}
}
Top.Write(outputbasename + "_top_refdes.gbr");
Bottom.Write(outputbasename + "_bottom_refdes.gbr");
}
public void MergeBOM(BOM B, BOMNumberSet set, double dx, double dy, double cx, double cy, double angle)
{
foreach (var a in B.DeviceTree)
{
foreach (var b in a.Value)
{
foreach (var c in b.Value.RefDes)
{
double X = c.x;
double Y = c.y;
Helpers.Transform(dx, dy, cx, cy, angle, ref X, ref Y);
OptionalOut<BOMEntry> bom = new OptionalOut<BOMEntry>();
AddBOMItemInt(b.Value.PackageName, b.Value.Name, b.Value.Value, c.OriginalName, set, c.SourceBoard, X, Y, (c.angle - angle) % 360, c.Side, bom);
bom.Result.SetCombined(b.Value.Combined());
bom.Result.Mounting = b.Value.Mounting;
}
}
}
}
public int GetPartCount(List<String> ToIgnore)
{
int partcount = 0;
foreach (var a in DeviceTree)
{
//Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
if (ToIgnore.Contains(b.Value.PackageName) == false)
{
partcount += b.Value.RefDes.Count;
}
}
}
return partcount;
}
public int GetUniquePartCount(List<String> ToIgnore)
{
int partcount = 0;
foreach (var a in DeviceTree)
{
//Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
if (ToIgnore.Contains(b.Value.PackageName) == false)
{
partcount++;
}
}
}
return partcount;
}
public void LoadPrinted(string filename)
{
BOMNumberSet BS = new BOMNumberSet();
try
{
var L = File.ReadAllLines(filename);
//string Header = "Count,Name,Type,Package,Value,MfgPartNumber,RefDes";
int idxcount = 0;
int idxname = 1;
int idxtype = 2;
int idxpackage = 3;
int idxvalue = 4;
int idxmfg = 5;
int idxrefdes = 6;
var Hsplit = L[0].Split(',');
for (int l = 1; l < L.Count(); l++)
{
var lsplit = L[l].Split(',');
var refsplit = lsplit[idxrefdes].Split(' ');
foreach (var refdes in refsplit)
{
AddBOMItemInt(lsplit[idxpackage], lsplit[idxname], lsplit[idxvalue], refdes, BS, filename, 0, 0, 0);
}
}
}
catch (Exception)
{
}
}
public List<string> PrintBOM(List<String> IgnoreList, bool AddDefaultIgnoreList = true)
{
List<string> ToIgnore;
if (AddDefaultIgnoreList)
{
ToIgnore = new List<string>() { "FENIXINTERNALCONNECTIONPAD" };
}
else
{
ToIgnore = new List<string>();
}
ToIgnore.AddRange(IgnoreList);
List<Tuple<string, string, string>> Lines = new List<Tuple<string, string, string>>();
string Header = "Count,Name,Type,Package,Value,MfgPartNumber,RefDes";
Lines.Add(new Tuple<string, string, string>("!", "!", Header));
int partcount = 0;
List<String> re = new List<string>();
foreach (var a in DeviceTree)
{
//Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
if (ToIgnore.Contains(b.Value.PackageName) == false)
{
partcount += b.Value.RefDes.Count;
string L = String.Format("{3},{4}, {0}, {1}, {2}, {5}, ", b.Value.Name, b.Value.PackageName, b.Value.Value, b.Value.RefDes.Count, b.Value.Combined(), b.Value.MfgPartNumber);
foreach (var c in b.Value.RefDes)
{
L = L + String.Format("{0} ", c.NameOnBoard);
}
Lines.Add(new Tuple<string, string, string>(b.Value.Name, b.Value.Value, L));
}
}
}
foreach (var a in Lines.OrderBy(x => x.Item1).ThenBy(x => x.Item2))
{
re.Add(a.Item3);
}
re.Add(String.Format("{0} parts total.", partcount));
return re;
}
public List<string> PrintBOMperModule(List<String> IgnoreList)
{
Dictionary<string, bool> Boards = new Dictionary<string, bool>();
foreach (var a in DeviceTree)
{
//Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
foreach (var c in b.Value.RefDes)
{
Boards[c.SourceBoard] = true;
}
}
}
List<string> ToIgnore = new List<string>() { "FENIXINTERNALCONNECTIONPAD" };
ToIgnore.AddRange(IgnoreList);
List<String> re = new List<string>();
foreach (var board in Boards.Keys)
{
int partcount = 0;
re.Add(String.Format("***** {0}", board));
List<Tuple<string, string, string>> Lines = new List<Tuple<string, string, string>>();
foreach (var a in DeviceTree)
{
//Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
if (ToIgnore.Contains(b.Value.PackageName) == false)
{
int cnt = b.Value.RefDes.Where(x => x.SourceBoard == board).Count();
if (cnt > 0)
{
partcount += cnt;
string L = String.Format("{3},{4}, {0}, {1}, {2}, ", b.Value.Name, b.Value.PackageName, b.Value.Value, cnt, b.Value.Combined());
foreach (var c in b.Value.RefDes.Where(x => x.SourceBoard == board))
{
L = L + String.Format("{0}({1}) ", c.NameOnBoard, c.OriginalName);
}
Lines.Add(new Tuple<string, string, string>(b.Value.Name, b.Value.Value, L));
}
}
}
}
foreach (var a in Lines.OrderBy(x => x.Item1).ThenBy(x => x.Item2))
{
re.Add(a.Item3);
}
re.Add(String.Format("{0} parts total.", partcount));
re.Add(String.Format(""));
}
return re;
}
public void FillPartno(string basefolder)
{
var map = File.ReadAllLines(Path.Combine(basefolder, "partnomapping.txt"));
foreach (var l in map)
{
var A = l.Split(' ');
if (A.Count() == 2)
{
string from = A[0];
string to = A[1];
SetPartno(from, to);
}
}
}
public static double ParseValue(string value)
{
var r = new Regex("^([1-9][0-9]*(?:\\.[0-9]+)?)([pnumkMG])?$");
Match m = r.Match(value);
String valstring = m.Groups[1].Value.Replace('.', ',');
double v = Convert.ToDouble(valstring);
if (m.Groups.Count == 3)
{
Dictionary<string, double> Scale = new Dictionary<string, double>();
Scale["p"] = 1e-12;
Scale["n"] = 1e-9;
Scale["u"] = 1e-6;
Scale["m"] = 1e-3;
Scale[""] = 1;
Scale["k"] = 1e3;
Scale["M"] = 1e6;
Scale["G"] = 1e9;
v *= Scale[m.Groups[2].Value];
}
return v;
}
public static string KemetC0GPartno(string value)
{
var r = new Regex("CAP_C0G_0603_50V_5%_CAP_0603_([^_]*)$");
Match m = r.Match(value);
if (m.Groups.Count != 2) return "";
double val = ParseValue(m.Groups[1].Value) * 1000000000000;
int n = 0;
string valstring = "";
if (val >= 100)
{
while (val >= 100)
{
n++;
val /= 10;
}
valstring = Convert.ToString(val);
valstring += n;
}
else if (val < 10)
{
valstring = Math.Round(val * 10) + "9";
}
else if (val < 100)
{
valstring = Math.Round(val) + "8";
}
string s = "C0603C" + valstring + "J?G";
return s;
}
public static string VishayThickFilmResistorPartno(string value)
{
var r = new Regex("RES_0603_1%_RES_0603_([^_]*)$");
Match m = r.Match(value);
if (m.Groups.Count != 2) return "";
double val = ParseValue(m.Groups[1].Value);
String valstring = "";
if (val < 1000)
{
double i = Math.Floor(val);
double frac = val - i;
valstring = i + "R";
if (valstring.Length < 4)
{
for (int k = 0; k < 4 - valstring.Length; k++)
{
frac = frac * 10;
}
valstring += Math.Round(frac);
}
}
else if (val < 1000000)
{
val /= 1000;
double i = Math.Floor(val);
double frac = val - i;
valstring = i + "K";
if (valstring.Length < 4)
{
for (int k = 0; k < 4 - valstring.Length; k++)
{
frac = frac * 10;
}
valstring += Math.Round(frac);
}
}
else if (val < 1000000000)
{
val /= 1000000;
double i = Math.Floor(val);
double frac = val - i;
valstring = i + "M";
if (valstring.Length < 4)
{
for (int k = 0; k < 4 - valstring.Length; k++)
{
frac = frac * 10;
}
valstring += Math.Round(frac);
}
}
string s = "CRCW0603" + valstring + "FK";
return s;
}
public static string SusumuThinFilmResistorPartno(string value)
{
var r = new Regex("RES_0603_1%_THIN_FILM_RES_0603_([^_]*)$");
Match m = r.Match(value);
if (m.Groups.Count != 2) return "";
double val = ParseValue(m.Groups[1].Value);
string tempco = "P";
if (val < 92) tempco = "Q";
int n = 0;
while (val >= 100)
{
n++;
val /= 10;
}
string s = "RR0816" + tempco + "-" + val + n + "-D";
return s;
}
public static string XiconThroughHolePartno(string value)
{
var r = new Regex("R-US__0204V_([^_]*)$");
Match m = r.Match(value);
if (m.Groups.Count != 2) return "";
string val = m.Groups[1].Value;
string s = "270-" + val + "-RC";
return s;
}
public static string MakePartNo(string partno, string value)
{
if (partno.Equals("%%KEMETC0G%%"))
{
return KemetC0GPartno(value);
}
else if (partno.Equals("%%MULTICOMPTHICKRES%%"))
{
return MulticompThickFilmResistorPartno(value);
}
else if (partno.Equals("%%VISHAYTHICKRES%%"))
{
return VishayThickFilmResistorPartno(value);
}
else if (partno.Equals("%%SUSUMUTHINRES%%"))
{
return SusumuThinFilmResistorPartno(value);
}
else if (partno.Equals("%%XICONTHROUGHHOLE%%"))
{
return XiconThroughHolePartno(value);
}
return partno;
}
public static Dictionary<string, string> MulticompReels = new Dictionary<string, string>();
public static Dictionary<string, string> MulticompOrderList = new Dictionary<string, string>();
private static string MulticompThickFilmResistorPartno(string value)
{
value = value.Replace(',', '.');
var r = new Regex("RES_0603_1%_RES_0603_([^_]*)$");
Match m = r.Match(value);
if (m.Groups.Count != 2) return "";
string valuestring = m.Groups[1].Value;
double val = ParseValue(valuestring);
int n = 0;
while (val > 1000)
{
n++;
val /= 10;
}
while (Math.Floor(val / 10.0) < (val / 10.0))
{
n--;
val *= 10;
}
string s = "MCWR06X" + Math.Floor(val) + n + "FTL";
/* if (AlreadyHave.Contains(valuestring) == false)
{
MulticompReels[value] = s;
}
if (needthese.Contains(valuestring))
{
MulticompOrderList[valuestring] = s;
}*/
return s;
}
public void SetPartno(string pattern, string partno)
{
var r = new Regex(pattern);
foreach (var a in DeviceTree)
{
foreach (var b in a.Value)
{
string cop = b.Value.Combined().Trim();
if (b.Value.MfgPartNumber == null && r.Match(cop).Success)
{
b.Value.MfgPartNumber = MakePartNo(partno, cop);
}
}
}
}
public void Remap(ProgressLog log, string basefolder)
{
log.PushActivity("Remap");
var D = PartLibrary.CreatePassivesMapping();
File.WriteAllLines(Path.Combine(basefolder, "genmapping.txt"), (from i in D select i.Key + " " + i.Value).ToList());
var map = File.ReadAllLines(Path.Combine(basefolder, "bommapping.txt"));
log.AddString("Loaded bommapping!");
foreach (var l in map)
{
var A = l.Split(' ');
if (A.Count() >= 2)
{
string from = A[0];
string to = A[1];
bool dooverride = false;
if (A.Count() > 2)
{
if (A[2] == "override") { dooverride = true; };
}
RemapPair(log, from, to, dooverride);
//Console.WriteLine("remapped {0} to {1}", from, to);
}
}
foreach (var l in D)
{
RemapPair(log, l.Key, l.Value, false);
}
log.PopActivity();
}
private void RemapPair(ProgressLog log, string from, string to, bool overridevalue)
{
log.PushActivity("RemapPair");
if (from != to)
{
var F = FindEntry(from, overridevalue);
var T = FindEntry(to, overridevalue);
if (F != null)
{
if (T != null)
{
foreach (var rd in F.RefDes)
{
T.RefDes.Add(rd);
}
F.RefDes.Clear();
RemoveEntry(F);
}
else
{
log.AddString(String.Format("From found, but no To: {0}", from));
F.SetCombined(to);
}
}
}
log.PopActivity();
}
private void RemoveEntry(BOMEntry f)
{
foreach (var a in DeviceTree)
{
foreach (var item in a.Value.Where(kvp => kvp.Value == f).ToList())
{
a.Value.Remove(item.Key);
}
}
}
private BOMEntry FindEntry(string q, bool overridevalue = false)
{
foreach (var a in DeviceTree)
{
//Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
string cop = b.Value.Combined().Trim();
if (cop == q)
{
return b.Value;
}
}
}
return null;
}
public void SaveBom(string bomFile)
{
var L = PrintBOM(new List<string>(), false);
File.WriteAllLines(bomFile, L.ToArray());
}
public void SaveCentroids(string centroidFile)
{
List<String> Output = new List<string>();
Output.Add("\"REFDES\",\"X\",\"Y\",\"ANGLE\",\"SIDE\"");
foreach (var a in DeviceTree)
{
foreach (var b in a.Value)
{
foreach (var c in b.Value.RefDes)
{
Output.Add(String.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\"", c.NameOnBoard, c.x.ToString().Replace(',', '.'), c.y.ToString().Replace(',', '.'), c.angle.ToString().Replace(',', '.'), c.Side.ToString()));
}
}
}
File.WriteAllLines(centroidFile, Output.ToArray());
}
internal int GetPartCount()
{
int partcount = 0;
foreach (var a in DeviceTree)
{
foreach (var b in a.Value)
{
partcount += b.Value.RefDes.Count;
}
}
return partcount;
}
internal static BOM ScanFolderForBoms(string gerberPath, ProgressLog Log)
{
string ultiboardfolder = Path.Combine(gerberPath, "ultiboard");
if (Directory.Exists(ultiboardfolder))
{
BOM R = new BOM();
var F = Directory.GetFiles(ultiboardfolder);
string Centroids = "";
string BOMFile = "";
foreach (var a in F)
{
if (a.ToLower().Contains("bill of materials"))
{
BOMFile = a;
}
if (a.ToLower().Contains("parts centroids"))
{
Centroids = a;
}
}
if (File.Exists(Centroids) && File.Exists(BOMFile)) R.LoadUltiboard(BOMFile, Centroids);
return R;
}
string diptracefolder = Path.Combine(gerberPath, "diptraceasc");
if (Directory.Exists(diptracefolder))
{
BOM R = new BOM();
var F = Directory.GetFiles(diptracefolder, "*.asc");
foreach (var a in F)
{
R.LoadDiptraceASC(a, Log);
return R;
}
}
return null;
}
public class SNode
{
public override string ToString()
{
return Name + String.Format(" ({0} children)", Children.Count);
}
public string Print(int tab = 0)
{
var res = tab.ToString() + " ";
for (int i = 0; i < tab; i++)
{
res += " ";
}
res += String.Format("{0}", Name) + "\n";
foreach (var a in Children)
{
res += a.Print(tab + 1);
}
return res;
}
public void Load(string s)
{
Children = ReadExpression(s);
}
public void Read(string s)
{
int R = FindWhiteSpace(s);
if (R == -1) R = s.Length - 1;
int start = 0;
while (s[start] == '(') start++;
Name = s.Substring(start, R - start).Trim();
int i = s.LastIndexOf(')');
Load(s.Substring(R, i - R));
}
private int FindWhiteSpace(string s)
{
int idx = 0;
while (idx < s.Length)
{
if (char.IsWhiteSpace(s[idx])) return idx;
idx++;
}
return idx;
}
public string Name;
public List<SNode> Children = new List<SNode>();
string currenttoken = "";
int owntokens = 0;
public int Read(string s, int start)
{
int P = start;
bool quoted = false;
bool escaped = false;
int depth = 1;
int written = 0;
while (P < s.Length && depth > 0)
{
if (quoted)
{
// Console.Write("{0}", s[P]);
written++;
if (written > 100)
{
// Console.WriteLine("");
written = 0;
}
}
else
{
if (written > 0)
{
// Console.WriteLine("");
written = 0;
}
}
switch (s[P])
{
case '\\':
{
if (escaped)
{
currenttoken += s[P];
escaped = false;
}
else
{
escaped = true;
}
P++;
}
break;
case '"':
if (quoted)
{
if (escaped)
{
currenttoken += s[P];
escaped = false;
}
else
{
quoted = false;
CheckTokenAndConsume();
}
}
else
{
if (escaped)
{
currenttoken += s[P];
escaped = false;
}
else
{
// Console.Write("escaping:");
for (int R = Math.Max(P - 140, 0); R != P + 1; R++)
{
// Console.Write("{0}", s[R]);
}
//Console.WriteLine("-- escaping {0}", P);
quoted = true;
escaped = false;
}
}
P++;
break;
case '\r':
case '\n':
case '\t':
case ' ':
if (quoted)
{
currenttoken += s[P];
}
else
{
CheckTokenAndConsume();
}
P++;
break;
case '(':
if (!quoted)
{
CheckTokenAndConsume();
SNode child = new SNode();
P = child.Read(s, P + 1);
Children.Add(child);
}
else
{
currenttoken += s[P];
P++;
}
break;
case ')':
if (!quoted)
{
CheckTokenAndConsume();
return P + 1;
}
else
{
currenttoken += s[P];
P++;
}break;
default:
currenttoken += s[P];
P++;
escaped = false;
break;
}
}
return P;
}
private void CheckTokenAndConsume()
{
if (currenttoken.Length > 0)
{
if (owntokens == 0)
{
Name = currenttoken;
}
else
{
Children.Add(new SNode() { Name = currenttoken });
}
owntokens++;
currenttoken = "";
}
}
public static List<SNode> ReadExpression(string s)
{
List<SNode> res = new List<SNode>();
string currenttoken = "";
int R = 0;
bool escaped =false ;
while (R < s.Length)
{
if (escaped)
{
switch (s[R])
{
case '"':
escaped = false;
break;
}
R++;
}
else
{
switch (s[R])
{
/*case '"':
escaped = true;
R++;
break;*/
case '\r':
case '\n':
case '\t':
case ' ':
currenttoken = "";
R++;
break;
default:
currenttoken += s[R];
R++;
break;
case '(':
{
SNode child = new SNode();
R = child.Read(s, R + 1);
res.Add(child);
}
break;
}
}
}
return res;
}
public static List<SNode> aReadExpression(string s)
{
List<SNode> res = new List<SNode>();
int R = 0;
while (R < s.Length)
{
switch (s[R])
{
case '\r':
case '\n':
case '\t':
case ' ':
R++;
break;
default:
{
int E = R + 1;
while (E < s.Length && digits(s[E]))
{
E++;
}
SNode c = new SNode();
c.Name = s.Substring(R, E - R);
res.Add(c);
R = E + 1;
}
break;
case '(':
{
int depth = 1;
int pos = R + 1;
while (depth > 0 && pos < s.Length)
{
if (s[pos] == '(')
{
depth++;
}
if (s[pos] == ')')
{
depth--;
}
pos++;
}
int E = pos + 1;
SNode c = new SNode();
c.Read(s.Substring(R, E - R - 1));
res.Add(c);
R = E + 1;
}
break;
case '"':
{
int E = R + 1;
while (s[E] != '"')
{
E++;
}
SNode c = new SNode();
c.Name = s.Substring(R + 1, E - R - 1);
res.Add(c);
R = E + 1;
}
break;
}
}
// Name = s.Substring(1, R);
return res;
}
private static bool digits(char v)
{
if (char.IsWhiteSpace(v)) return false;
return true;
}
public List<SNode> Find(string v, bool recurse = true)
{
List<SNode> R = new List<SNode>();
foreach (var a in Children)
{
if (a.Name == v)
{
R.Add(a);
}
if (recurse) R.AddRange(a.Find(v, true));
}
return R;
}
}
static void DipRotateAndAdjust(double X, double Y, double OriginX, double OriginY, double Angle, int Orientation, int PatternOrientation, bool flipped, BOMEntry.RefDesc RD, double fileoriginX, double fileoriginY, double UnitMult)
{
if (flipped) OriginX = -OriginX;
double pat_rot = ((Orientation) * 90) * 3.141592654 / 180.0;
double r_orig_x = 0;
double r_orig_y = 0;
if (flipped)
{
r_orig_x = OriginX * Math.Cos(pat_rot) - OriginY * Math.Sin(pat_rot);
r_orig_y = -OriginX * Math.Sin(pat_rot) - OriginY * Math.Cos(pat_rot);
}
else
{
r_orig_x = -OriginX * Math.Cos(pat_rot) - OriginY * Math.Sin(pat_rot);
r_orig_y = OriginX * Math.Sin(pat_rot) - OriginY * Math.Cos(pat_rot);
}
double p_x = (X - r_orig_x);
double p_y = (Y - r_orig_y);
// p_y = -p_y;
double p_angle = ((Orientation) * 90) + Angle;
if (flipped) //: # maybe this should check BottomSide instead
{
p_angle = 360 - p_angle;
}
p_angle = (p_angle + 10 * 360) % 360;
RD.x = (p_x - fileoriginX) * UnitMult;
RD.y = -(p_y - fileoriginY) * UnitMult;
RD.angle = -p_angle;
}
public void LoadDiptraceASC(string InputFile, ProgressLog Log)
{
Log.PushActivity("DIPTrace BOM Loader");
Log.AddString(String.Format("Loading Diptrace module: {0}", Path.GetFileNameWithoutExtension(InputFile)));
string S = System.IO.File.ReadAllText(InputFile);
S = S.Replace("\n", "");
var Root = new SNode();
Root.Load(S);
var Src = Root.Find("Source");
float AngleMult = 1.0f;
if (Src.Count > 0)
{
if (Src.First().Children[0].Name == "DipTrace-PCBN")
{
Log.AddString("New Dip Asc");
AngleMult = 360.0f / ((float)Math.PI * 2.0f);
}
else
{
if (Src.First().Children[0].Name == "DipTrace-PCB")
{
Log.AddString("Old Dip Asc");
AngleMult = 1.0f;
}
}
}
// string Out = Root.Print();
float UnitMult = 10.0f / 25.4f;
UnitMult = 10.0f / 30.0f;
var C = Root.Find("Board", false).First().Find("Components", false);
var Shapes = Root.Find("Board", false).First().Find("Shapes", false);
float originx = 0;
float originy = 0;
var ox = Root.Find("OriginX");
var oy = Root.Find("OriginY");
if (ox.Count > 0)
{
originx = float.Parse(ox.First().Children[0].Name.Replace('.', ','));
}
if (oy.Count > 0)
{
originy = float.Parse(oy.First().Children[0].Name.Replace('.', ','));
}
var Um = Root.Find("mm");
if (Um.Count > 0) UnitMult = 10.0f / 30.0f;
var Umil = Root.Find("mil");
if (Umil.Count > 0) UnitMult = 10.0f / 30.0f;
/* var Pts = Root.Find("Board", false).First().Find("Points", false);
List<PointF> Outline = new List<PointF>();
foreach (var p in Pts.First().Children)
{
Outline.Add(new PointF((float.Parse(p.Children[0].Name.Replace('.', ',')) - originx) * UnitMult, -(float.Parse(p.Children[1].Name.Replace('.', ',')) - originy) * UnitMult));
}
for (int i = 0; i < Outline.Count; i++)
{
int idx2 = (i + 1) % Outline.Count;
AddWire(Outline[i].X, Outline[i].Y, Outline[idx2].X, Outline[idx2].Y);
}
foreach (var s in Shapes[0].Children)
{
var ShapeNmae = s.Find("Name", false).FirstOrDefault();
if (ShapeNmae != null)
{
if (ShapeNmae.Children[0].Name == "Panel Area")
{
var pts = s.Find("Points", false);
if (pts != null && pts[0].Children.Count == 2)
{
var c1 = pts[0].Children[0];
var c2 = pts[0].Children[1];
var x1 = (float.Parse(c1.Children[0].Name.Replace('.', ',')) - originx) * UnitMult;
var y1 = -(float.Parse(c1.Children[1].Name.Replace('.', ',')) - originy) * UnitMult;
var x2 = (float.Parse(c2.Children[0].Name.Replace('.', ',')) - originx) * UnitMult;
var y2 = -(float.Parse(c2.Children[1].Name.Replace('.', ',')) - originy) * UnitMult;
this.HasGrid = true;
this.GridOffset = new vec2(Math.Min(x1, x2), Math.Max(y1, y2));
this.HasEnd = true;
this.EndPos = new vec2(Math.Max(x1, x2), Math.Min(y1, y2));
}
}
}
}
*/
foreach (var a in C[0].Children)
{
float partoriginx = 0;
float partoriginy = 0;
var pox = a.Find("OriginX");
var poy = a.Find("OriginY");
if (pox.Count > 0)
{
partoriginx = float.Parse(pox.First().Children[0].Name.Replace('.', ','));
}
if (poy.Count > 0)
{
partoriginy = float.Parse(poy.First().Children[0].Name.Replace('.', ','));
}
float x = -1;
float y = -1;
string name = "unknown";
string id = "id";
// try
{
name = a.Children[0].Name;
id = a.Children[1].Name;
string descattrib = "";
string sizeattrib = "";
string value = "";
var vV = a.Find("Value", false).FirstOrDefault();
var pP = a.Find("Pattern", false).FirstOrDefault();
if (vV != null && vV.Children.Count > 0)
{
descattrib = vV.Children[0].Name;
value = vV.Children[0].Name;
}
BoardSide side = BoardSide.Top;
var BottomSide = a.Find("BottomSide", false).FirstOrDefault();
if (BottomSide != null && BottomSide.Children.Count > 0)
{
string V = BottomSide.Children[0].Name;
if (V == "Y") side = BoardSide.Bottom;
}
string pattern = "";
if (pP != null && pP.Children.Count > 0)
{
pattern = pP.Children[0].Name;
}
var X = a.Find("X", false).FirstOrDefault();
if (X != null && X.Children.Count > 0)
{
string V = X.Children[0].Name;
if (V[0] == '.') V = "0" + V;
V = V.Replace('.', ',');
x = float.Parse(V);
}
var Y = a.Find("Y", false).FirstOrDefault();
if (Y != null && Y.Children.Count > 0)
{
string V = Y.Children[0].Name;
if (V[0] == '.') V = "0" + V;
V = V.Replace('.', ',');
y = float.Parse(V);
}
float angle = 0;
float orientangle = 0;
int orientidx = 0;
var O = a.Find("Orientation", false).FirstOrDefault();
if (O != null && O.Children.Count > 0)
{
string V = O.Children[0].Name;
if (V[0] == '0') { orientangle = 0; orientidx = 0; };
if (V[0] == '1') { orientangle = 90; orientidx = 1; };
if (V[0] == '2') { orientangle = 180; orientidx = 2; };
if (V[0] == '3') { orientangle = 270; orientidx = 3; };
}
float pangle = 0;
int partorientidx = 0;
var PO = a.Find("PatternOrientation", false).FirstOrDefault();
if (PO != null && PO.Children.Count > 0)
{
string V = PO.Children[0].Name;
if (V[0] == '0') { pangle = 0; partorientidx = 0; }
if (V[0] == '1') { pangle = 90; partorientidx = 1; }
if (V[0] == '2') { pangle = 180; partorientidx = 2; }
if (V[0] == '3') { pangle = 270; partorientidx = 3; }
}
var A = a.Find("Angle", false).FirstOrDefault();
if (A != null && A.Children.Count > 0)
{
angle = float.Parse(A.Children[0].Name.Replace('.', ',')) * AngleMult;
}
bool Flipped = false;
var nFlipped = a.Find("Flipped", false).FirstOrDefault();
if (nFlipped != null && BottomSide.Children.Count > 0)
{
string V = nFlipped.Children[0].Name;
if (V == "Y")
{
Flipped = true;
}
}
var placement = AddBOMItemExt(pattern, name, value, id, null, System.IO.Path.GetFileNameWithoutExtension(InputFile), 0, 0, 0, side);
var BE = GetBOMEntry(placement);
float DipComp = 0;// DipCompensationAngle(BE.Combined(), side);
// orientangle += DipComp;
var RD = GetRefDes(placement);
DipRotateAndAdjust(x, y, partoriginx, partoriginy, angle, orientidx, partorientidx, Flipped, RD, originx, originy, UnitMult);
if (side == BoardSide.Bottom) RD.angle = -RD.angle;
RD.angle += DipComp;
if (id == "C10")
{
Console.WriteLine(RD);
}
}
}
Log.PopActivity();
}
class CSVLine
{
public List<string> columns = new List<string>();
public void Parse(string inp)
{
const char splitter = ',';
const char escaper = '"';
bool escaped = false;
string current = "";
for (int i = 0; i < inp.Length; i++)
{
switch (inp[i])
{
case escaper:
if (escaped)
{
escaped = false;
}
else
{
escaped = true;
}
break;
case splitter:
if (escaped)
{
current += splitter;
}
else
{
columns.Add(current);
current = "";
}
break;
default:
current += inp[i];
break;
}
}
if (current.Length > 0) columns.Add(current);
}
}
class CSVLoader
{
public List<CSVLine> Lines = new List<CSVLine>();
public void LoadFile(string file)
{
var L = File.ReadAllLines(file);
foreach (var l in L)
{
string S = l.Trim();
if (S.Length > 0)
{
var CSVL = new CSVLine();
CSVL.Parse(S);
Lines.Add(CSVL);
}
}
}
}
private void LoadUltiboard(string bOMFile, string centroids)
{
Dictionary<string, BOMEntry.RefDesc> positions = new Dictionary<string, BOMEntry.RefDesc>();
CSVLoader centroidloader = new CSVLoader();
centroidloader.LoadFile(centroids);
int FirstRow = -1;
for (int i = 0; i < centroidloader.Lines.Count; i++)
{
if (centroidloader.Lines[i].columns[0] == "REFDES")
{
FirstRow = i + 1;
}
}
if (FirstRow > -1)
{
for (int i = FirstRow; i < centroidloader.Lines.Count; i++)
{
var Line = centroidloader.Lines[i];
string rd = Line.columns[0];
double X = 0, Y = 0, Angle = 0;
X = Double.Parse(Line.columns[3]) / 1000000.0;
Y = Double.Parse(Line.columns[4]) / 1000000.0;
Angle = Double.Parse(Line.columns[5]);
BoardSide Side = BoardSide.Top;
if (Line.columns[6] != "TOP") Side = BoardSide.Bottom;
positions[rd] = new BOMEntry.RefDesc() { angle = Angle, x = X, y = Y, OriginalName = rd, NameOnBoard = rd, SourceBoard = bOMFile, Side = Side };
}
}
BOMNumberSet Set = new BOMNumberSet();
CSVLoader bomloader = new CSVLoader();
bomloader.LoadFile(bOMFile);
FirstRow = -1;
for (int i = 0; i < bomloader.Lines.Count; i++)
{
if (bomloader.Lines[i].columns[0] == "VALUE")
{
FirstRow = i + 1;
}
}
if (FirstRow > -1)
{
for (int i = FirstRow; i < bomloader.Lines.Count; i++)
{
string value = bomloader.Lines[i].columns[0];
string package = bomloader.Lines[i].columns[1];
var refdes = bomloader.Lines[i].columns[3].Split(',');
foreach (var rd in refdes)
{
var S = positions[rd];
AddBOMItemExt(package, "", value, rd, Set, bOMFile, S.x, S.y, S.angle, S.Side);
}
}
}
}
/* public void WriteJLCXLS(string BaseFolder, string Name)
{
Workbook BOMworkbook = new Workbook();
Worksheet BOMworksheet = new Worksheet(String.Format("{0} BOM", Name));
BOMworksheet.Cells[0, 0] = new Cell("Comment");
BOMworksheet.Cells[0, 1] = new Cell("Designator");
BOMworksheet.Cells[0, 2] = new Cell("Footprint");
BOMworksheet.Cells[0, 3] = new Cell("LCSC Part #");
int currentrow = 1;
foreach (var ds in DeviceTree)
{
foreach (var v in ds.Value.Values)
{
BOMworksheet.Cells[currentrow, 0] = new Cell(v.Value);
string refdescs = v.RefDes[0].NameOnBoard;
for (int i = 1; i < v.RefDes.Count; i++)
{
refdescs += ", " + v.RefDes[i].NameOnBoard;
}
BOMworksheet.Cells[currentrow, 1] = new Cell(refdescs);
BOMworksheet.Cells[currentrow, 2] = new Cell(v.PackageName);
BOMworksheet.Cells[currentrow, 3] = new Cell(v.MfgPartNumber);
currentrow++;
}
}
BOMworkbook.Worksheets.Add(BOMworksheet);
BOMworkbook.Save(BaseFolder + "\\" + Name + "_BOM.xls");
Workbook PNPworkbook = new Workbook();
Worksheet PNPworksheet = new Worksheet(String.Format("{0} PnP", Name));
PNPworksheet.Cells[0, 0] = new Cell("Designator");
PNPworksheet.Cells[0, 1] = new Cell("Mid X");
PNPworksheet.Cells[0, 2] = new Cell("Mid Y");
PNPworksheet.Cells[0, 3] = new Cell("Layer");
PNPworksheet.Cells[0, 4] = new Cell("Rotation");
currentrow = 1;
foreach (var ds in DeviceTree)
{
foreach (var v in ds.Value.Values)
{
foreach (var p in v.RefDes)
{
PNPworksheet.Cells[currentrow, 0] = new Cell(p.NameOnBoard);
PNPworksheet.Cells[currentrow, 1] = new Cell(p.x.ToString().Replace(",",".") + "mm");
PNPworksheet.Cells[currentrow, 2] = new Cell(p.y.ToString().Replace(",", ".") + "mm");
PNPworksheet.Cells[currentrow, 3] = new Cell(p.Side == BoardSide.Top ? "T" : "B");
PNPworksheet.Cells[currentrow, 4] = new Cell(p.angle);
currentrow++;
}
}
}
PNPworkbook.Worksheets.Add(PNPworksheet);
PNPworkbook.Save(BaseFolder + "\\" + Name + "_PNP.xls");
}
*/
public void WriteJLCCSV(string BaseFolder, string Name, bool EllagePreference)
{
WriteJLCBom(BaseFolder, Name);
WriteJLCPnpFile(BaseFolder, Name, EllagePreference);
}
public void WriteJLCBom(string BaseFolder, string Name)
{
List<string> outlinesBOM = new List<string>();
List<string> OutlinesRotations = new List<string>();
outlinesBOM.Add("Comment,Designator,Footprint,LCSC Part #,combinedname,name");
foreach (var ds in DeviceTree)
{
foreach (var v in ds.Value.Values)
{
SetRotationOffset(v.Combined(), GetRotationOffset(v.Combined()));
string refdescs = "\"" + v.RefDes[0].NameOnBoard;
for (int i = 1; i < v.RefDes.Count; i++)
{
refdescs += ", " + v.RefDes[i].NameOnBoard;
}
refdescs += "\"";
string V = v.Value;
if (V.Trim().Length == 0)
{
V = v.MfgPartNumber;
}
string mfg = "";
if (v.MfgPartNumber != null)
{
mfg = v.MfgPartNumber.Replace(',', '.');
}
string line = String.Format("{0},{1},{2},{3},{4},{5}", V, refdescs, v.PackageName, mfg, v.Combined(), v.Name);
outlinesBOM.Add(line);
}
}
File.WriteAllLines(BaseFolder + "\\" + Name + "_BOM.csv", outlinesBOM);
foreach (var a in RotationOffsets)
{
OutlinesRotations.Add(String.Format("{0} {1}", a.Key, a.Value));
}
OutlinesRotations.Sort();
File.WriteAllLines(DefaultRotationFile, OutlinesRotations);
}
public static String EllageFormat(double inp, int digits = 2)
{
string fmt = "{0:F" + digits.ToString() + "}";
return String.Format(fmt, inp).Replace(",", ".");
}
public static String QuantFormat(double inp, int digits = 2)
{
string fmt = "{0:F" + digits.ToString() + "}";
return String.Format(fmt, inp).Replace(".", ",");
}
public void WriteJLCPnpFile(string BaseFolder, string Name, bool ellagepreference)
{
List<string> outlinesPNP = new List<string>();
if (ellagepreference)
{
outlinesPNP.Add("Designator;Mid X mm;Mid Y mm;Rotation deg");
}
else
{
outlinesPNP.Add("Designator,Mid X,Mid Y,Layer,Rotation");
}
foreach (var ds in DeviceTree)
{
foreach (var v in ds.Value.Values)
{
foreach (var p in v.RefDes)
{
if (ellagepreference)
{
double A = (p.angle + 360 + GetRotationOffset(v.Combined())) % 360;
while (A > 180) A -= 360;
while (A < -180) A += 360;
string line = String.Format("{0};{1};{2};{3}",
p.NameOnBoard,
EllageFormat(p.x,2),
EllageFormat(p.y,2),
EllageFormat(A,0));
outlinesPNP.Add(line);
}
else
{
string line = String.Format("{0},{1},{2},{3},{4}",
p.NameOnBoard,
p.x.ToString().Replace(",", ".") + "mm",
p.y.ToString().Replace(",", ".") + "mm",
p.Side == BoardSide.Top ? "T" : "B",
(p.angle + 360 + GetRotationOffset(v.Combined())) % 360);
outlinesPNP.Add(line);
}
}
}
}
File.WriteAllLines(BaseFolder + "\\" + Name + "_PNP.csv", outlinesPNP);
}
public static Dictionary<string, int> RotationOffsets = new Dictionary<string, int>();
public static int GetRotationOffset(string name)
{
if (RotationOffsets.ContainsKey(name)) return RotationOffsets[name];
return 0;
}
public static void SetRotationOffset(string name, int off)
{
RotationOffsets[name] = off;
}
public static string DefaultRotationFile = "RotationOffsets.txt";
public static void LoadRotationOffsets(string v = "")
{
if (v.Length == 0) v = DefaultRotationFile; else DefaultRotationFile = v;
Console.WriteLine("Loading rotations from {0}", Path.GetFullPath(v));
try
{
var L = File.ReadAllLines(v);
foreach (var s in L)
{
try
{
var items = s.Split(' ');
string t = items[0];
int rot = int.Parse(items[1]);
RotationOffsets[t] = rot;
}
catch (Exception)
{
}
}
}
catch (Exception)
{
}
}
public string OriginalBasefolder = "";
public string OriginalPnpName = "";
public string OriginalBomName = "";
public void LoadJLC(string bOMFile, string pnPFile)
{
OriginalBasefolder = Path.GetDirectoryName(bOMFile);
OriginalPnpName = Path.GetFileNameWithoutExtension(pnPFile);
OriginalBomName = Path.GetFileNameWithoutExtension(bOMFile);
Dictionary<string, BOMEntry.RefDesc> positions = new Dictionary<string, BOMEntry.RefDesc>();
var bomlines = File.ReadAllLines(bOMFile);
var regex = new Regex("(?<=^|,)(\"(?:[^\"]|\"\")*\"|[^,]*)");
if (pnPFile != null)
{
var pnplines = File.ReadAllLines(pnPFile);
//outlinesBOM.Add("Comment,Designator,Footprint,LCSC Part #");
int RefdesIdx = 0;
int Xidx = 1;
int Yidx = 2;
int Sideidx = 3;
int Angleidx = 4;
var Headers = pnplines[0].Split(',');
for (int i = 0; i < Headers.Count(); i++)
{
var H = StripCSV(Headers[i].ToLower());
switch (H)
{
case "x": Xidx = i; break;
case "y": Yidx = i; break;
case "mid x": Xidx = i; break;
case "mid y": Yidx = i; break;
case "refdes": RefdesIdx = i; break;
case "designator": RefdesIdx = i; break;
case "side": Sideidx = i; break;
case "angle": Angleidx = i; break;
}
}
//outlinesPNP.Add("Designator,Mid X,Mid Y,Layer,Rotation");
for (int i = 1; i < pnplines.Count(); i++)
{
var s = pnplines[i];
List<string> items = new List<string>();
foreach (Match m in regex.Matches(s))
{
items.Add(m.Value);
}
var rd = StripCSV(items[RefdesIdx]);
var X = ConvertDimension(items[Xidx]);
var Y = ConvertDimension(items[Yidx]);
var Side = GetSide(StripCSV(items[Sideidx]));
var Angle = Double.Parse(StripCSV(items[Angleidx]));
positions[rd] = new BOMEntry.RefDesc() { angle = Angle, x = X, y = Y, OriginalName = rd, NameOnBoard = rd, SourceBoard = bOMFile, Side = Side };
}
}
BOMNumberSet Set = new BOMNumberSet();
var headers = bomlines[0].Split(',');
for (int i = 1; i < bomlines.Count(); i++)
{
var s = bomlines[i];
List<string> items = new List<string>();
foreach (Match m in regex.Matches(s))
{
items.Add(StripCSV(m.Value.Trim()));
}
var refdesc = items[1].Trim(); ;
if (refdesc.StartsWith("\""))
{
refdesc = refdesc.Substring(1, refdesc.Length - 2);
}
var rd = refdesc.Split(',');
var value = items[0];
var package = items[2];
foreach (var rd_ in rd)
{
if (positions.ContainsKey(rd_.Trim()))
{
var S = positions[rd_.Trim()];
if (headers.Count() > 5)
{
OptionalOut<BOMEntry> Entr = new OptionalOut<BOMEntry>(); ;
string name = items[5];
string combined = items[4];
AddBOMItemInt(package, name, value, rd_.Trim(), Set, bOMFile, S.x, S.y, S.angle, S.Side, Entr);
Entr.Result.SetCombined(combined);
//AddBOMItemExt(package, name, value, rd_, Set, bOMFile, S.x, S.y, S.angle, S.Side);
}
else
{
AddBOMItemExt(package, "", value, rd_.Trim(), Set, bOMFile, S.x, S.y, S.angle, S.Side);
}
}
else
{
Console.WriteLine("wtf!");
}
}
}
}
private string StripCSV(string H)
{
if (H.Length > 2 && H[0] == '"' && H[H.Length - 1] == '"')
{
return H.Substring(1, H.Length - 2);
}
return H;
}
private BoardSide GetSide(string v)
{
switch (v.ToLower())
{
case "t":
case "top":
return BoardSide.Top;
case "b":
case "bottom":
return BoardSide.Bottom;
}
return BoardSide.Unknown;
}
private double ConvertDimension(string v)
{
v = v.Trim();
if (v.EndsWith("mm"))
{
v = v.Substring(0, v.Length - 2).Trim(); ;
}
if (v[0] == '"' && v[v.Length -1] == '"')
{
v = v.Substring(1, v.Length - 2);
}
return double.Parse(v.Replace('.', ','));
}
public int GetSolderedPartCount(List<string> toIgnore)
{
int partcount = 0;
foreach (var a in DeviceTree)
{
//Console.WriteLine(a.Key);
foreach (var b in a.Value)
{
if (toIgnore.Contains(b.Value.PackageName) == false)
{
if (b.Value.Soldered == true) partcount += b.Value.RefDes.Count;
}
}
}
return partcount;
}
public BOMEntry.RefDesc GetRefDes(string rdi)
{
foreach (var t in DeviceTree)
{
foreach (var b in t.Value.Values)
{
foreach (var rd in b.RefDes)
{
if (rd.NameOnBoard == rdi)
{
return rd;
}
}
}
}
return null;
}
public BOMEntry GetBOMEntry(string rdi)
{
foreach (var t in DeviceTree)
{
foreach (var b in t.Value.Values)
{
foreach (var rd in b.RefDes)
{
if (rd.NameOnBoard == rdi)
{
return b;
}
}
}
}
return null;
}
public void FixupAngles(StockDocument doc)
{
foreach (var t in DeviceTree)
{
foreach (var b in t.Value.Values)
{
var partname = b.Combined();
var p = doc.FindPart(partname);
bool symmetric = false;
if (p != null) symmetric = p.IsPolarized ? false : true;
foreach (var rd in b.RefDes)
{
if (rd.angle > 180)
{
rd.angle -= 360;
}
if (symmetric)
{
rd.angle = (rd.angle + 180.0 * 10.0) % 180;
if (rd.angle >= 90) rd.angle -= 180;
}
}
}
}
}
public void SwapXY()
{
foreach (var t in DeviceTree)
{
foreach (var b in t.Value.Values)
{
foreach (var rd in b.RefDes)
{
var tt = rd.x;
rd.x = rd.y;
rd.y = tt;
rd.angle = 45 + (45 - rd.angle);
}
}
}
}
public void FlipX()
{
foreach (var t in DeviceTree)
{
foreach (var b in t.Value.Values)
{
foreach (var rd in b.RefDes)
{
rd.x = -rd.x;
rd.angle = -rd.angle;
}
}
}
}
public void FlipSides()
{
foreach (var t in DeviceTree)
{
foreach (var b in t.Value.Values)
{
foreach (var rd in b.RefDes)
{
switch (rd.Side)
{
case BoardSide.Bottom:
rd.Side = BoardSide.Top;
break;
case BoardSide.Top:
rd.Side = BoardSide.Bottom;
break;
}
}
}
}
}
public static void RenderPackage(GraphicsInterface g, double x, double y, double angle, string packageName, BoardSide side)
{
var t = g.Transform;
g.TranslateTransform((float)x, (float)y);
if (side == BoardSide.Bottom)
{
g.ScaleTransform(-1, 1);
g.RotateTransform((float)angle);
}
else
{
g.RotateTransform((float)-angle);
}
switch(packageName.Trim())
{
case "3MMLED":
RenderLed(g);
break;
case "TC33X":
case "MINITRIM":
RenderTrimPot(g);
break;
case "SOT363":
RenderSOT363(g);
break;
case "SOT-223":
case "SOT223":
case "SOT223-4":
RenderSOT223(g);
break;
case "POL3528":
case "CASE-A_3216":
RenderTantalum(g);
break;
case "SOT-323-ZENER":
case "SOT-323":
case "SOT323":
RenderSot323(g);
break;
case "SOT23-BEC":
case "SOT-23":
case "SOT23":
RenderSot23(g);
break;
case "DO214AC":
case "DO-214AC":
RenderDO214Diode(g);
break;
case "CAPAE-5.3x5.3h5.4":
RenderECap(g, 5.3f);
break;
case "C5B4.5":
case "CAP-5.08/7.6x5":
RenderBigCap(g,7, 4.0f, Color.FromRgb(200, 60, 60));
break;
case "RES_2512":
RenderSMD2Pin(g, 25, 12, Color.FromRgb(60, 60, 60));
break;
case "R0603":
case "0603":
RenderSMD2Pin(g, 6, 3, Color.FromRgb(60, 60, 60));
break;
case "L0805":
RenderSMD2Pin(g, 8, 5, Color.FromRgb(60, 70, 80));
break;
case "0402":
RenderSMD2Pin(g, 4, 2, Color.FromRgb(160, 130, 60));
break;
case "C0603":
RenderSMD2Pin(g, 6, 3, Color.FromRgb(160, 130, 60));
break;
case "C3225":
RenderSMD2Pin(g, 32*10/25.4f, 25*10/25.4f, Color.FromRgb(160, 130, 60));
break;
case "FERRITE_1812":
RenderSMD2Pin(g, 18, 12, Color.FromRgb(20, 20, 20));
break;
case "RES_0805":
case "R0805":
case "0805":
RenderSMD2Pin(g, 8, 5, Color.FromRgb(60, 60, 60));
break;
case "C0805":
RenderSMD2Pin(g, 8, 5, Color.FromRgb(160, 130, 60));
break;
case "SO14":
case "SOIC14":
case "SOIC-14/150mil":
RenderSOIC(g, 14);
break;
case "SO16":
case "SOIC16":
case "SOIC-16/150mil":
RenderSOIC(g, 16);
break;
case "SO8":
case "SOIC-8/150mil":
case "SO08":
case "SOIC8-N_MC":
case "SOIC8":
RenderSOIC(g, 8);
break;
default:
Console.WriteLine("unknown package: {0}", packageName);
break;
case "TSSOP14":
case "TSSOP-14":
RenderSSOP(g, 14);
break;
case "TSSOP8":
case "TSSOP-8":
RenderSSOP(g, 8);
break;
case "UMAX8":
RenderSSOP(g, 8,3.0f);
break;
case "TSSOP16":
case "TSSOP-16":
RenderSSOP(g, 16);
break;
case "SSOP24":
RenderSSOP(g, 24);
break;
case "PANASONIC_C":
RenderECap(g, 5.3f);
break;
case "CASE_B":
RenderECap(g, 4.3f);
break;
case "CAPAE-6.6x6.6h5.4":
case "PANASONIC_D":
RenderECap(g, 6);
break;
case "LMZM33606":
RenderQFN(g, 10.15f, 16.15f, 9,15, 0.8f);
break;
case "QFN-32/5x5x0.5":
RenderQFN(g, 5, 5, 8, 8, 0.5f);
break;
case "QFN50P400X400X100-25N":
RenderQFN(g, 4,4,6,6, 0.5f);
break;
case "PTV09A":
case "ALPS_POT_SQUAREHOLES":
RenderPot(g);
break;
case "PB6149L":
RenderButton(g);
break;
case "TOOLINGHOLE":
case "SWDPADS":
case "SQUAREFIDUCIAL":
case "JUSTATINYROCKET_DATECODE":
case "FENIXPOWERBACKPACK_BOARD":
case "FENIXPOWERBACKPACK":
case "POWERTESTPAD_MEDIUM":
case "POWERTESTPAD":
case "POWERTESTPAD_LARGE":
case "GROUNDLOOP":
case "MINISWD-SMD":
case "IPSLCD1.3":
case "FRONTPANELSTANDOFF_SCREWONONESIDE":
case "3":
case "":
break;
case "3.5MM-JACK-SWITCH-13MM-NOHOLES":
RenderJack(g);
break;
case "TS-23E01":
RenderToggleSwitch(g);
break;
case "TRIMPOT":
RenderBigTrim(g);
break;
case "SOT23-5":
case "SOT-23-5":
RenderSot23_5(g);
break;
case "HDR-1x2T/2.54/5x2":
RenderPinHeader(g, 2, 1, 2.54f);
break;
case "M50-3600542":
RenderPinHeader(g, 5, 2, 1.27f);
break;
case "2X3-SHROUDED":
RenderPinHeader(g, 2, 3, 2.54f, true);
break;
case "SPU0410HR5H-PB":
DrawMic(g);
break;
}
g.Transform = t;
}
private static void DrawMic(GraphicsInterface g)
{
float L = 2.95f;
float W = 3.76f;
g.FillRectangle(new SolidBrush(Color.FromRgb((byte)(200),(byte)(180),(byte)( 20))), -L / 2, -W / 2, L, W);
g.FillEllipse(new SolidBrush(Color.Black), new RectangleF(-0.25f, W / 2 - 1.184f + 0.25f, 0.5f, 0.5f));
}
private static void RenderPinHeader(GraphicsInterface g, int wpin, int hpin, float pinspacing, bool shroud = false)
{
float L = (wpin ) * pinspacing;
float W = (hpin ) * pinspacing; ;
g.FillRectangle(new SolidBrush(Color.FromRgb(30, 30, 30)), -L / 2, -W / 2, L, W);
RectangleF pinrect = new RectangleF(0, 0, 0.4f, 0.4f);
float woffs = (wpin/ 2);
if ((wpin% 2) != 1) woffs -= 0.5f;
float hoffs = (hpin / 2);
if ((hpin % 2) != 1) hoffs -= 0.5f;
float pinw = 0.6f;
for (int p = 0; p < wpin; p++)
{
for (int q = 0; q < hpin; q++)
{
float x = (p - woffs) * pinspacing - pinw /2;
float y = (q - hoffs) * pinspacing - pinw / 2;
g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 130)), x,y,pinw,pinw);
}
}
W += 5.45f;
L += 0.05f+pinspacing;
if (shroud)
{
g.DrawRectangle(new Pen(Color.FromRgb(40, 40, 40),1.4f), -L / 2, -W / 2, L, W);
}
}
private static void RenderSot23_5(GraphicsInterface g)
{
float L = 3;
float W = 1.4f;
g.FillRectangle(new SolidBrush(Color.FromRgb(60, 60, 60)), -L / 2, -W / 2, L, W);
float pinspacing = 0.8f;
int sidepins = 6 / 2;
RectangleF pinrect = new RectangleF(0, 0, 0.4f, 0.4f);
float offs = (sidepins / 2);
if ((sidepins % 2) != 1) offs -= 0.5f;
List<bool> top = new List<bool>() { true, true, true};
List<bool> bottom = new List<bool>() { true, false, true };
for (int p = 0; p < sidepins; p++)
{
pinrect.X = (p - offs) * pinspacing - 0.2f;
pinrect.Y = -1.25f;
if (top[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
pinrect.Y = 1.25f - 0.5f;
if (bottom[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
}
pinrect.X = (0 - offs) * pinspacing - pinrect.Width/2;
pinrect.Y = -0.4f;
g.FillEllipse(new SolidBrush(Color.FromRgb(190, 190, 190)), pinrect);
}
private static void RenderBigTrim(GraphicsInterface g)
{
float W = 2.54f*4;
float H = 2.54f*2;
g.FillRectangle(new SolidBrush(Color.FromRgb(20, 20, 160)), -W / 2, -H / 2, W, H);
float L = 2.54f;
g.FillEllipse(new SolidBrush(Color.FromRgb(145, 145, 10)), -W / 2 , H / 2 - L, L, L);
g.FillRectangle(new SolidBrush(Color.FromRgb(120, 120, 0)), -W / 2, H /2 - L + L/2 -0.1f, L, 0.2f);
}
private static void RenderToggleSwitch(GraphicsInterface g)
{
float W = 23;
float H = 11;
g.FillRectangle(new SolidBrush(Color.FromRgb(130, 130, 130)), -W / 2, -H / 2, W, H);
float L = 5.0f;
g.FillEllipse(new SolidBrush(Color.FromRgb(145, 145, 145)), -L / 2, -L / 2, L, L);
}
private static void RenderJack(GraphicsInterface g)
{
float W = 10;
float H = 10;
g.FillRectangle(new SolidBrush(Color.FromRgb(30, 30, 30)), -W / 2, -H / 2, W, H);
float L = 9.5f;
g.FillEllipse(new SolidBrush(Color.FromRgb(35, 35, 35)), -L / 2, -L / 2, L, L);
L = 3.5f;
g.FillEllipse(new SolidBrush(Color.FromRgb(2, 2, 2)), -L / 2, -L / 2, L, L);
}
private static void RenderButton(GraphicsInterface g)
{
float W = 6;
float H = 6;
g.FillRectangle(new SolidBrush(Color.FromRgb(120, 120, 120)), -W / 2, -H / 2, W, H);
float L = 6;
g.FillEllipse(new SolidBrush(Color.FromRgb(200, 180, 0)), -L / 2, -L / 2, L, L);
}
private static void RenderPot(GraphicsInterface g)
{
float W = 9;
float H = 9;
g.FillRectangle(new SolidBrush(Color.FromRgb(120, 120, 120)), -W / 2, -H / 2, W, H);
}
private static void RenderQFN(GraphicsInterface g, float W, float H, int wpins, int hpins, float spacingbetweenpins)
{
g.FillRectangle(new SolidBrush(Color.FromRgb(50, 50, 50)), -W / 2, -H / 2, W, H);
float woffs = (wpins/ 2);
if ((wpins % 2) != 1) woffs -= 0.5f;
float hoffs = (hpins / 2);
if ((hpins % 2) != 1) hoffs -= 0.5f;
RectangleF hpin = new RectangleF(0, 0, spacingbetweenpins * 0.8f, spacingbetweenpins * 0.2f);
RectangleF vpin = new RectangleF(0, 0, spacingbetweenpins * 0.2f, spacingbetweenpins * 0.8f);
SolidBrush b = new SolidBrush(Color.FromRgb(160, 160, 160));
for (int p = 0; p < wpins; p++)
{
hpin.X = (p - woffs) * spacingbetweenpins - hpin.Width/2;
hpin.Y = -H / 2 - hpin.Height;
g.FillRectangle(b, hpin);
hpin.Y = H / 2;
g.FillRectangle(b, hpin);
}
for (int p = 0; p < hpins; p++)
{
vpin.Y = (p - hoffs) * spacingbetweenpins - vpin.Height / 2;
vpin.X = -W / 2 - vpin.Width;
g.FillRectangle(b, vpin);
vpin.X = W / 2;
g.FillRectangle(b, vpin);
}
float dotsize = 0.5f;
RectangleF dot = new RectangleF();
dot.X = -W / 2 + 0.2f;
dot.Y = H / 2 - 0.2f - dotsize; ;
dot.Width = dotsize;
dot.Height = dotsize;
g.FillEllipse(new SolidBrush(Color.FromRgb(190, 190, 190)), dot);
}
public static void RenderECap(GraphicsInterface g, float candiameter)
{
float L = candiameter*0.9f;
float L2 = L*1.1f;
float L23 = L2 / 3;
List<PointF> polyvert = new List<PointF>();
polyvert.Add(new PointF( L2 / 2, L23 / 2));
polyvert.Add(new PointF( L23 / 2, L2/2));
polyvert.Add(new PointF( -L2 / 2, L2 / 2));
polyvert.Add(new PointF( -L2 / 2, -L2 / 2));
polyvert.Add(new PointF( L23 / 2, -L2 / 2));
polyvert.Add(new PointF( L2 / 2, -L23 / 2));
g.FillPolygon(new SolidBrush(Color.FromRgb((byte)(76),(byte)(80),(byte)(85))), polyvert.ToArray());
g.FillEllipse(new SolidBrush(Color.FromRgb(110, 110, 110)), -L / 2, -L / 2, L, L);
}
private static void RenderDO214Diode(GraphicsInterface g)
{
RenderSMD2Pin(g, 3.2f * 100 / 25.4f, 1.6f * 100 / 25.4f, Color.FromRgb(60, 60, 60), Color.FromRgb(180, 180, 180), Color.FromRgb(60, 60, 60));
}
private static void RenderLed(GraphicsInterface g)
{
float L = 3;
g.FillEllipse(new SolidBrush(Color.FromRgb(200, 180, 0)), -L / 2, -L / 2, L, L);
}
private static void RenderTrimPot(GraphicsInterface g)
{
float L = 3.0f;
float W = 3.8f;
float extendH = 4.1f / 2;
g.FillRectangle(new SolidBrush(Color.FromRgb(120, 120, 120)), -L / 2, -W / 2, L, W);
g.FillEllipse(new SolidBrush(Color.FromRgb(110, 110, 110)), -L / 2, -L / 2, L, L);
g.FillRectangle(new SolidBrush(Color.FromRgb(90, 90, 90)), -L*0.6f / 2, -L * 0.1f / 2, L * 0.6f, L * 0.1f);
g.FillRectangle(new SolidBrush(Color.FromRgb(90, 90, 90)), -L * 0.1f / 2, -L * 0.6f / 2, L * 0.1f, L * 0.6f);
float pinspacing = 0.9f;
int sidepins = 6 / 2;
RectangleF pinrect = new RectangleF(0, 0, 0.65f, 0.1f);
RectangleF pinrectpad = new RectangleF(0, 0,0.65f, 0.1f);
float offs = (sidepins / 2);
if ((sidepins % 2) != 1) offs -= 0.5f;
List<bool> bottom = new List<bool>() { false, true, false };
List<bool> top = new List<bool>() { true, false, true };
for (int p = 0; p < sidepins; p++)
{
pinrect.X = (p - offs) * pinspacing - 0.35f;
pinrect.Y = -extendH;
if (top[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
pinrectpad.X = (p - offs) * pinspacing - 0.35f;
pinrectpad.Y = extendH - pinrect.Height;
if (bottom[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrectpad);
}
}
private static void RenderSOT363(GraphicsInterface g)
{
float L = 2;
float W = 1.25f;
float extendH = 2.1f / 2;
g.FillRectangle(new SolidBrush(Color.FromRgb(60, 60, 60)), -L / 2, -W / 2, L, W);
float pinspacing = 0.65f;
int sidepins = 6 / 2;
RectangleF pinrect = new RectangleF(0, 0, 0.2f, extendH-W / 2);
float offs = (sidepins / 2);
if ((sidepins % 2) != 1) offs -= 0.5f;
List<bool> bottom = new List<bool>() { true , true, true };
List<bool> top = new List<bool>() { true, true, true };
for (int p = 0; p < sidepins; p++)
{
pinrect.X = (p - offs) * pinspacing - pinrect.Width/2;
pinrect.Y = -extendH;
if (top[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
pinrect.Y = extendH - pinrect.Height;
if (bottom[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
}
pinrect.Width = 0.3f;
pinrect.Height = 0.3f;
pinrect.X = (0 - offs) * pinspacing - pinrect.Width / 2;
pinrect.Y = -0.4f;
g.FillEllipse(new SolidBrush(Color.FromRgb(190, 190, 190)), pinrect);
}
private static void RenderSOT223(GraphicsInterface g)
{
float L = 6.5f;
float W = 3.5f;
g.FillRectangle(new SolidBrush(Color.FromRgb(60, 60, 60)), -L / 2, -W / 2, L, W);
float pinspacing = 2.3f;
int sidepins = 6 / 2;
RectangleF pinrect = new RectangleF(0, 0, 0.7f, 1.75f);
RectangleF pinrectpad = new RectangleF(0, 0, 3, 1.75f);
float offs = (sidepins / 2);
if ((sidepins % 2) != 1) offs -= 0.5f;
List<bool> bottom = new List<bool>() { false, true, false };
List<bool> top = new List<bool>() { true, true, true };
for (int p = 0; p < sidepins; p++)
{
pinrect.X = (p - offs) * pinspacing - 0.35f;
pinrect.Y = -3.5f;
if (top[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
pinrectpad.X = (p - offs) * pinspacing - 1.5f;
pinrectpad.Y = 3.5f - 1.75f;
if (bottom[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrectpad);
}
}
private static void RenderSot23(GraphicsInterface g)
{
float L = 3;
float W = 1.4f;
g.FillRectangle(new SolidBrush(Color.FromRgb(60, 60, 60)), -L / 2, -W / 2, L, W);
float pinspacing = 0.8f;
int sidepins = 6 / 2;
RectangleF pinrect = new RectangleF(0, 0, 0.4f, 0.4f);
float offs = (sidepins / 2);
if ((sidepins % 2) != 1) offs -= 0.5f;
List<bool> bottom = new List<bool>() { false, true, false };
List<bool> top = new List<bool>() { true, false, true };
for (int p = 0; p < sidepins; p++)
{
pinrect.X = (p - offs) * pinspacing - 0.2f;
pinrect.Y = -1.25f;
if (top[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
pinrect.Y = 1.25f - 0.5f;
if (bottom[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
}
}
private static void RenderTantalum(GraphicsInterface g)
{
RenderSMD2Pin(g, 3.2f * 100 / 25.4f, 1.6f* 100 / 25.4f, Color.FromRgb((byte)(160),(byte)(100),(byte)(30)), Color.FromRgb((byte)(160),(byte)(10),(byte)(10)));
}
private static void RenderSot323(GraphicsInterface g)
{
float L = 2;
float W = 1.25f;
g.FillRectangle(new SolidBrush(Color.FromRgb((byte)(60),(byte)(60),(byte)(60))), -L / 2, -W / 2, L, W);
float pinspacing = 0.65f;
int sidepins = 6 / 2;
RectangleF pinrect = new RectangleF(0, 0, 0.4f, 0.4f);
float offs = (sidepins / 2);
if ((sidepins % 2) != 1) offs -= 0.5f;
List<bool> bottom = new List<bool>() { false, true, false };
List<bool> top = new List<bool>() {true, false, true };
for (int p = 0; p < sidepins; p++)
{
pinrect.X = (p - offs) * pinspacing - 0.2f;
pinrect.Y = -1;
if (top[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
pinrect.Y = 1-0.5f;
if (bottom[p]) g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
}
}
private static void RenderBigCap(GraphicsInterface g, float L, float W, Color color)
{
g.FillRectangle(new SolidBrush(color), -L/ 2 , -W / 2, L,W);
}
public static void RenderSMD2Pin(GraphicsInterface g, float w, float h, Color BodyColor, Color ?pin1mark = null, Color? pin2mark = null)
{
w *= 25.4f/100.0f;
h *= 25.4f/100.0f;
g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), -w / 2, -h / 2, w ,h);
g.FillRectangle(new SolidBrush(BodyColor), -(w*0.8f) / 2, -h / 2, (w*0.8f), h);
if (pin1mark !=null)
{
g.FillRectangle(new SolidBrush((Color)pin1mark), (-w * 0.8f) / 2, -h / 2, (w * 0.2f), h);
}
if (pin2mark != null)
{
g.FillRectangle(new SolidBrush((Color)pin2mark), (w * 0.4f) / 2, -h / 2, (w * 0.2f), h);
}
}
public static void RenderSOIC(GraphicsInterface g, int v)
{
int sidepins = v / 2;
float length = (sidepins - 1) * 1.27f;
g.FillRectangle(new SolidBrush(Color.FromRgb(60, 60, 60)), -length / 2 - 0.5f, -3.9f / 2, length + 1, 3.9f);
RectangleF pinrect = new RectangleF(0,0,0.4f,1);
float offs = (sidepins / 2) ;
if ((sidepins % 2) != 1) offs -= 0.5f;
for(int p = 0;p<sidepins ;p++)
{
pinrect.X = (p - offs) * 1.27f - 0.2f;
pinrect.Y = -3;
g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
pinrect.Y = 2;
g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
}
pinrect.X = (0 - offs) * 1.27f - 0.2f;
pinrect.Y = -1.4f;
pinrect.Width = 0.4f;
pinrect.Height = 0.4f;
g.FillEllipse(new SolidBrush(Color.FromRgb(190, 190, 190)), pinrect);
}
public static void RenderSSOP(GraphicsInterface g, int v, float W = 3.9f)
{
float pinspacing = 0.65f;
int sidepins = v / 2;
float length = (sidepins - 1) * pinspacing;
g.FillRectangle(new SolidBrush(Color.FromRgb(60, 60, 60)), -length / 2 - 0.5f, -W / 2, length + 1, W);
RectangleF pinrect = new RectangleF(0, 0, 0.4f, 1);
float offs = (sidepins / 2);
if ((sidepins % 2) != 1) offs -= 0.5f;
for (int p = 0; p < sidepins; p++)
{
pinrect.X = (p - offs) * pinspacing - 0.2f;
pinrect.Y = -(W/2)-pinrect.Height;
g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
pinrect.Y = (W / 2 );
g.FillRectangle(new SolidBrush(Color.FromRgb(160, 160, 160)), pinrect);
}
pinrect.X = (0 - offs) * pinspacing - 0.2f;
pinrect.Y = -1.4f;
pinrect.Width = 0.4f;
pinrect.Height = 0.4f;
g.FillEllipse(new SolidBrush(Color.FromRgb(190, 190, 190)), pinrect);
}
public void WriteQuantPnPFiles(string BaseFolder, string Name)
{
List<string> outlinesPNP = new List<string>();
outlinesPNP.Add("Variant: No variations");
outlinesPNP.Add("Units used: mm");
outlinesPNP.Add("");
outlinesPNP.Add("\"Designator,\"\"Comment\"\",\"\"Layer\"\",\"\"Footprint\"\",\"\"Center-X(mm)\"\",\"\"Center-Y(mm)\"\",\"\"Rotation\"\",\"\"Part Number\"\",\"\"Description\"\",\"\"Variation\"\",\"\"Mounting\"\"\"");;
foreach (var ds in DeviceTree)
{
foreach (var v in ds.Value.Values)
{
foreach (var p in v.RefDes)
{
double A = (p.angle + 360 + GetRotationOffset(v.Combined())) % 360;
while (A > 180) A -= 360;
while (A < -180) A += 360;
string line = String.Format("\"{0}\",\"\"{1}\"\",\"\"{2}\"\",\"\"{3}\"\",\"\"{4}\"\",\"\"{5}\"\",\"\"{6}\"\",\"\"{7}\"\",\"\"{8}\"\",\"\"{9}\"\",\"\"{10}\"\"\"",
p.NameOnBoard,
v.Value,
p.Side== BoardSide.Top?"TopLayer":"BottomLayer",
v.PackageName,
QuantFormat(p.x, 4),
QuantFormat(p.y, 4),
QuantFormat(A, 0),
v.CombinedName,
v.Value,
"",
QuantMounting(v.Mounting));
outlinesPNP.Add(line);
}
}
}
File.WriteAllLines(BaseFolder + "\\" + Name + "_PNP.csv", outlinesPNP);
}
private string QuantMounting(MountingType mounting)
{
switch(mounting)
{
case MountingType.Meta: return "";
case MountingType.SMD: return "SMD";
case MountingType.Throughhole: return "TH";
}
return "";
}
public void UpdateMountingTypesFromStock(StockDocument stockDoc)
{
foreach (var ds in DeviceTree)
{
foreach (var v in ds.Value.Values)
{
foreach (var p in stockDoc.Parts)
{
if ( p.name == v.Combined())
{
v.Mounting = p.Mounting;
}
}
}
}
}
public void WriteQuantBOMFile(string BaseFolder, string Name)
{
List<string> outlinesBOM = new List<string>();
outlinesBOM.Add("Designator,Comment,Characteristic,Outline,Manufacturer + Part Number,Fitted,Quantity,Mounting");
foreach (var ds in DeviceTree)
{
foreach (var v in ds.Value.Values)
{
SetRotationOffset(v.Combined(), GetRotationOffset(v.Combined()));
string refdescs = "\"" + v.RefDes[0].NameOnBoard;
for (int i = 1; i < v.RefDes.Count; i++)
{
refdescs += ", " + v.RefDes[i].NameOnBoard;
}
refdescs += "\"";
string V = v.Value;
if (V.Trim().Length == 0)
{
V = v.MfgPartNumber;
}
string mfg = "";
if (v.MfgPartNumber != null)
{
mfg = v.MfgPartNumber.Replace(',', '.');
}
string line = String.Format("{0},{1},{2},{3},{4},{5},{6},{7}", refdescs, V,v.Value, v.PackageName, mfg,"Fitted", v.RefDes.Count.ToString(), v.Mounting);
outlinesBOM.Add(line);
}
}
File.WriteAllLines(BaseFolder + "\\" + Name + "_QUANT_BOM.csv", outlinesBOM);
}
public void LoadKicad(string kicadschname, string kicadpcbname, StandardConsoleLog Log)
{
Log.PushActivity("KiCAD BOM Loader");
Log.AddString(String.Format("Loading Kicad board files for: {0}", Path.GetFileNameWithoutExtension(kicadschname)));
string S = System.IO.File.ReadAllText(kicadschname);
S = S.Replace("\n", "");
string S2 = System.IO.File.ReadAllText(kicadpcbname);
S2 = S2.Replace("\n", "");
var SchRoot = new SNode();
SchRoot.Load(S);
var PCBRoot = new SNode();
PCBRoot.Load(S2);
float originx = 0, originy= 0, UnitMult = 1;
var pcb = PCBRoot.Find("kicad_pcb");
float AngleMult = 1.0f;
var C = pcb[0].Find("footprint");
foreach (var a in C)
{
BoardSide side = BoardSide.Top;
var AT = a.Find("at");
var FP = a.Children[0].Name;
if (FP.Contains(":"))
{
FP = FP.Split(':').Last();
}
int layerdesc = 1;
string siden = "";
for (int i =0;i<a.Children.Count();i++)
{
if (a.Children[i].Name == "layer")
{
siden = a.Children[i].Children[0].Name;
}
}
if (a.Children[1].Name == "locked") layerdesc++;
if (siden != "F.Cu") side = BoardSide.Bottom;
var fp_text = a.Find("fp_text");
bool skip = false;
var attr = a.Find("attr");
float Angle = 0;
float X = float.Parse(AT[0].Children[0].Name.Replace('.', ','));
float Y = float.Parse(AT[0].Children[1].Name.Replace('.', ','));
if (AT[0].Children.Count > 2)
{
Angle = float.Parse(AT[0].Children[2].Name.Replace('.', ','));
}
string reference = "";
string value = "";
foreach (var t in attr)
{
foreach (var c in t.Children)
{
if (c.Name == "exclude_from_pos_files") skip = true;
if (c.Name == "exclude_from_bom") skip = true;
}
}
foreach (var t in fp_text)
{
if (t.Children[0].Name == "reference")
{
reference = t.Children[1].Name;
}
if (t.Children[0].Name == "value")
{
value= t.Children[1].Name;
}
}
Console.WriteLine("{0} {1} {2} {3}", reference, value, X, Y, Angle);
if (!skip)
{
var placement = AddBOMItemExt(FP, FP, value, reference, null, System.IO.Path.GetFileNameWithoutExtension(kicadschname), X, Y, Angle, side);
// var BE = GetBOMEntry(placement);
// float DipComp = 0;// DipCompensationAngle(BE.Combined(), side);
// // orientangle += DipComp;
var RD = GetRefDes(placement);
}
// DipRotateAndAdjust(x, y, partoriginx, partoriginy, angle, orientidx, partorientidx, Flipped, RD, originx, originy, UnitMult);
// if (side == BoardSide.Bottom) RD.angle = -RD.angle;
// RD.angle += DipComp;
//float partoriginx = 0;
//float partoriginy = 0;
//var pox = a.Find("OriginX");
//var poy = a.Find("OriginY");
//if (pox.Count > 0)
//{
// partoriginx = float.Parse(pox.First().Children[0].Name.Replace('.', ','));
//}
//if (poy.Count > 0)
//{
// partoriginy = float.Parse(poy.First().Children[0].Name.Replace('.', ','));
//}
//float x = -1;
//float y = -1;
//string name = "unknown";
//string id = "id";
//// try
//{
// name = a.Children[0].Name;
// id = a.Children[1].Name;
// string descattrib = "";
// string sizeattrib = "";
// string value = "";
// var vV = a.Find("Value", false).FirstOrDefault();
// var pP = a.Find("Pattern", false).FirstOrDefault();
// if (vV != null && vV.Children.Count > 0)
// {
// descattrib = vV.Children[0].Name;
// value = vV.Children[0].Name;
// }
// BoardSide side = BoardSide.Top;
// var BottomSide = a.Find("BottomSide", false).FirstOrDefault();
// if (BottomSide != null && BottomSide.Children.Count > 0)
// {
// string V = BottomSide.Children[0].Name;
// if (V == "Y") side = BoardSide.Bottom;
// }
// string pattern = "";
// if (pP != null && pP.Children.Count > 0)
// {
// pattern = pP.Children[0].Name;
// }
// var X = a.Find("X", false).FirstOrDefault();
// if (X != null && X.Children.Count > 0)
// {
// string V = X.Children[0].Name;
// if (V[0] == '.') V = "0" + V;
// V = V.Replace('.', ',');
// x = float.Parse(V);
// }
// var Y = a.Find("Y", false).FirstOrDefault();
// if (Y != null && Y.Children.Count > 0)
// {
// string V = Y.Children[0].Name;
// if (V[0] == '.') V = "0" + V;
// V = V.Replace('.', ',');
// y = float.Parse(V);
// }
// float angle = 0;
// float orientangle = 0;
// int orientidx = 0;
// var O = a.Find("Orientation", false).FirstOrDefault();
// if (O != null && O.Children.Count > 0)
// {
// string V = O.Children[0].Name;
// if (V[0] == '0') { orientangle = 0; orientidx = 0; };
// if (V[0] == '1') { orientangle = 90; orientidx = 1; };
// if (V[0] == '2') { orientangle = 180; orientidx = 2; };
// if (V[0] == '3') { orientangle = 270; orientidx = 3; };
// }
// float pangle = 0;
// int partorientidx = 0;
// var PO = a.Find("PatternOrientation", false).FirstOrDefault();
// if (PO != null && PO.Children.Count > 0)
// {
// string V = PO.Children[0].Name;
// if (V[0] == '0') { pangle = 0; partorientidx = 0; }
// if (V[0] == '1') { pangle = 90; partorientidx = 1; }
// if (V[0] == '2') { pangle = 180; partorientidx = 2; }
// if (V[0] == '3') { pangle = 270; partorientidx = 3; }
// }
// var A = a.Find("Angle", false).FirstOrDefault();
// if (A != null && A.Children.Count > 0)
// {
// angle = float.Parse(A.Children[0].Name.Replace('.', ',')) * AngleMult;
// }
// bool Flipped = false;
// var nFlipped = a.Find("Flipped", false).FirstOrDefault();
// if (nFlipped != null && BottomSide.Children.Count > 0)
// {
// string V = nFlipped.Children[0].Name;
// if (V == "Y")
// {
// Flipped = true;
// }
// }
// var placement = AddBOMItemExt(pattern, name, value, id, null, System.IO.Path.GetFileNameWithoutExtension(kicadschname), 0, 0, 0, side);
// var BE = GetBOMEntry(placement);
// float DipComp = 0;// DipCompensationAngle(BE.Combined(), side);
// // orientangle += DipComp;
// var RD = GetRefDes(placement);
// DipRotateAndAdjust(x, y, partoriginx, partoriginy, angle, orientidx, partorientidx, Flipped, RD, originx, originy, UnitMult);
// if (side == BoardSide.Bottom) RD.angle = -RD.angle;
// RD.angle += DipComp;
// if (id == "C10")
// {
// Console.WriteLine(RD);
// }
}
Log.PopActivity();
}
}
}
bdcd7ef8dThis file is pinned to the selected release. Download the original to open it in your design tool.