All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
contour.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2014, Andrew W. Steiner
5 
6  This file is part of O2scl.
7 
8  O2scl is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12 
13  O2scl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
20 
21  -------------------------------------------------------------------
22 */
23 /** \file contour.h
24  \brief File defining \ref o2scl::contour
25 */
26 #ifndef O2SCL_CONTOUR_H
27 #define O2SCL_CONTOUR_H
28 
29 #include <cmath>
30 
31 #include <gsl/gsl_math.h>
32 
33 #include <boost/numeric/ublas/vector.hpp>
34 #include <boost/numeric/ublas/matrix.hpp>
35 
36 #include <o2scl/interp.h>
37 #include <o2scl/uniform_grid.h>
38 
39 #ifndef DOXYGEN_NO_O2NS
40 namespace o2scl {
41 #endif
42 
43  /** \brief A contour line
44 
45  The contour lines generated by the \ref o2scl::contour class are given
46  as objects of this type.
47 
48  \future Make this a subclass of \ref o2scl::contour .
49  */
50  class contour_line {
51 
52  public:
53 
55 
56  /// The contour level
57  double level;
58  /// The line x coordinates
59  std::vector<double> x;
60  /// The line y coordinates
61  std::vector<double> y;
62 
63  /// Create an empty line
65  }
66 
67  /// Copy constructor
69  level=c.level;
70  x=c.x;
71  y=c.y;
72  }
73 
74  /// Copy constructor with operator=()
76  if (this==&c) return *this;
77  level=c.level;
78  x=c.x;
79  y=c.y;
80  return *this;
81  }
82 
83  };
84 
85  /** \brief Edges for the contour class
86 
87  The edge crossings generated by the \ref contour class are given
88  as objects of this type.
89 
90  The \ref status matrix contains one of four possible values
91  - 0 - empty (no edge)
92  - 1 - edge which has not yet been assigned to a contour
93  - 2 - edge assigned to contour point
94  - 3 - edge which has been designated as a contour endpoint
95 
96  The matrices returned by \ref contour are not square, their
97  size depends on whether or not they contain the "bottom edges"
98  or the "right edges".
99 
100  \future Make this a subclass of \ref o2scl::contour .
101  */
103 
104  public:
105 
110 
111  /// Edge status
113  /// Edge values
115 
116  /// Create an empty object
118  }
119 
120  /// Copy constructor
122  status=ec.status;
123  values=ec.values;
124  }
125 
126  /// Copy constructor with operator=()
128  if (this==&ec) return *this;
129  status=ec.status;
130  values=ec.values;
131  return *this;
132  }
133 
134  };
135 
136  /** \brief Calculate contour lines from a two-dimensional data set
137 
138  \b Basic \b Usage
139 
140  - Specify the data as a two-dimensional square grid of "heights"
141  with set_data().
142  - Specify the contour levels with set_levels().
143  - Compute the contours with calc_contours()
144 
145  The contours are generated as a series of x- and y-coordinates,
146  defining a line. If the contour is closed, then the first and
147  the last set of coordinates will be equal.
148 
149  The convention used by this class is that the first (row) index
150  of the matrix enumerates the x coordinate and that the second
151  (column) index enumerates the y coordinate. See the discussion
152  in the User's guide in the section called \ref rowcol_subsect.
153 
154  The data is copied by set_data(), so changing the data will not
155  change the contours unless set_data() is called again. The
156  functions set_levels() and calc_contours() can be called several
157  times for the same data without calling set_data() again.
158 
159  Note that in order to simplify the algorithm for computing
160  contour lines, the calc_contours() function will adjust the
161  user-specified contour levels slightly in order to ensure that
162  no contour line passes exactly through any data point on the
163  grid. The contours are adjusted by multiplying the original
164  contour level by 1 plus a small number (\f$ 10^{-8} \f$ by
165  default), which is specified in \ref lev_adjust.
166 
167  Linear interpolation is used to decide whether or not a line
168  segment from the grid and a contour cross. This choice is
169  intentional, since (in addition to making the algorithm much
170  simpler) it is the user (and not this contour class) which is
171  likely best able to refine the data. In case a simple refinement
172  scheme is desired, the method regrid_data() is provided which
173  refines the internally stored data for any interpolation type.
174 
175  Since linear interpolation is used, the contour calculation
176  implicitly assumes that there is not more than one intersection
177  of any contour level with any line segment. For contours which
178  do not close inside the region of interest, the results will
179  always end at either the minimum or maximum values of the x or y
180  grid points (no extrapolation is ever done). Note also that the
181  points defining the contour are not necessarily equally spaced.
182  Two neighboring points will never be farther apart than the
183  distance across opposite corners of one cell in the grid.
184 
185  \b The \b Algorithm:
186 
187  This works by viewing the data as defining a square
188  two-dimensional grid. The function calc_contours() exhaustively
189  enumerates every line segment in the grid which involves a level
190  crossing and then organizes the points defined by the
191  intersection of a line segment with a level curve into a full
192  contour line.
193 
194  \todo Convert distances in find_next_point functions to
195  be scaled by grid spacing.
196 
197  \todo Copy constructor
198 
199  \future Rewrite the code which adjusts the contour levels
200  to ensure contours don't go through the data to adjust the
201  internal copy of the data instead? This should be more
202  accurate because we're perturbing one point instead of
203  perturbing the entire line.
204 
205  \future It would be nice to have a function which creates a set
206  of closed regions to fill which represent the data. However,
207  this likely requires a completely new algorithm, because it's
208  not easy to simply close the contours already generated by the
209  calc_contours() function. There are, for example, several cases
210  which are difficult to handle, such as filling a region in
211  between several closed contours
212 
213  \future Change nx and ny to size_t?
214 
215  \comment
216 
217  6/28/12 - Thinking about how the algorithm could work.
218 
219  1) Start at the lowest contour level.
220 
221  2) How to create the enclosure in general if it's closed?
222  Just make sure that lines betwen closed region and boundary
223  don't go through any other contours of the same level.
224 
225  3) If one of the two enclosures would enclose a different
226  contour line with the same level, and choose the other
227  enclosure. If neither enclosure would enclose a contour line
228  with the same level, then only one enclosure encloses all other
229  contour lines, so that is the one to choose.
230 
231  4) Proceed to the next contour line of the same level, and
232  then go to the next contour line of the second lowest
233  contour level.
234 
235  \endcomment
236  */
237  class contour {
238 
239  public:
240 
244 
245  contour();
246 
247  ~contour();
248 
249  /// \name Basic usage
250  //@{
251 
252  /** \brief Set the data
253 
254  The types \c vec_t and \c mat_t can be any types which have \c
255  operator[] and \c operator[][] for array and matrix indexing.
256 
257  Note that this method copies all of the user-specified data to
258  local storage so that changes in the data after calling this
259  function will not be reflected in the contours that are
260  generated.
261  */
262  template<class vec_t, class mat_t>
263  void set_data(size_t sizex, size_t sizey, const vec_t &x_fun,
264  const vec_t &y_fun, const mat_t &udata) {
265 
266  if (sizex<2 || sizey<2) {
267  O2SCL_ERR("Not enough data (must be at least 2x2) in set_data().",
268  exc_einval);
269  }
270 
271  nx=sizex;
272  ny=sizey;
273  xfun.resize(nx);
274  yfun.resize(ny);
275  data.resize(nx,ny);
276  for(int i=0;i<nx;i++) xfun[i]=x_fun[i];
277  for(int i=0;i<ny;i++) yfun[i]=y_fun[i];
278  for(int i=0;i<nx;i++) {
279  for(int j=0;j<ny;j++) {
280  data(i,j)=udata(i,j);
281  }
282  }
283 
284  check_data();
285  return;
286  }
287 
288  /** \brief Set the data
289 
290  The type \c mat_t can be any type which has \c operator[][]
291  for matrix indexing.
292 
293  Note that this method copies all of the user-specified data to
294  local storage so that changes in the data after calling this
295  function will not be reflected in the contours that are
296  generated.
297  */
298  template<class mat_t>
299  void set_data(const uniform_grid<double> &ugx,
300  const uniform_grid<double> &ugy,
301  const mat_t &udata) {
302 
303  size_t sizex=ugx.get_npoints();
304  size_t sizey=ugy.get_npoints();
305 
306  if (sizex<2 || sizey<2) {
307  O2SCL_ERR("Not enough data (must be at least 2x2) in set_data().",
308  exc_einval);
309  }
310 
311  nx=sizex;
312  ny=sizey;
313  xfun.resize(nx);
314  yfun.resize(ny);
315  data.resize(nx,ny);
316  for(int i=0;i<nx;i++) xfun[i]=ugx[i];
317  for(int i=0;i<ny;i++) yfun[i]=ugy[i];
318  for(int i=0;i<nx;i++) {
319  for(int j=0;j<ny;j++) {
320  data(i,j)=udata(i,j);
321  }
322  }
323 
324  check_data();
325  return;
326  }
327 
328  /** \brief Set the contour levels
329 
330  This is separate from the function calc_contours() so that
331  the user can compute the contours for different data sets using
332  the same levels.
333  */
334  template<class vec_t> void set_levels(size_t nlevels, vec_t &ulevels) {
335  nlev=nlevels;
336  levels.resize(nlevels);
337  for(size_t i=0;i<nlevels;i++) {
338  levels[i]=ulevels[i];
339  }
340  levels_set=true;
341  return;
342  }
343 
344  /** \brief Calculate the contours
345 
346  \note There may be zero or more than one contour line for
347  each level, so the size of \c clines is not necessarily
348  equal to the number of levels specified in \ref set_levels().
349  */
350  void calc_contours(std::vector<contour_line> &clines);
351  //@}
352 
353  /// \name Regrid function
354  //@{
355  /** \brief Regrid the data
356 
357  Use interpolation to refine the data set. This can be called
358  before calc_contours() in order to attempt make the contour
359  levels smoother by providing a smaller grid size. If the
360  original number of data points is \f$
361  (\mathrm{nx},\mathrm{ny}) \f$, then the new number of data
362  points is
363  \f[
364  (\mathrm{xfact}~(\mathrm{nx}-1)+1,
365  \mathrm{yfact}~(\mathrm{ny}-1)+1)
366  \f]
367  The parameters \c xfact and \c yfact must both be larger than
368  zero and they cannot both be 1.
369  */
370  void regrid_data(size_t xfact, size_t yfact,
371  size_t interp_type=o2scl::itp_cspline);
372  //@}
373 
374  /// \name Obtain internal data
375  //@{
376  /** \brief Get the data
377 
378  This is useful to see how the data has changed after
379  a call to regrid_data().
380 
381  \future There is probably a better way than returning
382  pointers to the internal data.
383  */
384  void get_data(size_t &sizex, size_t &sizey, ubvector *&x_fun,
385  ubvector *&y_fun, ubmatrix *&udata) {
386  if (nx==0) {
387  O2SCL_ERR("Data not set in get_data().",exc_einval);
388  }
389  sizex=nx;
390  sizey=ny;
391  x_fun=&xfun;
392  y_fun=&yfun;
393  udata=&data;
394  return;
395  }
396 
397  /** \brief Return the edges for each contour level
398 
399  The size of \c rt_edges and \c bm_edges will both be equal to
400  the number of levels set by \ref set_levels().
401  */
402  void get_edges(std::vector<edge_crossings> &rt_edges,
403  std::vector<edge_crossings> &bm_edges) {
404  rt_edges=red;
405  bm_edges=bed;
406  return;
407  }
408 
409  /// Print out the edges to cout
410  void print_edges(edge_crossings &right,
411  edge_crossings &bottom);
412 
413  //@}
414 
415  /** \brief Verbosity parameter (default 0)
416 
417  If verbose is greater than 0, then adjustments to the contour
418  levels will be output and the contour lines will be output as
419  they are built up from the intersections. If verbose is
420  greater than 1, then all edges will be output. If verbose is
421  greater than 2, a keypress will be required after each contour
422  line is constructed.
423  */
424  int verbose;
425 
426  /// (default \f$ 10^{-8} \f$)
427  double lev_adjust;
428 
429  /// \name Edge status
430  //@{
431  static const int empty=0;
432  static const int edge=1;
433  static const int contourp=2;
434  static const int endpoint=3;
435  //@}
436 
437 #ifndef DOXYGEN_INTERNAL
438 
439  protected:
440 
441  /// \name Edge direction
442  //@{
443  static const int dright=0;
444  static const int dbottom=1;
445  //@}
446 
447  /// \name Edge found or not found
448  //@{
449  static const int efound=1;
450  static const int enot_found=0;
451  //@}
452 
453  /// \name User-specified data
454  //@{
455  int nx, ny;
456  ubvector xfun, yfun;
457  ubmatrix data;
458  //@}
459 
460  /// \name User-specified contour levels
461  //@{
462  int nlev;
463  ubvector levels;
464  bool levels_set;
465  //@}
466 
467  /// Right edge list
468  std::vector<edge_crossings> red;
469  /// Bottom edge list
470  std::vector<edge_crossings> bed;
471 
472  /// Find next point starting from a point on a right edge
473  int find_next_point_right(int j, int k, int &jnext, int &knext,
474  int &dir_next, int nsw,
475  edge_crossings &right,
476  edge_crossings &bottom);
477 
478  /// Find next point starting from a point on a bottom edge
479  int find_next_point_bottom(int j, int k, int &jnext, int &knext,
480  int &dir_next, int nsw,
481  edge_crossings &right,
482  edge_crossings &bottom);
483 
484  /// Find all of the intersections of the edges with the contour level
485  void find_intersections(size_t ilev, double &level,
486  edge_crossings &right, edge_crossings &bottom);
487 
488  /// Interpolate all right edge crossings
489  void right_edges(double level, interp<ubvector> &si,
490  edge_crossings &right);
491 
492  /// Interpolate all bottom edge crossings
493  void bottom_edges(double level, interp<ubvector> &si,
494  edge_crossings &bottom);
495 
496  /// Create a contour line from a starting edge
497  void process_line(int j, int k, int dir, std::vector<double> &x,
498  std::vector<double> &y,
499  bool first, edge_crossings &right,
500  edge_crossings &bottom);
501 
502  /// Check to ensure the x- and y-arrays are monotonic
503  void check_data();
504 
505  private:
506 
507  contour(const contour &);
508  contour& operator=(const contour&);
509 
510 #endif
511 
512  };
513 
514 #ifndef DOXYGEN_NO_O2NS
515 }
516 #endif
517 
518 #endif
519 
520 
edge_crossings()
Create an empty object.
Definition: contour.h:117
Edges for the contour class.
Definition: contour.h:102
void check_data()
Check to ensure the x- and y-arrays are monotonic.
contour_line()
Create an empty line.
Definition: contour.h:64
void get_edges(std::vector< edge_crossings > &rt_edges, std::vector< edge_crossings > &bm_edges)
Return the edges for each contour level.
Definition: contour.h:402
std::vector< edge_crossings > bed
Bottom edge list.
Definition: contour.h:470
edge_crossings(const edge_crossings &ec)
Copy constructor.
Definition: contour.h:121
int find_next_point_right(int j, int k, int &jnext, int &knext, int &dir_next, int nsw, edge_crossings &right, edge_crossings &bottom)
Find next point starting from a point on a right edge.
invalid argument supplied by user
Definition: err_hnd.h:59
contour_line(const contour_line &c)
Copy constructor.
Definition: contour.h:68
int find_next_point_bottom(int j, int k, int &jnext, int &knext, int &dir_next, int nsw, edge_crossings &right, edge_crossings &bottom)
Find next point starting from a point on a bottom edge.
void set_data(size_t sizex, size_t sizey, const vec_t &x_fun, const vec_t &y_fun, const mat_t &udata)
Set the data.
Definition: contour.h:263
void process_line(int j, int k, int dir, std::vector< double > &x, std::vector< double > &y, bool first, edge_crossings &right, edge_crossings &bottom)
Create a contour line from a starting edge.
Cubic spline for natural boundary conditions.
Definition: interp.h:50
void get_data(size_t &sizex, size_t &sizey, ubvector *&x_fun, ubvector *&y_fun, ubmatrix *&udata)
Get the data.
Definition: contour.h:384
Calculate contour lines from a two-dimensional data set.
Definition: contour.h:237
ubmatrix_int status
Edge status.
Definition: contour.h:112
ubmatrix values
Edge values.
Definition: contour.h:114
void right_edges(double level, interp< ubvector > &si, edge_crossings &right)
Interpolate all right edge crossings.
std::vector< edge_crossings > red
Right edge list.
Definition: contour.h:468
std::vector< double > x
The line x coordinates.
Definition: contour.h:59
#define O2SCL_ERR(d, n)
Set an error with message d and code n.
Definition: err_hnd.h:273
void bottom_edges(double level, interp< ubvector > &si, edge_crossings &bottom)
Interpolate all bottom edge crossings.
void set_data(const uniform_grid< double > &ugx, const uniform_grid< double > &ugy, const mat_t &udata)
Set the data.
Definition: contour.h:299
A contour line.
Definition: contour.h:50
double lev_adjust
(default )
Definition: contour.h:427
int verbose
Verbosity parameter (default 0)
Definition: contour.h:424
A class representing a uniform linear or logarithmic grid.
Definition: uniform_grid.h:38
double level
The contour level.
Definition: contour.h:57
void set_levels(size_t nlevels, vec_t &ulevels)
Set the contour levels.
Definition: contour.h:334
void calc_contours(std::vector< contour_line > &clines)
Calculate the contours.
edge_crossings & operator=(const edge_crossings &ec)
Copy constructor with operator=()
Definition: contour.h:127
void find_intersections(size_t ilev, double &level, edge_crossings &right, edge_crossings &bottom)
Find all of the intersections of the edges with the contour level.
contour_line & operator=(const contour_line &c)
Copy constructor with operator=()
Definition: contour.h:75
void print_edges(edge_crossings &right, edge_crossings &bottom)
Print out the edges to cout.
std::vector< double > y
The line y coordinates.
Definition: contour.h:61
Interpolation class for general vectors.
Definition: interp.h:1299
void regrid_data(size_t xfact, size_t yfact, size_t interp_type=o2scl::itp_cspline)
Regrid the data.
size_t get_npoints() const
Get the number of points in the grid (always get_nbins()+1)
Definition: uniform_grid.h:179

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).
Hosted at Get Object-oriented Scientific Computing
Lib at SourceForge.net. Fast, secure and Free Open Source software
downloads..