private void MenuShowChart_Clicked(object sender, RoutedEventArgs e) { try { Func <double, double> fx = this.Fx.CompileDynamicMethod(); Func <double, double> gx = this.Gx.CompileDynamicMethod(); if (this.chartData.YTo == null || this.chartData.YFrom == null) //chart data y-values were not initialized { Parallel.Invoke(() => { Extremum extremum = DiagramWindow.FuncFindMinMax(new Func <double, double>[] { fx, gx }, this.chartData.XFrom, this.chartData.XTo); this.chartData.YFrom = -Math.Abs(1.5 * Math.Max(Math.Abs(extremum.Min), Math.Abs(extremum.Max))); this.chartData.YTo = -chartData.YFrom; }); } DiagramWindow diagWnd = new DiagramWindow(chartData.XFrom, chartData.XTo, chartData.YFrom, chartData.YTo, chartData.Dx); diagWnd.DrawGraph(new Func <double, double>[] { fx, gx }, this.chartData.XFrom, this.chartData.XTo); diagWnd.Owner = this; diagWnd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen; diagWnd.ShowDialog(); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }
private void MenuChartConfig_Clicked(object sender, RoutedEventArgs e) { double xFrom = this.chartData.XFrom; double xTo = this.chartData.XTo; Func <double, double> fx = this.Fx.CompileDynamicMethod(); Func <double, double> gx = this.Gx.CompileDynamicMethod(); Extremum extremum = DiagramWindow.FuncFindMinMax(new Func <double, double>[] { fx, gx }, xFrom, xTo); double yFrom = this.chartData.YFrom ?? -Math.Abs(1.5 * Math.Max(Math.Abs(extremum.Min), Math.Abs(extremum.Max))); double yTo = -yFrom; ChartConfigWindow configWnd = new ChartConfigWindow(xFrom, xTo, yFrom, yTo, this.chartData.Dx, this.BindYToFx, this.BindYToGx); configWnd.ChartConfigChanged += delegate(object o, ChartEventArgs eArgs) { this.chartData.XFrom = eArgs.From.X; this.chartData.XTo = eArgs.To.X; this.chartData.YFrom = eArgs.From.Y; this.chartData.YTo = eArgs.To.Y; this.chartData.Dx = eArgs.Dx; this.BindYToFx = eArgs.BindToFx; this.BindYToGx = eArgs.BindToGx; if (this.BindYToFx && this.BindYToGx) { extremum = DiagramWindow.FuncFindMinMax(new Func <double, double>[] { fx, gx }, xFrom, xTo); } else if (this.BindYToFx) { extremum = DiagramWindow.FuncFindMinMax(new Func <double, double>[] { fx }, xFrom, xTo); } else if (this.BindYToGx) { extremum = DiagramWindow.FuncFindMinMax(new Func <double, double>[] { gx }, xFrom, xTo); } this.chartData.YFrom = -Math.Abs(1.5 * Math.Max(Math.Abs(extremum.Min), Math.Abs(extremum.Max))); this.chartData.YTo = -this.chartData.YFrom; }; configWnd.Owner = this; configWnd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner; configWnd.Show(); }
private void DrawGraph(DrawArgs args, Action EndCallback = null) { double from = args.From, to = args.To; //while (!Dispatcher.Invoke<bool>(() => drawCanvas.IsLoaded)) //{ //} int width = args.UIWidth; //(int)drawCanvas.ActualWidth; int height = args.UIHeight; //(int)drawCanvas.ActualHeight; DrawingVisual drawingVisual = new DrawingVisual(); using (DrawingContext c = drawingVisual.RenderOpen()) { //Brushes SolidColorBrush textBrush = new SolidColorBrush(Colors.Black); Pen axisPen = new Pen(Brushes.Black, 1); //Pen graphPen = new Pen(Brushes.Red, 1); const int FontSize = 12; double xFrom, xTo; double yFrom, yTo; // Func<double, double> f = args.F; this.xFrom = xFrom = from; this.xTo = xTo = to; Extremum extremum = FuncFindMinMax(args.F, xFrom, xTo); if (this.yFrom == null || this.yTo == null) { this.yFrom = yFrom = -Math.Abs(1.5 * Math.Max(Math.Abs(extremum.Min), Math.Abs(extremum.Max))); //чтобы хотя бы часть графика попала в область отображения this.yTo = yTo = -yFrom; } else { yFrom = this.yFrom.Value; yTo = this.yTo.Value; } //інтервал повинен бути симетричним (потрібно для рисування осей координат) if (-xFrom != xTo) { double radius = Math.Max(Math.Abs(xFrom), Math.Abs(xTo)); xFrom = -radius; xTo = radius; } //Scales double xScale = width / (xTo - xFrom); double yScale = height / (yTo - yFrom); //Origin int x0 = width / 2, y0 = height / 2; //draw horizontal axis c.DrawLine(axisPen, new Point(0, y0), new Point(width, y0)); //draw verical axis c.DrawLine(axisPen, new Point(x0, 0), new Point(x0, height)); //draw horizontal divisions int N = 10; //number of divisions double valueX = (xTo - xFrom) / N, //ціна поділки divHeight = 2; //висота поділки int stepX = width / N; //крок по вісі Х (від поділки до поділки) double divCounter = xFrom; for (int x = x0 % stepX; x < width; x += stepX, divCounter += valueX) { c.DrawLine(axisPen, new Point(x, y0 - divHeight), new Point(x, y0 + divHeight)); FormattedText formattedText = new FormattedText(Math.Round(divCounter, 4) + "", new System.Globalization.CultureInfo("en-us"), FlowDirection.LeftToRight, new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), FontSize, textBrush); c.DrawText(formattedText, new Point(x - FontSize, y0 + divHeight)); //!!!!!!!!FontSize } //draw vertical divisions double valueY = (yTo - yFrom) / N; double divWidth = divHeight; //division width (height for horizontal axis) int stepY = height / N; divCounter = yTo; for (int y = y0 % stepY; y < height; y += stepY, divCounter -= valueY) { if (y == y0) { continue; } c.DrawLine(axisPen, new Point(x0 - divWidth, y), new Point(x0 + divWidth, y)); int divCounterLength = divCounter.ToString().Length; //кількість символів у числовому записі поділки FormattedText formattedText = new FormattedText(Math.Round(divCounter, 4) + "", new System.Globalization.CultureInfo("en-us"), FlowDirection.LeftToRight, new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), FontSize, textBrush); c.DrawText(formattedText, new Point(x0 - ((Math.Truncate(yTo)).ToString().Length + 5) * 8 - 2 * divWidth, y - FontSize)); //!!!!!!!!FontSize //* FontSize - divWidth * 2 } //draw desired graph int colorIndex = 0; foreach (Func <double, double> f in args.F) { Pen graphPen = new Pen(new SolidColorBrush(this.lineColors[colorIndex]), 1); //set line color colorIndex++; xFrom = from; xTo = to; //dx = valueX / 10000.0;//CalculateDX(f);//0.00001; double xPrev = xFrom, yPrev = f(xFrom); float xCorrection = x0 % stepX; float yCorrection = y0 % stepY; Dispatcher.Invoke(() => { progressBar.Value = xFrom; progressBar.Minimum = xFrom; progressBar.Maximum = xTo; }); for (double x = xFrom + dx; x < xTo; x += dx) { double fx; try { fx = f(x); } catch (DivideByZeroException) { continue; } if (fx > 2 * yTo || fx < 2 * yFrom) //если график ушел на бесконечность { while (fx > 2 * yTo || fx < 2 * yFrom) //пропустить этот участок { manualResetEvent.WaitOne(); cancelToken.Token.ThrowIfCancellationRequested(); if (x > xTo) { break; } x += dx; try { fx = f(x); } catch (DivideByZeroException) { continue; } } xPrev = x; yPrev = fx; } //if (Math.Abs(fx - yPrev) < 0.02) //avoid drawing the same point multiple times = пропустить очень-очень близкие пары значений // continue; if (ArePointsEqual(PointToScreen( new Point(xPrev, yPrev), extremum.Max, extremum.Min, width, height), PointToScreen(new Point(x, fx), extremum.Max, extremum.Min, width, height), 1)) { continue; } manualResetEvent.WaitOne(); cancelToken.Token.ThrowIfCancellationRequested(); c.DrawLine(graphPen, new Point(xPrev * xScale + x0, -yPrev * yScale + y0), new Point(x * xScale + x0, -fx * yScale + y0)); Dispatcher.Invoke(() => progressBar.Value = x); xPrev = x; yPrev = fx; } } } manualResetEvent.WaitOne(); cancelToken.Token.ThrowIfCancellationRequested(); if (EndCallback != null) { EndCallback(); } args.visualTargetPS.RootVisual = drawingVisual; //updating visual tree }
private void MenuReport_Click(object sender, RoutedEventArgs e) { try { Func <double, double> fx = this.Fx.CompileDynamicMethod(); Func <double, double> gx = this.Gx.CompileDynamicMethod(); if (this.chartData.YTo == null || this.chartData.YFrom == null) //chart data y-values were not initialized { Parallel.Invoke(() => { Extremum extremum = DiagramWindow.FuncFindMinMax(new Func <double, double>[] { fx, gx }, this.chartData.XFrom, this.chartData.XTo); this.chartData.YFrom = -Math.Abs(1.5 * Math.Max(Math.Abs(extremum.Min), Math.Abs(extremum.Max))); this.chartData.YTo = -chartData.YFrom; }); } DiagramWindow diagWnd = new DiagramWindow(chartData.XFrom, chartData.XTo, chartData.YFrom, chartData.YTo, chartData.Dx); diagWnd.Owner = this; RenderTargetBitmap rtb = diagWnd.DrawGraphToImage(new Func <double, double>[] { fx, gx }, width: 800, height: 800); diagWnd.Close(); PngBitmapEncoder png = new PngBitmapEncoder(); png.Frames.Add(BitmapFrame.Create(rtb)); using (Stream stm = File.Create("diagram.png")) { png.Save(stm); } //generate pdf-------------------------------------------------------- PdfDocument doc = new PdfDocument(); doc.Info.Title = "RootFinder Report"; PdfPage page1 = doc.AddPage(); // Get an XGraphics object for drawing XGraphics gfx = XGraphics.FromPdfPage(page1); // Create a font XFont font = new XFont("Times New Roman", 14, XFontStyle.Regular); //generate a report--------------------------------------------------------------------------------------------------------------- StringBuilder report = new StringBuilder(); string task = "Finding roots of equations using dynamic expression tree generation and function interpolation\r\n" + "\tUsed algorithms: Shunting-yard algorithm and Lagrange interpolation.\r\n\r\n"; report.Append(task); report.AppendFormat("Search interval: {0}\r\n", lblSrcInterval.Content); report.AppendFormat("Eps.: {0}\r\n", lblEps.Content); report.AppendFormat("Interpolation error: {0}\r\n", lblInterpError.Content); report.AppendFormat("Number of roots: {0}\r\n", lblRoots.Content); report.AppendFormat("Power of Lagrange polynomial: {0}\r\n", lblLagPower.Content); report.AppendFormat("Roots are shown on the page #2\r\n", lblInterpError.Content); //generate a report--------------------------------------------------------------------------------------------------------------- XTextFormatter tf = new XTextFormatter(gfx); XRect rect = new XRect(10, 10, page1.Width - 10, 150); gfx.DrawRectangle(XBrushes.SeaShell, rect); //tf.Alignment = ParagraphAlignment.Left; tf.DrawString(report.ToString(), font, XBrushes.Black, rect, XStringFormats.TopLeft); XImage img = XImage.FromFile("diagram.png"); gfx.DrawImage(img, (page1.Width - img.PixelWidth / 1.5) / 2.0, 250, img.PixelWidth / 1.5, img.PixelHeight / 1.5); //page#2 - roots const int stringsPerPage = 50; int k = 0; for (; k < this.roots.Count; k += stringsPerPage) { StringBuilder rootsStr = new StringBuilder(); if (k == 0) { rootsStr.AppendLine("Roots found:\r\n"); } for (int i = 0; i < stringsPerPage && i + k < this.roots.Count; i++) { rootsStr.AppendLine(string.Format("{0}", this.roots[i + k])); } PdfPage page2 = doc.AddPage(); gfx = XGraphics.FromPdfPage(page2); gfx.DrawRectangle(XBrushes.White, rect); tf = new XTextFormatter(gfx); rect = new XRect(10, 10, page2.Width - 10, page2.Height - 10); tf.DrawString(rootsStr.ToString(), font, XBrushes.Black, rect, XStringFormats.TopLeft); } using (FileStream fStream = new FileStream("report.pdf", FileMode.Create)) { doc.Save(fStream); } Process.Start("report.pdf"); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }