GraphDisplay: A Bezier based control for graphing functions and curves
This is an alternative for "GraphDisplay: a Bezier based control for graphing functions and curves"
Introduction
I really like this approach and intend to use the code as a library in one of my projects which will mostly display polar curves so I thought that adding an alternative polar grid would be useful.
I hope that this is an acceptable very minor addition to an excellent project.
Using the code
I added a several new functions to the GraphDisplay
class following the style of the author, specifically
- A function
AddPolarGrid
to build the grid from circular and radial rules - A function
AddCircularRule
to add a Circular rule to the display - A function
AddRadialRule
to add a Radial rule to the display - I also renamed the original
AddGrid
function to AddRectanglarGrid
/// <summary>
/// Adds a polar grid to the GraphDisplay
/// </summary>
/// <param name="x" />The r Size of the grid radius in graphed units
/// <param name="y" />The a Size of the grid angle in graphed units
/// <param name="style" />The style information for the graph
public void AddPolarGrid(double r, double a, GraphStyle style)
{
int rLeft = (int)Math.Ceiling(Math.Abs(XRight) / r);
int rRight = (int)Math.Ceiling(Math.Abs(XLeft) / r);
int rHoriz = Math.Max(rLeft,rRight);
int rTop = (int)Math.Ceiling(Math.Abs(YTop) / r);
int rBot = (int)Math.Ceiling(Math.Abs(YBottom) / r);
int rVert = Math.Max(rTop,rBot);
int imax = Math.Max(rHoriz,rVert);
double rmax = r * (imax + 1);
for (int i = 0; i < imax + 1; i++)
{
AddCircularRule((i + 1)* r, style);
}
for (double aa = 0; aa <= 360 ; aa += a)
{
double rad = aa * Math.PI / 180.0;
double cos = Math.Cos(rad);
double sin = Math.Sin(rad);
Point orig = new Point(r * cos, r * sin);
Point end = new Point(rmax * cos, rmax * sin );
AddRadialRule(orig,end,style);
}
}
/// <summary>
/// Adds a Circular rule at the specified radial value
/// </summary>
/// <param name="r" />The radius of the rule
/// <param name="style" />The Graphstyle for the rule
public void AddCircularRule(double r, GraphStyle style)
{
Path p = new Path();
EllipseGeometry eg = new EllipseGeometry();
eg.Center = new Point( mXTransform.Value(0), mYTransform.Value(0));
eg.RadiusX = mXTransform.Value(r) - eg.Center.X;
eg.RadiusY = mYTransform.Value(r) - eg.Center.Y;
p.Data = eg;
p.Fill = style.Fill;
p.Stroke = style.Stroke;
p.StrokeThickness = style.Thickness;
DisplayCanvas.Children.Add(p);
}
/// <summary>
/// Adds a Radial rule from centre to the specified X,Y value
/// </summary>
/// <param name="x" />The X position for the rule
/// <param name="y" />The Y position for the rule
/// <param name="style" />The Graphstyle for the rule
public void AddRadialRule(Point orig, Point end, GraphStyle style)
{
Path p = new Path();
LineGeometry lg = new LineGeometry();
lg.StartPoint = new Point(mXTransform.Value(orig.X), mYTransform.Value(orig.Y));
lg.EndPoint = new Point(mXTransform.Value(end.X), mYTransform.Value(end.Y));
p.Data = lg;
p.Fill = style.Fill;
p.Stroke = style.Stroke;
p.StrokeThickness = style.Thickness;
DisplayCanvas.Children.Add(p);
}
I also made some simple xaml changes to RoseCurveDisplay
, I added a checkbox
to the Decorations Expander in RoseCurveDisplay
and gave each checkbox a name to allow the polar grid to be selected.
<expander removed="{StaticResource HeaderBrush}" isexpanded="True" name="exDecorations"
dockpanel.dock="Top" grid.column="1">
...
<grid removed="{StaticResource InteriorBrush}">
<stackpanel>
<checkbox unchecked="checkBoxChanged" checked="checkBoxChanged"
margin="22,0,0,0" name="chkShowGrid">Show Grid</checkbox>
<checkbox unchecked="checkBoxChanged" checked="checkBoxChanged"
margin="22,0,0,0" name="chkGridPolar">Polar Grid</checkbox>
...
<textblock x:name="GridXWidth">X width</textblock>
...
<textblock grid.row="1" x:name="GridYWidth">Y width</textblock>
</stackpanel>
</grid>
</expander>
and added code expose the new checkbox status as a property, and modified the RoseCurveDisplay.checkBoxChanged
event handler
so that the text of the two labels describing the two data items required by the grid would be dependent on the selected grid type.
public bool IsGridPolar
{
get { return (bool)chkGridPolar.IsChecked; }
set { chkGridPolar.IsChecked = value; }
}
private void checkBoxChanged(object sender, RoutedEventArgs e)
{
// change text to reflect this
if (IsGridPolar)
{
GridXWidth.Text = "R width";
GridYWidth.Text = "Angle";
}
else
{
GridXWidth.Text = "X width";
GridYWidth.Text = "Y width";
}
// original code
if (GraphChanged != null)
{
GraphChanged(this, new EventArgs());
}
}
Finally I altered MainWindow.DisplayRoseCurve
to display the correct grid.
public void DisplayRoseCurve()
{
...
if (rcd.IsGridVisible)
{
if (!rcd.IsGridPolar)
this.gDisplay.AddRectangularGrid(rcd.GridX, rcd.GridY, gridStyle);
else
this.gDisplay.AddPolarGrid(rcd.GridX, rcd.GridY, gridStyle);
...
}
Points of Interest
You could also add code into checkBoxChanged to alter the slider ranges for the GridWidth values to be dependent on the grid type. For example you may wish to make the slider range values for the Y values (which are used to give the angular width for a polar grid) go from 1 to 180 degrees.