/// <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 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); } }
/// <summary> /// Tries to parse an optional coordinate. /// </summary> /// <param name="lexer">The lexer.</param> /// <param name="diagnostics">The diagnostics.</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 SvgPathDataLexer lexer, IDiagnosticHandler diagnostics, 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 = 0.0; diagnostics?.Post(new DiagnosticMessage(SeverityLevel.Warning, "DRAW001", $"Expected coordinate")); 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); }
/// <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> /// 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); }
/// <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> /// 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; } } }