Initial Commit

This commit is contained in:
2024-02-23 00:46:06 -05:00
commit 2bbedc0178
470 changed files with 46035 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
public class DataHeightRestriction : ViewportRestriction, ISupportAttachToViewport
{
private double yEnlargeCoeff = 1.1;
public double YEnlargeCoeff
{
get { return yEnlargeCoeff; }
set
{
if (yEnlargeCoeff != value)
{
yEnlargeCoeff = value;
RaiseChanged();
}
}
}
public override DataRect Apply(DataRect oldDataRect, DataRect newDataRect, Viewport2D viewport)
{
DataRect overallBounds = DataRect.Empty;
foreach (var chart in viewport.ContentBoundsHosts)
{
var plotterElement = chart as IPlotterElement;
var visual = viewport.Plotter.VisualBindings[plotterElement];
var points = (ReadOnlyCollection<Point>)PointsGraphBase.GetVisiblePoints(visual);
if (points != null)
{
// searching for indices of chart's visible points which are near left and right borders of newDataRect
double startX = newDataRect.XMin;
double endX = newDataRect.XMax;
if (points[0].X > endX || points[points.Count - 1].X < startX)
{
continue;
}
int startIndex = -1;
// we assume that points are sorted by x values ascending
if (startX <= points[0].X)
{
startIndex = 0;
}
else
{
for (int i = 1; i < points.Count - 1; i++)
{
if (points[i].X <= startX && startX < points[i + 1].X)
{
startIndex = i;
break;
}
}
}
int endIndex = points.Count;
if (points[points.Count - 1].X < endX)
{
endIndex = points.Count;
}
else
{
for (int i = points.Count - 1; i >= 1; i--)
{
if (points[i - 1].X <= endX && endX < points[i].X)
{
endIndex = i;
break;
}
}
}
Rect bounds = Rect.Empty;
for (int i = startIndex; i < endIndex; i++)
{
bounds.Union(points[i]);
}
if (startIndex > 0)
{
Point pt = GetInterpolatedPoint(startX, points[startIndex], points[startIndex - 1]);
bounds.Union(pt);
}
if (endIndex < points.Count - 1)
{
Point pt = GetInterpolatedPoint(endX, points[endIndex], points[endIndex + 1]);
bounds.Union(pt);
}
overallBounds.Union(bounds);
}
}
if (!overallBounds.IsEmpty)
{
double y = overallBounds.YMin;
double height = overallBounds.Height;
if (height == 0)
{
height = newDataRect.Height;
y -= height / 2;
}
newDataRect = new DataRect(newDataRect.XMin, y, newDataRect.Width, height);
newDataRect = DataRectExtensions.ZoomY(newDataRect, newDataRect.GetCenter(), yEnlargeCoeff);
}
return newDataRect;
}
private static Point GetInterpolatedPoint(double x, Point p1, Point p2)
{
double xRatio = (x - p1.X) / (p2.X - p1.X);
double y = (1 - xRatio) * p1.Y + xRatio * p2.Y;
return new Point(x, y);
}
#region ISupportAttach Members
void ISupportAttachToViewport.Attach(Viewport2D viewport)
{
((INotifyCollectionChanged)viewport.ContentBoundsHosts).CollectionChanged += OnContentBoundsHostsChanged;
foreach (var item in viewport.ContentBoundsHosts)
{
PointsGraphBase chart = item as PointsGraphBase;
if (chart != null)
{
chart.ProvideVisiblePoints = true;
}
}
}
private void OnContentBoundsHostsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (var item in e.NewItems)
{
PointsGraphBase chart = item as PointsGraphBase;
if (chart != null)
{
chart.ProvideVisiblePoints = true;
}
}
}
// todo probably set ProvideVisiblePoints to false on OldItems
}
void ISupportAttachToViewport.Detach(Viewport2D viewport)
{
((INotifyCollectionChanged)viewport.ContentBoundsHosts).CollectionChanged -= OnContentBoundsHostsChanged;
}
#endregion
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
public sealed class DateTimeHorizontalAxisRestriction : ViewportRestriction
{
private readonly double minSeconds = new TimeSpan(DateTime.MinValue.Ticks).TotalSeconds;
private readonly double maxSeconds = new TimeSpan(DateTime.MaxValue.Ticks).TotalSeconds;
public override DataRect Apply(DataRect previousDataRect, DataRect proposedDataRect, Viewport2D viewport)
{
DataRect borderRect = DataRect.Create(minSeconds, proposedDataRect.YMin, maxSeconds, proposedDataRect.YMax);
if (proposedDataRect.IntersectsWith(borderRect))
{
DataRect croppedRect = DataRect.Intersect(proposedDataRect, borderRect);
return croppedRect;
}
return previousDataRect;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
public sealed class DateTimeVerticalAxisRestriction : ViewportRestriction
{
private readonly double minSeconds = new TimeSpan(DateTime.MinValue.Ticks).TotalSeconds;
private readonly double maxSeconds = new TimeSpan(DateTime.MaxValue.Ticks).TotalSeconds;
public override DataRect Apply(DataRect previousDataRect, DataRect proposedDataRect, Viewport2D viewport)
{
DataRect borderRect = DataRect.Create(proposedDataRect.XMin, minSeconds, proposedDataRect.XMax, maxSeconds);
if (proposedDataRect.IntersectsWith(borderRect))
{
DataRect croppedRect = DataRect.Intersect(proposedDataRect, borderRect);
return croppedRect;
}
return previousDataRect;
}
}
}

View File

@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay.Common;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
/// <summary>
/// Represents a restriction which returns data rectangle, intersected with specified data domain.
/// </summary>
public class DomainRestriction : ViewportRestriction
{
/// <summary>
/// Initializes a new instance of the <see cref="DomainRestriction"/> class.
/// </summary>
public DomainRestriction() { }
/// <summary>
/// Initializes a new instance of the <see cref="DomainRestriction"/> class with given domain property.
/// </summary>
/// <param name="domain">The domain.</param>
public DomainRestriction(DataRect domain)
{
this.Domain = domain;
}
private DataRect domain = new DataRect(-1, -1, 2, 2);
/// <summary>
/// Gets or sets the domain.
/// </summary>
/// <value>The domain.</value>
public DataRect Domain
{
get { return domain; }
set
{
if (domain != value)
{
domain = value;
RaiseChanged();
}
}
}
/// <summary>
/// Applies the specified old data rect.
/// </summary>
/// <param name="oldDataRect">The old data rect.</param>
/// <param name="newDataRect">The new data rect.</param>
/// <param name="viewport">The viewport.</param>
/// <returns></returns>
public override DataRect Apply(DataRect oldDataRect, DataRect newDataRect, Viewport2D viewport)
{
DataRect res = domain;
if (domain.IsEmpty)
{
res = newDataRect;
}
else if (newDataRect.IntersectsWith(domain))
{
res = newDataRect;
if (newDataRect.Size == oldDataRect.Size)
{
if (res.XMin < domain.XMin) res.XMin = domain.XMin;
if (res.YMin < domain.YMin) res.YMin = domain.YMin;
if (res.XMax > domain.XMax) res.XMin += domain.XMax - res.XMax;
if (res.YMax > domain.YMax) res.YMin += domain.YMax - res.YMax;
}
else
{
res = DataRect.Intersect(newDataRect, domain);
}
}
return res;
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.ComponentModel;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
/// <summary>
/// Represents a viewport restriction which modifies x coordinates of result visible rect to be adjacent to the right border of initial rect and have a fixed given width.
/// Probably is better to add to FitToViewRestrictions collection of <see cref="Viewport"/>.
/// </summary>
public class FollowWidthRestriction : ViewportRestriction
{
/// <summary>
/// Initializes a new instance of the <see cref="FollowWidthRestriction"/> class.
/// </summary>
public FollowWidthRestriction() { }
/// <summary>
/// Initializes a new instance of the <see cref="FollowWidthRestriction"/> class with the given width.
/// </summary>
/// <param name="width">The width.</param>
public FollowWidthRestriction(double width)
{
Width = width;
}
private double width = 1;
/// <summary>
/// Gets or sets the width of result visible rectangle.
/// Default value is 1.0.
/// </summary>
/// <value>The width.</value>
[DefaultValue(1.0)]
public double Width
{
get { return width; }
set
{
if (width != value)
{
width = value;
RaiseChanged();
}
}
}
/// <summary>
/// Applies the restriction.
/// </summary>
/// <param name="previousDataRect">Previous data rectangle.</param>
/// <param name="proposedDataRect">Proposed data rectangle.</param>
/// <param name="viewport">The viewport, to which current restriction is being applied.</param>
/// <returns>New changed visible rectangle.</returns>
public override DataRect Apply(DataRect previousDataRect, DataRect proposedDataRect, Viewport2D viewport)
{
if (proposedDataRect.IsEmpty)
return proposedDataRect;
double followWidth = proposedDataRect.Width;
if (!viewport.UnitedContentBounds.IsEmpty)
{
followWidth = Math.Min(width, viewport.UnitedContentBounds.Width);
}
if (followWidth.IsInfinite())
followWidth = width;
Rect visible = new Rect(proposedDataRect.XMin + proposedDataRect.Width - followWidth, proposedDataRect.YMin, followWidth, proposedDataRect.Height);
return visible;
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
/// <summary>
/// Represents a restriction which is capable to attach to or detach from <see cref="Viewport"/>, to which it is applied.
/// </summary>
public interface ISupportAttachToViewport
{
/// <summary>
/// Attaches the specified viewport to a restriction.
/// </summary>
/// <param name="viewport">The viewport.</param>
void Attach(Viewport2D viewport);
/// <summary>
/// Detaches the specified viewport from a restriction.
/// </summary>
/// <param name="viewport">The viewport.</param>
void Detach(Viewport2D viewport);
}
}

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
public delegate DataRect ViewportRestrictionCallback(DataRect proposedDataRect);
public class InjectionDelegateRestriction : ViewportRestriction
{
public InjectionDelegateRestriction(Viewport2D masterViewport, ViewportRestrictionCallback callback)
{
if (callback == null)
throw new ArgumentNullException("callback");
if (masterViewport == null)
throw new ArgumentNullException("masterViewport");
this.callback = callback;
this.masterViewport = masterViewport;
masterViewport.PropertyChanged += masterViewport_PropertyChanged;
}
void masterViewport_PropertyChanged(object sender, ExtendedPropertyChangedEventArgs e)
{
if (e.PropertyName == "Visible")
{
RaiseChanged();
}
}
private Viewport2D masterViewport;
private ViewportRestrictionCallback callback;
public override DataRect Apply(DataRect previousDataRect, DataRect proposedDataRect, Viewport2D viewport)
{
return callback(proposedDataRect);
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
/// <summary>
/// Represents a restriction, which limits the maximal size of <see cref="Viewport"/>'s Visible property.
/// </summary>
public class MaximalSizeRestriction : ViewportRestriction
{
/// <summary>
/// Initializes a new instance of the <see cref="MaximalSizeRestriction"/> class.
/// </summary>
public MaximalSizeRestriction() { }
/// <summary>
/// Initializes a new instance of the <see cref="MaximalSizeRestriction"/> class with the given maximal size of Viewport's Visible.
/// </summary>
/// <param name="maxSize">Maximal size of Viewport's Visible.</param>
public MaximalSizeRestriction(double maxSize)
{
MaxSize = maxSize;
}
private double maxSize = 1000;
/// <summary>
/// Gets or sets the maximal size of Viewport's Visible.
/// The default value is 1000.0.
/// </summary>
/// <value>The size of the max.</value>
public double MaxSize
{
get { return maxSize; }
set
{
if (maxSize != value)
{
maxSize = value;
RaiseChanged();
}
}
}
/// <summary>
/// Applies the specified old data rect.
/// </summary>
/// <param name="oldDataRect">The old data rect.</param>
/// <param name="newDataRect">The new data rect.</param>
/// <param name="viewport">The viewport.</param>
/// <returns></returns>
public override DataRect Apply(DataRect oldDataRect, DataRect newDataRect, Viewport2D viewport)
{
bool decreasing = newDataRect.Width < oldDataRect.Width || newDataRect.Height < oldDataRect.Height;
if (!decreasing && (newDataRect.Width > maxSize || newDataRect.Height > maxSize))
return oldDataRect;
return newDataRect;
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
/// <summary>
/// Represents a ViewportRestriction, which the minimal size of <see cref="Viewport"/>'s Visible.
/// </summary>
public class MinimalSizeRestriction : ViewportRestriction
{
private double minSize = 1E-11;
/// <summary>
/// Gets or sets the minimal size of Viewport's Visible.
/// </summary>
/// <value>The minimal size of Viewport's Visible.</value>
public double MinSize
{
get { return minSize; }
set
{
if (minSize != value)
{
minSize = value;
RaiseChanged();
}
}
}
/// <summary>
/// Applies the restriction.
/// </summary>
/// <param name="previousDataRect">Previous data rectangle.</param>
/// <param name="proposedDataRect">Proposed data rectangle.</param>
/// <param name="viewport">The viewport, to which current restriction is being applied.</param>
/// <returns>New changed visible rectangle.</returns>
public override DataRect Apply(DataRect previousDataRect, DataRect proposedDataRect, Viewport2D viewport)
{
if (proposedDataRect.Width < minSize || proposedDataRect.Height < minSize)
return previousDataRect;
return proposedDataRect;
}
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
/// <summary>
/// Represents a restriction in which actual visible rect's proportions depends on
/// actual output rect's proportions.
/// </summary>
public sealed class PhysicalProportionsRestriction : ViewportRestriction
{
/// <summary>
/// Initializes a new instance of the <see cref="PhysicalProportionsRestriction"/> class.
/// </summary>
public PhysicalProportionsRestriction() { }
/// <summary>
/// Initializes a new instance of the <see cref="PhysicalProportionsRestriction"/> class with the given proportion ratio.
/// </summary>
/// <param name="proportionRatio">The proportion ratio.</param>
public PhysicalProportionsRestriction(double proportionRatio)
{
ProportionRatio = proportionRatio;
}
private double proportionRatio = 1.0;
/// <summary>
/// Gets or sets the proportion ratio.
/// Default value is 1.0.
/// </summary>
/// <value>The proportion ratio.</value>
public double ProportionRatio
{
get { return proportionRatio; }
set
{
if (proportionRatio != value)
{
proportionRatio = value;
RaiseChanged();
}
}
}
/// <summary>
/// Applies the restriction.
/// </summary>
/// <param name="previousDataRect">Previous data rectangle.</param>
/// <param name="proposedDataRect">Proposed data rectangle.</param>
/// <param name="viewport">The viewport, to which current restriction is being applied.</param>
/// <returns>New changed visible rectangle.</returns>
public override DataRect Apply(DataRect previousDataRect, DataRect proposedDataRect, Viewport2D viewport)
{
Rect output = viewport.Output;
if (output.Width == 0 || output.Height == 0)
return proposedDataRect;
double screenRatio = output.Width / output.Height;
double viewportRatio = proposedDataRect.Width / proposedDataRect.Height;
double ratio = screenRatio / viewportRatio;
double width = proportionRatio * proposedDataRect.Width * ratio;
double height = proposedDataRect.Height;
if (width < proposedDataRect.Width)
{
height = proposedDataRect.Height / proportionRatio / ratio;
width = proposedDataRect.Width;
}
Point center = proposedDataRect.GetCenter();
Rect res = RectExtensions.FromCenterSize(center, width, height);
return res;
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
public sealed class ProportionsRestriction : ViewportRestriction
{
private double widthToHeightRatio = 1;
public double WidthToHeightRatio
{
get { return widthToHeightRatio; }
set
{
if (widthToHeightRatio != value)
{
widthToHeightRatio = value;
RaiseChanged();
}
}
}
public override DataRect Apply(DataRect oldDataRect, DataRect newDataRect, Viewport2D viewport)
{
double ratio = newDataRect.Width / newDataRect.Height;
double coeff = Math.Sqrt(ratio);
double newWidth = newDataRect.Width / coeff;
double newHeight = newDataRect.Height * coeff;
Point center = newDataRect.GetCenter();
DataRect res = DataRect.FromCenterSize(center, newWidth, newHeight);
return res;
}
}
}

View File

@@ -0,0 +1,69 @@
using System.Linq;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay;
using Microsoft.Research.DynamicDataDisplay.Common;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
using System;
using System.Collections.Specialized;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
/// <summary>
/// Represents a collection of <see cref="ViewportRestriction"/>s.
/// <remarks>
/// ViewportRestriction that is being added should not be null.
/// </remarks>
/// </summary>
public sealed class RestrictionCollection : D3Collection<ViewportRestriction>
{
private readonly Viewport2D viewport;
internal RestrictionCollection(Viewport2D viewport)
{
if (viewport == null)
throw new ArgumentNullException("viewport");
this.viewport = viewport;
}
protected override void OnItemAdding(ViewportRestriction item)
{
if (item == null)
throw new ArgumentNullException("item");
}
protected override void OnItemAdded(ViewportRestriction item)
{
item.Changed += OnItemChanged;
ISupportAttachToViewport attachable = item as ISupportAttachToViewport;
if (attachable != null)
{
attachable.Attach(viewport);
}
}
private void OnItemChanged(object sender, EventArgs e)
{
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
protected override void OnItemRemoving(ViewportRestriction item)
{
ISupportAttachToViewport attachable = item as ISupportAttachToViewport;
if (attachable != null)
{
attachable.Detach(viewport);
}
item.Changed -= OnItemChanged;
}
internal DataRect Apply(DataRect oldVisible, DataRect newVisible, Viewport2D viewport)
{
DataRect res = newVisible;
foreach (var restriction in this)
{
res = restriction.Apply(oldVisible, res, viewport);
}
return res;
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
public class ScaleInjectionRestriction : ViewportRestriction
{
private Viewport2D parentViewport;
public ScaleInjectionRestriction(Viewport2D parentViewport)
{
if (parentViewport == null)
throw new ArgumentNullException("parentViewport");
this.parentViewport = parentViewport;
parentViewport.PropertyChanged += parentViewport_PropertyChanged;
}
private void parentViewport_PropertyChanged(object sender, ExtendedPropertyChangedEventArgs e)
{
if (e.PropertyName == "Visible")
{
RaiseChanged();
}
}
public void SetHorizontalTransform(double parentMin, double childMin, double parentMax, double childMax)
{
xScale = (childMax - childMin) / (parentMax - parentMin);
xShift = childMin - parentMin;
}
public void SetVerticalTransform(double parentMin, double childMin, double parentMax, double childMax)
{
yScale = (childMax - childMin) / (parentMax - parentMin);
yShift = childMin - parentMin;
}
private double xShift = 0;
private double xScale = 1;
private double yShift = 0;
private double yScale = 1;
public override DataRect Apply(DataRect previousDataRect, DataRect proposedDataRect, Viewport2D viewport)
{
DataRect parentVisible = parentViewport.Visible;
double xmin = parentVisible.XMin * xScale + xShift;
double xmax = parentVisible.XMax * xScale + xShift;
double ymin = parentVisible.YMin * yScale + yShift;
double ymax = parentVisible.YMax * yScale + yShift;
return DataRect.Create(xmin, ymin, xmax, ymax);
}
}
}

View File

@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay.Common;
namespace Microsoft.Research.DynamicDataDisplay.ViewportRestrictions
{
/// <summary>
/// Represents a base class for all restrictions that are being applied to viewport's visible rect.
/// </summary>
public abstract class ViewportRestriction
{
#region IViewportRestriction Members
/// <summary>
/// Applies the restriction.
/// </summary>
/// <param name="previousDataRect">Previous data rectangle.</param>
/// <param name="proposedDataRect">Proposed data rectangle.</param>
/// <param name="viewport">The viewport, to which current restriction is being applied.</param>
/// <returns>New changed visible rectangle.</returns>
public abstract DataRect Apply(DataRect previousDataRect, DataRect proposedDataRect, Viewport2D viewport);
/// <summary>
/// Raises the changed event.
/// </summary>
protected void RaiseChanged()
{
Changed.Raise(this);
}
/// <summary>
/// Occurs when restriction changes.
/// Causes update of <see cref="Viewport"/>'s Visible property.
/// </summary>
public event EventHandler Changed;
#endregion
}
}