/// <summary> /// Reset the range to the empty state /// </summary> public virtual void Reset() { var oldRange = new Range(Min, Max); Minimum = double.NaN; Maximum = double.NaN; OnRangeChanged(oldRange); }
public virtual void ForceUpdate(double min, double max) { var oldRange = new Range(Min, Max); if (!double.IsNaN(min) && !double.IsInfinity(min) && (double.IsNaN(Minimum) || (Math.Abs(Minimum - min) > double.Epsilon))) Minimum = min; if (!double.IsNaN(max) && !double.IsInfinity(max) && (double.IsNaN(Maximum) || (Math.Abs(Maximum - max) > double.Epsilon))) Maximum = max; OnRangeChanged(oldRange); }
public RangeAnimation(Range from, Range to, Duration duration, FillBehavior fillBehavior = FillBehavior.Stop, IEasingFunction easingFunction = null) { From = from; To = to; Duration = duration; FillBehavior = fillBehavior; EasingFunction = easingFunction; }
//[UsedImplicitly] PropertyObserver<DataAxisViewModel> _propertyObserver; public DataAxisViewModel() { DataRange = new RangeCollection(); Label = "Axis"; AxisTicks = new ObservableList<DataAxisTick>(); AxisMarkers = new ObservableList<DataAxisTick>(); VisibleRange = new Range(1, 2); }
protected void OnRangeChanged(Range oldRange) { var handlers = RangeChanged; if (handlers == null) return; foreach (EventHandler<NotifyRangeChangedEventArgs> handler in handlers.GetInvocationList()) { if (handler.Target is DispatcherObject) { var localHandler = handler; ((DispatcherObject)handler.Target).Dispatcher.InvokeIfRequired(() => localHandler(this, new NotifyRangeChangedEventArgs(oldRange))); } else handler(this, new NotifyRangeChangedEventArgs(oldRange)); } }
public virtual void Update(double min, double max) { var isChanged = false; var oldRange = new Range(Min, Max); if (!double.IsNaN(min) && !double.IsInfinity(min) && (double.IsNaN(Minimum) || (Math.Abs(Minimum - min) > double.Epsilon))) { Minimum = min; isChanged = true; } if (!double.IsNaN(max) && !double.IsInfinity(max) && (double.IsNaN(Maximum) || (Math.Abs(Maximum - max) > double.Epsilon))) { Maximum = max; isChanged = true; } if (isChanged) OnRangeChanged(oldRange); }
public virtual void Clear() { var oldRange = new Range(this); Minimum = double.NaN; Maximum = double.NaN; OnRangeChanged(oldRange); }
void FromPropertyChanged() { _from = new Range(From); }
public RadialViewModel() { FullRange = new Range(0, 200); StatisticalRange = new Range(75, 125); AnimationTargetRange = new Range(); AnimationTime = TimeSpan.FromSeconds(0); AxisSeriesViewModel.DataSeriesCollection.Add(_imageSeriesViewModel); AxisSeriesViewModel.DataSeriesCollection.Add(_bottomProfileViewModel); AxisSeriesViewModel.XAxis.Label = "Range (m)"; AxisSeriesViewModel.XAxisTicks = null; AxisSeriesViewModel.YAxis.IsInverted = true; AxisSeriesViewModel.YAxis.Label = "Depth (m)"; AxisSeriesViewModel.YAxisTicks = null; _fourAxisSeriesObserver = new PropertyObserver<FourAxisSeriesViewModel>(AxisSeriesViewModel) .RegisterHandler(a => a.IsMouseOver, UpdateStatusProperties); _xAxisPropertyObserver = new PropertyObserver<DataAxisViewModel>(AxisSeriesViewModel.XAxis) .RegisterHandler(x => x.MouseDataLocation, UpdateStatusProperties); _yAxisPropertyObserver = new PropertyObserver<DataAxisViewModel>(AxisSeriesViewModel.YAxis) .RegisterHandler(y => y.MouseDataLocation, UpdateStatusProperties); _instanceObservers.Add(Observable.FromEventPattern<PropertyChangedEventArgs>(AxisSeriesViewModel.YAxis, "PropertyChanged") .ObserveOn(TaskPoolScheduler.Default) .Where(e => e.EventArgs.PropertyName == "VisibleRange") .Select(e => AxisSeriesViewModel.YAxis.VisibleRange) .Throttle(TimeSpan.FromMilliseconds(100)) .Subscribe(visibleRange => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Entering VisibleRangeChanged", DateTime.Now)); //Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Visible range on Y axis changed to {1}", DateTime.Now, visibleRange == null ? "(null)" : visibleRange.ToString())); if (visibleRange == null) { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving (1) VisibleRangeChanged", DateTime.Now)); return; } CalculateBottomProfileGeometry(); Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving VisibleRangeChanged", DateTime.Now)); }, e => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: VisibleRangeChanged exception: {1}", DateTime.Now, e.Message)); Debugger.Break(); })); _instanceObservers.Add(Observable.FromEventPattern<PropertyChangedEventArgs>(this, "PropertyChanged") .ObserveOn(TaskPoolScheduler.Default) .Where(e => e.EventArgs.PropertyName == "AxisRange") .Select(e => AxisRange) .DistinctUntilChanged() .Subscribe(axisRange => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Entering AxisRangeChanged", DateTime.Now)); if (_axisRangeObserver != null) { _instanceObservers.Remove(_axisRangeObserver); _axisRangeObserver.Dispose(); } if (axisRange == null) { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving (1) AxisRangeChanged", DateTime.Now)); return; } _axisRangeObserver = axisRange.ObserveOn(TaskPoolScheduler.Default).Subscribe(r => { if (FullRange == null) FullRange = new Range(axisRange); else FullRange.Update(axisRange); }); _instanceObservers.Add(_axisRangeObserver); Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving AxisRangeChanged", DateTime.Now)); }, e => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: AxisRangeChanged exception: {1}", DateTime.Now, e.Message)); Debugger.Break(); })); _instanceObservers.Add(Observable.FromEventPattern<PropertyChangedEventArgs>(AxisSeriesViewModel, "PropertyChanged") .ObserveOn(TaskPoolScheduler.Default) .Where(e => (e.EventArgs.PropertyName == "ActualWidth" || e.EventArgs.PropertyName == "ActualHeight")) .Select(e => new { AxisSeriesViewModel.ActualWidth, AxisSeriesViewModel.ActualHeight }) .Sample(TimeSpan.FromMilliseconds(100)) .DistinctUntilChanged() .Subscribe(e => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Entering ActualHeightWidthChanged", DateTime.Now)); Render(); //CalculateBottomProfileGeometry(); Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving ActualHeightWidthChanged", DateTime.Now)); }, e => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: ActualHeightWidthChanged exception: {1}", DateTime.Now, e.Message)); Debugger.Break(); })); _instanceObservers.Add(Observable.FromEventPattern<PropertyChangedEventArgs>(this, "PropertyChanged") .ObserveOn(TaskPoolScheduler.Default) .Where(e => e.EventArgs.PropertyName == "Radial") .Subscribe(e => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Entering RadialChanged", DateTime.Now)); _radialObservers.ForEach(o => o.Dispose()); _radialObservers.Clear(); WriteableBitmapVisibility = Visibility.Collapsed; if (Radial == null || !Radial.IsCalculated) { WriteableBitmapVisibility = Visibility.Collapsed; if (Radial == null) WaitToRenderText = "Please wait..."; else { if (!string.IsNullOrEmpty(Radial.Errors)) { var sb = new StringBuilder(); sb.AppendLine("This radial was not calculated due to the following error(s):"); sb.AppendLine(Radial.Errors); WaitToRenderText = sb.ToString(); } else WaitToRenderText = "This radial has not yet been calculated"; } Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving (1) RadialChanged", DateTime.Now)); return; } try { _shadeFile = ShadeFile.Read(Radial.BasePath + ".shd", (float)Radial.Bearing); _shadeFile.BottomDepths = Radial.BottomDepths; _imageSeriesViewModel.Top = Radial.Depths.First(); _imageSeriesViewModel.Left = Radial.Ranges.First(); _imageSeriesViewModel.Bottom = Radial.Depths.Last(); _imageSeriesViewModel.Right = Radial.Ranges.Last(); StatisticalRange.Update(_shadeFile.StatMin, _shadeFile.StatMax); ColorMapViewModel.Range.Update(StatisticalRange); AxisSeriesViewModel.XAxis.DataRange.Update(_imageSeriesViewModel.Left, _imageSeriesViewModel.Right); AxisSeriesViewModel.YAxis.DataRange.Update(_imageSeriesViewModel.Top, _imageSeriesViewModel.Bottom); _radialObservers.Add(ColorMapViewModel.Range.ObserveOn(TaskPoolScheduler.Default).Sample(TimeSpan.FromMilliseconds(50)).Subscribe(r => Render())); Render(); CalculateBottomProfileGeometry(); } catch (Exception ex) { WriteableBitmapVisibility = Visibility.Collapsed; WaitToRenderText = ex.Message; _shadeFile = null; } Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving RadialChanged", DateTime.Now)); }, e => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: RadialChanged exception: {1}", DateTime.Now, e.Message)); Debugger.Break(); })); _instanceObservers.Add( ColorMapViewModel.Range.ObserveOn(TaskPoolScheduler.Default).Subscribe( r => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Entering ColorMapViewModel.RangeChanged", DateTime.Now)); _dispatcher.InvokeInBackgroundIfRequired(() => { AxisMarkers.Clear(); if (ColorMapViewModel.Range != FullRange) { AxisMarkers.Add(new DataAxisTick(ColorMapViewModel.Range.Min, string.Format("{0:0}", ColorMapViewModel.Range.Min), true, Brushes.White, Brushes.Black, Brushes.Black)); AxisMarkers.Add(new DataAxisTick(ColorMapViewModel.Range.Max, string.Format("{0:0}", ColorMapViewModel.Range.Max), true, Brushes.White, Brushes.Black, Brushes.Black)); } Debug.WriteLine("{0:HH:mm:ss.fff} ColorMapViewModel.Range changed to {1}", DateTime.Now, r); }); Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving ColorMapViewModel.RangeChanged", DateTime.Now)); }, e => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: ColorMapViewModel.RangeChanged exception: {1}", DateTime.Now, e.Message)); Debugger.Break(); })); _displayQueue .ObserveOn(TaskPoolScheduler.Default) .Subscribe(result => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Entering DisplayQueue", DateTime.Now)); _dispatcher.InvokeInBackgroundIfRequired(() => { var pixelBuffer = result.Item1; var renderRect = result.Item2; var sequenceNumber = result.Item3; //Debug.WriteLine(string.Format("Got completed event for sequence number {0} completed", sequenceNumber)); if (sequenceNumber < _displayedSequenceNumber) { Debug.WriteLine("Discarding image buffer: Old image sequence"); Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving (1) DisplayQueue", DateTime.Now)); return; } if (WriteableBitmap == null || Math.Abs(renderRect.Width - WriteableBitmap.Width) > double.Epsilon || Math.Abs(renderRect.Height - WriteableBitmap.Height) > double.Epsilon) WriteableBitmap = new WriteableBitmap(renderRect.Width, renderRect.Height, 96, 96, PixelFormats.Bgr32, null); _displayedSequenceNumber = sequenceNumber; WriteableBitmap.Lock(); WriteableBitmap.WritePixels(renderRect, pixelBuffer, WriteableBitmap.BackBufferStride, 0, 0); WriteableBitmap.AddDirtyRect(renderRect); OnPropertyChanged("WriteableBitmap"); WriteableBitmap.Unlock(); WriteableBitmapVisibility = Visibility.Visible; _imageSeriesViewModel.ImageSource = WriteableBitmap; }); Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: Leaving DisplayQueue", DateTime.Now)); }, e => { Debug.WriteLine(string.Format("{0:HH:mm:ss.fff} RadialViewModel: DisplayQueue exception: {1}", DateTime.Now, e.Message)); Debugger.Break(); }); }
GeneralTransform CreateAxisTransform(Range visbleRange, Size newSize, bool includeSwapTransform, bool isInverted, bool isLogarithmic) { double tickDirectionScale; double originScale; double axisDirectionTranslation; double tickDirectionTranslation; double axisLength; switch (AxisLocation) { case AxisLocation.Top: tickDirectionScale = -1.0; originScale = 1.0; axisDirectionTranslation = isInverted ? newSize.Width - (StrokeWeight / 2): StrokeWeight / 2; tickDirectionTranslation = newSize.Height - (StrokeWeight / 2); axisLength = newSize.Width; break; case AxisLocation.Bottom: tickDirectionScale = 1.0; originScale = 1.0; axisDirectionTranslation = isInverted ? newSize.Width - (StrokeWeight / 2): StrokeWeight / 2; tickDirectionTranslation = StrokeWeight / 2; axisLength = newSize.Width; break; case AxisLocation.Left: tickDirectionScale = -1.0; originScale = -1.0; axisDirectionTranslation = isInverted ? StrokeWeight / 2 : newSize.Height - (StrokeWeight / 2); tickDirectionTranslation = newSize.Width - (StrokeWeight / 2); axisLength = newSize.Height; break; case AxisLocation.Right: tickDirectionScale = 1.0; originScale = -1.0; axisDirectionTranslation = isInverted ? StrokeWeight / 2 : newSize.Height - (StrokeWeight / 2); tickDirectionTranslation = StrokeWeight / 2; axisLength = newSize.Height; break; default: throw new ApplicationException("DataAxis: Unknown AxisLocation value."); } if (isInverted) originScale *= -1; // The intent of this transform is to make every axis draw the same as a Bottom axis (i.e. the StartValue is at // transformed-X of 0, and the axis line is drawn from top left to top right, axis ticks from top to tickLength) var result = new GeneralTransformGroup(); // If this is a logarithmic axis, take the log of the data point. // If the data point is zero or negative, an exception will be thrown if (isLogarithmic) result.Children.Add(new LogTransform(10)); // Reduce the data point by the minimum visible value, which normalizes the data with respect to the axis origin result.Children.Add(new TranslateTransform(-visbleRange.Min, 0)); // Scale the data by an amount that will place the maximum visible value at the end of the axis // Takes axis direction (and partially axis inversion) into account with originScale, which is set according to those parameters result.Children.Add(new ScaleTransform(originScale * ((axisLength - StrokeWeight) / visbleRange.Size), tickDirectionScale)); // Shift the result so that the data point is now located at the point along the axis that corresponds to the original data value result.Children.Add(new TranslateTransform(axisDirectionTranslation, tickDirectionTranslation)); // if the includeSwapTransform parameter is true, then swap the X and Y values produced if this is a Left or Right axis if (includeSwapTransform && AxisLocation == AxisLocation.Left || AxisLocation == AxisLocation.Right) result.Children.Add(new SwapTransform()); return result; }