/// <summary> /// Reset zoom on all plot axes. /// </summary> /// <param name="sender">Not used.</param> /// <param name="e">Not used.</param> private void ButtonResetZoom_Click(object sender, RoutedEventArgs e) { PlotView.ResetAllAxes(); }
public MainWindow() : base(new[] { "resm:OxyPlot.Avalonia.Themes.Default.xaml?assembly=OxyPlot.Avalonia" }) { var grRoot = new Grid() { DataContext = m, Margin = new Thickness(10) }; grRoot.RowDefinitions.Add(new RowDefinition(1, GridUnitType.Auto)); grRoot.RowDefinitions.Add(new RowDefinition(1, GridUnitType.Star)); grRoot.RowDefinitions.Add(new RowDefinition(100, GridUnitType.Pixel)); pv = new PlotView(); pv.Model = new PlotModel(); Grid.SetRow(pv, 1); grRoot.Children.Add(pv); var grSplit = new GridSplitter() { Height = 10, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top }; Grid.SetRow(grSplit, 2); grRoot.Children.Add(grSplit); tboxLog = new TextBox() { Margin = new Thickness(0, 20, 0, 0) }; Grid.SetRow(tboxLog, 2); grRoot.Children.Add(tboxLog); var durationConverter = new QuantityConverter((s, c) => Duration.Parse(s, c)); var rotationalSpeedConverter = new QuantityConverter((s, c) => RotationalSpeed.Parse(s, c)); { var sp = new StackPanel() { Orientation = Avalonia.Layout.Orientation.Vertical }; Func <string, TextBlock> tblkField = (s) => new TextBlock { Text = s, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, FontWeight = FontWeight.Bold, Margin = new Thickness(10, 0, 0, 0) }; Func <string, IValueConverter, TextBox> tboxField = (propname, cvt) => { var tbox = new TextBox { MinWidth = 100, Margin = new Thickness(10, 0, 0, 0) }; tbox[!TextBox.TextProperty] = new Binding(propname) { Mode = BindingMode.TwoWay, Converter = cvt }; return(tbox); }; { var spH = new StackPanel() { Orientation = Avalonia.Layout.Orientation.Horizontal }; sp.Children.Add(spH); TextBox durationTbox = null; spH.Children.Add(tblkField("Duration").Eval((tblk) => { tblk.Margin = new Thickness(); return(tblk); })); spH.Children.Add(durationTbox = tboxField("Duration", durationConverter)); var sld = new Slider() { Width = 200, Minimum = 0.5, Maximum = 10, LargeChange = 0.5, SmallChange = 0.5, Value = m.Duration.Seconds }; sld.PropertyChanged += (a, b) => { if (b.Property.Name == "Value") { var prev = m.Duration.Seconds; var next = sld.Value.MRound(0.5); if (prev != next) { m.Duration = Duration.FromSeconds(next); durationTbox.Text = m.Duration.ToString(); Recompute(); } } }; spH.Children.Add(sld); spH.Children.Add(tblkField("TargetSpeed")); spH.Children.Add(tboxField("TargetSpeed", rotationalSpeedConverter)); spH.Children.Add(tblkField("RenderPts")); spH.Children.Add(tboxField("RenderPts", null)); } { sp.Children.Add(new TextBlock() { Text = "plot mouse LEFT:(show value) - WHEEL:(zoom 1clk=rect-zoom 2clk=fit) - RIGHT:pan", Margin = new Thickness(0, 10, 0, 0) }); } var btnRefresh = new Button() { Content = "Refresh" }; btnRefresh.Click += (a, b) => { Recompute(); }; sp.Children.Add(btnRefresh); Grid.SetRow(sp, 0); grRoot.Children.Add(sp); } { Recompute(); pv.ResetAllAxes(); pv.InvalidatePlot(); } this.Content = grRoot; }
void Recompute() { pv.Model.Series.Clear(); var sb = new StringBuilder(); var accelBase = "1-cos(t)"; var accelOverDuration = accelBase.Substitute("t", $"(t/(d/2)*2*pi)"); var accelCoeff = $"s / abs({accelOverDuration.Integrate("t").Substitute("t", "(d/2)")})"; var accel = $"({accelCoeff}) * ({accelOverDuration})"; var accelInt = accel.Integrate("t"); var speed = accelInt; var speedAtHalf = accelInt.Substitute("t", "(d/2)"); var speedInt = speed.Integrate("t"); var posAtZero = speedInt.Substitute("t", 0); var pos = $"({speedInt})-{(posAtZero)}"; var posAtHalf = pos.Substitute("t", "(d/2)"); var targetspeed = $"{pos.ToString()}=x".Substitute("t", "d/2").Solve("s"); var deAccelBase = "cos(t)-1"; var deAccelOverDuration = deAccelBase.Substitute("t", $"(t/(d/2)*2*pi)"); var deAccelCoeff = $"s / abs({deAccelOverDuration.Integrate("t").Substitute("t", "(d/2)")})"; var deAccel = $"({deAccelCoeff})*({deAccelOverDuration})"; var deAccelInt = deAccel.Integrate("t"); var deSpeedAtZero = deAccelInt.Substitute("t", 0); var deSpeedAtHalf = deAccelInt.Substitute("t", "(d/2)"); var deSpeed = $"({deAccelInt})-({deSpeedAtZero})+({speedAtHalf})"; var deSpeedInt = deSpeed.Integrate("t"); var dePosAtZero = deSpeedInt.Substitute("t", 0); var dePos = $"({deSpeedInt})-({dePosAtZero})+({posAtHalf})"; var t = Duration.FromSeconds(0); var t_step = m.Duration / m.RenderPts; var accelDataSet = new List <PlotData>(); var speedDataSet = new List <PlotData>(); var posDataSet = new List <PlotData>(); var deAccelDataSet = new List <PlotData>(); var deSpeedDataSet = new List <PlotData>(); var dePosDataSet = new List <PlotData>(); var accelCompiled = accel .Substitute("s", m.TargetSpeed.RevolutionsPerSecond) .Substitute("d", m.Duration.Seconds) .Compile("t"); var deAccelCompiled = deAccel .Substitute("s", m.TargetSpeed.RevolutionsPerSecond) .Substitute("d", m.Duration.Seconds) .Compile("t"); var speedCompiled = speed .Substitute("s", m.TargetSpeed.RevolutionsPerSecond) .Substitute("d", m.Duration.Seconds) .Compile("t"); var deSpeedCompiled = deSpeed .Substitute("s", m.TargetSpeed.RevolutionsPerSecond) .Substitute("d", m.Duration.Seconds) .Compile("t"); var posCompiled = pos .Substitute("s", m.TargetSpeed.RevolutionsPerSecond) .Substitute("d", m.Duration.Seconds) .Compile("t"); var dePosCompiled = dePos .Substitute("s", m.TargetSpeed.RevolutionsPerSecond) .Substitute("d", m.Duration.Seconds) .Compile("t"); var halfDuration = m.Duration / 2; var timeTol = Duration.FromNanoseconds(1); while (t.LessThanOrEqualsTol(timeTol, m.Duration)) { if (t.LessThanOrEqualsTol(timeTol, halfDuration)) { accelDataSet.Add(new PlotData( t.Seconds, double.Parse(accelCompiled.Substitute(t.Seconds).Real.ToString()))); speedDataSet.Add(new PlotData( t.Seconds, double.Parse(speedCompiled.Substitute(t.Seconds).Real.ToString()))); posDataSet.Add(new PlotData( t.Seconds, double.Parse(posCompiled.Substitute(t.Seconds).Real.ToString()))); } if (t.GreatThanOrEqualsTol(timeTol, halfDuration)) { deAccelDataSet.Add(new PlotData( t.Seconds, double.Parse(deAccelCompiled.Substitute((t - halfDuration).Seconds).Real.ToString()))); deSpeedDataSet.Add(new PlotData( t.Seconds, double.Parse(deSpeedCompiled.Substitute((t - halfDuration).Seconds).Real.ToString()))); dePosDataSet.Add(new PlotData( t.Seconds, double.Parse(dePosCompiled.Substitute((t - halfDuration).Seconds).Real.ToString()))); } t += t_step; } var accelSerie = new OxyPlot.Series.LineSeries() { Title = "Accel (rps2)", DataFieldX = "x", DataFieldY = "y", ItemsSource = accelDataSet, Color = OxyColor.Parse("#9ccc65") }; pv.Model.Series.Add(accelSerie); var deAccelSerie = new OxyPlot.Series.LineSeries() { Title = "DeAccel (rps2)", DataFieldX = "x", DataFieldY = "y", ItemsSource = deAccelDataSet, Color = OxyColor.Parse("#6b9b37") }; pv.Model.Series.Add(deAccelSerie); var speedSerie = new OxyPlot.Series.LineSeries() { Title = "Speed (rps)", DataFieldX = "x", DataFieldY = "y", ItemsSource = speedDataSet, Color = OxyColor.Parse("#42a5f5") }; pv.Model.Series.Add(speedSerie); var deSpeedSerie = new OxyPlot.Series.LineSeries() { Title = "DeSpeed (rps)", DataFieldX = "x", DataFieldY = "y", ItemsSource = deSpeedDataSet, Color = OxyColor.Parse("#0077c2") }; pv.Model.Series.Add(deSpeedSerie); var posSerie = new OxyPlot.Series.LineSeries() { Title = "Pos (rev)", DataFieldX = "x", DataFieldY = "y", ItemsSource = posDataSet, Color = OxyColor.Parse("#ef5350") }; pv.Model.Series.Add(posSerie); var dePosSerie = new OxyPlot.Series.LineSeries() { Title = "DePos (rev)", DataFieldX = "x", DataFieldY = "y", ItemsSource = dePosDataSet, Color = OxyColor.Parse("#b61827") }; pv.Model.Series.Add(dePosSerie); pv.Model.Annotations.Clear(); var note = new OxyPlot.Annotations.ArrowAnnotation { StartPoint = new DataPoint(m.Duration.Seconds / 2, m.TargetSpeed.RevolutionsPerSecond * 1.3), EndPoint = new DataPoint(m.Duration.Seconds / 2, m.TargetSpeed.RevolutionsPerSecond), Text = "targetspeed" }; pv.Model.Annotations.Add(note); pv.ResetAllAxes(); foreach (var x in pv.Model.Axes) { x.MajorGridlineStyle = LineStyle.Dot; } pv.InvalidatePlot(); tboxLog.Text = sb.ToString(); }
public MainWindow() : base(new[] { "resm:OxyPlot.Avalonia.Themes.Default.xaml?assembly=OxyPlot.Avalonia" }) { Title = csv_pathfilename; string hdr = ""; using (var sr = new StreamReader(csv_pathfilename)) { hdr = sr.ReadLine(); } var hdr_ss = hdr.Split(','); var cols = new List <int>(); foreach (var chanFilter in chansFilter.Split(',')) { int idx = -1; for (int i = 0; i < hdr_ss.Length; ++i) { if (hdr_ss[i].Trim().StripBegin('"').StripEnd('"') == chanFilter.Trim().StripBegin('"').StripEnd('"')) { idx = i; break; } } if (idx != -1) { cols.Add(idx); } } if (cols.Count == 0) { System.Console.WriteLine($"no matching cols"); Environment.Exit(1); } var grRoot = new Grid() { Margin = new Thickness(10) }; this.Content = grRoot; pv = new PlotView(); pv.Model = new PlotModel(); grRoot.Children.Add(pv); var series = new List <OxyPlot.Series.LineSeries>(); foreach (var col in cols) { var csv_data = new List <CsvItem>(); using (var sr = new StreamReader(csv_pathfilename)) { sr.ReadLine(); while (!sr.EndOfStream) { var str = sr.ReadLine(); var ss = str.Split(','); csv_data.Add(new CsvItem { t = ss[0].InvDoubleParse(), v = ss[col].InvDoubleParse() != 0 }); } } CsvItem periodBegin = null; foreach (var x in csv_data.WithPrev()) { if (x.item.v) { if (periodBegin == null) { periodBegin = x.item; } if (x.prev != null && !x.prev.v) { x.item.prev = periodBegin; periodBegin.periodSec = x.item.t - periodBegin.t; periodBegin = x.item; } } } var speed_items = csv_data .Where(r => r.periodSec > 0) .Select(x => new PlotData( x.t + x.periodSec / 2, 1.0 / x.periodSec )) .OrderBy(w => w.x); var f1 = new OxyPlot.Series.LineSeries() { Title = hdr_ss[col] + $" ({speed_items.Count()}pts)", DataFieldX = "x", DataFieldY = "y", ItemsSource = speed_items }; pv.Model.Series.Add(f1); } pv.ResetAllAxes(); pv.InvalidatePlot(); }