private static void AssignOwners(SchComponent component) { foreach (var primitive in component.Primitives) { var owner = component.Primitives.ElementAtOrDefault(primitive.OwnerIndex - 1); primitive.Owner = owner; } }
/// <summary> /// Reads a component stored in the <paramref name="resourceName"/> section key /// in the current file. /// </summary> /// <param name="resourceName"> /// Section key where to look for the schematic component symbol data. /// </param> /// <returns>Component instance.</returns> private SchComponent ReadComponent(string resourceName) { var componentStorage = Cf.TryGetStorage(resourceName) ?? throw new ArgumentException($"Symbol resource not found: {resourceName}"); BeginContext(resourceName); SchComponent component = null; var pinsWideText = ReadPinWideText(componentStorage); var pinsTextData = ReadPinTextData(componentStorage); var pinsSymbolLineWidth = ReadPinSymbolLineWidth(componentStorage); int pinIndex = 0; using (var reader = componentStorage.GetStream("Data").GetBinaryReader()) { while (reader.BaseStream.Position < reader.BaseStream.Length) { var primitiveStartPosition = reader.BaseStream.Position; var primitive = ReadRecord(reader, size => ReadAsciiRecord(reader, size), size => { ParameterCollection pinWideText = null; byte[] pinTextData = null; ParameterCollection pinSymbolLineWidth = null; pinsWideText?.TryGetValue(pinIndex, out pinWideText); pinsTextData?.TryGetValue(pinIndex, out pinTextData); pinsSymbolLineWidth?.TryGetValue(pinIndex, out pinSymbolLineWidth); pinIndex++; return(ReadPinRecord(reader, size, pinWideText, pinTextData, pinSymbolLineWidth)); }); primitive.SetRawData(ExtractStreamData(reader, primitiveStartPosition, reader.BaseStream.Position)); if (component == null) { // First primitive read must be the component SchComponent AssertValue(nameof(primitive), primitive.GetType().Name, typeof(SchComponent).Name); component = (SchComponent)primitive; } else { component.Primitives.Add(primitive); } } } AssignOwners(component); EndContext(); return(component); }
/// <summary> /// Writes a component to the adequate section key in the current file. /// </summary> /// <param name="component">Component to be serialized.</param> private void WriteComponent(SchComponent component) { var resourceName = GetSectionKeyFromComponentPattern(component.LibReference); var componentStorage = Cf.RootStorage.GetOrAddStorage(resourceName); var pinsFrac = new Dictionary <int, (int, int, int)>(); var pinsWideText = new Dictionary <int, ParameterCollection>(); var pinsTextData = new Dictionary <int, byte[]>(); var pinsSymbolLineWidth = new Dictionary <int, ParameterCollection>(); componentStorage.GetOrAddStream("Data").Write(writer => { WriteComponentPrimitives(writer, component, pinsFrac, pinsWideText, pinsTextData, pinsSymbolLineWidth); }); WritePinFrac(componentStorage, pinsFrac); WritePinTextData(componentStorage, pinsTextData); WriteComponentExtendedParameters(componentStorage, "PinWideText", pinsWideText); WriteComponentExtendedParameters(componentStorage, "PinSymbolLineWidth", pinsSymbolLineWidth); }
/// <summary> /// Reads a component stored in the <paramref name="resourceName"/> section key /// in the current file. /// </summary> /// <param name="resourceName"> /// Section key where to look for the schematic component symbol data. /// </param> /// <returns>Component instance.</returns> private SchComponent ReadComponent(string resourceName) { var symbolStorage = Cf.TryGetStorage(resourceName) ?? throw new ArgumentException($"Symbol resource not found: {resourceName}"); BeginContext(resourceName); SchComponent component = null; using (var reader = symbolStorage.GetStream("Data").GetBinaryReader()) { while (reader.BaseStream.Position < reader.BaseStream.Length) { var primitiveStartPosition = reader.BaseStream.Position; var primitive = ReadRecord(reader, size => ReadAsciiRecord(reader, size), size => ReadPinRecord(reader, size)); primitive.SetRawData(ExtractStreamData(reader, primitiveStartPosition, reader.BaseStream.Position)); if (component == null) { // First primitive read must be the component SchComponent AssertValue(nameof(primitive), primitive.GetType().Name, typeof(SchComponent).Name); component = (SchComponent)primitive; } else { component.Primitives.Add(primitive); } } } EndContext(); return(component); }
/// <summary> /// Instantiates a record according to its record type number. /// </summary> /// <param name="recordType">Integer representing the record type.</param> /// <returns>A new empty instance of a record primitive.</returns> private SchPrimitive CreateRecord(int recordType) { SchPrimitive record; switch (recordType) { case 1: record = new SchComponent(); break; case 2: record = new PinRecord(); break; case 3: record = new SymbolRecord(); break; case 4: record = new TextStringRecord(); break; case 5: record = new BezierRecord(); break; case 6: record = new PolylineRecord(); break; case 7: record = new PolygonRecord(); break; case 8: record = new EllipseRecord(); break; case 9: record = new PieChartRecord(); break; case 10: record = new RoundedRectangleRecord(); break; case 11: record = new EllipticalArcRecord(); break; case 12: record = new ArcRecord(); break; case 13: record = new LineRecord(); break; case 14: record = new RectangleRecord(); break; case 28: case 209: record = new TextFrameRecord(); break; case 30: record = new ImageRecord(); break; case 34: record = new Record34(); break; case 41: record = new Record41(); break; case 44: record = new Record44(); break; case 45: record = new Record45(); break; case 46: record = new Record46(); break; case 48: record = new Record48(); break; default: EmitWarning($"Record {recordType} not supported"); record = new SchPrimitive(); break; } return(record); }
/// <summary> /// Converts the components and their schematic symbols from a BxlSharp document /// to the equivalent AltiumSharp schematic library. /// <remarks> /// This ignores the components' footprints. /// </remarks> /// </summary> /// <param name="document">BxlSharp document to have their schematic library data converted</param> /// <param name="hideAllParameters"> /// Many BXL documents have by default <c>RefDes</c> and <c>Value</c> attributes marked as /// being visible. If this argument is <c>true</c> then the visibility is ignored when /// creating the respective AltiumSharp component schematic parameters.</param> /// <param name="overrideRectangleLineWidth"> /// Optional value to be used when creating the rectangles in the document, instead of the /// values provided in the BxlSharp document. /// </param> /// <returns></returns> public static SchLib ConvertSymbols(BxlDocument document, bool hideAllParameters = false, LineWidth?overrideRectangleLineWidth = null, bool convertOverlines = true) { var schlib = new SchLib(); foreach (var component in document.Components) { var schComponent = new SchComponent { LibReference = component.Name, Designator = { Text = $"{component.RefDesPrefix}?" } }; // Read the general parameters for the component foreach (var libitem in component.Data) { SchPrimitive schPrimitive = null; switch (libitem) { case LibAttribute libAttribute: schPrimitive = new SchParameter { Location = ConvertPoint(libAttribute.Origin), Name = libAttribute.Name, Text = libAttribute.Text, FontId = GetFontId(schlib, document, libAttribute.TextStyle), Justification = ConvertJustification(libAttribute.Justify), Orientation = ConvertRotatation(libAttribute.Rotate), IsMirrored = libAttribute.IsFlipped, IsHidden = true, }; if (libAttribute.Name?.Equals("DESCRIPTION", StringComparison.InvariantCultureIgnoreCase) == true) { schComponent.ComponentDescription = libAttribute.Text; } break; case LibWizard libWizard: schPrimitive = new SchParameter { Location = ConvertPoint(libWizard.Origin), Name = libWizard.VarName, Text = libWizard.VarData }; break; } if (schPrimitive != null) { schComponent.Add(schPrimitive); } } // needed for fetching some parameter values var footprint = document.GetFootprint(component.PatternName); // each component has a set of schematic symbols equivalent to AD display modes and part numbers, // so we group them by part number and then iterate over each part's display modes var attachedSymbolsByPartNum = component.AttachedSymbols.Where(s => !string.IsNullOrEmpty(s.SymbolName)) .GroupBy(s => s.PartNum); foreach (var group in attachedSymbolsByPartNum) { var partNum = group.Key; if (partNum > schComponent.PartCount) { schComponent.AddPart(); } var displayMode = 0; foreach (var attachedSymbol in group) { var symbol = document.GetSymbol(attachedSymbol.SymbolName); if (symbol == null) { continue; } if (displayMode >= schComponent.DisplayModeCount) { schComponent.AddDisplayMode(); } var ignored = new HashSet <LibItem>(); // detect rectangles first so the are drawn in the background for (int j = 0; j < symbol.Data.Count; ++j) { if (DetectRectangle(symbol.Data, j, out var rectangle)) { ignored.Add(symbol.Data[j]); ignored.Add(symbol.Data[j + 1]); ignored.Add(symbol.Data[j + 2]); ignored.Add(symbol.Data[j + 3]); j += 3; rectangle.LineWidth = overrideRectangleLineWidth ?? rectangle.LineWidth; schComponent.Add(rectangle); } } foreach (var libitem in symbol.Data.Where(li => !ignored.Contains(li))) { SchPrimitive schPrimitive = null; switch (libitem) { case LibLine libLine: schPrimitive = new SchLine { Location = ConvertPoint(libLine.Origin), Corner = ConvertPoint(libLine.EndPoint), LineWidth = ConvertWidth(libLine.Width) }; break; case LibPoly libPoly: schPrimitive = new SchPolyline { Vertices = ConvertPoints(libPoly.Points), LineWidth = ConvertWidth(libPoly.Width) }; break; case LibArc libArc: schPrimitive = new SchArc { Location = ConvertPoint(libArc.Origin), Radius = Coord.FromMils(libArc.Radius), StartAngle = libArc.StartAngle, EndAngle = libArc.StartAngle + libArc.SweepAngle, LineWidth = ConvertWidth(libArc.Width) }; break; case LibText libText: schPrimitive = new SchLabel { Location = ConvertPoint(libText.Origin), Text = libText.Text, FontId = GetFontId(schlib, document, libText.TextStyle), Justification = ConvertJustification(libText.Justify), Orientation = ConvertRotatation(libText.Rotate), IsMirrored = libText.IsFlipped, IsHidden = !libText.IsVisible, }; break; case LibPin libPin: schPrimitive = new SchPin { Location = ConvertPoint(libPin.Origin), Designator = libPin.Designator.Text, Name = ConvertPinName(libPin.Name.Text, convertOverlines), NameVisible = libPin.Name.IsVisible, Orientation = ConvertRotatation(libPin.Rotate), DesignatorVisible = libPin.Designator.IsVisible, PinLength = Coord.FromMils(libPin.PinLength) }; break; case LibAttribute libAttribute: if (schComponent.GetParameter(libAttribute.Name) != null) { break; } var parameterValue = libAttribute.Text; if (string.IsNullOrEmpty(parameterValue) && footprint != null) { // when the value is empty, and not present in the component, Ultimate Librarian // gets the parameter value from the fooprint when exporting to Altium parameterValue = footprint.GetAttribute(libAttribute.Name)?.Text; } if (string.IsNullOrEmpty(parameterValue)) { parameterValue = component.GetAttribute(libAttribute.Name)?.Text; } schPrimitive = new SchParameter { Location = ConvertPoint(libAttribute.Origin), Name = libAttribute.Name, Text = parameterValue ?? string.Empty, FontId = GetFontId(schlib, document, libAttribute.TextStyle), Justification = ConvertJustification(libAttribute.Justify), Orientation = ConvertRotatation(libAttribute.Rotate), IsMirrored = libAttribute.IsFlipped, IsHidden = hideAllParameters || !libAttribute.IsVisible, }; break; case LibWizard libWizard: if (schComponent.GetParameter(libWizard.VarName) != null) { break; } schPrimitive = new SchParameter { Location = ConvertPoint(libWizard.Origin), Name = libWizard.VarName, Text = libWizard.VarData }; break; case null: break; default: throw new ArgumentOutOfRangeException(nameof(libitem)); } if (schPrimitive != null) { schPrimitive.OwnerPartDisplayMode = displayMode; schComponent.Add(schPrimitive); } } displayMode++; } } schComponent.DisplayMode = 0; schComponent.CurrentPartId = 1; schlib.Add(schComponent); } return(schlib); }
private static void WriteComponentPrimitives(BinaryWriter writer, SchComponent component, Dictionary <int, (int x, int y, int length)> pinsFrac,