Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GP-MoveOperators/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.cs @ 12774

Last change on this file since 12774 was 8660, checked in by gkronber, 12 years ago

#1847 merged r8205:8635 from trunk into branch

File size: 21.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Drawing;
25using System.Linq;
26using System.Windows.Forms;
27using System.Windows.Forms.DataVisualization.Charting;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
30using HeuristicLab.Core.Views;
31using HeuristicLab.MainForm;
32
33namespace HeuristicLab.Analysis.Views {
34  [View("ScatterPlot View")]
35  [Content(typeof(ScatterPlot), true)]
36  public partial class ScatterPlotView : NamedItemView {
37    protected List<Series> invisibleSeries;
38    protected Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow> pointsRowsTable;
39
40    public new ScatterPlot Content {
41      get { return (ScatterPlot)base.Content; }
42      set { base.Content = value; }
43    }
44
45    public ScatterPlotView() {
46      InitializeComponent();
47      pointsRowsTable = new Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow>();
48      invisibleSeries = new List<Series>();
49      chart.CustomizeAllChartAreas();
50      chart.ChartAreas[0].CursorX.Interval = 1;
51    }
52
53    #region Event Handler Registration
54    protected override void DeregisterContentEvents() {
55      foreach (ScatterPlotDataRow row in Content.Rows)
56        DeregisterScatterPlotDataRowEvents(row);
57      Content.VisualPropertiesChanged -= new EventHandler(Content_VisualPropertiesChanged);
58      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
59      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
60      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
61      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
62      base.DeregisterContentEvents();
63    }
64    protected override void RegisterContentEvents() {
65      base.RegisterContentEvents();
66      Content.VisualPropertiesChanged += new EventHandler(Content_VisualPropertiesChanged);
67      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
68      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
69      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
70      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
71    }
72
73    protected virtual void RegisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
74      row.NameChanged += new EventHandler(Row_NameChanged);
75      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
76      pointsRowsTable.Add(row.Points, row);
77      row.Points.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
78      row.Points.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
79      row.Points.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
80      row.Points.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
81    }
82    protected virtual void DeregisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
83      row.Points.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
84      row.Points.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
85      row.Points.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
86      row.Points.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
87      pointsRowsTable.Remove(row.Points);
88      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
89      row.NameChanged -= new EventHandler(Row_NameChanged);
90    }
91    #endregion
92
93    protected override void OnContentChanged() {
94      base.OnContentChanged();
95      invisibleSeries.Clear();
96      chart.Titles[0].Text = string.Empty;
97      chart.ChartAreas[0].AxisX.Title = string.Empty;
98      chart.ChartAreas[0].AxisY.Title = string.Empty;
99      chart.Series.Clear();
100      if (Content != null) {
101        chart.Titles[0].Text = Content.Name;
102        AddScatterPlotDataRows(Content.Rows);
103        ConfigureChartArea(chart.ChartAreas[0]);
104        RecalculateAxesScale(chart.ChartAreas[0]);
105      }
106    }
107
108    protected override void SetEnabledStateOfControls() {
109      base.SetEnabledStateOfControls();
110      chart.Enabled = Content != null;
111    }
112
113    protected virtual void AddScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
114      foreach (var row in rows) {
115        RegisterScatterPlotDataRowEvents(row);
116        Series series = new Series(row.Name);
117        if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
118        else series.LegendText = row.Name;
119        ConfigureSeries(series, row);
120        FillSeriesWithRowValues(series, row);
121        chart.Series.Add(series);
122      }
123      ConfigureChartArea(chart.ChartAreas[0]);
124      RecalculateAxesScale(chart.ChartAreas[0]);
125      UpdateYCursorInterval();
126    }
127
128    protected virtual void RemoveScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
129      foreach (var row in rows) {
130        DeregisterScatterPlotDataRowEvents(row);
131        Series series = chart.Series[row.Name];
132        chart.Series.Remove(series);
133        if (invisibleSeries.Contains(series))
134          invisibleSeries.Remove(series);
135      }
136      RecalculateAxesScale(chart.ChartAreas[0]);
137    }
138
139    private void ConfigureSeries(Series series, ScatterPlotDataRow row) {
140      series.BorderWidth = 1;
141      series.BorderDashStyle = ChartDashStyle.Solid;
142      series.BorderColor = Color.Empty;
143
144      if (row.VisualProperties.Color != Color.Empty)
145        series.Color = row.VisualProperties.Color;
146      else series.Color = Color.Empty;
147      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
148      series.ChartType = SeriesChartType.FastPoint;
149      series.MarkerSize = row.VisualProperties.PointSize;
150      series.MarkerStyle = ConvertPointStyle(row.VisualProperties.PointStyle);
151      series.XAxisType = AxisType.Primary;
152      series.YAxisType = AxisType.Primary;
153
154      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
155      else series.LegendText = row.Name;
156
157      string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
158                      ? "X"
159                      : Content.VisualProperties.XAxisTitle;
160      string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
161                            ? "Y"
162                            : Content.VisualProperties.YAxisTitle;
163      series.ToolTip =
164        series.LegendText + Environment.NewLine +
165        xAxisTitle + " = " + "#VALX," + Environment.NewLine +
166        yAxisTitle + " = " + "#VAL";
167    }
168
169    private void ConfigureChartArea(ChartArea area) {
170      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
171      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
172      chart.Titles[0].Text = Content.VisualProperties.Title;
173
174      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
175      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
176      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
177      area.AxisX.MajorGrid.Enabled = Content.VisualProperties.XAxisGrid;
178
179      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
180      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
181      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
182      area.AxisY.MajorGrid.Enabled = Content.VisualProperties.YAxisGrid;
183    }
184
185    private void RecalculateAxesScale(ChartArea area) {
186      // Reset the axes bounds so that RecalculateAxesScale() will assign new bounds
187      foreach (Axis a in area.Axes) {
188        a.Minimum = double.NaN;
189        a.Maximum = double.NaN;
190      }
191      area.RecalculateAxesScale();
192      area.AxisX.IsMarginVisible = false;
193
194      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
195      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
196      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
197      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
198      if (area.AxisX.Minimum >= area.AxisX.Maximum) area.AxisX.Maximum = area.AxisX.Minimum + 1;
199      if (area.AxisY.Minimum >= area.AxisY.Maximum) area.AxisY.Maximum = area.AxisY.Minimum + 1;
200    }
201
202    protected virtual void UpdateYCursorInterval() {
203      double interestingValuesRange = (
204        from series in chart.Series
205        where series.Enabled
206        let values = (from point in series.Points
207                      where !point.IsEmpty
208                      select point.YValues[0]).DefaultIfEmpty(1.0)
209        let range = values.Max() - values.Min()
210        where range > 0.0
211        select range
212        ).DefaultIfEmpty(1.0).Min();
213
214      double digits = (int)Math.Log10(interestingValuesRange) - 3;
215      double yZoomInterval = Math.Pow(10, digits);
216      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
217    }
218
219    #region Event Handlers
220    #region Content Event Handlers
221    protected override void Content_NameChanged(object sender, EventArgs e) {
222      if (InvokeRequired)
223        Invoke(new EventHandler(Content_NameChanged), sender, e);
224      else {
225        chart.Titles[0].Text = Content.Name;
226        base.Content_NameChanged(sender, e);
227      }
228    }
229    private void Content_VisualPropertiesChanged(object sender, EventArgs e) {
230      if (InvokeRequired)
231        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
232      else {
233        ConfigureChartArea(chart.ChartAreas[0]);
234        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
235      }
236    }
237    #endregion
238    #region Rows Event Handlers
239    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
240      if (InvokeRequired)
241        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded), sender, e);
242      else {
243        AddScatterPlotDataRows(e.Items);
244      }
245    }
246    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
247      if (InvokeRequired)
248        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved), sender, e);
249      else {
250        RemoveScatterPlotDataRows(e.Items);
251      }
252    }
253    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
254      if (InvokeRequired)
255        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced), sender, e);
256      else {
257        RemoveScatterPlotDataRows(e.OldItems);
258        AddScatterPlotDataRows(e.Items);
259      }
260    }
261    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
262      if (InvokeRequired)
263        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset), sender, e);
264      else {
265        RemoveScatterPlotDataRows(e.OldItems);
266        AddScatterPlotDataRows(e.Items);
267      }
268    }
269    #endregion
270    #region Row Event Handlers
271    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
272      if (InvokeRequired)
273        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
274      else {
275        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
276        Series series = chart.Series[row.Name];
277        series.Points.Clear();
278        ConfigureSeries(series, row);
279        FillSeriesWithRowValues(series, row);
280        RecalculateAxesScale(chart.ChartAreas[0]);
281      }
282    }
283    private void Row_NameChanged(object sender, EventArgs e) {
284      if (InvokeRequired)
285        Invoke(new EventHandler(Row_NameChanged), sender, e);
286      else {
287        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
288        chart.Series[row.Name].Name = row.Name;
289      }
290    }
291    #endregion
292    #region Points Event Handlers
293    private void Points_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
294      if (InvokeRequired)
295        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded), sender, e);
296      else {
297        ScatterPlotDataRow row = null;
298        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
299        if (row != null) {
300          Series rowSeries = chart.Series[row.Name];
301          if (!invisibleSeries.Contains(rowSeries)) {
302            rowSeries.Points.Clear();
303            FillSeriesWithRowValues(rowSeries, row);
304            RecalculateAxesScale(chart.ChartAreas[0]);
305            UpdateYCursorInterval();
306          }
307        }
308      }
309    }
310    private void Points_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
311      if (InvokeRequired)
312        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved), sender, e);
313      else {
314        ScatterPlotDataRow row = null;
315        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
316        if (row != null) {
317          Series rowSeries = chart.Series[row.Name];
318          if (!invisibleSeries.Contains(rowSeries)) {
319            rowSeries.Points.Clear();
320            FillSeriesWithRowValues(rowSeries, row);
321            RecalculateAxesScale(chart.ChartAreas[0]);
322            UpdateYCursorInterval();
323          }
324        }
325      }
326    }
327    private void Points_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
328      if (InvokeRequired)
329        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced), sender, e);
330      else {
331        ScatterPlotDataRow row = null;
332        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
333        if (row != null) {
334          Series rowSeries = chart.Series[row.Name];
335          if (!invisibleSeries.Contains(rowSeries)) {
336            rowSeries.Points.Clear();
337            FillSeriesWithRowValues(rowSeries, row);
338            RecalculateAxesScale(chart.ChartAreas[0]);
339            UpdateYCursorInterval();
340          }
341        }
342      }
343    }
344    private void Points_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
345      if (InvokeRequired)
346        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset), sender, e);
347      else {
348        ScatterPlotDataRow row = null;
349        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
350        if (row != null) {
351          Series rowSeries = chart.Series[row.Name];
352          if (!invisibleSeries.Contains(rowSeries)) {
353            rowSeries.Points.Clear();
354            FillSeriesWithRowValues(rowSeries, row);
355            RecalculateAxesScale(chart.ChartAreas[0]);
356            UpdateYCursorInterval();
357          }
358        }
359      }
360    }
361    #endregion
362    #endregion
363
364    #region Chart Event Handlers
365    private void chart_MouseDown(object sender, MouseEventArgs e) {
366      HitTestResult result = chart.HitTest(e.X, e.Y);
367      if (result.ChartElementType == ChartElementType.LegendItem) {
368        ToggleSeriesVisible(result.Series);
369      }
370    }
371    private void chart_MouseMove(object sender, MouseEventArgs e) {
372      HitTestResult result = chart.HitTest(e.X, e.Y);
373      if (result.ChartElementType == ChartElementType.LegendItem)
374        this.Cursor = Cursors.Hand;
375      else
376        this.Cursor = Cursors.Default;
377    }
378    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
379      foreach (LegendItem legendItem in e.LegendItems) {
380        var series = chart.Series[legendItem.SeriesName];
381        if (series != null) {
382          bool seriesIsInvisible = invisibleSeries.Contains(series);
383          foreach (LegendCell cell in legendItem.Cells) {
384            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
385          }
386        }
387      }
388    }
389    #endregion
390
391    private void ToggleSeriesVisible(Series series) {
392      if (!invisibleSeries.Contains(series)) {
393        series.Points.Clear();
394        invisibleSeries.Add(series);
395      } else {
396        invisibleSeries.Remove(series);
397        if (Content != null) {
398
399          var row = (from r in Content.Rows
400                     where r.Name == series.Name
401                     select r).Single();
402          FillSeriesWithRowValues(series, row);
403          this.chart.Legends[series.Legend].ForeColor = Color.Black;
404          RecalculateAxesScale(chart.ChartAreas[0]);
405          UpdateYCursorInterval();
406        }
407      }
408    }
409
410    private void FillSeriesWithRowValues(Series series, ScatterPlotDataRow row) {
411      for (int i = 0; i < row.Points.Count; i++) {
412        var value = row.Points[i];
413        DataPoint point = new DataPoint();
414        if (IsInvalidValue(value.X) || IsInvalidValue(value.Y))
415          point.IsEmpty = true;
416        else {
417          point.XValue = value.X;
418          point.YValues = new double[] { value.Y };
419        }
420        series.Points.Add(point);
421      }
422    }
423
424    #region Helpers
425    public static IEnumerable<double> DoubleRange(double min, double max, double step) {
426      double i;
427      for (i = min; i <= max; i += step)
428        yield return i;
429
430      if (i != max + step)
431        yield return i;
432    }
433
434    private double HumanRoundRange(double range) {
435      double base10 = Math.Pow(10.0, Math.Floor(Math.Log10(range)));
436      double rounding = range / base10;
437      if (rounding <= 1.5) rounding = 1;
438      else if (rounding <= 2.25) rounding = 2;
439      else if (rounding <= 3.75) rounding = 2.5;
440      else if (rounding <= 7.5) rounding = 5;
441      else rounding = 10;
442      return rounding * base10;
443    }
444
445    private double HumanRoundMax(double max) {
446      double base10;
447      if (max > 0) base10 = Math.Pow(10.0, Math.Floor(Math.Log10(max)));
448      else base10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(-max)));
449      double rounding = (max > 0) ? base10 : -base10;
450      while (rounding < max) rounding += base10;
451      return rounding;
452    }
453
454    private MarkerStyle ConvertPointStyle(ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle pointStyle) {
455      switch (pointStyle) {
456        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Circle:
457          return MarkerStyle.Circle;
458        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Cross:
459          return MarkerStyle.Cross;
460        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Diamond:
461          return MarkerStyle.Diamond;
462        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Square:
463          return MarkerStyle.Square;
464        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star4:
465          return MarkerStyle.Star4;
466        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star5:
467          return MarkerStyle.Star5;
468        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star6:
469          return MarkerStyle.Star6;
470        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star10:
471          return MarkerStyle.Star10;
472        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Triangle:
473          return MarkerStyle.Triangle;
474        default:
475          return MarkerStyle.None;
476      }
477    }
478
479    protected static bool IsInvalidValue(double x) {
480      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
481    }
482    #endregion
483  }
484}
Note: See TracBrowser for help on using the repository browser.