private static List <ChartString> CookDashSigns(ChartOptions options, Offsets offsets, List <int> dashesX, List <int> dashesY) { List <ChartString> result = new List <ChartString>(); // X dashes' signs foreach (int i in dashesX) { float tx = options.SizeX * (i - options.MinX) / (options.MaxX - options.MinX); if (i != 0 && tx - i.ToString().Length *AproximateCharWidth >= 0 && tx + i.ToString().Length *AproximateCharWidth <= options.SizeX) { result.Add(new ChartString { Location = new PointF(tx - i.ToString().Length *AproximateCharWidth, offsets.SignOffsetX), Text = i.ToString() }); } } // Y dashes signs foreach (int i in dashesY) { float ty = options.SizeY - options.SizeY * (i - options.MinY) / (options.MaxY - options.MinY); if (i != 0 && ty - i.ToString().Length *AproximateCharHigh >= 0 && ty + i.ToString().Length *AproximateCharHigh <= options.SizeY) { result.Add(new ChartString { Location = new PointF(offsets.SignOffsetY, ty - AproximateCharHigh), Text = i.ToString() }); } } return(result); }
private static List <ChartLine> CookDashLines(ChartOptions options, Offsets offsets, float xAxisLocation, float yAxisLocation, List <int> dashesX, List <int> dashesY) { List <ChartLine> result = new List <ChartLine>(); // X axis dashes foreach (int i in dashesX) { float tx = options.SizeX * (i - options.MinX) / (options.MaxX - options.MinX); if (xAxisLocation == -1 || tx <= options.SizeX - AxisArrowLength) { result.Add(new ChartLine { Start = new PointF(tx, offsets.DashStartX), End = new PointF(tx, offsets.DashEndX) }); } } // Y axis dashes foreach (int i in dashesY) { float ty = options.SizeY - options.SizeY * (i - options.MinY) / (options.MaxY - options.MinY); if (yAxisLocation == -1 || ty >= AxisArrowLength) { result.Add(new ChartLine { Start = new PointF(offsets.DashStartY, ty), End = new PointF(offsets.DashEndY, ty) }); } } return(result); }
private static Bitmap DrawGrid(List <ChartLine> gridLines, ChartOptions options) { Bitmap result = new Bitmap(options.SizeX + 1, options.SizeY + 1); DrawLines(result, gridLines, GridPen); return(result); }
public static Offsets Cook(ChartOptions options, float xAxisLocation, float yAxisLocation) { // X axis elements Offsets result = new Offsets(); if (options.MinY >= 0) { result.DashStartX = options.SizeY - DashLengthHalf; result.DashEndX = options.SizeY; result.SignOffsetX = options.SizeY - SignOffsetAboveLeft; } else if (options.MaxY <= 0) { result.DashStartX = 1; result.DashEndX = DashLengthHalf + 1; result.SignOffsetX = DashLengthHalf + 1; } else { result.DashStartX = (int)Math.Round(xAxisLocation - DashLengthHalf); result.DashEndX = (int)Math.Round(xAxisLocation + DashLengthHalf); if (Math.Abs(options.MinY) > options.MaxY) { result.SignOffsetX = (int)Math.Round(xAxisLocation) + DashLengthHalf + 1; } else { result.SignOffsetX = (int)Math.Round(xAxisLocation) - SignOffsetAboveLeft; } } // Y axis elements if (options.MinX >= 0) { result.DashStartY = 1; result.DashEndY = DashLengthHalf + 1; result.SignOffsetY = DashLengthHalf + 1; } else if (options.MaxX <= 0) { result.DashStartY = options.SizeX - DashLengthHalf; result.DashStartY = options.SizeX; result.SignOffsetY = options.SizeX - SignOffsetAboveLeft; } else { result.DashStartY = (int)Math.Round(yAxisLocation - DashLengthHalf); result.DashEndY = (int)Math.Round(yAxisLocation + DashLengthHalf); if (Math.Abs(options.MinX) > options.MaxX) { result.SignOffsetY = (int)Math.Round(yAxisLocation) - SignOffsetAboveLeft; } else { result.SignOffsetY = (int)Math.Round(yAxisLocation) + DashLengthHalf + 1; } } return(result); }
private static List <ChartLine> CookAxisLines(ChartOptions options, out float xAxisLocation, out float yAxisLocation) { List <ChartLine> result = new List <ChartLine>(); xAxisLocation = -1; yAxisLocation = -1; // X Axis and arrow if (options.MinY <= 0 && options.MaxY >= 0) { xAxisLocation = options.SizeY - options.SizeY * (-options.MinY) / (-options.MinY + options.MaxY); if (xAxisLocation < 0.5) { xAxisLocation = 1; } result.Add(new ChartLine { Start = new PointF(0, xAxisLocation), End = new PointF(options.SizeX, xAxisLocation) }); if (options.MinY < 0) { result.Add(new ChartLine { Start = new PointF(options.SizeX - AxisArrowLength, xAxisLocation + AxisArrowWidth), End = new PointF(options.SizeX, xAxisLocation) }); } if (options.MaxY > 0) { result.Add(new ChartLine { Start = new PointF(options.SizeX - AxisArrowLength, xAxisLocation - AxisArrowWidth), End = new PointF(options.SizeX, xAxisLocation) }); } } // Y Axis and arrow if (options.MinX <= 0 && options.MaxX >= 0) { yAxisLocation = options.SizeX * (-options.MinX) / (-options.MinX + options.MaxX); if (yAxisLocation < 0.5) { yAxisLocation = 1; } result.Add(new ChartLine { Start = new PointF(yAxisLocation, 0), End = new PointF(yAxisLocation, options.SizeY) }); if (options.MinX < 0) { result.Add(new ChartLine { Start = new PointF(yAxisLocation - AxisArrowWidth, AxisArrowLength + 1), End = new PointF(yAxisLocation, 1) }); } if (options.MaxX > 0) { result.Add(new ChartLine { Start = new PointF(yAxisLocation + AxisArrowWidth, AxisArrowLength + 1), End = new PointF(yAxisLocation, 1) }); } } return(result); }
private static List <List <PointF> > CalculateChartGraph(ChartOptions chartOptions, MathFunction f) { List <List <PointF> > allFragments = new List <List <PointF> >(); List <PointF> fragment = new List <PointF>(); for (int i = 1; i <= chartOptions.SizeX; i++) { // Cook curve fragments (list of points for every fragment) double x = GetRealX(chartOptions, i); double y = f(x); if (double.IsInfinity(y) || double.IsNaN(y)) // For example: when processing x asymptote or logarithm of negative value { if (fragment.Count > 0) { allFragments.Add(fragment); fragment = new List <PointF>(); } } else { float wy = GetRealY(chartOptions, (float)y); if ((float)y > chartOptions.MaxY || (float)y < chartOptions.MinY) { if (fragment.Count > 0) { fragment.Add(new PointF(i, wy)); allFragments.Add(fragment); fragment = new List <PointF>(); } } else { if (fragment.Count == 0) { fragment.Add(new PointF(i, wy)); } else { fragment.Add(new PointF(i, wy)); } } } } if (fragment.Count > 0) { allFragments.Add(fragment); } return(allFragments); }
private static int DetectStep(ChartOptions options) { int step; if ((options.MaxX - options.MinX) > (options.MaxY - options.MinY)) { step = Convert.ToInt32(Math.Round((options.MaxX - options.MinX) / StepDeviderMax)); } else { step = Convert.ToInt32(Math.Round((options.MaxY - options.MinY) / StepDeviderMax)); } if (step == 0) { step = 1; } return(step); }
private void Build_Click(object sender, EventArgs e) { if (Func_box.Text != null) { Func_box.Text = Func_box.Text.Replace(" ", ""); } if (string.IsNullOrEmpty(Func_box.Text)) { MessageBox.Show("Не задана функция графика"); return; } // Code generation of math function MathFuncCodeGenerator generatedFuncCode = MathFuncCodeGenerator.Generate(Func_box.Text); if (string.IsNullOrEmpty(generatedFuncCode.Error)) { FuncCode_box.Text = "Код функции : " + generatedFuncCode.OutputText; } else { MessageBox.Show("Ошибка : " + generatedFuncCode.Error); return; } // Compile (with reflection) method with generated math function CompiledMathFunction compiledMathFunction = MathFuncCodeCompiler.CompileMathFuction(generatedFuncCode.OutputText); if (!string.IsNullOrWhiteSpace(compiledMathFunction.Error)) { FuncCode_box.Text = $"{FuncCode_box.Text}\nВозникли ошибки компиляции: {compiledMathFunction.Error}"; return; } ChartOptions chartOptions = AnalyzeChartInputParametersAndCookChartOptions(Xmin_box.Text, Xmax_box.Text, Ymin_box.Text, Ymax_box.Text); if (chartOptions.Errors.Count > 0) { MessageBox.Show("Обнаружны ошибки задания диапазона: " + string.Join("! ", chartOptions.Errors)); return; } // Create ChartWindow form ChartWindow f = new ChartWindow(); f.InitializeChart(Func_box.Text, chartOptions, compiledMathFunction.Func); f.Show(); }
public void InitializeChart(string mathFuncText, ChartOptions chartParametrs, MathFunction mathFunc) { FunctionLabel.Text = "y=" + mathFuncText; // Adjusting of window and chart area Size = new Size(chartParametrs.SizeX + 23, chartParametrs.SizeY + 66); FormBorderStyle = FormBorderStyle.FixedSingle; Chart.Size = new Size(chartParametrs.SizeX + 1, chartParametrs.SizeY + 1); Chart.Location = new Point(3, 23); Chart.Visible = true; // Initialization and drawing of chart images Images = new ChartWindowGraphics(chartParametrs); Images.CookBitmaps(); Images.AddChartImage(ChartImageGraphics.GetChartImage(chartParametrs, mathFunc)); // Initialization and adjusting of axis/grid options' checks GridOption.Location = new Point(chartParametrs.SizeX - 100, 3); AxisOption.Location = new Point(chartParametrs.SizeX - 40, 3); AxisOption.Checked = true; GridOption.Checked = false; }
private static Bitmap DrawImage(ChartOptions chartOptions, List <List <PointF> > allFragments) { Bitmap image = new Bitmap(chartOptions.SizeX + 1, chartOptions.SizeY + 1); Graphics g = Graphics.FromImage(image); using (g) { g.Clear(Color.White); Pen p = new Pen(Color.Blue, 2); p.Alignment = System.Drawing.Drawing2D.PenAlignment.Center; foreach (List <PointF> onef in allFragments) { if (onef.Count == 1) { onef.Add(onef[0]); } // If fragment contains only 1 point - add the same second point in order to draw line g.DrawCurve(p, onef.ToArray()); } } return(image); }
private static List <ChartLine> CookGridLines(ChartOptions options, List <int> dashesX, List <int> dashesY) { List <ChartLine> result = new List <ChartLine>(); // Y parallels foreach (int i in dashesX) { float tx = options.SizeX * (i - options.MinX) / (options.MaxX - options.MinX); result.Add(new ChartLine { Start = new PointF(tx, 0), End = new PointF(tx, options.SizeY + 1) }); } // X parallels foreach (int i in dashesY) { float ty = options.SizeY - options.SizeY * (i - options.MinY) / (options.MaxY - options.MinY); result.Add(new ChartLine { Start = new PointF(0, ty), End = new PointF(options.SizeX + 1, ty) }); } return(result); }
public ChartWindowGraphics(ChartOptions options) { Options = options; }
public static ChartOptions AnalyzeChartInputParametersAndCookChartOptions( string minX, string maxX, string minY, string maxY) { ChartOptions chartOptions = new ChartOptions(); chartOptions.Errors = new List <string>(); if (!float.TryParse(minX, out chartOptions.MinX)) { chartOptions.Errors.Add("Нечисловое значение в поле дипазона \"min X\""); } if (!float.TryParse(maxX, out chartOptions.MaxX)) { chartOptions.Errors.Add("Нечисловое значение в поле дипазона \"max X\""); } if (!float.TryParse(minY, out chartOptions.MinY)) { chartOptions.Errors.Add("Нечисловое значение в поле дипазона \"min Y\""); } if (!float.TryParse(maxY, out chartOptions.MaxY)) { chartOptions.Errors.Add("Нечисловое значение в поле дипазона \"max Y\""); } if (chartOptions.Errors.Count != 0) { return(chartOptions); } if (chartOptions.MinX > 1000 || chartOptions.MinX < -1000) { chartOptions.Errors.Add("Значение в поле \"min X\" находится за пределами допустимого диапазона [-1000..1000]"); } if (chartOptions.MaxX > 1000 || chartOptions.MaxX < -1000) { chartOptions.Errors.Add("Значение в поле \"max X\" находится за пределами допустимого диапазона [-1000..1000]"); } if (chartOptions.MinY > 1000 || chartOptions.MinY < -1000) { chartOptions.Errors.Add("Значение в поле \"min Y\" находится за пределами допустимого диапазона [-1000..1000]"); } if (chartOptions.MaxY > 1000 || chartOptions.MaxY < -1000) { chartOptions.Errors.Add("Значение в поле \"max Y\" находится за пределами допустимого диапазона [-1000..1000]"); } if (chartOptions.MinX == chartOptions.MaxX) { chartOptions.Errors.Add("\"min X\" и \"max X\" не могут быть равными"); } if (chartOptions.MinY == chartOptions.MaxY) { chartOptions.Errors.Add("\"min Y\" и \"max Y\" не могут быть равными"); } if (chartOptions.Errors.Count != 0) { return(chartOptions); } if (chartOptions.MinX > chartOptions.MaxX) { SwapFloats(ref chartOptions.MinX, ref chartOptions.MaxX); } if (chartOptions.MinY > chartOptions.MaxY) { SwapFloats(ref chartOptions.MinY, ref chartOptions.MaxY); } double lx = chartOptions.MaxX - chartOptions.MinX; double ly = chartOptions.MaxY - chartOptions.MinY; double dxy = lx / ly; if (dxy < 50.0 / 800 || dxy > 800 / 50.0) { chartOptions.Errors.Add("Соотношение диапазонов вывода не может быть больше 16"); return(chartOptions); } if (lx > ly) { chartOptions.SizeX = 800; chartOptions.SizeY = (int)Math.Round(800 * ly / lx); } else { chartOptions.SizeY = 800; chartOptions.SizeX = (int)Math.Round(800 * lx / ly); } return(chartOptions); }
private static float GetRealY(ChartOptions me, float y) { return((me.MaxY - y) * me.SizeY / (me.MaxY - me.MinY)); }
private static float GetRealX(ChartOptions me, int x) { return(me.MinX + (me.MaxX - me.MinX) * x / me.SizeX); }
public static Bitmap GetChartImage(ChartOptions chartOptions, MathFunction f) { List <List <PointF> > allFragments = CalculateChartGraph(chartOptions, f); return(DrawImage(chartOptions, allFragments)); }