#include <contour.h>
Basic Usage
The data should be stored so that the y-index is first, i.e. data[iy][ix]. One can always switch x_fun
and y_fun
if this is not the case. The data is copied by set_data(), so changing the data will not change the contours unless set_data() is called again. The functions set_levels() and calc() can be called several times for the same data without calling set_data() again.
Linear interpolation is used to decide whether or not a line segment and a contour cross. This choice is intentional, since (in addition to making the algorithm much simpler) it is the user (and not the class) which is likely best able to refine the data. In case a simple refinement scheme is desired, the method regrid_data() is provided which uses cubic spline interpolation to refine the data and thus make the curves more continuous.
Since linear interpolation is used, the contour calculation implicitly assumes that there is not more than one intersection of any contour level with any line segment, so if this is the case, then either a more refined data set should be specified or regrid_data() should be used. For contours which do not close inside the region of interest, the results will always end at either the minimum or maximum values of x_fun
or y_fun
(no extrapolation is ever done).
As an example, for the function
a 10x10 grid gives the contours:
contourg.png
While after a call to regrid_data(3,3), the contours are a little smoother:
contourg2.png
Mathematica gives a similar result:
contourg3.png
The Algorithm:
This works by viewing the data as defining a square two-dimensional grid. The function calc() exhaustively enumerates every line segment in the grid which involves a level crossing and then organizing the points defined by the intersection of a line segment with a level curve into a full contour.
Representing Contours by Fill Regions
If the user wants to "shade" the contours to provide a shaded or colored contour plot, then it is useful to provide a set of closed contours to be shaded instead of the (possibly) open contours returned by calc_contours(). After a call to calc_contours(), the function regions() can be used to organize the closed contours into regions to be shaded. Open contours are closed by adding points defining lines along the edges of the data and closed contours are inverted (if necessary) by adding an external line emanating from the closed contour and properly including the boundary edges.
Definition at line 126 of file contour.h.
Public Member Functions | |
Basic usage | |
template<class vec_t, class mat_t> | |
int | 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. | |
template<class vec_t> | |
int | set_levels (size_t nlevels, vec_t &ulevels) |
Set the contour levels. | |
template<class vec_t> | |
int | calc_contours (vec_t &new_levels, bool debug=false) |
Calculate the contours. | |
int | get_contour_size (int index) |
Return the number of points in the specified contour. | |
template<class vec_t> | |
int | get_contour (int index, double &val, int &csize, vec_t &x, vec_t &y) |
Get a contour. | |
int | regions (bool larger) |
Compute closed contour regions (unfinished). | |
Regrid function | |
int | regrid_data (size_t xfact, size_t yfact) |
Regrid the data. | |
Obtain internal data | |
int | get_data (size_t &sizex, size_t &sizey, const ovector *&x_fun, const ovector *&y_fun, const ovector **&udata) |
Get the data. | |
int | get_edges (const std::vector< omatrix_int * > *rints, const std::vector< omatrix_int * > *bints, const std::vector< omatrix * > *rpoints, const std::vector< omatrix * > *bpoints) |
Return the edges used to compute the contours. | |
int | get_edges_for_level (size_t nl, omatrix_int &rints, omatrix_int &bints, omatrix &rpoints, omatrix &bpoints) |
Return the edges used to compute the contours. | |
Data Fields | |
int | verbose |
Verbosity parameter. | |
double | lev_adjust |
(default ![]() | |
Protected Member Functions | |
int | find_next_point_right (int j, int k, int &jnext, int &knext, int &dir_next, int nsw=1) |
Find next point starting from a point on a right edge. | |
int | find_next_point_bottom (int j, int k, int &jnext, int &knext, int &dir_next, int nsw=1) |
Find next point starting from a point on a bottom edge. | |
int | find_intersections (size_t ilev, double &level) |
Find all of the intersections of the edges with the contour level. | |
int | right_edges (double level, o2scl::sm_interp *si) |
Interpolate all right edge crossings. | |
int | bottom_edges (double level, o2scl::sm_interp *si) |
Interpolate all bottom edge crossings. | |
int | process_line (int j, int k, int dir, std::vector< double > &x, std::vector< double > &y, bool first=true) |
Create a contour line from a starting edge. | |
bool | is_point_inside_old (double x1, double y1, const ovector_view &x, const ovector_view &y, double xscale=0.01, double yscale=0.01) |
Test if a point is inside a closed contour (unfinished). | |
int | free_memory () |
Free memory. | |
bool | lines_cross_old (double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) |
Check if lines cross. | |
int | check_data () |
Check to ensure the x- and y-arrays are monotonic. | |
int | smooth_contours (size_t nfact) |
Smooth the contours by adding internal points using cubic interpolation (this doesn't work). | |
Protected Attributes | |
int | new_debug |
pinside | pi |
Object to find if a point is inside a polygon. | |
User-specified data | |
int | nx |
int | ny |
ovector * | xfun |
ovector * | yfun |
ovector ** | data |
User-specified contour levels | |
int | nlev |
ovector | levels |
bool | levels_set |
Generated curves | |
int | ncurves |
std::vector< int > | csizes |
std::vector< double > | vals |
std::vector < std::vector < double > > | xc |
std::vector < std::vector < double > > | yc |
Storage for edges | |
std::vector< omatrix * > | redges |
std::vector< omatrix * > | bedges |
std::vector < omatrix_int * > | re |
std::vector < omatrix_int * > | be |
omatrix_int * | rep |
omatrix_int * | bep |
omatrix * | redgesp |
omatrix * | bedgesp |
Static Protected Attributes | |
Edge direction | |
static const int | dright = 0 |
static const int | dbottom = 1 |
Edge status | |
static const int | empty = 0 |
static const int | edge = 1 |
static const int | contourp = 2 |
static const int | endpoint = 3 |
Edge found or not found | |
static const int | efound = 1 |
static const int | enot_found = 0 |
int set_data | ( | size_t | sizex, | |
size_t | sizey, | |||
const vec_t & | x_fun, | |||
const vec_t & | y_fun, | |||
const mat_t & | udata | |||
) | [inline] |
Set the data.
The types vec_t
and mat_t
can be any types which have operator[]
and operator[]
[] for array and matrix indexing.
Note that this method copies all of the user-specified data to local storage so that changes in the data after calling this function will not be reflected in the contours that are generated.
int set_levels | ( | size_t | nlevels, | |
vec_t & | ulevels | |||
) | [inline] |
Set the contour levels.
This is separate from the function calc_contours() so that the user can compute the contours for different data sets using the same levels
int calc_contours | ( | vec_t & | new_levels, | |
bool | debug = false | |||
) | [inline] |
Calculate the contours.
The function calc_contours() returns the total number of contours found. Since there may be more than one disconnected contours for the same contour level, or no contours for a given level, the total number of contours may be less than or greater than the number of levels given by set_levels().
If an error occurs, zero is returned.
int get_contour | ( | int | index, | |
double & | val, | |||
int & | csize, | |||
vec_t & | x, | |||
vec_t & | y | |||
) | [inline] |
Get a contour.
Given the index
, which is between 0 and the number of contours returned by calc_contours() minus 1 (inclusive), this returns the level for this contour with the x and y-values in x
and y
which are both of length csize
. The vectors x
and y
must have been previously allocated. The user can obtain the necessary size for x
and y
by calling get_contour_size().
int regrid_data | ( | size_t | xfact, | |
size_t | yfact | |||
) |
Regrid the data.
The uses cubic spline interpolation to refine the data set, ideally used before attempting to calculate the contour levels. If the original number of data points is , then the new number of data points is
int get_data | ( | size_t & | sizex, | |
size_t & | sizey, | |||
const ovector *& | x_fun, | |||
const ovector *& | y_fun, | |||
const ovector **& | udata | |||
) | [inline] |
Get the data.
This is useful to see how the data has changed after a call to regrid_data().
int get_edges_for_level | ( | size_t | nl, | |
omatrix_int & | rints, | |||
omatrix_int & | bints, | |||
omatrix & | rpoints, | |||
omatrix & | bpoints | |||
) |
Return the edges used to compute the contours.
This function allocates memory for rints
, bints
, rpoints
, and bpoints
and fills them with a copy of the data that the class is using. As such, there is no need for them to be const.
bool is_point_inside_old | ( | double | x1, | |
double | y1, | |||
const ovector_view & | x, | |||
const ovector_view & | y, | |||
double | xscale = 0.01 , |
|||
double | yscale = 0.01 | |||
) | [protected] |
Test if a point is inside a closed contour (unfinished).
This returns true if the point (x1,y1) is "inside" the contour (i.e. a collection of line segments) given in x
and y
. The arrays x
and y
must be "ordered" so that adjacent points are placed at adjacent entries. The result is undefined if this is not the case or if the contours are not properly closed. The first and last points in x
and y
should be the same to indicate a closed contour. The values xscale and yscale should be an approximate scale for the contours x
and y
.
bool lines_cross_old | ( | double | x1, | |
double | y1, | |||
double | x2, | |||
double | y2, | |||
double | x3, | |||
double | y3, | |||
double | x4, | |||
double | y4 | |||
) | [protected] |
Check if lines cross.
Returns true if the line segment defined by (x1,y1) and (x2,y2) and the line segment defined by (x3,y3) and (x4,y4) have an intersection point that is between the endpoints of both segments. The function handles vertical and horizontal lines appropriately. This function will fail if x1==y1 and x2==y2 or if x3==y3 and x4==y4, i.e. if the points do not really define a line. If the function fails, it returns false.
int smooth_contours | ( | size_t | nfact | ) | [protected] |
Smooth the contours by adding internal points using cubic interpolation (this doesn't work).
This makes the contours smoother by adding internal points between each contour line segment determined by cubic spline interpolation.
For more accurate contours, it is better to provide the original data on a finer grid, or use regrid_data().