Object-oriented Scientific Computing Library: Version 0.910
contour.h
00001 /*
00002   -------------------------------------------------------------------
00003 
00004   Copyright (C) 2006-2012, Andrew W. Steiner
00005 
00006   This file is part of O2scl.
00007 
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012 
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017 
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_CONTOUR_H
00024 #define O2SCL_CONTOUR_H
00025 
00026 #include <cmath>
00027 #include <gsl/gsl_math.h>
00028 #include <o2scl/smart_interp.h>
00029 #include <o2scl/omatrix_tlate.h>
00030 
00031 #ifndef DOXYGENP
00032 namespace o2scl {
00033 #endif
00034 
00035   /** \brief A contour line 
00036 
00037       The contour lines generated by the \ref contour class are given
00038       as objects of this type.
00039 
00040       \future Write HDF I/O for contour lines?
00041       \future Make this a subclass of \ref contour .
00042    */
00043   class contour_line {
00044   public:
00045     /// The contour level
00046     double level;
00047     /// The line x coordinates
00048     ovector x;
00049     /// The line y coordinates
00050     ovector y;
00051 
00052     /// Create an empty line
00053     contour_line() {
00054     }
00055 
00056     /// Copy constructor for STL allocator
00057     contour_line(const contour_line &c) {
00058       level=c.level;
00059       x=c.x;
00060       y=c.y;
00061     }
00062   };
00063 
00064   /** \brief Edges for the contour class
00065       
00066       The edge crossings generated by the \ref contour class are given
00067       as objects of this type.
00068 
00069       The \ref status matrix contains one of four possible values
00070       - 0 - empty (no edge)
00071       - 1 - edge which has not yet been assigned to a contour
00072       - 2 - edge assigned to contour point
00073       - 3 - edge which has been designated as a contour endpoint
00074 
00075       The matrices returned by \ref contour are not square, their
00076       size depends on whether or not they contain the "bottom edges"
00077       or the "right edges". 
00078 
00079       \future Write HDF I/O object for edge crossings
00080       \future Make this a subclass of \ref contour .
00081   */
00082   class edge_crossings {
00083 
00084   public:
00085 
00086     /// Edge status
00087     omatrix_int status;
00088     /// Edge values
00089     omatrix values;
00090   };
00091 
00092   /** \brief Calculate contour lines from a two-dimensional data set
00093 
00094       \b Basic \b Usage
00095       
00096       - Specify the data as a two-dimensional square grid of "heights"
00097       with set_data().
00098       - Specify the contour levels with set_levels().
00099       - Compute the contours with calc_contours()
00100 
00101       The contours are generated as a series of x- and y-coordinates,
00102       defining a line. If the contour is closed, then the first and
00103       the last set of coordinates will be equal. 
00104 
00105       The storage of the matrix to be specified in the function
00106       set_data() and this function is designed to follow the format:
00107       \f[
00108       \begin{array}{cccc}
00109       & x_0 & x_1 & x_2 \\
00110       y_0 & M_{00} & M_{01} & M_{02} \\
00111       y_1 & M_{10} & M_{11} & M_{12} \\
00112       y_2 & M_{20} & M_{21} & M_{22}
00113       \end{array}
00114       \f]
00115       thus the matrix should be \c M[i][j] where \c i is the y index
00116       and \c j is the row index. (See also the discussion in the
00117       User's guide in the section called \ref rowcol_subsect.) 
00118 
00119       The data is copied by set_data(), so changing the data will not
00120       change the contours unless set_data() is called again. The
00121       functions set_levels() and calc() can be called several times
00122       for the same data without calling set_data() again.
00123 
00124       Note that in order to simplify the algorithm for computing
00125       contour lines, the calc_contours() function will adjust the
00126       user-specified contour levels slightly in order to ensure that
00127       no contour line passes exactly through any data point on the
00128       grid. The contours are adjusted by multiplying the original
00129       contour level by 1 plus a small number (\f$ 10^{-8} \f$ by
00130       default), which is specified in \ref lev_adjust.
00131 
00132       Linear interpolation is used to decide whether or not a line
00133       segment and a contour cross. This choice is intentional, since
00134       (in addition to making the algorithm much simpler) it is the
00135       user (and not the class) which is likely best able to refine the
00136       data. In case a simple refinement scheme is desired, the method
00137       regrid_data() is provided which refines the data for any
00138       interpolation type.
00139 
00140       Since linear interpolation is used, the contour calculation
00141       implicitly assumes that there is not more than one intersection
00142       of any contour level with any line segment. For contours which
00143       do not close inside the region of interest, the results will
00144       always end at either the minimum or maximum values of the x or y
00145       grid points (no extrapolation is ever done). Note also that the
00146       points defining the contour are not necessarily equally spaced,
00147       but two neighboring points will never be farther apart than the
00148       distance across opposite corners of one cell in the grid.
00149 
00150       \b The \b Algorithm:
00151 
00152       This works by viewing the data as defining a square
00153       two-dimensional grid. The function calc_contours() exhaustively
00154       enumerates every line segment in the grid which involves a level
00155       crossing and then organizes the points defined by the
00156       intersection of a line segment with a level curve into a full
00157       contour.
00158 
00159       \future Rewrite the code which adjusts the contour levels 
00160       to ensure contours don't go through the data to adjust the
00161       internal copy of the data instead. 
00162 
00163       \future It would be nice to have a function which creates a set
00164       of closed regions to fill which represent the data. However,
00165       this likely requires a completely new algorithm, because it's
00166       not easy to simply close the contours already generated by the
00167       calc_contours() function. There are, for example, several cases
00168       which are difficult to handle, such as filling a region in
00169       between several closed contours.
00170 
00171   */
00172   class contour {
00173     
00174   public:
00175     
00176     contour();
00177 
00178     ~contour();
00179 
00180     /// \name Basic usage
00181     //@{
00182 
00183     /** \brief Set the data 
00184 
00185         The types \c vec_t and \c mat_t can be any types which have \c
00186         operator[] and \c operator[][] for array and matrix indexing.
00187         
00188         Note that this method copies all of the user-specified data to
00189         local storage so that changes in the data after calling this
00190         function will not be reflected in the contours that are
00191         generated.
00192     */
00193     template<class vec_t, class mat_t>
00194       int set_data(size_t sizex, size_t sizey, const vec_t &x_fun, 
00195                    const vec_t &y_fun, const mat_t &udata) {
00196       
00197       if (sizex<2 || sizey<2) { 
00198         O2SCL_ERR_RET("Not enough data (must be at least 2x2) in set_data().",
00199                     gsl_einval);
00200       }
00201       
00202       nx=sizex;
00203       ny=sizey;
00204       xfun.allocate(nx);
00205       yfun.allocate(ny);
00206       data.allocate(ny,nx);
00207       for(int i=0;i<nx;i++) xfun[i]=x_fun[i];
00208       for(int i=0;i<ny;i++) yfun[i]=y_fun[i];
00209       for(int i=0;i<nx;i++) {
00210         for(int j=0;j<ny;j++) {
00211           data[j][i]=udata[j][i];
00212         }
00213       }
00214 
00215       return check_data();
00216     }
00217 
00218     /** \brief Set the contour levels 
00219         
00220         This is separate from the function calc_contours() so that
00221         the user can compute the contours for different data sets using
00222         the same levels.
00223     */
00224     template<class vec_t> int set_levels(size_t nlevels, vec_t &ulevels) {
00225       nlev=nlevels;
00226       levels.allocate(nlevels);
00227       for(size_t i=0;i<nlevels;i++) {
00228         levels[i]=ulevels[i];
00229       }
00230       levels_set=true;
00231       return 0;
00232     }
00233 
00234     /** \brief Calculate the contours 
00235 
00236         The function calc_contours() returns the total number of
00237         contours found.  Since there may be more than one disconnected
00238         contours for the same contour level, or no contours for a
00239         given level, the total number of contours may be less than or
00240         greater than the number of levels given by set_levels().
00241 
00242         If an error occurs, zero is returned.
00243     */
00244     int calc_contours(std::vector<contour_line> &clines,
00245                       bool debug=false);
00246 
00247     //@}
00248 
00249     /// \name Regrid function
00250     //@{
00251     /** \brief Regrid the data 
00252         
00253         Use interpolation to refine the data set. This can be called
00254         before calc_contours() in order to make the contour levels
00255         smoother by providing a smaller grid size. If the original
00256         number of data points is \f$ (\mathrm{nx},\mathrm{ny}) \f$,
00257         then the new number of data points is
00258         \f[
00259         (\mathrm{xfact}~(\mathrm{nx}-1)+1,
00260         \mathrm{yfact}~(\mathrm{ny}-1)+1)
00261         \f]
00262         The parameters \c xfact and \c yfact must both be larger than 
00263         zero and they cannot both be 1.
00264     */
00265     int regrid_data(size_t xfact, size_t yfact,
00266                     base_interp_mgr<ovector_const_view> &bim1,
00267                     base_interp_mgr<ovector_const_subvector> &bim2);
00268     //@}
00269 
00270     /// \name Obtain internal data
00271     //@{
00272     /** \brief Get the data 
00273         
00274         This is useful to see how the data has changed after
00275         a call to regrid_data().
00276 
00277         \future There is probably a better way than returning
00278         pointers to the internal data.
00279     */
00280     int get_data(size_t &sizex, size_t &sizey, ovector *&x_fun, 
00281                  ovector *&y_fun, omatrix *&udata) {
00282       if (nx==0) {
00283         O2SCL_ERR_RET("Data not set in calc().",gsl_einval);
00284       }
00285       sizex=nx;
00286       sizey=ny;
00287       x_fun=&xfun;
00288       y_fun=&yfun;
00289       udata=&data;
00290       return 0;
00291     }
00292 
00293     /// Return the edges
00294     int get_edges(std::vector<edge_crossings> &rt_edges,
00295                   std::vector<edge_crossings> &bm_edges) {
00296       rt_edges=red;
00297       bm_edges=bed;
00298       return 0;
00299     }
00300 
00301     /// Print out the edges to cout
00302     int print_edges(edge_crossings &right,
00303                     edge_crossings &bottom);
00304 
00305     //@}
00306 
00307     /// Verbosity parameter
00308     int verbose;
00309 
00310     /// (default \f$ 10^{-8} \f$)
00311     double lev_adjust;
00312     
00313 #ifndef DOXYGEN_INTERNAL
00314 
00315   protected:
00316 
00317     /// \name Edge direction
00318     //@{
00319     static const int dright=0;
00320     static const int dbottom=1;
00321     //@}
00322 
00323     /// \name Edge status
00324     //@{
00325     static const int empty=0;
00326     static const int edge=1;
00327     static const int contourp=2;
00328     static const int endpoint=3;
00329     //@}
00330 
00331     /// \name Edge found or not found
00332     //@{
00333     static const int efound=1;
00334     static const int enot_found=0;
00335     //@}
00336 
00337     /// \name User-specified data
00338     //@{
00339     int nx, ny;
00340     ovector xfun, yfun;
00341     omatrix data;
00342     //@}
00343 
00344     /// \name User-specified contour levels
00345     //@{
00346     int nlev;
00347     ovector levels;
00348     bool levels_set;
00349     //@}
00350 
00351     /// Right edge list
00352     std::vector<edge_crossings> red;
00353     /// Bottom edge list
00354     std::vector<edge_crossings> bed;
00355 
00356     /// Find next point starting from a point on a right edge
00357     int find_next_point_right(int j, int k, int &jnext, int &knext, 
00358                               int &dir_next, int nsw,
00359                               edge_crossings &right,
00360                               edge_crossings &bottom);
00361     
00362     /// Find next point starting from a point on a bottom edge
00363     int find_next_point_bottom(int j, int k, int &jnext, int &knext, 
00364                                int &dir_next, int nsw,
00365                                edge_crossings &right,
00366                                edge_crossings &bottom);
00367 
00368     /// Find all of the intersections of the edges with the contour level
00369     int find_intersections(size_t ilev, double &level,
00370                            edge_crossings &right, edge_crossings &bottom);
00371 
00372     /// Interpolate all right edge crossings 
00373     int right_edges(double level, o2scl::sm_interp *si,
00374                     edge_crossings &right);
00375     
00376     /// Interpolate all bottom edge crossings
00377     int bottom_edges(double level, o2scl::sm_interp *si,
00378                      edge_crossings &bottom);
00379 
00380     /// Create a contour line from a starting edge
00381     int process_line(int j, int k, int dir, ovector &x, ovector &y, 
00382                      bool first, edge_crossings &right,
00383                      edge_crossings &bottom);
00384 
00385     /// Check to ensure the x- and y-arrays are monotonic
00386     int check_data();
00387 
00388 #endif
00389 
00390   };
00391   
00392 #ifndef DOXYGENP
00393 }
00394 #endif
00395 
00396 #endif
00397 
00398 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).

Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads.