/// <inheritdoc /> public override void Register(CircuitContext context, IDiagnosticHandler diagnostics) { if (Fix) { RegisterFixed(context, diagnostics); return; } var map = context.Nodes.Shorts; var ckt = context.Circuit; string x = map[X]; string ox = map[_origin.X]; string y = map[Y]; string oy = map[_origin.Y]; var direction = _origin is ITransformingDrawable tfd?tfd.TransformNormal(Direction) : Direction; direction = direction.Order(ref ox, ref x, ref oy, ref y); // If we only work along one axis, we can simplify the schematic if (x == ox) { MinimumConstraint.AddMinimum(ckt, Y, oy, y, MinimumOffset); return; } if (y == oy) { MinimumConstraint.AddMinimum(ckt, X, ox, x, MinimumOffset); return; } // General case, both X and Y are different AddControlledMinimum(ckt, $"{Owner.Name}[{Name}]", ox, x, oy, y, direction); MinimumConstraint.AddMinimum(ckt, $"{Owner.Name}[{Name}].min.x", ox, x, direction.X * MinimumOffset); MinimumConstraint.AddMinimum(ckt, $"{Owner.Name}[{Name}].min.y", oy, y, direction.Y * MinimumOffset); }
/// <summary> /// Starts an interactive mode. /// </summary> /// <param name="diagnostics">The diagnostics message handler.</param> public static void InteractiveMode(IDiagnosticHandler diagnostics) { var regex = new Regex(@"""(?<value>[^""]+)""|(?<value>[^\s]+)"); bool keepGoing = true; while (keepGoing) { Console.Write("> "); string arguments = Console.ReadLine(); string[] args = regex.Matches(arguments).Cast <Match>().Select(m => m.Groups["value"].Value).ToArray(); if (args.Length == 0 || args.Length == 1 && ( StringComparer.OrdinalIgnoreCase.Equals(args[0], "quit") || StringComparer.OrdinalIgnoreCase.Equals(args[0], "exit"))) { keepGoing = false; } else { var jobs = ReadJobs(args, out _); DoJobs(jobs, diagnostics).GetAwaiter().GetResult(); } } }
/// <summary> /// Executes the job. /// </summary> /// <param name="textFormatter">The test formatter.</param> /// <param name="diagnostics">The diagnostic message handler.</param> public async Task Render(ChromiumElementFormatter textFormatter, IDiagnosticHandler diagnostics) { // Determine the output file string outputFilename = OutputFilename; if (string.IsNullOrWhiteSpace(outputFilename)) { outputFilename = Path.GetFileNameWithoutExtension(Filename) + ".svg"; } // Render if (_circuit != null && _circuit.Count > 0) { await textFormatter.UpdateStyle(_cssScript ?? GraphicalCircuit.DefaultStyle); var doc = _circuit.Render(diagnostics, textFormatter); // Finally write the resulting document to svg using (var writer = XmlWriter.Create(outputFilename, new XmlWriterSettings())) { doc.WriteTo(writer); } diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Info, "JOB01", $"Finished converting '{Filename}', output at '{outputFilename}'.")); } else { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Error, "JOB02", $"No circuit elements in '{Filename}'")); } }
/// <inheritdoc /> public void DiscoverNodeRelationships(NodeContext context, IDiagnosticHandler diagnostics) { if (Offset.IsZero()) { context.Shorts.Group(Lowest, Highest); } }
/// <summary> /// Tries to parse a vector attribute on an XML node. /// </summary> /// <param name="lexer">The lexer.</param> /// <param name="diagnostics">The diagnostics handler.</param> /// <param name="result">The result.</param> /// <returns>Returns <c>true</c> if the coordinate was parsed; otherwise, <c>false</c>.</returns> public static bool TryParseVector(this SvgPathDataLexer lexer, IDiagnosticHandler diagnostics, Vector2 defaultValue, out Vector2 result) { bool success = true; success &= TryParseCoordinate(lexer, diagnostics, defaultValue.X, out double x); success &= TryParseCoordinate(lexer, diagnostics, defaultValue.Y, out double y); result = new(x, y); return(success); }
public static IDiagnosticObserver CreateDiagnosticObserver(IDiagnosticHandler handler, DiagnosticListener listener) { var observer = CreateDiagnosticObserver(handler, options => { options.DiagnosticListenerName = listener.Name; }); return(observer); }
public static IDiagnosticObserver CreateDiagnosticObserver(IDiagnosticHandler handler, Action <DiagnosticObserverOptions <IDiagnosticHandler> > configure) { var logger = CreateLogger <DiagnosticObserver <IDiagnosticHandler> >(); var options = new DiagnosticObserverOptions <IDiagnosticHandler>(); configure(options); return(new DiagnosticObserver <IDiagnosticHandler>(options, handler)); }
/// <inheritdoc /> public void Register(CircuitContext context, IDiagnosticHandler diagnostics) { var lowest = context.Nodes.Shorts[Lowest]; var highest = context.Nodes.Shorts[Highest]; if (lowest != highest) { AddOffset(context.Circuit, $"constraint.{Name}", lowest, highest, Offset); } }
/// <inheritdoc /> public void Register(CircuitContext context, IDiagnosticHandler diagnostics) { var highest = context.Nodes.Shorts[Highest]; var lowest = context.Nodes.Shorts[Lowest]; if (highest != lowest) { AddMinimum(context.Circuit, Name, lowest, highest, Minimum); } }
/// <summary> /// Displays the diagnostic mesasges for this job. /// </summary> /// <param name="diagnostics">The diagnostic message handler.</param> public void DisplayMessages(IDiagnosticHandler diagnostics) { // First pass all the local messages if (diagnostics != null) { foreach (var message in _logger.Messages) { diagnostics.Post(new DiagnosticMessage(message.Severity, message.Code, $"{message.Message} for {Filename}")); } } }
/// <summary> /// Parses a series of points. /// </summary> /// <param name="lexer">The lexer.</param> /// <param name="diagnostics">The diagnostics.</param> /// <returns>The list of points.</returns> public static List <Vector2> ParsePoints(SvgPathDataLexer lexer, IDiagnosticHandler diagnostics) { var points = new List <Vector2>(); while (lexer.Type != TokenType.EndOfContent) { // Keep parsing vectors lexer.ParseVector(diagnostics, out var p); points.Add(p); } return(points); }
/// <inheritdoc /> public override void DiscoverNodeRelationships(NodeContext context, IDiagnosticHandler diagnostics) { Vector2 offset = _origin is ITransformingDrawable tfd?tfd.TransformOffset(Offset) : Offset; if (offset.X.IsZero()) { context.Shorts.Group(X, _origin.X); } if (offset.Y.IsZero()) { context.Shorts.Group(Y, _origin.Y); } }
/// <inheritdoc /> public void Update(IBiasingSimulationState state, CircuitContext context, IDiagnosticHandler diagnostics) { double x = 0, y = 0; if (state.TryGetValue(context.Nodes.Shorts[X], out var xValue)) { x = xValue.Value; } if (state.TryGetValue(context.Nodes.Shorts[Y], out var yValue)) { y = yValue.Value; } Location = new(x, y); }
public override void DiscoverNodeRelationships(NodeContext context, IDiagnosticHandler diagnostics) { // Deal with shorts var direction = _origin is ITransformingDrawable tfd?tfd.TransformNormal(Direction) : Direction; if (direction.X.IsZero()) { context.Shorts.Group(X, _origin.X); } if (direction.Y.IsZero()) { context.Shorts.Group(Y, _origin.Y); } }
/// <summary> /// Tries to parse an optional coordinate. /// </summary> /// <param name="lexer">The lexer.</param> /// <param name="diagnostics">The diagnostics.</param> /// <param name="defaultValue">The default value.</param> /// <param name="result">The result.</param> /// <returns>Returns <c>true</c> if the coordinate was parsed; otherwise, <c>false</c>.</returns> public static bool TryParseCoordinate(this SvgPathDataLexer lexer, IDiagnosticHandler diagnostics, double defaultValue, out double result) { if (lexer.Branch(TokenType.Number, out var value)) { if (!double.TryParse(value.Content.ToString(), NumberStyles.Float, Culture, out result)) { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Warning, "DRAW001", $"Expected coordinate")); return(false); } return(true); } else { result = defaultValue; return(false); } }
/// <summary> /// Parse a coordinate attribute on an XML node. /// </summary> /// <param name="node">The XML node.</param> /// <param name="attributeName">The name of the attribute.</param> /// <param name="diagnostics">The diagnostics handler.</param> /// <param name="result">The result.</param> /// <returns>Returns <c>true</c> if the coordinate was parsed; otherwise, <c>false</c>.</returns> public static bool ParseCoordinate(this XmlNode node, string attributeName, IDiagnosticHandler diagnostics, out double result) { string value = node.Attributes?[attributeName]?.Value; if (value == null) { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Warning, "DRAW001", $"Expected attribute '{attributeName}' on {node.Name}.")); result = 0.0; return(false); } if (!double.TryParse(value, NumberStyles.Float, Culture, out result)) { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Warning, "DRAW001", $"Expected coordinate for '{attributeName}' on {node.Name}, but was '{value}'.")); result = 0.0; return(false); } return(true); }
private void RegisterFixed(CircuitContext context, IDiagnosticHandler diagnostics) { // No need to go through all these difficult things, let's just apply directly var map = context.Nodes.Shorts; string x = map[X]; string ox = map[_origin.X]; string y = map[Y]; string oy = map[_origin.Y]; var direction = _origin is ITransformingDrawable tfd?tfd.TransformNormal(Direction) : Direction; direction = direction.Order(ref ox, ref x, ref oy, ref y); if (x != ox) { OffsetConstraint.AddOffset(context.Circuit, X, ox, x, direction.X * MinimumOffset); } if (y != oy) { OffsetConstraint.AddOffset(context.Circuit, Y, oy, y, direction.Y * MinimumOffset); } }
/// <summary> /// Starts a number of jobs to be converted. /// </summary> /// <param name="jobs">The jobs to convert.</param> /// <param name="diagnostics">The diagnostics handler.</param> public static async Task DoJobs(IReadOnlyList <Job> jobs, IDiagnosticHandler diagnostics) { if (jobs == null || jobs.Count == 0) { return; } // Let's try to do as much as possible in parallel here ChromiumElementFormatter formatter = null; var formatterTask = Task.Run(() => formatter = new ChromiumElementFormatter()); try { var tasks = new Task[jobs.Count]; for (int i = 0; i < jobs.Count; i++) { tasks[i] = jobs[i].Compute(); } Task.WaitAll(tasks); // Render all the completed tasks await formatterTask; if (formatter == null) { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Warning, "SC001", "Could not create formatter")); } for (int i = 0; i < jobs.Count; i++) { jobs[i].DisplayMessages(diagnostics); if (!jobs[i].HasErrors) { await jobs[i].Render(formatter, diagnostics); } } } finally { // Dispose of our created formatter formatter?.Dispose(); } }
/// <summary> /// Posts a diagnostic message based on an error code and token. /// </summary> /// <param name="handler">The diagnostic message handler.</param> /// <param name="token">The token.</param> /// <param name="code">The error code.</param> /// <param name="arguments">The arguments for the error message.</param> public static SeverityLevel Post(this IDiagnosticHandler handler, Token token, ErrorCodes code, params string[] arguments) { // Get the severity and code from the attribute var attributes = typeof(ErrorCodes).GetField(code.ToString()).GetCustomAttributes(typeof(DiagnosticAttribute), false); if (attributes == null || attributes.Length == 0) { handler.Post(new DiagnosticMessage(SeverityLevel.Error, "?", $"Could not find error code data for '{code}'")); return(SeverityLevel.Error); } var info = (DiagnosticAttribute)attributes[0]; // Search for the message in the resource var message = Properties.Resources.ResourceManager.GetString(code.ToString(), CultureInfo.CurrentCulture); if (message == null) { message = info.Message; } handler.Post(new TokenDiagnosticMessage(token, info.Severity, info.Code, string.Format(message, arguments))); return(info.Severity); }
/// <inheritdoc /> public override void Register(CircuitContext context, IDiagnosticHandler diagnostics) { Vector2 offset = _origin is ITransformingDrawable tfd?tfd.TransformOffset(Offset) : Offset; var map = context.Nodes.Shorts; string x = map[X]; string ox = map[_origin.X]; string y = map[Y]; string oy = map[_origin.Y]; if (x != ox) { string i = $"{X}.i"; context.Circuit.Add(new Resistor($"R{X}", i, x, 1e-3)); context.Circuit.Add(new VoltageSource($"V{X}", i, ox, offset.X)); } if (y != oy) { string i = $"{Y}.i"; context.Circuit.Add(new Resistor($"R{Y}", i, y, 1e-3)); context.Circuit.Add(new VoltageSource($"V{Y}", y, oy, offset.Y)); } }
/// <inheritdoc /> public void Register(CircuitContext context, IDiagnosticHandler diagnostics) { _pins.Register(context, diagnostics); }
/// <summary> /// Parse a vector attribute on an XML node. /// </summary> /// <param name="node">The XML node.</param> /// <param name="xAttribute">The name of the attribute representing the X-coordinate.</param> /// <param name="yAttribute">The name of the attribute representing the Y-coordinate.</param> /// <param name="diagnostics">The diagnostics handler.</param> /// <param name="result">The result.</param> /// <returns>Returns <c>true</c> if the coordinate was parsed; otherwise, <c>false</c>.</returns> public static bool ParseVector(this XmlNode node, string xAttribute, string yAttribute, IDiagnosticHandler diagnostics, out Vector2 result) { bool success = true; success &= ParseCoordinate(node, xAttribute, diagnostics, out double x); success &= ParseCoordinate(node, yAttribute, diagnostics, out double y); result = new(x, y); return(success); }
/// <inheritdoc /> public abstract void Register(CircuitContext context, IDiagnosticHandler diagnostics);
/// <inheritdoc /> public override void Register(CircuitContext context, IDiagnosticHandler diagnostics) { // Left to whoever owns this pin... }
/// <summary> /// Creates a new subcircuit factory. /// </summary> /// <param name="key">The key.</param> /// <param name="definition">The definition.</param> /// <param name="pins">The pins.</param> /// <param name="diagnostics">The diagnostic handler.</param> /// <exception cref="ArgumentNullException">Thrown if an argument is <c>null</c>.</exception> public Subcircuit(string key, GraphicalCircuit definition, IEnumerable <IPin> pins, IDiagnosticHandler diagnostics) { if (string.IsNullOrWhiteSpace(key)) { throw new ArgumentNullException(nameof(key)); } _key = key; _circuit = definition ?? throw new ArgumentNullException(nameof(definition)); _pins = pins ?? throw new ArgumentNullException(nameof(pins)); if (!_circuit.Solved) { _circuit.Solve(diagnostics); } }
/// <inheritdoc /> public override void DiscoverNodeRelationships(NodeContext context, IDiagnosticHandler diagnostics) { // Left to whoever owns this pin... }
/// <inheritdoc /> public void Update(IBiasingSimulationState state, CircuitContext context, IDiagnosticHandler diagnostics) { }
/// <summary> /// Parse Svg path. /// </summary> /// <param name="lexer">The lexer.</param> /// <param name="b">The path builder.</param> /// <param name="diagnostics">The diagnostics message handler.</param> public static void Parse(SvgPathDataLexer lexer, PathBuilder b, IDiagnosticHandler diagnostics) { while (lexer.Type != TokenType.EndOfContent) { Vector2 h1, h2, p; double d; bool result = true; if (!lexer.Branch(TokenType.Command, out var cmd)) { diagnostics?.Post(new TokenDiagnosticMessage(cmd, SeverityLevel.Error, "DW001", $"Could not recognize the SVG path command '{cmd.Content}'")); break; } switch (cmd.Content.Span[0]) { case 'M': if (!lexer.ParseVector(diagnostics, out p)) { lexer.Skip(~TokenType.Command); continue; } b.MoveTo(p); while (lexer.TryParseVector(diagnostics, new(), out p)) { b.LineTo(p); } break; case 'm': if (!lexer.ParseVector(diagnostics, out p)) { lexer.Skip(~TokenType.Command); continue; } b.Move(p); while (lexer.TryParseVector(diagnostics, new(), out p)) { b.Line(p); } break; case 'L': if (!lexer.ParseVector(diagnostics, out p)) { lexer.Skip(~TokenType.Command); continue; } b.LineTo(p); while (lexer.TryParseVector(diagnostics, new(), out p)) { b.LineTo(p); } break; case 'l': if (!lexer.ParseVector(diagnostics, out p)) { lexer.Skip(~TokenType.Command); continue; } b.Line(p); while (lexer.TryParseVector(diagnostics, new(), out p)) { b.Line(p); } break; case 'H': if (!lexer.ParseCoordinate(diagnostics, out d)) { lexer.Skip(~TokenType.Command); continue; } b.HorizontalTo(d); while (lexer.TryParseCoordinate(diagnostics, 0.0, out d)) { b.HorizontalTo(d); } break; case 'h': if (!lexer.ParseCoordinate(diagnostics, out d)) { lexer.Skip(~TokenType.Command); continue; } b.Horizontal(d); while (lexer.TryParseCoordinate(diagnostics, 0.0, out d)) { b.Horizontal(d); } break; case 'V': if (!lexer.ParseCoordinate(diagnostics, out d)) { lexer.Skip(~TokenType.Command); continue; } b.VerticalTo(d); while (lexer.TryParseCoordinate(diagnostics, 0.0, out d)) { b.VerticalTo(d); } break; case 'v': if (!lexer.ParseCoordinate(diagnostics, out d)) { lexer.Skip(~TokenType.Command); continue; } b.Vertical(d); while (lexer.TryParseCoordinate(diagnostics, 0.0, out d)) { b.Vertical(d); } break; case 'C': result &= lexer.ParseVector(diagnostics, out h1); result &= lexer.ParseVector(diagnostics, out h2); result &= lexer.ParseVector(diagnostics, out p); if (!result) { lexer.Skip(~TokenType.Command); continue; } b.CurveTo(h1, h2, p); while (lexer.TryParseVector(diagnostics, new(), out h1) && lexer.ParseVector(diagnostics, out h2) && lexer.ParseVector(diagnostics, out p)) { b.CurveTo(h1, h2, p); } break; case 'c': result &= lexer.ParseVector(diagnostics, out h1); result &= lexer.ParseVector(diagnostics, out h2); result &= lexer.ParseVector(diagnostics, out p); if (!result) { lexer.Skip(~TokenType.Command); continue; } b.Curve(h1, h2, p); while (lexer.TryParseVector(diagnostics, new(), out h1) && lexer.ParseVector(diagnostics, out h2) && lexer.ParseVector(diagnostics, out p)) { b.Curve(h1, h2, p); } break; case 'S': result &= lexer.ParseVector(diagnostics, out h2); result &= lexer.ParseVector(diagnostics, out p); if (!result) { lexer.Skip(~TokenType.Command); continue; } b.SmoothTo(h2, p); while (lexer.TryParseVector(diagnostics, new(), out h2) && lexer.ParseVector(diagnostics, out p)) { b.SmoothTo(h2, p); } break; case 's': result &= lexer.ParseVector(diagnostics, out h2); result &= lexer.ParseVector(diagnostics, out p); if (!result) { lexer.Skip(~TokenType.Command); continue; } b.Smooth(h2, p); while (lexer.TryParseVector(diagnostics, new(), out h2) && lexer.ParseVector(diagnostics, out p)) { b.Smooth(h2, p); } break; case 'Q': result &= lexer.ParseVector(diagnostics, out h1); result &= lexer.ParseVector(diagnostics, out p); if (!result) { lexer.Skip(~TokenType.Command); continue; } b.QuadCurveTo(h1, p); while (lexer.TryParseVector(diagnostics, new(), out h1) && lexer.ParseVector(diagnostics, out p)) { b.QuadCurveTo(h1, p); } break; case 'q': result &= lexer.ParseVector(diagnostics, out h1); result &= lexer.ParseVector(diagnostics, out p); if (!result) { lexer.Skip(~TokenType.Command); continue; } b.QuadCurve(h1, p); while (lexer.TryParseVector(diagnostics, new(), out h1) && lexer.ParseVector(diagnostics, out p)) { b.QuadCurve(h1, p); } break; case 'T': if (!lexer.ParseVector(diagnostics, out p)) { lexer.Skip(~TokenType.Command); continue; } b.SmoothQuadTo(p); while (lexer.TryParseVector(diagnostics, new(), out p)) { b.SmoothQuadTo(p); } break; case 't': if (!lexer.ParseVector(diagnostics, out p)) { lexer.Skip(~TokenType.Command); continue; } b.SmoothQuad(p); while (lexer.TryParseVector(diagnostics, new(), out p)) { b.SmoothQuad(p); } break; case 'z': case 'Z': b.Close(); break; default: diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Error, "DRAW001", $"Could not recognize path command '{cmd}'.")); break; } } }
/// <inheritdoc /> public void DiscoverNodeRelationships(NodeContext context, IDiagnosticHandler diagnostics) { }
/// <inheritdoc /> public void Update(IBiasingSimulationState state, CircuitContext context, IDiagnosticHandler diagnostics) { var map = context.Nodes.Shorts; double x, y; if (state.TryGetValue(map[X], out var value)) { x = value.Value; } else { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Error, "U001", $"Could not find variable '{X}'.")); x = 0.0; } if (state.TryGetValue(map[Y], out value)) { y = value.Value; } else { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Error, "U001", $"Could not find variable '{X}'.")); y = 0.0; } Location = new(x, y); if (state.TryGetValue(map[_pins.Right], out value)) { x = value.Value; } else { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Error, "U001", $"Could not find variable '{X}'.")); x = 0.0; } if (state.TryGetValue(map[_pins.Bottom], out value)) { y = value.Value; } else { diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Error, "U001", $"Could not find variable '{X}'.")); y = 0.0; } EndLocation = new(x, y); // Update all pin locations as well // We ignore pin 0, because that is a dummy pin for (int i = 1; i < _pins.Count; i++) { _pins[i].Update(state, context, diagnostics); } }