00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 using System;
00055 using System.Drawing;
00056 using System.Diagnostics;
00057 using System.Collections;
00058
00059 namespace NPlot
00060 {
00061
00066 public class PlotSurface2D : IPlotSurface2D
00067 {
00068
00072 public enum XAxisPosition
00073 {
00077 Top = 1,
00078
00082 Bottom = 3,
00083 }
00084
00085
00089 public enum YAxisPosition
00090 {
00094 Left = 1,
00095
00099 Right = 3,
00100 }
00101
00102
00103 private System.Drawing.StringFormat titleDrawFormat_;
00104
00105 private Font titleFont_;
00106 private string title_;
00107 private Brush titleBrush_;
00108 private int padding_;
00109 private Axis xAxis1_;
00110 private Axis yAxis1_;
00111 private Axis xAxis2_;
00112 private Axis yAxis2_;
00113 private PhysicalAxis pXAxis1Cache_;
00114 private PhysicalAxis pYAxis1Cache_;
00115 private PhysicalAxis pXAxis2Cache_;
00116 private PhysicalAxis pYAxis2Cache_;
00117 private bool autoScaleAutoGeneratedAxes_ = false;
00118 private bool autoScaleTitle_ = false;
00119
00120 private object plotAreaBoundingBoxCache_;
00121 private object bbXAxis1Cache_;
00122 private object bbXAxis2Cache_;
00123 private object bbYAxis1Cache_;
00124 private object bbYAxis2Cache_;
00125 private object bbTitleCache_;
00126
00127 private object plotBackColor_ = null;
00128 private System.Drawing.Bitmap plotBackImage_ = null;
00129 private IRectangleBrush plotBackBrush_ = null;
00130
00131 private System.Collections.ArrayList drawables_;
00132 private System.Collections.ArrayList xAxisPositions_;
00133 private System.Collections.ArrayList yAxisPositions_;
00134 private System.Collections.ArrayList zPositions_;
00135 private System.Collections.SortedList ordering_;
00136
00137 private System.Drawing.Drawing2D.SmoothingMode smoothingMode_;
00138
00139 private ArrayList axesConstraints_ = null;
00140
00141 private Legend legend_;
00142
00143
00147 public Rectangle PlotAreaBoundingBoxCache
00148 {
00149 get
00150 {
00151 if (plotAreaBoundingBoxCache_ == null)
00152 {
00153 return Rectangle.Empty;
00154 }
00155 else
00156 {
00157 return (Rectangle)plotAreaBoundingBoxCache_;
00158 }
00159 }
00160 }
00161
00168 public System.Collections.ArrayList HitTest(Point p)
00169 {
00170
00171 System.Collections.ArrayList a = new System.Collections.ArrayList();
00172
00173
00174 if (bbXAxis1Cache_ == null)
00175 {
00176 return a;
00177 }
00178 else if (bbXAxis1Cache_ != null && ((Rectangle) bbXAxis1Cache_ ).Contains(p))
00179 {
00180 a.Add( this.xAxis1_ );
00181 return a;
00182 }
00183 else if (bbYAxis1Cache_ != null && ((Rectangle) bbYAxis1Cache_ ).Contains(p))
00184 {
00185 a.Add( this.yAxis1_ );
00186 return a;
00187 }
00188 else if (bbXAxis2Cache_ != null && ((Rectangle) bbXAxis2Cache_ ).Contains(p))
00189 {
00190 a.Add( this.xAxis2_ );
00191 return a;
00192 }
00193 else if (bbXAxis2Cache_ != null && ((Rectangle) bbYAxis2Cache_ ).Contains(p))
00194 {
00195 a.Add( this.yAxis2_ );
00196 return a;
00197 }
00198 else if (bbTitleCache_ != null && ((Rectangle) bbTitleCache_ ).Contains(p))
00199 {
00200 a.Add( this );
00201 return a;
00202 }
00203 else if (plotAreaBoundingBoxCache_ != null && ((Rectangle) plotAreaBoundingBoxCache_ ).Contains(p))
00204 {
00205 a.Add( this );
00206 return a;
00207 }
00208
00209 return a;
00210 }
00211
00212
00216 public Axis XAxis1
00217 {
00218 get
00219 {
00220 return xAxis1_;
00221 }
00222 set
00223 {
00224 xAxis1_ = value;
00225 }
00226 }
00227
00228
00232 public Axis YAxis1
00233 {
00234 get
00235 {
00236 return yAxis1_;
00237 }
00238 set
00239 {
00240 yAxis1_ = value;
00241 }
00242 }
00243
00244
00248 public Axis XAxis2
00249 {
00250 get
00251 {
00252 return xAxis2_;
00253 }
00254 set
00255 {
00256 xAxis2_ = value;
00257 }
00258 }
00259
00260
00264 public Axis YAxis2
00265 {
00266 get
00267 {
00268 return yAxis2_;
00269 }
00270 set
00271 {
00272 yAxis2_ = value;
00273 }
00274 }
00275
00276
00280 public PhysicalAxis PhysicalXAxis1Cache
00281 {
00282 get
00283 {
00284 return pXAxis1Cache_;
00285 }
00286 }
00287
00288
00292 public PhysicalAxis PhysicalYAxis1Cache
00293 {
00294 get
00295 {
00296 return pYAxis1Cache_;
00297 }
00298 }
00299
00300
00304 public PhysicalAxis PhysicalXAxis2Cache
00305 {
00306 get
00307 {
00308 return pXAxis2Cache_;
00309 }
00310 }
00311
00312
00316 public PhysicalAxis PhysicalYAxis2Cache
00317 {
00318 get
00319 {
00320 return pYAxis2Cache_;
00321 }
00322 }
00323
00324
00325
00329 public string Title
00330 {
00331 get
00332 {
00333 return title_;
00334 }
00335 set
00336 {
00337 title_ = value;
00338 }
00339 }
00340
00341
00345 public Font TitleFont
00346 {
00347 get
00348 {
00349 return titleFont_;
00350 }
00351 set
00352 {
00353 titleFont_ = value;
00354 }
00355 }
00356
00357
00362 public int Padding
00363 {
00364 get
00365 {
00366 return padding_;
00367 }
00368 set
00369 {
00370 padding_ = value;
00371 }
00372 }
00373
00374
00378 public Color TitleColor
00379 {
00380 set
00381 {
00382 titleBrush_ = new SolidBrush( value );
00383 }
00384 }
00385
00386
00390 public Brush TitleBrush
00391 {
00392 get
00393 {
00394 return titleBrush_;
00395 }
00396 set
00397 {
00398 titleBrush_ = value;
00399 }
00400 }
00401
00402
00406 public System.Drawing.Color PlotBackColor
00407 {
00408 set
00409 {
00410 plotBackColor_ = value;
00411 plotBackBrush_ = null;
00412 plotBackImage_ = null;
00413 }
00414 }
00415
00416
00420 public System.Drawing.Bitmap PlotBackImage
00421 {
00422 set
00423 {
00424 plotBackImage_ = value;
00425 plotBackColor_ = null;
00426 plotBackBrush_ = null;
00427 }
00428 }
00429
00430
00434 public IRectangleBrush PlotBackBrush
00435 {
00436 set
00437 {
00438 plotBackBrush_ = value;
00439 plotBackColor_ = null;
00440 plotBackImage_ = null;
00441 }
00442 }
00443
00444
00448 public System.Drawing.Drawing2D.SmoothingMode SmoothingMode
00449 {
00450 get
00451 {
00452 return smoothingMode_;
00453 }
00454 set
00455 {
00456 this.smoothingMode_ = value;
00457 }
00458 }
00459
00460
00461 private void Init()
00462 {
00463 drawables_ = new ArrayList();
00464 xAxisPositions_ = new ArrayList();
00465 yAxisPositions_ = new ArrayList();
00466 zPositions_ = new ArrayList();
00467 ordering_ = new SortedList();
00468 FontFamily fontFamily = new FontFamily("Arial");
00469 TitleFont = new Font(fontFamily, 14, FontStyle.Regular, GraphicsUnit.Pixel);
00470 padding_ = 10;
00471 title_ = "";
00472 autoScaleTitle_ = false;
00473 autoScaleAutoGeneratedAxes_ = false;
00474 xAxis1_ = null;
00475 xAxis2_ = null;
00476 yAxis1_ = null;
00477 yAxis2_ = null;
00478 pXAxis1Cache_ = null;
00479 pYAxis1Cache_ = null;
00480 pXAxis2Cache_ = null;
00481 pYAxis2Cache_ = null;
00482 titleBrush_ = new SolidBrush( Color.Black );
00483 plotBackColor_ = Color.White;
00484
00485 this.legend_ = null;
00486
00487 smoothingMode_ = System.Drawing.Drawing2D.SmoothingMode.None;
00488
00489 axesConstraints_ = new ArrayList();
00490 }
00491
00492
00496 public PlotSurface2D()
00497 {
00498
00499 titleDrawFormat_ = new StringFormat();
00500 titleDrawFormat_.Alignment = StringAlignment.Center;
00501
00502 Init();
00503 }
00504
00505
00506 private float DetermineScaleFactor( int w, int h )
00507 {
00508
00509 float diag = (float)Math.Sqrt( w*w + h*h );
00510 float scaleFactor = (diag / 1400.0f)*2.4f;
00511
00512 if ( scaleFactor > 1.0f )
00513 {
00514 return scaleFactor;
00515 }
00516 else
00517 {
00518 return 1.0f;
00519 }
00520 }
00521
00522
00528 public void Add(IDrawable p)
00529 {
00530 Add(p, 0);
00531 }
00532
00533
00540 public void Add( IDrawable p, int zOrder )
00541 {
00542 Add( p, XAxisPosition.Bottom, YAxisPosition.Left, zOrder );
00543 }
00544
00545
00554 public void Add(IDrawable p, XAxisPosition xp, YAxisPosition yp)
00555 {
00556 Add(p, xp, yp, 0);
00557 }
00558
00559
00568 public void Add( IDrawable p, XAxisPosition xp, YAxisPosition yp, int zOrder )
00569 {
00570 drawables_.Add( p );
00571 xAxisPositions_.Add( xp );
00572 yAxisPositions_.Add( yp );
00573 zPositions_.Add((double)zOrder);
00574
00575 double fraction = (double)(++uniqueCounter_)/10000000.0f;
00576 ordering_.Add( (double)zOrder + fraction, drawables_.Count - 1 );
00577
00578
00579 if ( p is IPlot )
00580 {
00581 UpdateAxes( false );
00582 }
00583
00584 }
00585
00586 private int uniqueCounter_ = 0;
00587
00588
00589 private void UpdateAxes( bool recalculateAll )
00590 {
00591 if (drawables_.Count != xAxisPositions_.Count || drawables_.Count != yAxisPositions_.Count)
00592 {
00593 throw new NPlotException("plots and axis position arrays our of sync");
00594 }
00595
00596 int position = 0;
00597
00598
00599
00600 if (!recalculateAll)
00601 {
00602 position = drawables_.Count - 1;
00603 if (position < 0) position = 0;
00604 }
00605
00606 if (recalculateAll)
00607 {
00608 this.xAxis1_ = null;
00609 this.yAxis1_ = null;
00610 this.xAxis2_ = null;
00611 this.yAxis2_ = null;
00612 }
00613
00614 for (int i = position; i < drawables_.Count; ++i)
00615 {
00616
00617
00618 if (!(drawables_[position] is IPlot))
00619 continue;
00620
00621 IPlot p = (IPlot)drawables_[position];
00622 XAxisPosition xap = (XAxisPosition)xAxisPositions_[position];
00623 YAxisPosition yap = (YAxisPosition)yAxisPositions_[position];
00624
00625 if (xap == XAxisPosition.Bottom)
00626 {
00627 if (this.xAxis1_ == null)
00628 {
00629 this.xAxis1_ = p.SuggestXAxis();
00630 if (this.xAxis1_ != null)
00631 {
00632 this.xAxis1_.TicksAngle = -(float)Math.PI / 2.0f;
00633 }
00634 }
00635 else
00636 {
00637 this.xAxis1_.LUB(p.SuggestXAxis());
00638 }
00639
00640 if (this.xAxis1_ != null)
00641 {
00642 this.xAxis1_.MinPhysicalLargeTickStep = 50;
00643
00644 if (this.AutoScaleAutoGeneratedAxes)
00645 {
00646 this.xAxis1_.AutoScaleText = true;
00647 this.xAxis1_.AutoScaleTicks = true;
00648 this.xAxis1_.TicksIndependentOfPhysicalExtent = true;
00649 }
00650 else
00651 {
00652 this.xAxis1_.AutoScaleText = false;
00653 this.xAxis1_.AutoScaleTicks = false;
00654 this.xAxis1_.TicksIndependentOfPhysicalExtent = false;
00655 }
00656 }
00657 }
00658
00659 if (xap == XAxisPosition.Top)
00660 {
00661 if (this.xAxis2_ == null)
00662 {
00663 this.xAxis2_ = p.SuggestXAxis();
00664 if (this.xAxis2_ != null)
00665 {
00666 this.xAxis2_.TicksAngle = (float)Math.PI / 2.0f;
00667 }
00668 }
00669 else
00670 {
00671 this.xAxis2_.LUB(p.SuggestXAxis());
00672 }
00673
00674 if (this.xAxis2_ != null)
00675 {
00676 this.xAxis2_.MinPhysicalLargeTickStep = 50;
00677
00678 if (this.AutoScaleAutoGeneratedAxes)
00679 {
00680 this.xAxis2_.AutoScaleText = true;
00681 this.xAxis2_.AutoScaleTicks = true;
00682 this.xAxis2_.TicksIndependentOfPhysicalExtent = true;
00683 }
00684 else
00685 {
00686 this.xAxis2_.AutoScaleText = false;
00687 this.xAxis2_.AutoScaleTicks = false;
00688 this.xAxis2_.TicksIndependentOfPhysicalExtent = false;
00689 }
00690 }
00691 }
00692
00693 if (yap == YAxisPosition.Left)
00694 {
00695 if (this.yAxis1_ == null)
00696 {
00697 this.yAxis1_ = p.SuggestYAxis();
00698 if (this.yAxis1_ != null)
00699 {
00700 this.yAxis1_.TicksAngle = (float)Math.PI / 2.0f;
00701 }
00702 }
00703 else
00704 {
00705 this.yAxis1_.LUB(p.SuggestYAxis());
00706 }
00707
00708 if (this.yAxis1_ != null)
00709 {
00710 if (this.AutoScaleAutoGeneratedAxes)
00711 {
00712 this.yAxis1_.AutoScaleText = true;
00713 this.yAxis1_.AutoScaleTicks = true;
00714 this.yAxis1_.TicksIndependentOfPhysicalExtent = true;
00715 }
00716 else
00717 {
00718 this.yAxis1_.AutoScaleText = false;
00719 this.yAxis1_.AutoScaleTicks = false;
00720 this.yAxis1_.TicksIndependentOfPhysicalExtent = false;
00721 }
00722 }
00723 }
00724
00725 if (yap == YAxisPosition.Right)
00726 {
00727 if (this.yAxis2_ == null)
00728 {
00729 this.yAxis2_ = p.SuggestYAxis();
00730 if (this.yAxis2_ != null)
00731 {
00732 this.yAxis2_.TicksAngle = -(float)Math.PI / 2.0f;
00733 }
00734 }
00735 else
00736 {
00737 this.yAxis2_.LUB(p.SuggestYAxis());
00738 }
00739
00740 if (this.yAxis2_ != null)
00741 {
00742 if (this.AutoScaleAutoGeneratedAxes)
00743 {
00744 this.yAxis2_.AutoScaleText = true;
00745 this.yAxis2_.AutoScaleTicks = true;
00746 this.yAxis2_.TicksIndependentOfPhysicalExtent = true;
00747 }
00748 else
00749 {
00750 this.yAxis2_.AutoScaleText = false;
00751 this.yAxis2_.AutoScaleTicks = false;
00752 this.yAxis2_.TicksIndependentOfPhysicalExtent = false;
00753 }
00754 }
00755
00756 }
00757 }
00758
00759 }
00760
00761
00762 private void DetermineAxesToDraw( out Axis xAxis1, out Axis xAxis2, out Axis yAxis1, out Axis yAxis2 )
00763 {
00764 xAxis1 = this.xAxis1_;
00765 xAxis2 = this.xAxis2_;
00766 yAxis1 = this.yAxis1_;
00767 yAxis2 = this.yAxis2_;
00768
00769 if (this.xAxis1_ == null)
00770 {
00771 if (this.xAxis2_ == null)
00772 {
00773 throw new NPlotException( "Error: No X-Axis specified" );
00774 }
00775 xAxis1 = (Axis)this.xAxis2_.Clone();
00776 xAxis1.HideTickText = true;
00777 xAxis1.TicksAngle = -(float)Math.PI / 2.0f;
00778 }
00779
00780 if (this.xAxis2_ == null)
00781 {
00782
00783 xAxis2 = (Axis)this.xAxis1_.Clone();
00784 xAxis2.HideTickText = true;
00785 xAxis2.TicksAngle = (float)Math.PI / 2.0f;
00786 }
00787
00788 if (this.yAxis1_ == null)
00789 {
00790 if (this.yAxis2_ == null)
00791 {
00792 throw new NPlotException( "Error: No Y-Axis specified" );
00793 }
00794 yAxis1 = (Axis)this.yAxis2_.Clone();
00795 yAxis1.HideTickText = true;
00796 yAxis1.TicksAngle = (float)Math.PI / 2.0f;
00797 }
00798
00799 if (this.yAxis2_ == null)
00800 {
00801
00802 yAxis2 = (Axis)this.yAxis1_.Clone();
00803 yAxis2.HideTickText = true;
00804 yAxis2.TicksAngle = -(float)Math.PI / 2.0f;
00805 }
00806
00807 }
00808
00809
00810 private void DeterminePhysicalAxesToDraw( Rectangle bounds,
00811 Axis xAxis1, Axis xAxis2, Axis yAxis1, Axis yAxis2,
00812 out PhysicalAxis pXAxis1, out PhysicalAxis pXAxis2,
00813 out PhysicalAxis pYAxis1, out PhysicalAxis pYAxis2 )
00814 {
00815
00816 System.Drawing.Rectangle cb = bounds;
00817
00818 pXAxis1 = new PhysicalAxis( xAxis1,
00819 new Point( cb.Left, cb.Bottom ), new Point( cb.Right, cb.Bottom ) );
00820 pYAxis1 = new PhysicalAxis( yAxis1,
00821 new Point( cb.Left, cb.Bottom ), new Point( cb.Left, cb.Top ) );
00822 pXAxis2 = new PhysicalAxis( xAxis2,
00823 new Point( cb.Left, cb.Top), new Point( cb.Right, cb.Top) );
00824 pYAxis2 = new PhysicalAxis( yAxis2,
00825 new Point( cb.Right, cb.Bottom ), new Point( cb.Right, cb.Top ) );
00826
00827 int bottomIndent = padding_;
00828 if (!pXAxis1.Axis.Hidden)
00829 {
00830
00831 Rectangle bb = pXAxis1.GetBoundingBox();
00832
00833 bottomIndent = bottomIndent + bb.Bottom - cb.Bottom;
00834 }
00835
00836 int leftIndent = padding_;
00837 if (!pYAxis1.Axis.Hidden)
00838 {
00839
00840 Rectangle bb = pYAxis1.GetBoundingBox();
00841
00842 leftIndent = leftIndent - bb.Left + cb.Left;
00843 }
00844
00845 int topIndent = padding_;
00846 float scale = this.DetermineScaleFactor( bounds.Width, bounds.Height );
00847 int titleHeight;
00848 if (this.AutoScaleTitle)
00849 {
00850 titleHeight = Utils.ScaleFont(titleFont_, scale).Height;
00851 }
00852 else
00853 {
00854 titleHeight = titleFont_.Height;
00855 }
00856
00857
00858 int nlCount = 0;
00859 for (int i=0; i<title_.Length; ++i)
00860 {
00861 if (title_[i] == '\n')
00862 nlCount += 1;
00863 }
00864 titleHeight = (int)( ((float)nlCount*0.75 + 1.0f) * (float)titleHeight);
00865
00866 if (!pXAxis2.Axis.Hidden)
00867 {
00868
00869 Rectangle bb = pXAxis2.GetBoundingBox();
00870 topIndent = topIndent - bb.Top + cb.Top;
00871
00872
00873
00874 if (title_ != "" )
00875 {
00876 topIndent += (int)(titleHeight * 1.3f);
00877 }
00878 }
00879
00880 int rightIndent = padding_;
00881 if (!pYAxis2.Axis.Hidden)
00882 {
00883
00884 Rectangle bb = pYAxis2.GetBoundingBox();
00885
00886
00887 rightIndent = (int)(rightIndent + bb.Right-cb.Right);
00888 }
00889
00890
00891
00892
00893
00894 pXAxis1.PhysicalMin = new Point( cb.Left+leftIndent, cb.Bottom-bottomIndent );
00895 pXAxis1.PhysicalMax = new Point( cb.Right-rightIndent, cb.Bottom-bottomIndent );
00896 pYAxis1.PhysicalMin = new Point( cb.Left+leftIndent, cb.Bottom-bottomIndent );
00897 pYAxis1.PhysicalMax = new Point( cb.Left+leftIndent, cb.Top+topIndent );
00898
00899
00900 pXAxis2.PhysicalMin = new Point( cb.Left+leftIndent, cb.Top+topIndent );
00901 pXAxis2.PhysicalMax = new Point( cb.Right-rightIndent, cb.Top+topIndent );
00902 pYAxis2.PhysicalMin = new Point( cb.Right-rightIndent, cb.Bottom-bottomIndent );
00903 pYAxis2.PhysicalMax = new Point( cb.Right-rightIndent, cb.Top+topIndent );
00904
00905 }
00906
00907
00908
00916 public void Draw( Graphics g, Rectangle bounds )
00917 {
00918
00919 float scale = DetermineScaleFactor( bounds.Width, bounds.Height );
00920
00921
00922 if ( drawables_.Count == 0 )
00923 {
00924
00925 float x_center = (bounds.Left + bounds.Right)/2.0f;
00926 float y_center = (bounds.Top + bounds.Bottom)/2.0f;
00927 Font scaled_font;
00928 if (this.AutoScaleTitle)
00929 {
00930 scaled_font = Utils.ScaleFont( titleFont_, scale );
00931 }
00932 else
00933 {
00934 scaled_font = titleFont_;
00935 }
00936 g.DrawString( title_, scaled_font, this.titleBrush_, new PointF(x_center,y_center), titleDrawFormat_ );
00937
00938 return;
00939 }
00940
00941
00942 Axis xAxis1 = null;
00943 Axis xAxis2 = null;
00944 Axis yAxis1 = null;
00945 Axis yAxis2 = null;
00946 this.DetermineAxesToDraw( out xAxis1, out xAxis2, out yAxis1, out yAxis2 );
00947
00948
00949
00950 if (xAxis1.AutoScaleTicks)
00951 xAxis1.TickScale = scale;
00952 if (xAxis1.AutoScaleText)
00953 xAxis1.FontScale = scale;
00954 if (yAxis1.AutoScaleTicks)
00955 yAxis1.TickScale = scale;
00956 if (yAxis1.AutoScaleText)
00957 yAxis1.FontScale = scale;
00958 if (xAxis2.AutoScaleTicks)
00959 xAxis2.TickScale = scale;
00960 if (xAxis2.AutoScaleText)
00961 xAxis2.FontScale = scale;
00962 if (yAxis2.AutoScaleTicks)
00963 yAxis2.TickScale = scale;
00964 if (yAxis2.AutoScaleText)
00965 yAxis2.FontScale = scale;
00966
00967
00968 PhysicalAxis pXAxis1 = null;
00969 PhysicalAxis pYAxis1 = null;
00970 PhysicalAxis pXAxis2 = null;
00971 PhysicalAxis pYAxis2 = null;
00972 this.DeterminePhysicalAxesToDraw(
00973 bounds, xAxis1, xAxis2, yAxis1, yAxis2,
00974 out pXAxis1, out pXAxis2, out pYAxis1, out pYAxis2 );
00975
00976 float oldXAxis2Height = pXAxis2.PhysicalMin.Y;
00977
00978
00979 for (int i=0; i<axesConstraints_.Count; ++i)
00980 {
00981 ((AxesConstraint)axesConstraints_[i]).ApplyConstraint(
00982 pXAxis1, pYAxis1, pXAxis2, pYAxis2 );
00983 }
00984
00986
00987
00988
00989 Point legendPosition = new Point(0,0);
00990 if (this.legend_ != null)
00991 {
00992 legend_.UpdateAxesPositions(
00993 pXAxis1, pYAxis1, pXAxis2, pYAxis2,
00994 this.drawables_, scale, this.padding_, bounds,
00995 out legendPosition );
00996 }
00997
00998 float newXAxis2Height = pXAxis2.PhysicalMin.Y;
00999
01000 float titleExtraOffset = oldXAxis2Height - newXAxis2Height;
01001
01002
01003
01004 plotAreaBoundingBoxCache_ = new Rectangle(
01005 Math.Min( pXAxis1.PhysicalMin.X, pXAxis1.PhysicalMax.X ),
01006 Math.Min( pYAxis1.PhysicalMax.Y, pYAxis1.PhysicalMin.Y ),
01007 Math.Abs( pXAxis1.PhysicalMax.X - pXAxis1.PhysicalMin.X + 1 ),
01008 Math.Abs( pYAxis1.PhysicalMin.Y - pYAxis1.PhysicalMax.Y + 1 )
01009 );
01010 bbXAxis1Cache_ = pXAxis1.GetBoundingBox();
01011 bbXAxis2Cache_ = pXAxis2.GetBoundingBox();
01012 bbYAxis1Cache_ = pYAxis1.GetBoundingBox();
01013 bbYAxis2Cache_ = pYAxis2.GetBoundingBox();
01014
01015
01016 if ( this.plotBackColor_ != null )
01017 {
01018 g.FillRectangle(
01019 new System.Drawing.SolidBrush( (Color)this.plotBackColor_ ),
01020 (Rectangle)plotAreaBoundingBoxCache_ );
01021 }
01022 else if (this.plotBackBrush_ != null)
01023 {
01024 g.FillRectangle(
01025 this.plotBackBrush_.Get( (Rectangle)plotAreaBoundingBoxCache_ ),
01026 (Rectangle)plotAreaBoundingBoxCache_ );
01027 }
01028 else if (this.plotBackImage_ != null)
01029 {
01030 g.DrawImage(
01031 Utils.TiledImage( this.plotBackImage_ , new Size(
01032 ((Rectangle)plotAreaBoundingBoxCache_).Width,
01033 ((Rectangle)plotAreaBoundingBoxCache_).Height ) ),
01034 (Rectangle)plotAreaBoundingBoxCache_ );
01035 }
01036
01037
01038 float xt = (pXAxis2.PhysicalMax.X + pXAxis2.PhysicalMin.X)/2.0f;
01039 float yt = bounds.Top + this.padding_ - titleExtraOffset;
01040 Font scaledFont;
01041 if (this.AutoScaleTitle)
01042 {
01043 scaledFont = Utils.ScaleFont( titleFont_, scale );
01044 }
01045 else
01046 {
01047 scaledFont = titleFont_;
01048 }
01049 g.DrawString( title_, scaledFont, this.titleBrush_, new PointF(xt,yt), titleDrawFormat_ );
01050
01051
01052 int nlCount = 0;
01053 for (int i=0; i<title_.Length; ++i)
01054 {
01055 if (title_[i] == '\n')
01056 nlCount += 1;
01057 }
01058
01059 SizeF s = g.MeasureString(title_,scaledFont);
01060 bbTitleCache_ = new Rectangle( (int)(xt-s.Width/2), (int)(yt), (int)(s.Width), (int)(s.Height)*(nlCount+1) );
01061
01062
01063 System.Drawing.Drawing2D.SmoothingMode smoothSave = g.SmoothingMode;
01064
01065 g.SmoothingMode = this.smoothingMode_;
01066
01067 bool legendDrawn = false;
01068
01069 for ( int i_o = 0; i_o < ordering_.Count; ++i_o )
01070 {
01071
01072 int i = (int)ordering_.GetByIndex(i_o);
01073 double zOrder = (double)ordering_.GetKey( i_o );
01074 if (zOrder > this.legendZOrder_)
01075 {
01076
01077 if ( !legendDrawn && this.legend_ != null )
01078 {
01079 legend_.Draw( g, legendPosition, this.drawables_, scale );
01080 legendDrawn = true;
01081 }
01082 }
01083
01084 IDrawable drawable = (IDrawable)drawables_[i];
01085 XAxisPosition xap = (XAxisPosition)xAxisPositions_[i];
01086 YAxisPosition yap = (YAxisPosition)yAxisPositions_[i];
01087
01088 PhysicalAxis drawXAxis;
01089 PhysicalAxis drawYAxis;
01090
01091 if ( xap == XAxisPosition.Bottom )
01092 {
01093 drawXAxis = pXAxis1;
01094 }
01095 else
01096 {
01097 drawXAxis = pXAxis2;
01098 }
01099
01100 if ( yap == YAxisPosition.Left )
01101 {
01102 drawYAxis = pYAxis1;
01103 }
01104 else
01105 {
01106 drawYAxis = pYAxis2;
01107 }
01108
01109
01110 g.Clip = new Region((Rectangle)plotAreaBoundingBoxCache_);
01111
01112 drawable.Draw( g, drawXAxis, drawYAxis );
01113
01114 g.ResetClip();
01115 }
01116
01117 if ( !legendDrawn && this.legend_ != null )
01118 {
01119 legend_.Draw( g, legendPosition, this.drawables_, scale );
01120 }
01121
01122
01123 this.pXAxis1Cache_ = pXAxis1;
01124 this.pYAxis1Cache_ = pYAxis1;
01125 this.pXAxis2Cache_ = pXAxis2;
01126 this.pYAxis2Cache_ = pYAxis2;
01127
01128 g.SmoothingMode = smoothSave;
01129
01130
01131 Rectangle axisBounds;
01132 pXAxis1.Draw( g, out axisBounds );
01133 pXAxis2.Draw( g, out axisBounds );
01134 pYAxis1.Draw( g, out axisBounds );
01135 pYAxis2.Draw( g, out axisBounds );
01136
01137 #if DEBUG_BOUNDING_BOXES
01138 g.DrawRectangle( new Pen(Color.Orange), (Rectangle) bbXAxis1Cache_ );
01139 g.DrawRectangle( new Pen(Color.Orange), (Rectangle) bbXAxis2Cache_ );
01140 g.DrawRectangle( new Pen(Color.Orange), (Rectangle) bbYAxis1Cache_ );
01141 g.DrawRectangle( new Pen(Color.Orange), (Rectangle) bbYAxis2Cache_ );
01142 g.DrawRectangle( new Pen(Color.Red,5.0F),(Rectangle) plotAreaBoundingBoxCache_);
01143
01144 g.DrawRectangle( new Pen(Color.DeepPink,2.0F), (Rectangle) bbTitleCache_);
01145 #endif
01146
01147 }
01148
01149
01153 public void Clear()
01154 {
01155 Init();
01156 }
01157
01158
01163 public NPlot.Legend Legend
01164 {
01165 get
01166 {
01167 return this.legend_;
01168 }
01169 set
01170 {
01171 this.legend_ = value;
01172 }
01173 }
01174
01175
01182 public void AddAxesConstraint( AxesConstraint constraint )
01183 {
01184 this.axesConstraints_.Add( constraint );
01185 }
01186
01187
01191 public bool AutoScaleTitle
01192 {
01193 get
01194 {
01195 return autoScaleTitle_;
01196 }
01197 set
01198 {
01199 autoScaleTitle_ = value;
01200 }
01201 }
01202
01203
01212 public bool AutoScaleAutoGeneratedAxes
01213 {
01214 get
01215 {
01216 return autoScaleAutoGeneratedAxes_;
01217 }
01218 set
01219 {
01220 autoScaleAutoGeneratedAxes_ = value;
01221 }
01222 }
01223
01224
01231 public void Remove( IDrawable p, bool updateAxes )
01232 {
01233 int index = drawables_.IndexOf( p );
01234 if (index < 0)
01235 return;
01236 drawables_.RemoveAt( index );
01237 xAxisPositions_.RemoveAt( index );
01238 yAxisPositions_.RemoveAt( index );
01239 zPositions_.RemoveAt(index);
01240
01241 if (updateAxes)
01242 {
01243 this.UpdateAxes(true);
01244 }
01245
01246 this.RefreshZOrdering();
01247 }
01248
01249
01254 private void RefreshZOrdering()
01255 {
01256 uniqueCounter_ = 0;
01257 ordering_ = new SortedList();
01258 for (int i = 0; i < zPositions_.Count; ++i)
01259 {
01260 double zpos = Convert.ToDouble(zPositions_[i]);
01261 double fraction = (double)(++uniqueCounter_) / 10000000.0f;
01262 double d = zpos + fraction;
01263 ordering_.Add(d, i);
01264 }
01265 }
01266
01267
01268
01272 public ArrayList Drawables
01273 {
01274 get
01275 {
01276 return this.drawables_;
01277 }
01278 }
01279
01280
01286 public Axis WhichXAxis( IPlot plot )
01287 {
01288 int index = drawables_.IndexOf( plot );
01289 XAxisPosition p = (XAxisPosition)xAxisPositions_[index];
01290 if ( p == XAxisPosition.Bottom )
01291 return this.xAxis1_;
01292 else
01293 return this.xAxis2_;
01294 }
01295
01296
01302 public Axis WhichYAxis( IPlot plot )
01303 {
01304 int index = drawables_.IndexOf( plot );
01305 YAxisPosition p = (YAxisPosition)yAxisPositions_[index];
01306 if ( p == YAxisPosition.Left )
01307 return this.yAxis1_;
01308 else
01309 return this.yAxis2_;
01310 }
01311
01312
01317 public int LegendZOrder
01318 {
01319 get
01320 {
01321 return legendZOrder_;
01322 }
01323 set
01324 {
01325 legendZOrder_ = value;
01326 }
01327 }
01328 int legendZOrder_ = -1;
01329
01330
01331 }
01332 }
01333
01334