2
Copyright (c) 2013 Daniel Stahlke
4
Permission is hereby granted, free of charge, to any person obtaining a copy
5
of this software and associated documentation files (the "Software"), to deal
6
in the Software without restriction, including without limitation the rights
7
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
copies of the Software, and to permit persons to whom the Software is
9
furnished to do so, subject to the following conditions:
11
The above copyright notice and this permission notice shall be included in
12
all copies or substantial portions of the Software.
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
#if (__cplusplus >= 201103)
31
#include <boost/tuple/tuple.hpp>
32
#include <boost/array.hpp>
33
#include <boost/range/adaptor/transformed.hpp>
34
#include <boost/range/irange.hpp>
35
#include <boost/bind.hpp>
42
#include <blitz/array.h>
45
#include "gnuplot-iostream.h"
48
# define M_PI 3.14159265358979323846
51
const int num_steps = 100;
53
double get_x(int step, double shift) {
54
double theta = 2.0*M_PI*step/(num_steps-1);
55
return std::cos(theta) * (1 + 0.3*std::cos(3.0*theta+2.0*M_PI*shift));
58
double get_y(int step, double shift) {
59
double theta = 2.0*M_PI*step/(num_steps-1);
60
return std::sin(theta) * (1 + 0.3*std::cos(3.0*theta+2.0*M_PI*shift));
63
double get_z(int step, double shift) {
64
double theta = 2.0*M_PI*step/(num_steps-1);
65
return 0.3*std::sin(3.0*theta+2.0*M_PI*shift);
68
// This doesn't have to be a template. It's just a template to show that such things are
72
MyTriple() : x(0), y(0), z(0) { }
73
MyTriple(T _x, T _y, T _z) : x(_x), y(_y), z(_z) { }
78
// Tells gnuplot-iostream how to print objects of class MyTriple.
81
struct BinfmtSender<MyTriple<T> > {
82
static void send(std::ostream &stream) {
83
BinfmtSender<T>::send(stream);
84
BinfmtSender<T>::send(stream);
85
BinfmtSender<T>::send(stream);
90
struct BinarySender<MyTriple<T> > {
91
static void send(std::ostream &stream, const MyTriple<T> &v) {
92
BinarySender<T>::send(stream, v.x);
93
BinarySender<T>::send(stream, v.y);
94
BinarySender<T>::send(stream, v.z);
98
// We don't use text mode in this demo. This is just here to show how it would go.
100
struct TextSender<MyTriple<T> > {
101
static void send(std::ostream &stream, const MyTriple<T> &v) {
102
TextSender<T>::send(stream, v.x);
104
TextSender<T>::send(stream, v.y);
106
TextSender<T>::send(stream, v.z);
113
// for debugging, prints to console
114
//Gnuplot gp(stdout);
116
int num_examples = 11;
129
gp << "set zrange [-1:1]\n";
131
// I use temporary files rather than stdin because the syntax ends up being easier when
132
// plotting several datasets. With the stdin method you have to give the full plot
133
// command, then all the data. But I would rather give the portion of the plot command for
134
// the first dataset, then give the data, then the command for the second dataset, then the
140
std::vector<std::pair<std::pair<double, double>, double> > pts;
141
for(int i=0; i<num_steps; i++) {
142
pts.push_back(std::make_pair(std::make_pair(get_x(i, shift), get_y(i, shift)), get_z(i, shift)));
144
gp << gp.binFile1d(pts, "record") << "with lines title 'vector of nested std::pair'";
148
shift += 1.0/num_examples;
151
// complex is treated as if it were a pair
152
std::vector<std::pair<std::complex<double>, double> > pts;
153
for(int i=0; i<num_steps; i++) {
154
pts.push_back(std::make_pair(std::complex<double>(get_x(i, shift), get_y(i, shift)), get_z(i, shift)));
156
gp << gp.binFile1d(pts, "record") << "with lines title 'vector of pair of cplx and double'";
160
shift += 1.0/num_examples;
163
std::vector<boost::tuple<double, double, double> > pts;
164
for(int i=0; i<num_steps; i++) {
165
pts.push_back(boost::make_tuple(get_x(i, shift), get_y(i, shift), get_z(i, shift)));
167
gp << gp.binFile1d(pts, "record") << "with lines title 'vector of boost::tuple'";
171
shift += 1.0/num_examples;
174
std::vector<double> x_pts, y_pts, z_pts;
175
for(int i=0; i<num_steps; i++) {
176
x_pts.push_back(get_x(i, shift));
177
y_pts.push_back(get_y(i, shift));
178
z_pts.push_back(get_z(i, shift));
180
gp << gp.binFile1d(boost::make_tuple(x_pts, y_pts, z_pts), "record") << "with lines title 'boost::tuple of vector'";
184
shift += 1.0/num_examples;
187
std::vector<boost::array<double, 3> > pts(num_steps);
188
for(int i=0; i<num_steps; i++) {
189
pts[i][0] = get_x(i, shift);
190
pts[i][1] = get_y(i, shift);
191
pts[i][2] = get_z(i, shift);
193
gp << gp.binFile1d(pts, "record") << "with lines title 'vector of boost::array'";
197
shift += 1.0/num_examples;
200
std::vector<std::vector<double> > pts(num_steps);
201
for(int i=0; i<num_steps; i++) {
202
pts[i].push_back(get_x(i, shift));
203
pts[i].push_back(get_y(i, shift));
204
pts[i].push_back(get_z(i, shift));
206
gp << gp.binFile1d(pts, "record") << "with lines title 'vector of vector'";
210
shift += 1.0/num_examples;
213
std::vector<std::vector<double> > pts(3);
214
for(int i=0; i<num_steps; i++) {
215
pts[0].push_back(get_x(i, shift));
216
pts[1].push_back(get_y(i, shift));
217
pts[2].push_back(get_z(i, shift));
219
gp << gp.binFile1d_colmajor(pts, "record") << "with lines title 'vector of vector (colmajor)'";
223
shift += 1.0/num_examples;
226
std::vector<MyTriple<double> > pts;
227
for(int i=0; i<num_steps; i++) {
228
pts.push_back(MyTriple<double>(get_x(i, shift), get_y(i, shift), get_z(i, shift)));
230
gp << gp.binFile1d(pts, "record") << "with lines title 'vector of MyTriple'";
234
shift += 1.0/num_examples;
237
// Note: C style arrays seem to work, but are a bit fragile since they easily decay to
238
// pointers, causing them to forget their lengths. It is highly recommended that you
239
// use boost::array or std::array instead. These have the same size and efficiency of
240
// C style arrays, but act like STL containers.
241
double pts[num_steps][3];
242
for(int i=0; i<num_steps; i++) {
243
pts[i][0] = get_x(i, shift);
244
pts[i][1] = get_y(i, shift);
245
pts[i][2] = get_z(i, shift);
247
gp << gp.binFile1d(pts, "record") << "with lines title 'double[N][3]'";
251
shift += 1.0/num_examples;
254
// Note: C style arrays seem to work, but are a bit fragile since they easily decay to
255
// pointers, causing them to forget their lengths. It is highly recommended that you
256
// use boost::array or std::array instead. These have the same size and efficiency of
257
// C style arrays, but act like STL containers.
258
double pts[3][num_steps];
259
for(int i=0; i<num_steps; i++) {
260
pts[0][i] = get_x(i, shift);
261
pts[1][i] = get_y(i, shift);
262
pts[2][i] = get_z(i, shift);
264
gp << gp.binFile1d_colmajor(pts, "record") << "with lines title 'double[N][3] (colmajor)'";
268
shift += 1.0/num_examples;
271
// Note: C style arrays seem to work, but are a bit fragile since they easily decay to
272
// pointers, causing them to forget their lengths. It is highly recommended that you
273
// use boost::array or std::array instead. These have the same size and efficiency of
274
// C style arrays, but act like STL containers.
275
double x_pts[num_steps];
276
double y_pts[num_steps];
277
double z_pts[num_steps];
278
for(int i=0; i<num_steps; i++) {
279
x_pts[i] = get_x(i, shift);
280
y_pts[i] = get_y(i, shift);
281
z_pts[i] = get_z(i, shift);
283
gp << gp.binFile1d(boost::make_tuple(x_pts, y_pts, z_pts), "record") <<
284
"with lines title 'boost::tuple of double[N]'";
289
shift += 1.0/num_examples;
292
arma::mat pts(num_steps, 3);
293
for(int i=0; i<num_steps; i++) {
294
pts(i, 0) = get_x(i, shift);
295
pts(i, 1) = get_y(i, shift);
296
pts(i, 2) = get_z(i, shift);
298
gp << gp.binFile1d(pts, "record") << "with lines title 'armadillo N*3'";
302
shift += 1.0/num_examples;
305
arma::mat pts(3, num_steps);
306
for(int i=0; i<num_steps; i++) {
307
pts(0, i) = get_x(i, shift);
308
pts(1, i) = get_y(i, shift);
309
pts(2, i) = get_z(i, shift);
311
gp << gp.binFile1d_colmajor(pts, "record") << "with lines title 'armadillo 3*N (colmajor)'";
315
shift += 1.0/num_examples;
318
arma::Row<double> x_pts(num_steps);
319
arma::Col<double> y_pts(num_steps);
320
arma::Col<double> z_pts(num_steps);
321
for(int i=0; i<num_steps; i++) {
322
x_pts(i) = get_x(i, shift);
323
y_pts(i) = get_y(i, shift);
324
z_pts(i) = get_z(i, shift);
326
gp << gp.binFile1d(boost::make_tuple(x_pts, y_pts, z_pts), "record")
327
<< "with lines title 'boost tuple of arma Row,Col,Col'";
331
shift += 1.0/num_examples;
334
arma::field<boost::tuple<double,double,double> > pts(num_steps);
335
for(int i=0; i<num_steps; i++) {
336
pts(i) = boost::make_tuple(
342
gp << gp.binFile1d(pts, "record") << "with lines title 'armadillo field of boost tuple'";
348
shift += 1.0/num_examples;
351
blitz::Array<blitz::TinyVector<double, 3>, 1> pts(num_steps);
352
for(int i=0; i<num_steps; i++) {
353
pts(i)[0] = get_x(i, shift);
354
pts(i)[1] = get_y(i, shift);
355
pts(i)[2] = get_z(i, shift);
357
gp << gp.binFile1d(pts, "record") << "with lines title 'blitz::Array<blitz::TinyVector<double, 3>, 1>'";
361
shift += 1.0/num_examples;
364
blitz::Array<double, 2> pts(num_steps, 3);
365
for(int i=0; i<num_steps; i++) {
366
pts(i, 0) = get_x(i, shift);
367
pts(i, 1) = get_y(i, shift);
368
pts(i, 2) = get_z(i, shift);
370
gp << gp.binFile1d(pts, "record") << "with lines title 'blitz<double>(N*3)'";
374
shift += 1.0/num_examples;
377
blitz::Array<double, 2> pts(3, num_steps);
378
for(int i=0; i<num_steps; i++) {
379
pts(0, i) = get_x(i, shift);
380
pts(1, i) = get_y(i, shift);
381
pts(2, i) = get_z(i, shift);
383
gp << gp.binFile1d_colmajor(pts, "record") << "with lines title 'blitz<double>(3*N) (colmajor)'";
389
shift += 1.0/num_examples;
392
std::function<boost::tuple<double,double,double>(int)> f = [&shift](int i) {
393
return boost::make_tuple(get_x(i, shift), get_y(i, shift), get_z(i, shift)); };
395
auto pts = boost::irange(0, num_steps) | boost::adaptors::transformed(f);
397
gp << gp.binFile1d(pts, "record") << "with lines title 'boost transform to tuple'";
401
shift += 1.0/num_examples;
404
auto steps = boost::irange(0, num_steps);
406
gp << gp.binFile1d(boost::make_tuple(
407
steps | boost::adaptors::transformed(boost::bind(get_x, _1, shift)),
408
steps | boost::adaptors::transformed(boost::bind(get_y, _1, shift)),
409
steps | boost::adaptors::transformed(boost::bind(get_z, _1, shift))
410
), "record") << "with lines title 'tuple of boost transform'";
414
shift += 1.0/num_examples;
417
// Note: C style arrays seem to work, but are a bit fragile since they easily decay to
418
// pointers, causing them to forget their lengths. It is highly recommended that you
419
// use boost::array or std::array instead. These have the same size and efficiency of
420
// C style arrays, but act like STL containers.
421
double x_pts[num_steps];
422
double y_pts[num_steps];
423
double z_pts[num_steps];
424
for(int i=0; i<num_steps; i++) {
425
x_pts[i] = get_x(i, shift);
426
y_pts[i] = get_y(i, shift);
427
z_pts[i] = get_z(i, shift);
429
// Note: std::make_tuple doesn't work here since it makes the arrays decay to pointers,
430
// and as a result they forget their lengths.
431
gp << gp.binFile1d(std::tie(x_pts, y_pts, z_pts), "record") <<
432
"with lines title 'std::tie of double[N]'";
438
shift += 1.0/num_examples;
439
//std::cout << shift << std::endl;
440
assert(std::fabs(shift - 1.0) < 1e-12);
443
// For Windows, prompt for a keystroke before the Gnuplot object goes out of scope so that
444
// the gnuplot window doesn't get closed.
445
std::cout << "Press enter to exit." << std::endl;