SeriesList.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: SeriesList.cpp 3140 2012-06-18 15:03:02Z susancummins $"
00002 
00005 
00006 //============================================================================
00007 //
00008 //  This file is part of GPSTk, the GPS Toolkit.
00009 //
00010 //  The GPSTk is free software; you can redistribute it and/or modify
00011 //  it under the terms of the GNU Lesser General Public License as published
00012 //  by the Free Software Foundation; either version 2.1 of the License, or
00013 //  any later version.
00014 //
00015 //  The GPSTk is distributed in the hope that it will be useful,
00016 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 //  GNU Lesser General Public License for more details.
00019 //
00020 //  You should have received a copy of the GNU Lesser General Public
00021 //  License along with GPSTk; if not, write to the Free Software Foundation,
00022 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
00023 //  
00024 //  Copyright 2004, The University of Texas at Austin
00025 //
00026 //============================================================================
00027 
00028 #include <algorithm>
00029 
00030 #include "SeriesList.hpp"
00031 #include "Splitter.hpp"
00032 
00033 using namespace std;
00034 using namespace vdraw;
00035 
00036 namespace vplot
00037 {
00038   void SeriesList::findMinMax(double& minX, double &maxX, double& minY, double& maxY)
00039   {
00040     minX = DBL_MAX;
00041     maxX = DBL_MIN;
00042     minY = DBL_MAX;
00043     maxY = DBL_MIN;
00044 
00045     for(unsigned int i=0; i<pointlists.size(); i++)
00046     {
00047       vector<pair<double, double> >& series = pointlists[i];
00048       vector<pair<double, double> >::iterator it;
00049       for (it = series.begin(); it!=series.end(); it++)
00050       {
00051         double x = it->first;
00052         double y = it->second;
00053         maxX = (x>maxX ? x : maxX); 
00054         minX = (x<minX ? x : minX); 
00055         maxY = (y>maxY ? y : maxY); 
00056         minY = (y<minY ? y : minY); 
00057       } 
00058     } 
00059   }
00060 
00061   void SeriesList::drawInFrame(Frame& innerFrame, double minX, double maxX, double minY, double maxY)
00062   {
00063     double multX = innerFrame.getWidth()/(maxX-minX);
00064     double multY = innerFrame.getHeight()/(maxY-minY);
00065 
00066     // Draw lines
00067     for(int i=0;i<getNumSeries();i++)
00068     {
00069       innerFrame.push_state();
00070 
00071       StrokeStyle s = getStyle(i);          
00072       Marker m = getMarker(i);
00073 
00074       if(m.getColor().isClear() && s.getColor().isClear())
00075       {
00076         innerFrame << Comment("Plot contained data with clear stroke and marker.  Skipping.");
00077         continue;
00078       }
00079 
00080       vector< pair<double,double> >& vec = getPointList(i);
00081       Path curve(vec,innerFrame.lx(), innerFrame.ly());
00082 
00083       // What I'd give for a line of haskell...
00084       // map (\(x,y) -> (multX*(x-minX), multY*(y-minY))) vector
00085       map_object map_instance(multX,minX,multY,minY);
00086 
00087       innerFrame.setMarker(m);
00088       innerFrame.setLineStyle(s);
00089 
00090       if(s.getColor().isClear())
00091       {
00092         // crop
00093         auto_ptr< Path > cropX = Splitter::cropToBox(minX,maxX,minY,maxY,curve);
00094 
00095         // Fit it to the box.
00096         std::for_each(cropX->begin(), cropX->end(), map_instance);
00097 
00098         // Draw the line
00099         innerFrame.line(*cropX);
00100       }
00101       else 
00102       {
00103         // interpolate
00104         auto_ptr< std::list<Path> > interpX = Splitter::interpToBox(minX,maxX,minY,maxY,curve);
00105 
00106         for(std::list<Path>::iterator i=interpX->begin();i!=interpX->end();i++)
00107         {
00108           // Fit it to the box
00109           std::for_each(i->begin(), i->end(), map_instance);
00110 
00111           // Draw the line
00112           innerFrame.line(*i);
00113         }
00114       }
00115       innerFrame.pop_state();
00116     }
00117   }
00118 
00119   void SeriesList::drawLegend(Frame& frame, double pointsize, unsigned int columns)
00120   {
00121     if(columns <= 1)
00122       drawLegendSegment(frame,pointsize,0,titles.size());
00123     else
00124     {
00125       // Make a grid with one row and the correct number of columns
00126       GridLayout gl(frame,1,columns);
00127       // The number of elements in each column will be the same for all
00128       // columns but the last.
00129       unsigned int n = (titles.size()/columns) + (titles.size()%columns?1:0);
00130       // Add the legend segment for each column
00131       for(int i=0; i<columns; i++)
00132       {
00133         Frame t(gl.getFrame(0,i));
00134         drawLegendSegment(t,pointsize,i*n,min(n,(unsigned int)(titles.size()-i*n)));
00135       }
00136     }
00137   }
00138 
00139   void SeriesList::drawLegendSegment(Frame& frame, double pointsize, 
00140       unsigned int begin, unsigned int n)
00141   {
00142     // If we aren't drawing anything, don't bother with all the effort :)
00143     if(n == 0)
00144       return;
00145     // Spacer is the number of points between the drawn segment and the text
00146     // of the label as well as the added number of spacing between each
00147     // series in the list
00148     double spacer = 5;
00149     // Test to see if we are dealing with a scatter plot or not
00150     // as this determines what is drawn on the left
00151     bool lines = false;
00152     double mwidth = 0;
00153     double height = pointsize;
00154     for(unsigned int i=0;i<styles.size();i++)
00155     {
00156       if(!markers[i].getColor().isClear())
00157       {
00158         mwidth = max(mwidth,markers[i].getRange()*2);
00159         height = max(height,mwidth);
00160       }
00161 
00162       if(!styles[i].getColor().isClear())
00163         lines = true;
00164     }
00165     // Add spacer to the height
00166     height += spacer;
00167     // width = width needed to draw this
00168     // lbegin = x offset where line will begin
00169     // lwidth = length of the lines to draw the sample
00170     double width = 30;
00171     double lbegin = 0;
00172     double lwidth = 30;
00173     if(mwidth) // If we have markers...
00174     {
00175       lbegin = mwidth/2; 
00176       if(lines)
00177       {
00178         width = mwidth*3;
00179         lwidth = mwidth*2;
00180       }
00181       else
00182       {
00183         width = mwidth;
00184         lwidth = 0;
00185       }
00186     }
00187     // TextStyle
00188     TextStyle style;
00189     style.setPointSize(pointsize);
00190 
00191     // Begin drawing?
00192     for(unsigned int i=begin;i<begin+n;i++)
00193     {
00194       // Draw the sample:
00195       double y = frame.getHeight() - height/2.0 - height*i;
00196       Line l(lbegin+spacer,y,lbegin+lwidth+spacer,y);
00197       l.setStrokeStyle(styles[i]);
00198       l.setMarker(markers[i]);
00199       frame << l;
00200 
00201       // Add the series title
00202       frame <<  Text(titles[i].c_str(),width+spacer*2,(y-(pointsize/2.0)),style,Text::LEFT);
00203     }
00204   }
00205 }

Generated on Wed May 22 03:31:13 2013 for GPS ToolKit Software Library by  doxygen 1.3.9.1