private void RenderTextFramePrimitive(Graphics g, TextFrameRecord textFrame) { var penWidth = ScaleLineWidth(textFrame.LineWidth); var rect = ScreenFromWorld(textFrame.CalculateBounds()); if (textFrame.IsSolid) { using (var brush = new SolidBrush(textFrame.AreaColor)) { DrawingUtils.FillRectangle(g, brush, rect); } } if (textFrame.ShowBorder) { using (var pen = CreatePen(textFrame.Color, penWidth, lineJoin: LineJoin.Miter)) { DrawingUtils.DrawRectangle(g, pen, rect); } // reduce text area according to the penWidth rect.Inflate(-penWidth, -penWidth); } using (var brush = new SolidBrush(textFrame.TextColor)) using (var font = CreateFont(textFrame.FontId)) { DrawingUtils.DrawString(g, textFrame.Text, font, brush, rect, StringAlignment.Near, StringAlignment.Near, textFrame.ClipToRect, textFrame.WordWrap); } }
protected override void DoRender(Graphics graphics, bool fastRendering = false) { if (graphics == null) { throw new ArgumentNullException(nameof(graphics)); } var primitives = Component.GetPrimitivesOfType <PcbPrimitive>(); var orderedPrimitives = primitives .Where(p => IsPrimitiveVisible(graphics, p)) .OrderByDescending(p => p.Layer.DrawPriority) .ThenByDescending(p => p.Layer); Debug.WriteLine($"Rendering {orderedPrimitives.Count()} / {primitives.Count()}"); foreach (var primitive in orderedPrimitives) { // using Graphics.BeginContainer() instead of Graphics.Save() because // the former saves the previous transform as the default, and we // can then call Graphics.ResetTransform() to go back to the transform // that was set when the container was created. // Save() just resets the transform to identity var graphicsContainer = graphics.BeginContainer(); // Drawback is that we need to set SmothingMode, etc. for each container DrawingUtils.SetupGraphics(graphics, fastRendering); switch (primitive) { case PcbArc arc: RenderArcPrimitive(graphics, arc); break; case PcbPad pad: RenderPadPrimitive(graphics, pad); break; case PcbTrack track: RenderTrackPrimitive(graphics, track); break; case PcbString @string: RenderStringPrimitive(graphics, @string); break; case PcbRectangle rectangle: RenderRectanglePrimitive(graphics, rectangle); break; case PcbPolygon polygon: RenderPolygonPrimitive(graphics, polygon); break; } graphics.EndContainer(graphicsContainer); } }
private void RenderPadPrimitive(Graphics g, PcbPad pad) { var holeCenter = ScreenFromWorld(pad.Location.X, pad.Location.Y); g.TranslateTransform(holeCenter.X, holeCenter.Y); g.RotateTransform(-(float)pad.Rotation); DrawPad(g, pad, PcbPadPart.BottomSolder); DrawPad(g, pad, PcbPadPart.TopSolder); DrawPad(g, pad, PcbPadPart.BottomLayer); DrawPad(g, pad, PcbPadPart.TopLayer); if (pad.HasHole) { g.RotateTransform(-(float)pad.HoleRotation); using (var brush = new SolidBrush(Layer.GetLayerColor("PadHoleLayer"))) { var rect = ScaleRect(pad.CalculatePartRect(PcbPadPart.Hole, false)); switch (pad.HoleShape) { case PcbPadHoleShape.Round: g.FillEllipse(brush, rect); break; case PcbPadHoleShape.Square: DrawingUtils.FillRectangle(g, brush, rect); break; case PcbPadHoleShape.Slot: DrawingUtils.FillRoundedRect(g, brush, rect, 100); break; default: return; } } } g.ResetTransform(); const float MIN_FONT_DESCRIPTOR = 7; var fontSize = Math.Min(29f, ScaleCoord(pad.HasHole ? pad.HoleSize : pad.SizeTop.Y) * 0.5f); if (fontSize > MIN_FONT_DESCRIPTOR) { var fontColor = pad.HasHole ? Color.FromArgb(255, 227, 143) : Color.FromArgb(255, 181, 181); using (var brush = new SolidBrush(fontColor)) // TODO: add constant using (var font = new Font("Arial", fontSize)) { DrawingUtils.DrawString(g, pad.Designator, font, brush, holeCenter.X, holeCenter.Y, StringAlignmentKind.Tight, StringAlignment.Center, StringAlignment.Center); } } }
private void RenderPinPrimitive(Graphics g, PinRecord pin) { var location = ScreenFromWorld(pin.Location.X, pin.Location.Y); g.TranslateTransform(location.X, location.Y); var direction = 1.0f; var displayNameHorizontalAlignment = StringAlignment.Far; var designatorHorizontalAlignment = StringAlignment.Near; var penWidth = ScaleLineWidth(LineWidth.Small); using (var pen = CreatePen(pin.Color, penWidth, LineCap.Flat)) { if (pin.PinConglomerate.HasFlag(PinConglomerateFlags.Rotated)) { g.RotateTransform(-90); } if (pin.PinConglomerate.HasFlag(PinConglomerateFlags.Flipped)) { direction = -1.0f; displayNameHorizontalAlignment = StringAlignment.Near; designatorHorizontalAlignment = StringAlignment.Far; } var length = ScaleCoord(pin.PinLength) * direction; g.DrawLine(pen, -1.0f, 0.0f, length, 0.0f); } using (var brush = new SolidBrush(pin.Color)) using (var font = CreateFont("Times New Roman", 10f, FontStyle.Regular)) { if (pin.PinConglomerate.HasFlag(PinConglomerateFlags.DisplayNameVisible)) { var x = ScalePixelLength(-5.0f) * direction; var displayName = pin.Name.Replace(@"\", ""); DrawingUtils.DrawString(g, displayName, font, brush, x, ScalePixelLength(0.5), StringAlignmentKind.Default, displayNameHorizontalAlignment, StringAlignment.Center); using (var pen = CreatePen(pin.Color, ScaleLineWidth(LineWidth.Small))) { DrawOverline(g, pin.Name, font, pen, x, ScalePixelLength(0.5), StringAlignmentKind.Default, displayNameHorizontalAlignment, StringAlignment.Center); } } if (pin.PinConglomerate.HasFlag(PinConglomerateFlags.DesignatorVisible)) { DrawingUtils.DrawString(g, pin.Designator, font, brush, ScalePixelLength(8.0f) * direction, 0, StringAlignmentKind.Extent, designatorHorizontalAlignment, StringAlignment.Far); } } }
private void RenderRoundedRectPrimitive(Graphics g, RoundedRectangleRecord roundedRect) { var penWidth = ScaleLineWidth(roundedRect.LineWidth); using (var brush = new SolidBrush(roundedRect.AreaColor)) using (var pen = CreatePen(roundedRect.Color, penWidth)) { var rect = ScreenFromWorld(roundedRect.CalculateBounds()); var radiusX = ScaleCoord(roundedRect.CornerXRadius); var radiusY = ScaleCoord(roundedRect.CornerYRadius); DrawingUtils.FillRoundedRect(g, brush, rect, radiusX, radiusY); DrawingUtils.DrawRoundedRect(g, pen, rect, radiusX, radiusY); } }
private void RenderTextPrimitive(Graphics g, PcbText text) { var location = ScreenFromWorld(text.Corner1.X, text.Corner1.Y); var color = LayerMetadata.GetColor(text.Layer); var height = ScaleCoord(text.Height); var fontStyle = (text.FontItalic ? FontStyle.Italic : FontStyle.Regular) | (text.FontBold ? FontStyle.Bold : FontStyle.Regular); float fontWidth; float fontSize; if (text.TextKind == PcbTextKind.Stroke) { fontWidth = ScaleCoord(text.Width); fontSize = DrawingUtils.CalculateFontSizeForBaseline(g, StrokeFontFamily, fontStyle, height + fontWidth); } else { fontWidth = 0; fontSize = DrawingUtils.CalculateFontSizeForHeight(g, StrokeFontFamily, fontStyle, height); } g.TranslateTransform(location.X, location.Y); g.RotateTransform(-(float)text.Rotation); using (var brush = new SolidBrush(color)) using (var fontFamily = new FontFamily(text.FontName)) using (var font = new Font(text.TextKind == PcbTextKind.Stroke ? StrokeFontFamily : fontFamily, fontSize, fontStyle)) { var size = g.MeasureString(text.Text, font); if (size.Height < 5) { using (var pen = new Pen(brush)) { var rect = ScaleRect(text.CalculateRect(false)); g.DrawRectangle(pen, rect.Left, rect.Top, rect.Width, rect.Height); } } else { if (text.Mirrored) { g.ScaleTransform(-1.0f, 1.0f); } DrawingUtils.DrawString(g, text.Text, font, brush, 0, fontWidth * 0.5f, StringAlignmentKind.Tight, StringAlignment.Near, StringAlignment.Far); } } g.ResetTransform(); }
private void RenderImagePrimitive(Graphics g, ImageRecord image) { var rect = ScreenFromWorld(image.CalculateBounds()); if (_embeddedImages.TryGetValue(image.Filename, out var img)) { g.DrawImage(img, rect); } if (image.IsSolid) { var penWidth = ScaleLineWidth(image.LineWidth); using (var pen = CreatePen(image.Color, penWidth, lineJoin: LineJoin.Miter)) { DrawingUtils.DrawRectangle(g, pen, rect); } } }
private void RenderRectanglePrimitive(Graphics g, RectangleRecord rectangle) { var rect = ScreenFromWorld(rectangle.CalculateBounds()); if (rectangle.IsSolid) { using (var brush = new SolidBrush(rectangle.AreaColor)) { DrawingUtils.FillRectangle(g, brush, rect); } } var penWidth = ScaleLineWidth(rectangle.LineWidth); using (var pen = CreatePen(rectangle.Color, penWidth, lineJoin: LineJoin.Miter)) { DrawingUtils.DrawRectangle(g, pen, rect); } }
/// <summary> /// Draws a bar over the text of a pin to symbolize negative logic. /// </summary> private void DrawOverline(Graphics g, string text, Font font, Pen pen, float x, float y, StringAlignmentKind alignmentKind, StringAlignment horizontalAlignment, StringAlignment verticalAlignment) { var overlineRanges = OverlineHelper.Parse(text); if (overlineRanges.Length == 0) { return; } var plainText = text.Replace(@"\", ""); var offsetX = ScalePixelLength(0.5f); var offsetY = 0.0f; var rangeBounds = DrawingUtils.CalculateTextExtent(g, plainText, x, y, font, alignmentKind, horizontalAlignment, verticalAlignment, overlineRanges); foreach (var bound in rangeBounds) { var inflatedBound = bound.Inflated(-offsetX, -offsetY); g.DrawLine(pen, inflatedBound.X, inflatedBound.Y, inflatedBound.Right, inflatedBound.Y); } }
private void RenderTextStringPrimitive(Graphics g, TextStringRecord textString) { if (textString.IsHidden || textString.Record != 4) { return; } var location = ScreenFromWorld(textString.Location.X, textString.Location.Y); using (var brush = new SolidBrush(textString.Color)) using (var font = CreateFont(textString.FontId)) { StringAlignment horizontalAlignment; if (textString.Justification == TextJustification.BottomLeft || textString.Justification == TextJustification.MiddleLeft || textString.Justification == TextJustification.TopLeft) { horizontalAlignment = StringAlignment.Near; } else if (textString.Justification == TextJustification.BottomCenter || textString.Justification == TextJustification.MiddleCenter || textString.Justification == TextJustification.TopCenter) { horizontalAlignment = StringAlignment.Center; } else { horizontalAlignment = StringAlignment.Far; } StringAlignment verticalAlignment; if (textString.Justification == TextJustification.BottomLeft || textString.Justification == TextJustification.BottomCenter || textString.Justification == TextJustification.BottomRight) { verticalAlignment = StringAlignment.Far; } else if (textString.Justification == TextJustification.MiddleLeft || textString.Justification == TextJustification.MiddleCenter || textString.Justification == TextJustification.MiddleRight) { verticalAlignment = StringAlignment.Center; } else { verticalAlignment = StringAlignment.Near; } g.TranslateTransform(location.X, location.Y); if (textString.Orientations.HasFlag(TextOrientations.Rotated)) { g.RotateTransform(-90); } if (textString.Orientations.HasFlag(TextOrientations.Flipped)) { horizontalAlignment = StringAlignment.Far - (int)horizontalAlignment; verticalAlignment = StringAlignment.Far - (int)verticalAlignment; } DrawingUtils.DrawString(g, textString.Text, font, brush, 0, 0, horizontalAlignment, verticalAlignment, false); } }
/// <summary> /// Implements rendering of the SchLib. /// </summary> /// <param name="graphics"></param> /// <param name="fastRendering"></param> protected override void DoRender(Graphics graphics, bool fastRendering = false) { if (graphics == null) { throw new ArgumentNullException(nameof(graphics)); } var primitives = Component.GetPrimitivesOfType <SchPrimitive>(); var orderedPrimitives = primitives .Where(p => IsPrimitiveVisible(graphics, p)); Debug.WriteLine($"Rendering {orderedPrimitives.Count()} / {primitives.Count()}"); foreach (var primitive in orderedPrimitives) { // using Graphics.BeginContainer() instead of Graphics.Save() because // the former saves the previous transform as the default, and we // can then call Graphics.ResetTransform() to go back to the transform // that was set when the container was created. // Save() just resets the transform to identity var graphicsContainer = graphics.BeginContainer(); // Drawback is that we need to set SmothingMode, etc. for each container DrawingUtils.SetupGraphics(graphics, fastRendering); switch (primitive) { case PinRecord pin: RenderPinPrimitive(graphics, pin); break; case SymbolRecord symbol: RenderSymbolPrimitive(graphics, symbol); break; case TextStringRecord textString: // this can handle Record34 and Record41 through inheritance RenderTextStringPrimitive(graphics, textString); break; case BezierRecord bezier: RenderBezierPrimitive(graphics, bezier); break; case PolylineRecord polyline: RenderPolylinePrimitive(graphics, polyline); break; case PolygonRecord polygon: RenderPolygonPrimitive(graphics, polygon); break; case EllipseRecord ellipse: RenderEllipsePrimitive(graphics, ellipse); break; case PieChartRecord pieChart: RenderPieChartPrimitive(graphics, pieChart); break; case RoundedRectangleRecord roundedRect: RenderRoundedRectPrimitive(graphics, roundedRect); break; case ArcRecord arc: RenderArcPrimitive(graphics, arc); break; case LineRecord line: RenderLinePrimitive(graphics, line); break; case RectangleRecord rectangle: RenderRectanglePrimitive(graphics, rectangle); break; case TextFrameRecord textFrame: RenderTextFramePrimitive(graphics, textFrame); break; case ImageRecord image: RenderImagePrimitive(graphics, image); break; } graphics.EndContainer(graphicsContainer); } }
private void DrawPad(Graphics g, PcbPad pad, PcbPadPart padPart) { PcbPadShape shape; int cornerRadiusPercent; Color color; // setup parameters according to the current padPart switch (padPart) { case PcbPadPart.TopLayer: shape = pad.ShapeTop; cornerRadiusPercent = pad.CornerRadiusTop; color = LayerMetadata.GetColor(pad.Layer); break; case PcbPadPart.BottomLayer: shape = pad.ShapeBottom; cornerRadiusPercent = pad.CornerRadiusBot; color = LayerMetadata.GetColor(pad.Layer); break; case PcbPadPart.TopSolder: shape = pad.ShapeTop; cornerRadiusPercent = pad.CornerRadiusTop; color = LayerMetadata.GetColor("TopSolder"); break; case PcbPadPart.BottomSolder: shape = pad.ShapeBottom; cornerRadiusPercent = pad.CornerRadiusBot; color = LayerMetadata.GetColor("BottomSolder"); break; default: return; } var rect = ScaleRect(pad.CalculatePartRect(padPart, false)); using (var brush = new SolidBrush(color)) { switch (shape) { case PcbPadShape.Round: DrawingUtils.FillRoundedRect(g, brush, rect, 100); break; case PcbPadShape.Rectangular: DrawingUtils.FillRectangle(g, brush, rect); break; case PcbPadShape.Octogonal: DrawingUtils.FillOctagon(g, brush, rect); break; case PcbPadShape.RoundedRectangle: cornerRadiusPercent = cornerRadiusPercent > 0 ? cornerRadiusPercent : 100; DrawingUtils.FillRoundedRect(g, brush, rect, cornerRadiusPercent); break; default: return; } } }