PlotSurface2D.cs

Go to the documentation of this file.
00001 /*
00002 NPlot - A charting library for .NET
00003 
00004 PlotSurface2D.cs
00005 Copyright (C) 2003
00006 Matt Howlett, Paolo Pierini
00007 
00008 Redistribution and use of NPlot or parts there-of in source and
00009 binary forms, with or without modification, are permitted provided
00010 that the following conditions are met:
00011 
00012 1. Re-distributions in source form must retain at the head of each
00013    source file the above copyright notice, this list of conditions
00014    and the following disclaimer.
00015 
00016 2. Any product ("the product") that makes use NPlot or parts 
00017    there-of must either:
00018   
00019     (a) allow any user of the product to obtain a complete machine-
00020         readable copy of the corresponding source code for the 
00021         product and the version of NPlot used for a charge no more
00022         than your cost of physically performing source distribution,
00023         on a medium customarily used for software interchange, or:
00024 
00025     (b) reproduce the following text in the documentation, about 
00026         box or other materials intended to be read by human users
00027         of the product that is provided to every human user of the
00028         product: 
00029    
00030               "This product includes software developed as 
00031               part of the NPlot library project available 
00032               from: http://www.nplot.com/" 
00033 
00034         The words "This product" may optionally be replace with 
00035         the actual name of the product.
00036 
00037 ------------------------------------------------------------------------
00038 
00039 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00040 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00041 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00042 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00043 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00044 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00045 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00046 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00047 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00048 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00049 
00050 */
00051 
00052 // #define DEBUG_BOUNDING_BOXES
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                         //Center = 2,
00082                         Bottom = 3,
00083                 }
00084 
00085 
00089                 public enum YAxisPosition
00090                 {
00094                         Left = 1,
00095                         // Center
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                         // this is the case if PlotSurface has been cleared.
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                         // only create this once.
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             // fraction is to make key unique. With 10 million plots at same z, this buggers up.. 
00575             double fraction = (double)(++uniqueCounter_)/10000000.0f; 
00576             ordering_.Add( (double)zOrder + fraction, drawables_.Count - 1 );
00577             
00578             // if p is just an IDrawable, then it can't affect the axes.
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             // if we're not recalculating axes using all iplots then set
00599             // position to last one in list.
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                 // only update axes if this drawable is an IPlot.
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                                 // don't need to check if xAxis1_ == null, as case already handled above.
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                                 // don't need to check if yAxis1_ == null, as case already handled above.
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                                 // evaluate its bounding box
00831                                 Rectangle bb = pXAxis1.GetBoundingBox();
00832                                 // finally determine its indentation from the bottom
00833                                 bottomIndent = bottomIndent + bb.Bottom - cb.Bottom;
00834                         }
00835 
00836                         int leftIndent = padding_;
00837                         if (!pYAxis1.Axis.Hidden) 
00838                         {
00839                                 // evaluate its bounding box
00840                                 Rectangle bb = pYAxis1.GetBoundingBox();
00841                                 // finally determine its indentation from the left
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                         //count number of new lines in title.
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                                 // evaluate its bounding box
00869                                 Rectangle bb = pXAxis2.GetBoundingBox();
00870                                 topIndent = topIndent - bb.Top + cb.Top;
00871 
00872                                 // finally determine its indentation from the top
00873                                 // correct top indendation to take into account plot title
00874                                 if (title_ != "" )
00875                                 {
00876                                         topIndent += (int)(titleHeight * 1.3f);
00877                                 }
00878                         }
00879 
00880                         int rightIndent = padding_;
00881                         if (!pYAxis2.Axis.Hidden) 
00882                         {
00883                                 // evaluate its bounding box
00884                                 Rectangle bb = pYAxis2.GetBoundingBox();
00885 
00886                                 // finally determine its indentation from the right
00887                                 rightIndent = (int)(rightIndent + bb.Right-cb.Right);
00888                         }
00889 
00890                         // now we have all the default calculated positions and we can proceed to
00891                         // "move" the axes to their right places
00892 
00893                         // primary axes (bottom, left)
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                         // secondary axes (top, right)
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                         // determine font sizes and tick scale factor.
00919                         float scale = DetermineScaleFactor( bounds.Width, bounds.Height );
00920 
00921                         // if there is nothing to plot, return.
00922                         if ( drawables_.Count == 0 )
00923                         {
00924                                 // draw title
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                         // determine the [non physical] axes to draw based on the axis properties set.
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                         // apply scale factor to axes as desired.
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                         // determine the default physical positioning of those axes.
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                         // Apply axes constraints
00979                         for (int i=0; i<axesConstraints_.Count; ++i)
00980                         {
00981                                 ((AxesConstraint)axesConstraints_[i]).ApplyConstraint( 
00982                                         pXAxis1, pYAxis1, pXAxis2, pYAxis2 );
00983                         }
00984 
00986                         // draw legend if have one.
00987                         // Note: this will update axes if necessary. 
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                         // now we are ready to define the bounding box for the plot area (to use in clipping
01003                         // operations.
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                         // Fill in the background. 
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                         // draw title
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                         //count number of new lines in title.
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                         // draw drawables..
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                                         // draw legend.
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                                 // set the clipping region.. (necessary for zoom)
01110                                 g.Clip = new Region((Rectangle)plotAreaBoundingBoxCache_);
01111                                 // plot.
01112                                 drawable.Draw( g, drawXAxis, drawYAxis );
01113                                 // reset it..
01114                                 g.ResetClip();
01115                         }
01116                         
01117                         if ( !legendDrawn && this.legend_ != null )
01118                         {
01119                                 legend_.Draw( g, legendPosition, this.drawables_, scale );
01120                         }
01121 
01122                         // cache the physical axes we used on this draw;
01123                         this.pXAxis1Cache_ = pXAxis1;
01124                         this.pYAxis1Cache_ = pYAxis1;
01125                         this.pXAxis2Cache_ = pXAxis2;
01126                         this.pYAxis2Cache_ = pYAxis2;
01127 
01128                         g.SmoothingMode = smoothSave;
01129 
01130                         // now draw axes.
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                         //if(this.ShowLegend)g.DrawRectangle( new Pen(Color.Chocolate, 3.0F), (Rectangle) bbLegendCache_);
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 

Generated on Sat Nov 5 01:04:06 2005 for NPlot by  doxygen 1.4.5