private static PcbGraphics PolylineHelper(PcbUnits coordinateUnits,Piece item)
        {
            PcbGraphicsLayer l = PcbGraphicsLayer.TopSilk;
            PcbLineType      t = PcbLineType.Solid;

            if (Piece.GraphicsLayerMapping.ContainsKey(item.CurrentLayer))
            {
                l = Piece.GraphicsLayerMapping[item.CurrentLayer];
            }
            else
            {
                WarningListener.AddFormat(new NotImplementedException(),
                                          "Default graphics layer used instead of #{0}",item.CurrentLayer);
            }
            if (Piece.LineTypeMapping.ContainsKey(item.CurrentLineType))
            {
                t = Piece.LineTypeMapping[item.CurrentLineType];
            }
            else
            {
                WarningListener.AddFormat(new NotImplementedException(),
                                          "Default line type used instead of {0}",Enum.GetName(typeof(Piece.LineType),item.CurrentLineType));
            }
            PcbGraphics g = new PcbGraphics(coordinateUnits,coordinateUnits,l,item.XY.Count - 1);

            for (int i = 1; i < item.XY.Count; i++)
            {
                g.Lines.Add(new PcbSilkLine(item.XY[i - 1],item.XY[i],coordinateUnits,coordinateUnits,item.Width,t));
            }
            return(g);
        }
        private static void ProcessDecalPieces(PcbDesign res,PcbUnits coordinateUnits,Partdecal decal)
        {
            //Pieces are graphics and traces
            res.Traces.Capacity   += decal.Pieces.Count(x => x.CurrentType == Piece.PieceType.Copper);
            res.Graphics.Capacity += decal.Pieces.Count(x => x.CurrentType != Piece.PieceType.Copper);
            foreach (var item in decal.Pieces)
            {
                switch (item.CurrentType)
                {
                case Piece.PieceType.Open:
                    res.Graphics.Add(PolylineHelper(coordinateUnits,item));
                    break;

                case Piece.PieceType.Closed:
                    res.Graphics.Add(PolylineHelper(coordinateUnits,item));
                    break;

                case Piece.PieceType.Copper:
                    //Should move it to LINES instead of PARTDECAL
                    res.Traces.Add(
                        new PcbTrace(item.CurrentLayer == Piece.LayerAllNumber ? PcbLayer.All : (PcbLayer)item.CurrentLayer,
                                     item.Width,coordinateUnits,coordinateUnits,item.XY));
                    break;

                default:
                    WarningListener.AddFormat(new NotImplementedException(),
                                              "Decal type {0} ignored.",Enum.GetName(typeof(Piece.PieceType),item.CurrentType));
                    break;
                }
            }
        }
 public PcbGraphics(PcbUnits units, PcbUnits coordinateUnits, PcbGraphicsLayer layer, int capacity = 4)
 {
     Lines           = new List <PcbSilkLine>(capacity);
     Units           = units;
     CoordinateUnits = coordinateUnits;
     Layer           = layer;
 }
        public void SetUnits(PcbUnits units)
        {
            double mult = PcbDesign.GetUnitConversionMultiplier(Units) / PcbDesign.GetUnitConversionMultiplier(units);

            Thickness *= mult;
            Units      = units;
        }
        /// <summary>
        /// For easy modification inside foreach
        /// </summary>
        /// <param name="units">Target units</param>
        public void SetCoordinateUnits(PcbUnits units)
        {
            double mult = PcbDesign.GetUnitConversionMultiplier(CoordinateUnits) / PcbDesign.GetUnitConversionMultiplier(units);

            XY = XY.Select(x => new Point(x.X * mult, x.Y * mult)).ToList();
            CoordinateUnits = units;
        }
 public PcbPadStyle(PcbPadShape shape, PcbUnits units, double dim1, double dim2, double drill = 0)
 {
     Shape      = shape;
     Units      = units;
     Dimension1 = dim1;
     Dimension2 = dim2;
     Drill      = drill;
 }
 public PcbTrace(PcbLayer layer, double thickness, PcbUnits units, PcbUnits coordinateUnits, List <Point> points)
 {
     XY              = points;
     Layer           = layer;
     Units           = units;
     CoordinateUnits = coordinateUnits;
     Thickness       = thickness;
 }
        public void SetCoordinateUnits(PcbUnits units)
        {
            double mult = PcbDesign.GetUnitConversionMultiplier(CoordinateUnits) / PcbDesign.GetUnitConversionMultiplier(units);

            Start           = new Point(Start.X * mult, Start.Y * mult);
            End             = new Point(End.X * mult, End.Y * mult);
            CoordinateUnits = units;
        }
        /// <summary>
        /// For easy modification inside foreach
        /// </summary>
        /// <param name="units">Target units</param>
        public void SetCoordinateUnits(PcbUnits units)
        {
            double mult = PcbDesign.GetUnitConversionMultiplier(CoordinateUnits) / PcbDesign.GetUnitConversionMultiplier(units);

            X *= mult;
            Y *= mult;
            CoordinateUnits = units;
        }
        public void SetUnits(PcbUnits units)
        {
            double mult = PcbDesign.GetUnitConversionMultiplier(Units) / PcbDesign.GetUnitConversionMultiplier(units);

            Dimension1 *= mult;
            Dimension2 *= mult;
            Drill      *= mult;
            Units       = units;
        }
 public PcbSilkLine(Point start, Point end, PcbUnits units, PcbUnits coordinateUnits, double thickness,
                    PcbLineType type = PcbLineType.Solid)
 {
     Start           = start;
     End             = end;
     Units           = units;
     CoordinateUnits = coordinateUnits;
     Thickness       = thickness;
     Type            = type;
 }
 public void SynchronizeUnits(PcbUnits units)
 {
     foreach (var item in Lines)
     {
         if (item.Units != units)
         {
             item.SetUnits(units);
         }
     }
     Units = units;
 }
 public void SynchronizeCoordinateUnits(PcbUnits units)
 {
     foreach (var item in Lines)
     {
         if (item.CoordinateUnits != units)
         {
             item.SetCoordinateUnits(units);
         }
     }
     CoordinateUnits = units;
 }
 public PcbPad(string number, PcbUnits coordinateUnits, double x, double y,
               PcbLayer layer, PcbPadStyle style, string flags = null)
 {
     Number          = number;
     CoordinateUnits = coordinateUnits;
     X     = x;
     Y     = y;
     Layer = layer;
     Style = style;
     Flags = flags;
 }
        public static PcbDesign Parse(string contents)
        {
            //Parse units from the header
            int      i               = contents.IndexOf(FileHeaderDesignator,1);
            int      j               = contents.LastIndexOf(FileHeaderSeparator,i) + 1;
            string   temp            = contents.Substring(j,i - j);
            PcbUnits coordinateUnits = HeaderUnits.First(x => x.Value == temp).Key;

            //Get section boundaries
            i = contents.IndexOf(LineSeparator,i) + 1;
            Dictionary <ControlStatement,int> sections = new Dictionary <ControlStatement,int>(ControlStatements.Length);

            for (int k = 0; k < ControlStatements.Length; k++)
            {
                j = contents.IndexOf(ControlStatements[k],i);
                if (j > -1)
                {
                    j = contents.IndexOf(LineSeparator,j) + 1;
                    if (j < contents.Length)
                    {
                        if (contents[j] == LineSeparator)
                        {
                            j++;
                        }
                        if (contents[j] == CaretReset)
                        {
                            j += 2;
                        }
                    }
                    sections.Add((ControlStatement)k,j);
                }
            }
            //Parse partdecal
            int       currentSectionStart  = sections[ControlStatement.PARTDECAL];
            int       currentSectionEnd    = FindSectionEnd(sections,ControlStatement.PARTDECAL);
            int       currentSectionLength = currentSectionEnd - currentSectionStart;
            Partdecal decal = null;

            try
            {
                decal = Partdecal.Parse(contents.Substring(currentSectionStart,currentSectionLength));
            }
            catch (Exception e)
            {
                WarningListener.Add(e);
            }
            //Others are not needed yet

            return(PADSToPcbDesign(coordinateUnits,decal));
        }
 public void SynchronizeUnits(PcbUnits units)
 {
     foreach (var item in Pads)
     {
         if (item.Units != units)
         {
             item.SetUnits(units);
         }
     }
     foreach (var item in Traces)
     {
         if (item.Units != units)
         {
             item.SetUnits(units);
         }
     }
     foreach (var item in Graphics)
     {
         item.SynchronizeUnits(units);
     }
 }
 /// <summary>
 /// Converts CoordinateUnits of objects to the units of the design.
 /// </summary>
 public void SynchronizeCoordinateUnits(PcbUnits units)
 {
     foreach (var item in Pads)
     {
         if (item.CoordinateUnits != units)
         {
             item.SetCoordinateUnits(units);
         }
     }
     foreach (var item in Traces)
     {
         if (item.CoordinateUnits != units)
         {
             item.SetCoordinateUnits(units);
         }
     }
     foreach (var item in Graphics)
     {
         item.SynchronizeCoordinateUnits(units);
     }
     CoordinateUnits = units;
 }
        private static PcbPadStyle DeterminePadStyle(PadStack.StackLine line,PcbUnits coordinateUnits)
        {
            PcbPadStyle style;
            bool        drilled = line.Arguments[(int)PadStack.StackLine.DependentArguments.DrillSize].Present;

            switch (line.CurrentShape)
            {
            case PadStack.Shape.Round:     //"Round" pads with drill argument are used for drilled pads (not annular pads!)
                style = new PcbPadStyle(drilled ? PcbPadShape.CircularTH : PcbPadShape.CircularSMT,
                                        coordinateUnits,line.Size,0,
                                        drilled ? (double)line.Arguments[(int)PadStack.StackLine.DependentArguments.DrillSize].Value : 0);
                break;

            case PadStack.Shape.Square:
                style = new PcbPadStyle(drilled ? PcbPadShape.RectangularTH : PcbPadShape.RectangularSMT,
                                        coordinateUnits,line.Size,line.Size,
                                        drilled ? (double)line.Arguments[(int)PadStack.StackLine.DependentArguments.DrillSize].Value : 0);
                break;

            case PadStack.Shape.Annular:
                style = new PcbPadStyle(drilled ? PcbPadShape.CircularTH : PcbPadShape.CircularSMT,
                                        coordinateUnits,line.Size,
                                        (double)line.Arguments[(int)PadStack.StackLine.DependentArguments.InternalDiameter].Value,
                                        drilled ? (double)line.Arguments[(int)PadStack.StackLine.DependentArguments.DrillSize].Value : 0);
                break;

            case PadStack.Shape.RectangularFinger:
                style = new PcbPadStyle(PcbPadShape.RectangularSMT,coordinateUnits,line.Size,
                                        (double)line.Arguments[(int)PadStack.StackLine.DependentArguments.FingerLength].Value);
                WarningListener.Add(new NotImplementedException("Only Length argument is supported for RectangularFinger pad style!"));
                break;

            default:
                throw new NotImplementedException(string.Format(
                                                      "Pad shape {0} ignored.",Enum.GetName(typeof(PadStack.Shape),line.CurrentShape)));
            }
            return(style);
        }
        /// <summary>
        /// Get PCB (coordinate) units name
        /// </summary>
        /// <param name="units">Supported: Thou, Millimeter, TenNanometers, Inch</param>
        /// <returns>Name string</returns>
        public string this[PcbUnits units]
        {
            get
            {
                switch (units)
                {
                case PcbUnits.Thou:
                    return("1th");

                case PcbUnits.Millimeter:
                    return("1mm");

                case PcbUnits.TenNanometers:
                    return("10nm");

                case PcbUnits.Inch:
                    return("1in");

                default:
                    throw new ArgumentException("Bad units.");
                }
            }
        }
        /// <summary>
        /// Intended only for internal use
        /// </summary>
        /// <param name="from">Coordinate units</param>
        /// <returns>Multiplier that converts specified unit into 0.1nm-s (angstroms)</returns>
        public static double GetUnitConversionMultiplier(PcbUnits from)
        {
            switch (from)
            {
            case PcbUnits.Thou:
                return(254000);

            case PcbUnits.Millimeter:
                return(10000000);

            case PcbUnits.TenNanometers:
                return(100);

            case PcbUnits.Inch:
                return(254000000);

            case PcbUnits.TwoThirdsOfNanometer:
                return(20 / 3);

            default:
                throw new ArgumentException("Bad coordinate units.");
            }
        }
        private static PcbDesign PADSToPcbDesign(PcbUnits coordinateUnits,Partdecal decal)
        {
            PcbDesign res = new PcbDesign();

            //Partdecal
            try
            {
                if (decal != null)
                {
                    ProcessDecalPieces(res,coordinateUnits,decal);
                    ProcessDecalPads(res,coordinateUnits,decal);
                }
            }
            catch (Exception e)
            {
                WarningListener.Add(e);
            }

            //Others are not implemented yet

            //Header info
            res.SynchronizeCoordinateUnits(coordinateUnits);
            return(res);
        }
        private static void ProcessDecalPads(PcbDesign res,PcbUnits coordinateUnits,Partdecal decal)
        {
            //Terminals + padstacks = pads
            PadStack defaultStack = decal.PadStacks.FirstOrDefault(x => x.PinDesignator == PadStack.AllTerminalsDesignator);

            res.Pads.Capacity += decal.Terminals.Count;
            foreach (var item in decal.Terminals)
            {
                var padstack = FindSuitablePadstack(decal,item,defaultStack);
                if (padstack == null)
                {
                    WarningListener.Add(new ArgumentException(),"Can't find a suitable padstack for the terminal #" + item.PinDesignator);
                    continue;
                }
                var drillLine = padstack.StackLines.FirstOrDefault(x => x.Arguments[(int)PadStack.StackLine.DependentArguments.DrillSize].Present);
                if (drillLine != null)
                {
                    //Detect drill-only holes
                    double d = (double)drillLine.Arguments[(int)PadStack.StackLine.DependentArguments.DrillSize].Value;
                    if (d >= drillLine.Size)
                    {
                        res.Pads.Add(new PcbPad(item.PinDesignator,coordinateUnits,item.X,item.Y,PcbLayer.Drill,
                                                new PcbPadStyle(PcbPadShape.CircularTH,coordinateUnits,d,0,d)));
                        continue;
                    }
                }
                List <PadStack.StackLine> usefulLines =
                    padstack.StackLines.Where(x => (x.Size != 0 || x.Arguments.Any(y => y.Present))).ToList();
                if (usefulLines.Count == 3)   //Recognize layer "ALL"
                {
                    //PADS requires minimum of 3 layers specified, 0x0 size indicates that the pad is not actually present
                    //If some stacklines have 0 size and no useful arguments (shape does not count), then we effectively have less stacklines
                    if (usefulLines.Select(x => x.Layer).Union(PadStack.AllLayerPattern).Count() == 3)
                    {
                        //Find layer that contains the most arguments (drill for example appears only for component-side layer)
                        int maxArgs = 0;
                        for (int i = 1; i < usefulLines.Count; i++)
                        {
                            if (usefulLines[maxArgs].Arguments.Count(x => x.Present) <
                                usefulLines[i].Arguments.Count(x => x.Present))
                            {
                                maxArgs = i;
                            }
                        }
                        res.Pads.Add(new PcbPad(item.PinDesignator,coordinateUnits,item.X,item.Y,PcbLayer.All,
                                                DeterminePadStyle(usefulLines[maxArgs],coordinateUnits)));
                        continue;
                    }
                }
                //If this is not a special case, parse stacklines one-by-one
                foreach (var line in usefulLines)
                {
                    PcbPadStyle style = DeterminePadStyle(line,coordinateUnits);
                    PcbLayer    layer = DeterminePcbLayer(line);
                    res.Pads.Add(new PcbPad(item.PinDesignator,coordinateUnits,item.X,item.Y,layer,style));
                    //-1 stands for both "Internal layers", but we can return only a single layer, so fix it afterwards
                    if (layer == PcbLayer.InternalBottom)
                    {
                        res.Pads.Add(new PcbPad(item.PinDesignator,coordinateUnits,item.X,item.Y,
                                                PcbLayer.InternalTop,style));
                    }
                }
            }
        }
 public PcbTrace(PcbLayer layer, double thickness, PcbUnits units, PcbUnits coordinateUnits, int capacity = 4)
     : this(layer, thickness, units, coordinateUnits, new List <Point>(capacity))
 {
 }
 private Partdecal(int pieces,int terminals,int stacks,string name,PcbUnits units)
     : this(pieces,terminals,stacks)
 {
     Name  = name;
     Units = units;
 }
 /// <summary>
 /// Affects dimensions inside PcbPadStyle
 /// </summary>
 /// <param name="units">Target units</param>
 public void SetUnits(PcbUnits units)
 {
     Style.SetUnits(units);
 }