p1788 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/LICENSE +674 -201
- data/README.md +19 -13
- data/ext/libieeep1788_copy/p1788/decoration/decoration.hpp +1 -1
- data/ext/p1788/extconf.rb +11 -6
- data/ext/p1788/figure.cc +1284 -0
- data/ext/p1788/figure.hh +294 -0
- data/ext/p1788/figure_wrapper.cc +1249 -0
- data/ext/p1788/p1788.cc +3948 -935
- data/ext/p1788/p1788.hh +102 -0
- data/lib/p1788/version.rb +1 -1
- data/lib/p1788.rb +12 -17
- data/p1788.gemspec +9 -4
- data/samples/figure.rb +23 -0
- data/samples/sivia.rb +122 -0
- metadata +9 -4
- data/AUTHORS +0 -6
@@ -0,0 +1,1249 @@
|
|
1
|
+
/* Copyright (C) 2022 Théotime Bollengier <theotime.bollengier@ensta-bretagne.fr>
|
2
|
+
*
|
3
|
+
* This file is part of P1788. <https://gitlab.ensta-bretagne.fr/bollenth/p1788>
|
4
|
+
*
|
5
|
+
* P1788 is free software: you can redistribute it and/or modify it
|
6
|
+
* under the terms of the GNU General Public License as published
|
7
|
+
* by the Free Software Foundation, either version 3 of the License,
|
8
|
+
* or (at your option) any later version.
|
9
|
+
*
|
10
|
+
* P1788 is distributed in the hope that it will be useful,
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
13
|
+
* See the GNU General Public License for more details.
|
14
|
+
*
|
15
|
+
* You should have received a copy of the GNU General Public License
|
16
|
+
* along with P1788. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
*/
|
18
|
+
|
19
|
+
/* TODO
|
20
|
+
* wrapper:
|
21
|
+
* - commands
|
22
|
+
* - color
|
23
|
+
* reset figure
|
24
|
+
* do not repeat commands, ex: stroke on then stroke of
|
25
|
+
*/
|
26
|
+
|
27
|
+
#include <ruby.h>
|
28
|
+
#include "p1788.hh"
|
29
|
+
#include "figure.hh"
|
30
|
+
|
31
|
+
|
32
|
+
VALUE c_Figure;
|
33
|
+
|
34
|
+
|
35
|
+
static ID id_width;
|
36
|
+
static ID id_height;
|
37
|
+
static ID id_xrange;
|
38
|
+
static ID id_yrange;
|
39
|
+
static ID id_with_decorations;
|
40
|
+
static ID id_title;
|
41
|
+
static ID id_xlabel;
|
42
|
+
static ID id_ylabel;
|
43
|
+
static ID id_background_color;
|
44
|
+
static ID id_decoration_color;
|
45
|
+
static ID id_decoration_font;
|
46
|
+
static ID id_decoration_font_size;
|
47
|
+
static ID id_decoration_line_width;
|
48
|
+
static ID id_label_font_size;
|
49
|
+
static ID id_title_font_size;
|
50
|
+
static ID id_title_in_bold;
|
51
|
+
|
52
|
+
|
53
|
+
static void p1788_figure_free(void *p)
|
54
|
+
{
|
55
|
+
P1788Figure::Figure *f = (P1788Figure::Figure*)p;
|
56
|
+
delete f;
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
static size_t p1788_figure_size(const void* p)
|
61
|
+
{
|
62
|
+
P1788Figure::Figure *f = (P1788Figure::Figure*)p;
|
63
|
+
return f->allocated_size();
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
static const rb_data_type_t p1788_figure_type = {
|
68
|
+
.wrap_struct_name = "P1788::Figure",
|
69
|
+
.function = {
|
70
|
+
.dmark = NULL,
|
71
|
+
.dfree = p1788_figure_free,
|
72
|
+
.dsize = p1788_figure_size,
|
73
|
+
},
|
74
|
+
.parent = NULL,
|
75
|
+
.data = NULL,
|
76
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
77
|
+
};
|
78
|
+
|
79
|
+
|
80
|
+
static VALUE p1788_figure_alloc(VALUE klass)
|
81
|
+
{
|
82
|
+
P1788Figure::Figure *f = new P1788Figure::Figure();
|
83
|
+
return TypedData_Wrap_Struct(klass, &p1788_figure_type, f);
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
static inline P1788Figure::Figure& p1788_figure_rb2ref(VALUE obj) {
|
88
|
+
P1788Figure::Figure *f;
|
89
|
+
TypedData_Get_Struct(obj, P1788Figure::Figure, &p1788_figure_type, f);
|
90
|
+
return *f;
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
static const char *color_regexp = "^((\\#(\\h{8}))|(((\\#(\\h{6}))|([krgybmcwtKRGYBMCWT]))(\\.\\d+)?))$";
|
95
|
+
// match[] 12 3 456 7 8 9
|
96
|
+
|
97
|
+
/* Tango colors */
|
98
|
+
#define P1788_FIGURE_COLOR_k 0x00000000
|
99
|
+
#define P1788_FIGURE_COLOR_r 0xCC000000
|
100
|
+
#define P1788_FIGURE_COLOR_g 0x4E9A0600
|
101
|
+
#define P1788_FIGURE_COLOR_y 0xC4A00000
|
102
|
+
#define P1788_FIGURE_COLOR_b 0x3465A400
|
103
|
+
#define P1788_FIGURE_COLOR_m 0x75507B00
|
104
|
+
#define P1788_FIGURE_COLOR_c 0x06989A00
|
105
|
+
#define P1788_FIGURE_COLOR_w 0xD3D7CF00
|
106
|
+
#define P1788_FIGURE_COLOR_K 0x55575300
|
107
|
+
#define P1788_FIGURE_COLOR_R 0xEF292900
|
108
|
+
#define P1788_FIGURE_COLOR_G 0x8AE23400
|
109
|
+
#define P1788_FIGURE_COLOR_Y 0xFCE94F00
|
110
|
+
#define P1788_FIGURE_COLOR_B 0x739FCF00
|
111
|
+
#define P1788_FIGURE_COLOR_M 0xAD7FA800
|
112
|
+
#define P1788_FIGURE_COLOR_C 0x34E2E200
|
113
|
+
#define P1788_FIGURE_COLOR_W 0xFFFFFF00
|
114
|
+
|
115
|
+
|
116
|
+
static unsigned int p1788_figure_parse_color(VALUE c)
|
117
|
+
{
|
118
|
+
if (RB_TYPE_P(c, T_FIXNUM) | RB_TYPE_P(c, T_BIGNUM))
|
119
|
+
return NUM2UINT(c);
|
120
|
+
if (!RB_TYPE_P(c, T_STRING))
|
121
|
+
rb_raise(rb_eTypeError, "expecting a string or an integer, not a %" PRIsVALUE,
|
122
|
+
rb_class_name(rb_class_of(c)));
|
123
|
+
unsigned int col = 0;
|
124
|
+
VALUE cr = rb_str_new_static(color_regexp, 62);
|
125
|
+
VALUE regexp = rb_class_new_instance(1, &cr, rb_cRegexp);
|
126
|
+
VALUE match = rb_funcallv(c, id_match, 1, ®exp);
|
127
|
+
if (NIL_P(match))
|
128
|
+
rb_raise(rb_eRuntimeError, "cannot parse \"%" PRIsVALUE "\" as a color", c);
|
129
|
+
VALUE m;
|
130
|
+
|
131
|
+
/* Full hexa */
|
132
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(3));
|
133
|
+
if (m != Qnil)
|
134
|
+
col = NUM2UINT(rb_funcall(m, id_to_i, 1, INT2NUM(16)));
|
135
|
+
else {
|
136
|
+
/* Alpha */
|
137
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(9));
|
138
|
+
if (m != Qnil)
|
139
|
+
col |= std::min(255, std::max(0, (int)round(255.0*NUM2DBL(rb_funcall(m, id_to_f, 0)))));
|
140
|
+
else
|
141
|
+
col |= 0x000000ff;
|
142
|
+
/* Color hexa */
|
143
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(7));
|
144
|
+
if (m != Qnil)
|
145
|
+
col |= NUM2UINT(rb_funcall(m, id_to_i, 1, INT2NUM(16))) << 8;
|
146
|
+
/* Color leter */
|
147
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(8));
|
148
|
+
if (m != Qnil) {
|
149
|
+
switch (*StringValuePtr(m)) {
|
150
|
+
case 'k': col |= P1788_FIGURE_COLOR_k; break;
|
151
|
+
case 'r': col |= P1788_FIGURE_COLOR_r; break;
|
152
|
+
case 'g': col |= P1788_FIGURE_COLOR_g; break;
|
153
|
+
case 'y': col |= P1788_FIGURE_COLOR_y; break;
|
154
|
+
case 'b': col |= P1788_FIGURE_COLOR_b; break;
|
155
|
+
case 'm': col |= P1788_FIGURE_COLOR_m; break;
|
156
|
+
case 'c': col |= P1788_FIGURE_COLOR_c; break;
|
157
|
+
case 'w': col |= P1788_FIGURE_COLOR_w; break;
|
158
|
+
case 'K': col |= P1788_FIGURE_COLOR_K; break;
|
159
|
+
case 'R': col |= P1788_FIGURE_COLOR_R; break;
|
160
|
+
case 'G': col |= P1788_FIGURE_COLOR_G; break;
|
161
|
+
case 'Y': col |= P1788_FIGURE_COLOR_Y; break;
|
162
|
+
case 'B': col |= P1788_FIGURE_COLOR_B; break;
|
163
|
+
case 'M': col |= P1788_FIGURE_COLOR_M; break;
|
164
|
+
case 'C': col |= P1788_FIGURE_COLOR_C; break;
|
165
|
+
case 'W': col |= P1788_FIGURE_COLOR_W; break;
|
166
|
+
default:
|
167
|
+
col &= 0xffffff00;
|
168
|
+
}
|
169
|
+
}
|
170
|
+
}
|
171
|
+
return col;
|
172
|
+
}
|
173
|
+
|
174
|
+
|
175
|
+
static inline VALUE p1788_cppstring_to_rbstring_utf8(const std::string& cppstring) {
|
176
|
+
return rb_str_freeze(rb_utf8_str_new(cppstring.c_str(), cppstring.size()));
|
177
|
+
}
|
178
|
+
|
179
|
+
|
180
|
+
static std::string p1788_rbstring_to_cppstring(VALUE rbstring) {
|
181
|
+
if (!RB_TYPE_P(rbstring, T_STRING))
|
182
|
+
rb_raise(rb_eTypeError, "expecting a string, not a %" PRIsVALUE, rb_class_name(rb_class_of(rbstring)));
|
183
|
+
return std::string(StringValuePtr(rbstring), RSTRING_LEN(rbstring));
|
184
|
+
}
|
185
|
+
|
186
|
+
|
187
|
+
/* Return the number of bytes allocated for the figure.
|
188
|
+
* @!visibility private
|
189
|
+
* @return [Integer]
|
190
|
+
*/
|
191
|
+
static VALUE p1788_figure_allocated_size(VALUE self)
|
192
|
+
{
|
193
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
194
|
+
return SIZET2NUM(p1788_figure_size(&f));
|
195
|
+
}
|
196
|
+
|
197
|
+
|
198
|
+
/* The title to be drawn on top of the figure.
|
199
|
+
* Set the title to _nil_ to remove the title.
|
200
|
+
* @return [String, nil]
|
201
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :title; end; end
|
202
|
+
*/
|
203
|
+
static VALUE p1788_figure_get_title(VALUE self)
|
204
|
+
{
|
205
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
206
|
+
const std::string& t = f.title();
|
207
|
+
if (t.empty())
|
208
|
+
return Qnil;
|
209
|
+
return p1788_cppstring_to_rbstring_utf8(t);
|
210
|
+
}
|
211
|
+
|
212
|
+
|
213
|
+
static VALUE p1788_figure_set_title(VALUE self, VALUE str)
|
214
|
+
{
|
215
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
216
|
+
if (NIL_P(str))
|
217
|
+
f.set_title("");
|
218
|
+
else
|
219
|
+
f.set_title(p1788_rbstring_to_cppstring(rb_funcallv(str, id_to_s, 0, NULL)));
|
220
|
+
return self;
|
221
|
+
}
|
222
|
+
|
223
|
+
|
224
|
+
/* The label to be drawn below the horizontal axis.
|
225
|
+
* Set the label to _nil_ to remove it.
|
226
|
+
* @return [String, nil]
|
227
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :xlabel; end; end
|
228
|
+
*/
|
229
|
+
static VALUE p1788_figure_get_xlabel(VALUE self)
|
230
|
+
{
|
231
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
232
|
+
const std::string& t = f.xlabel();
|
233
|
+
if (t.empty())
|
234
|
+
return Qnil;
|
235
|
+
return p1788_cppstring_to_rbstring_utf8(t);
|
236
|
+
}
|
237
|
+
|
238
|
+
|
239
|
+
static VALUE p1788_figure_set_xlabel(VALUE self, VALUE str)
|
240
|
+
{
|
241
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
242
|
+
if (NIL_P(str))
|
243
|
+
f.set_xlabel("");
|
244
|
+
else
|
245
|
+
f.set_xlabel(p1788_rbstring_to_cppstring(rb_funcallv(str, id_to_s, 0, NULL)));
|
246
|
+
return self;
|
247
|
+
}
|
248
|
+
|
249
|
+
|
250
|
+
/* The label to be drawn on the left of the vertical axis.
|
251
|
+
* Set the label to _nil_ to remove it.
|
252
|
+
* @return [String, nil]
|
253
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :ylabel; end; end
|
254
|
+
*/
|
255
|
+
static VALUE p1788_figure_get_ylabel(VALUE self)
|
256
|
+
{
|
257
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
258
|
+
const std::string& t = f.ylabel();
|
259
|
+
if (t.empty())
|
260
|
+
return Qnil;
|
261
|
+
return p1788_cppstring_to_rbstring_utf8(t);
|
262
|
+
}
|
263
|
+
|
264
|
+
|
265
|
+
static VALUE p1788_figure_set_ylabel(VALUE self, VALUE str)
|
266
|
+
{
|
267
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
268
|
+
if (NIL_P(str))
|
269
|
+
f.set_ylabel("");
|
270
|
+
else
|
271
|
+
f.set_ylabel(p1788_rbstring_to_cppstring(rb_funcallv(str, id_to_s, 0, NULL)));
|
272
|
+
return self;
|
273
|
+
}
|
274
|
+
|
275
|
+
|
276
|
+
/* The font used to display the title, labels and graduations.
|
277
|
+
* Set the font to _nil_ to reset it to its default ("Sans").
|
278
|
+
* @return [String, nil]
|
279
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :decoration_font; end; end
|
280
|
+
*/
|
281
|
+
static VALUE p1788_figure_get_decoration_font(VALUE self)
|
282
|
+
{
|
283
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
284
|
+
const std::string& t = f.graduation_font();
|
285
|
+
if (t.empty())
|
286
|
+
return Qnil;
|
287
|
+
return p1788_cppstring_to_rbstring_utf8(t);
|
288
|
+
}
|
289
|
+
|
290
|
+
|
291
|
+
static VALUE p1788_figure_set_decoration_font(VALUE self, VALUE str)
|
292
|
+
{
|
293
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
294
|
+
if (NIL_P(str))
|
295
|
+
f.set_graduation_font("");
|
296
|
+
else
|
297
|
+
f.set_graduation_font(p1788_rbstring_to_cppstring(rb_funcallv(str, id_to_s, 0, NULL)));
|
298
|
+
return self;
|
299
|
+
}
|
300
|
+
|
301
|
+
|
302
|
+
/* Size of the font used to display the title, labels and graduations.
|
303
|
+
* @return [Float]
|
304
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :decoration_font_size; end; end
|
305
|
+
*/
|
306
|
+
static VALUE p1788_figure_get_decoration_font_size(VALUE self)
|
307
|
+
{
|
308
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
309
|
+
return DBL2NUM(f.graduation_font_size());
|
310
|
+
}
|
311
|
+
|
312
|
+
|
313
|
+
static VALUE p1788_figure_set_decoration_font_size(VALUE self, VALUE s)
|
314
|
+
{
|
315
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
316
|
+
if (NIL_P(s))
|
317
|
+
f.set_graduation_font_size(0.0);
|
318
|
+
else
|
319
|
+
f.set_graduation_font_size((float)NUM2DBL(rb_funcallv(s, id_to_f, 0, NULL)));
|
320
|
+
return self;
|
321
|
+
}
|
322
|
+
|
323
|
+
|
324
|
+
/* Size of the font used to display the title.
|
325
|
+
*
|
326
|
+
* If set to _nil_, the title will automatically be drawn at 1.23 times the decoration font size.
|
327
|
+
* @return [Float, nil]
|
328
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :title_font_size; end; end
|
329
|
+
*/
|
330
|
+
static VALUE p1788_figure_get_title_font_size(VALUE self)
|
331
|
+
{
|
332
|
+
double s = p1788_figure_rb2ref(self).title_font_size_as_set();
|
333
|
+
if (s <= 0.0)
|
334
|
+
return Qnil;
|
335
|
+
return DBL2NUM(s);
|
336
|
+
}
|
337
|
+
|
338
|
+
|
339
|
+
static VALUE p1788_figure_set_title_font_size(VALUE self, VALUE s)
|
340
|
+
{
|
341
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
342
|
+
if (NIL_P(s))
|
343
|
+
f.set_title_font_size(0.0);
|
344
|
+
else
|
345
|
+
f.set_title_font_size((float)NUM2DBL(rb_funcallv(s, id_to_f, 0, NULL)));
|
346
|
+
return self;
|
347
|
+
}
|
348
|
+
|
349
|
+
|
350
|
+
/* Size of the font used to display the labels.
|
351
|
+
*
|
352
|
+
* If set to _nil_, the labels will automatically be drawn at 1.1 times the decoration font size.
|
353
|
+
* @return [Float, nil]
|
354
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :label_font_size; end; end
|
355
|
+
*/
|
356
|
+
static VALUE p1788_figure_get_label_font_size(VALUE self)
|
357
|
+
{
|
358
|
+
double s = p1788_figure_rb2ref(self).label_font_size_as_set();
|
359
|
+
if (s <= 0.0)
|
360
|
+
return Qnil;
|
361
|
+
return DBL2NUM(s);
|
362
|
+
}
|
363
|
+
|
364
|
+
|
365
|
+
static VALUE p1788_figure_set_label_font_size(VALUE self, VALUE s)
|
366
|
+
{
|
367
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
368
|
+
if (NIL_P(s))
|
369
|
+
f.set_label_font_size(0.0);
|
370
|
+
else
|
371
|
+
f.set_label_font_size((float)NUM2DBL(rb_funcallv(s, id_to_f, 0, NULL)));
|
372
|
+
return self;
|
373
|
+
}
|
374
|
+
|
375
|
+
|
376
|
+
/* Line width for drawing the frame around the figure.
|
377
|
+
* @return [Float]
|
378
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :decoration_line_width; end; end
|
379
|
+
*/
|
380
|
+
static VALUE p1788_figure_get_decoration_line_width(VALUE self)
|
381
|
+
{
|
382
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
383
|
+
return DBL2NUM(f.graduation_stroke_width());
|
384
|
+
}
|
385
|
+
|
386
|
+
|
387
|
+
static VALUE p1788_figure_set_decoration_line_width(VALUE self, VALUE w)
|
388
|
+
{
|
389
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
390
|
+
f.set_graduation_stroke_width((float)NUM2DBL(rb_funcallv(w, id_to_f, 0, NULL)));
|
391
|
+
return self;
|
392
|
+
}
|
393
|
+
|
394
|
+
|
395
|
+
/* Color of the decoration (frame, graduations, title and axis labels).
|
396
|
+
*
|
397
|
+
* The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
|
398
|
+
* for the red, green, blue and alpha channels.
|
399
|
+
*
|
400
|
+
* This attribute can also be set to a string, like `"#cc000080"`, `"#cc0000.5"`,`"r.5"` or `"W"`.
|
401
|
+
* @return [Integer]
|
402
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :decoration_color; end; end
|
403
|
+
*/
|
404
|
+
static VALUE p1788_figure_get_decoration_color(VALUE self)
|
405
|
+
{
|
406
|
+
return UINT2NUM(p1788_figure_rb2ref(self).graduation_color());
|
407
|
+
}
|
408
|
+
|
409
|
+
static VALUE p1788_figure_set_decoration_color(VALUE self, VALUE c)
|
410
|
+
{
|
411
|
+
unsigned int n = p1788_figure_parse_color(c);
|
412
|
+
p1788_figure_rb2ref(self).set_graduation_color(n);
|
413
|
+
return self;
|
414
|
+
}
|
415
|
+
|
416
|
+
|
417
|
+
/* Background color of the figure.
|
418
|
+
*
|
419
|
+
* The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
|
420
|
+
* for the red, green, blue and alpha channels.
|
421
|
+
*
|
422
|
+
* This attribute can also be set to a string, like `"#cc000080"`, `"#cc0000.5"`,`"r.5"` or `"W"`.
|
423
|
+
* @return [Integer]
|
424
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :background_color; end; end
|
425
|
+
*/
|
426
|
+
static VALUE p1788_figure_get_background_color(VALUE self)
|
427
|
+
{
|
428
|
+
return UINT2NUM(p1788_figure_rb2ref(self).background_color());
|
429
|
+
}
|
430
|
+
|
431
|
+
static VALUE p1788_figure_set_background_color(VALUE self, VALUE c)
|
432
|
+
{
|
433
|
+
unsigned int n = p1788_figure_parse_color(c);
|
434
|
+
p1788_figure_rb2ref(self).set_background_color(n);
|
435
|
+
return self;
|
436
|
+
}
|
437
|
+
|
438
|
+
|
439
|
+
/* The width of the output image, in pixels.
|
440
|
+
* Set the width to _nil_ or 0 to get automatic sizing.
|
441
|
+
* @return [Integer, nil]
|
442
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :width; end; end
|
443
|
+
*/
|
444
|
+
static VALUE p1788_figure_get_width(VALUE self)
|
445
|
+
{
|
446
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
447
|
+
int i = f.width();
|
448
|
+
if (i < 1)
|
449
|
+
return Qnil;
|
450
|
+
return INT2NUM(i);
|
451
|
+
}
|
452
|
+
|
453
|
+
static VALUE p1788_figure_set_width(VALUE self, VALUE w)
|
454
|
+
{
|
455
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
456
|
+
if (NIL_P(w)) {
|
457
|
+
f.set_width(0);
|
458
|
+
return self;
|
459
|
+
}
|
460
|
+
int i = NUM2INT(rb_funcallv(w, id_to_i, 0, NULL));
|
461
|
+
if (i <= 0)
|
462
|
+
f.set_width(0);
|
463
|
+
else
|
464
|
+
f.set_width(i);
|
465
|
+
return self;
|
466
|
+
}
|
467
|
+
|
468
|
+
|
469
|
+
/* The height of the output image, in pixels.
|
470
|
+
* Set the height to _nil_ or 0 to get automatic sizing.
|
471
|
+
* @return [Integer, nil]
|
472
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :height; end; end
|
473
|
+
*/
|
474
|
+
static VALUE p1788_figure_get_height(VALUE self)
|
475
|
+
{
|
476
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
477
|
+
int i = f.height();
|
478
|
+
if (i < 1)
|
479
|
+
return Qnil;
|
480
|
+
return INT2NUM(i);
|
481
|
+
}
|
482
|
+
|
483
|
+
static VALUE p1788_figure_set_height(VALUE self, VALUE h)
|
484
|
+
{
|
485
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
486
|
+
if (NIL_P(h)) {
|
487
|
+
f.set_height(0);
|
488
|
+
return self;
|
489
|
+
}
|
490
|
+
int i = NUM2INT(rb_funcallv(h, id_to_i, 0, NULL));
|
491
|
+
if (i <= 0)
|
492
|
+
f.set_height(0);
|
493
|
+
else
|
494
|
+
f.set_height(i);
|
495
|
+
return self;
|
496
|
+
}
|
497
|
+
|
498
|
+
|
499
|
+
/* The horizontal range that will be displayed.
|
500
|
+
* Set _xrange_ to _nil_ or an empty interval to get automatic range adjustment.
|
501
|
+
* @return [Interval, nil]
|
502
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :xrange; end; end
|
503
|
+
*/
|
504
|
+
static VALUE p1788_figure_get_xrange(VALUE self)
|
505
|
+
{
|
506
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
507
|
+
const Interval& r = f.xlim();
|
508
|
+
if (!Interval::is_common_interval(r))
|
509
|
+
return Qnil;
|
510
|
+
VALUE res;
|
511
|
+
P1788_NEW_RB_INTERVAL(res, r);
|
512
|
+
return res;
|
513
|
+
}
|
514
|
+
|
515
|
+
static VALUE p1788_figure_set_xrange(VALUE self, VALUE rng)
|
516
|
+
{
|
517
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
518
|
+
if (NIL_P(rng))
|
519
|
+
f.set_xlimit(Interval());
|
520
|
+
else
|
521
|
+
f.set_xlimit(p1788_rbobj2interval(rng));
|
522
|
+
return self;
|
523
|
+
}
|
524
|
+
|
525
|
+
|
526
|
+
/* The vertical range that will be displayed.
|
527
|
+
* Set _yrange_ to _nil_ or an empty interval to get automatic range adjustment.
|
528
|
+
* @return [Interval, nil]
|
529
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :yrange; end; end
|
530
|
+
*/
|
531
|
+
static VALUE p1788_figure_get_yrange(VALUE self)
|
532
|
+
{
|
533
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
534
|
+
const Interval& r = f.ylim();
|
535
|
+
if (!Interval::is_common_interval(r))
|
536
|
+
return Qnil;
|
537
|
+
VALUE res;
|
538
|
+
P1788_NEW_RB_INTERVAL(res, r);
|
539
|
+
return res;
|
540
|
+
}
|
541
|
+
|
542
|
+
static VALUE p1788_figure_set_yrange(VALUE self, VALUE rng)
|
543
|
+
{
|
544
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
545
|
+
if (NIL_P(rng))
|
546
|
+
f.set_ylimit(Interval());
|
547
|
+
else
|
548
|
+
f.set_ylimit(p1788_rbobj2interval(rng));
|
549
|
+
return self;
|
550
|
+
}
|
551
|
+
|
552
|
+
|
553
|
+
/* Set the horizontal and vertical range that will be displayed.
|
554
|
+
*
|
555
|
+
* This is the same as calling both {xrange=} and {yrange=}.
|
556
|
+
* Set to _nil_ to reset ranges and get automatic display range according to the content.
|
557
|
+
* @param box [IntervalVector, nil] an interval vector with at least two elements, or nil
|
558
|
+
* @return [self]
|
559
|
+
*/
|
560
|
+
static VALUE p1788_figure_set_range(VALUE self, VALUE box)
|
561
|
+
{
|
562
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
563
|
+
if (NIL_P(box)) {
|
564
|
+
f.set_xlimit(Interval());
|
565
|
+
f.set_ylimit(Interval());
|
566
|
+
return self;
|
567
|
+
}
|
568
|
+
if (!is_an_interval_vector(box))
|
569
|
+
rb_raise(rb_eTypeError, "expecting a %" PRIsVALUE ", not a %" PRIsVALUE,
|
570
|
+
rb_class_name(c_IntervalVector), rb_class_name(rb_class_of(box)));
|
571
|
+
const IntervalVector& r = p1788_vector_rb2ref(box);
|
572
|
+
if (r.size() < 2)
|
573
|
+
rb_raise(rb_eRuntimeError, "the interval vector must have at least two elements (for the x an y axis)");
|
574
|
+
f.set_xlimit(r[0]);
|
575
|
+
f.set_ylimit(r[1]);
|
576
|
+
return self;
|
577
|
+
}
|
578
|
+
|
579
|
+
|
580
|
+
/* Draw decorations around the figure?.
|
581
|
+
*
|
582
|
+
* If set to _false_, no frame, ticks, title nor labels will be drawn around the figure,
|
583
|
+
* even if they are set. The output image size will be _width_ x _height_.
|
584
|
+
*
|
585
|
+
* If set to _true_, a frame and graduations will be drawn around the figure.
|
586
|
+
* If they are set, title and labels will also be drawn.
|
587
|
+
* The output image size will be larger than _width_ x _height_.
|
588
|
+
* @return [Boolean]
|
589
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :with_decorations; end; end
|
590
|
+
*/
|
591
|
+
static VALUE p1788_figure_get_with_decorations(VALUE self)
|
592
|
+
{
|
593
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
594
|
+
return f.print_graduations() ? Qtrue : Qfalse;
|
595
|
+
}
|
596
|
+
|
597
|
+
|
598
|
+
static VALUE p1788_figure_set_with_decorations(VALUE self, VALUE b)
|
599
|
+
{
|
600
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
601
|
+
f.set_print_graduations((NIL_P(b) || b == Qfalse) ? false : true);
|
602
|
+
return self;
|
603
|
+
}
|
604
|
+
|
605
|
+
|
606
|
+
/* Draw the title in a bold font?
|
607
|
+
*
|
608
|
+
* If {with_decorations} is set to _true_ and
|
609
|
+
* {title} is not _nil_ nor empty,
|
610
|
+
* the title will be drawn in bold or normal weight according
|
611
|
+
* to this attribute.
|
612
|
+
* @return [Boolean]
|
613
|
+
* @!parse [ruby] module P1788; class Figure; attr_accessor :title_in_bold; end; end
|
614
|
+
*/
|
615
|
+
static VALUE p1788_figure_get_title_in_bold(VALUE self)
|
616
|
+
{
|
617
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
618
|
+
return f.title_bold() ? Qtrue : Qfalse;
|
619
|
+
}
|
620
|
+
|
621
|
+
|
622
|
+
static VALUE p1788_figure_set_title_in_bold(VALUE self, VALUE b)
|
623
|
+
{
|
624
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
625
|
+
f.set_title_bold((NIL_P(b) || b == Qfalse) ? false : true);
|
626
|
+
return self;
|
627
|
+
}
|
628
|
+
|
629
|
+
|
630
|
+
/* Returns the union of all the boxes that have ben sent to the figure for drwawing.
|
631
|
+
* @return [IntervalVector] a two interval vector, for _x_ and _y_.
|
632
|
+
*/
|
633
|
+
static VALUE p1788_figure_content_range(VALUE self)
|
634
|
+
{
|
635
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
636
|
+
P1788Figure::Box b;
|
637
|
+
f.find_unbounded_limits(b);
|
638
|
+
|
639
|
+
IntervalVector *v = new IntervalVector(2);
|
640
|
+
(*v)[0] = b.x;
|
641
|
+
(*v)[1] = b.y;
|
642
|
+
return p1788_vector_alloc_from_pointer(v);
|
643
|
+
}
|
644
|
+
|
645
|
+
|
646
|
+
/* Returns a range that would be nice to display, according to the content of the figure.
|
647
|
+
* @return [IntervalVector] a two interval vector, for _x_ and _y_.
|
648
|
+
*/
|
649
|
+
static VALUE p1788_figure_nice_range(VALUE self)
|
650
|
+
{
|
651
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
652
|
+
P1788Figure::Box b, c;
|
653
|
+
f.find_limits(c, b);
|
654
|
+
|
655
|
+
IntervalVector *v = new IntervalVector(2);
|
656
|
+
(*v)[0] = b.x;
|
657
|
+
(*v)[1] = b.y;
|
658
|
+
return p1788_vector_alloc_from_pointer(v);
|
659
|
+
}
|
660
|
+
|
661
|
+
|
662
|
+
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
663
|
+
/* Generate the figure and write the output image in PNG format to file _file_name_.
|
664
|
+
* @param file_name [String] name of the file to write the image to.
|
665
|
+
* @return [self]
|
666
|
+
*/
|
667
|
+
static VALUE p1788_figure_write_png(VALUE self, VALUE file_name)
|
668
|
+
{
|
669
|
+
file_name = rb_funcallv(file_name, id_to_s, 0, NULL);
|
670
|
+
if (RSTRING_LEN(file_name) < 1)
|
671
|
+
rb_raise(rb_eRuntimeError, "file name is empty");
|
672
|
+
file_name = rb_funcallv(rb_cFile, rb_intern("absolute_path"), 1, &file_name);
|
673
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
674
|
+
std::string cppfname = p1788_rbstring_to_cppstring(file_name);
|
675
|
+
try {
|
676
|
+
f.write_png(cppfname);
|
677
|
+
} catch (const std::exception &e) {
|
678
|
+
rb_raise(rb_eRuntimeError, "%s", e.what());
|
679
|
+
}
|
680
|
+
return self;
|
681
|
+
}
|
682
|
+
|
683
|
+
/* Generate the figure and return its content as a string in the PNG format.
|
684
|
+
* @return [String]
|
685
|
+
*/
|
686
|
+
static VALUE p1788_figure_to_png(VALUE self)
|
687
|
+
{
|
688
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
689
|
+
std::string s;
|
690
|
+
try {
|
691
|
+
s = std::move(f.to_png());
|
692
|
+
} catch (const std::exception &e) {
|
693
|
+
rb_raise(rb_eRuntimeError, "%s", e.what());
|
694
|
+
}
|
695
|
+
return rb_usascii_str_new(s.c_str(), s.size());
|
696
|
+
}
|
697
|
+
#endif
|
698
|
+
|
699
|
+
|
700
|
+
#ifdef CAIRO_HAS_SVG_SURFACE
|
701
|
+
/* Generate the figure and write the output image in SVG format to file _file_name_.
|
702
|
+
* @param file_name [String] name of the file to write the image to.
|
703
|
+
* @return [self]
|
704
|
+
*/
|
705
|
+
static VALUE p1788_figure_write_svg(VALUE self, VALUE file_name)
|
706
|
+
{
|
707
|
+
file_name = rb_funcallv(file_name, id_to_s, 0, NULL);
|
708
|
+
if (RSTRING_LEN(file_name) < 1)
|
709
|
+
rb_raise(rb_eRuntimeError, "file name is empty");
|
710
|
+
file_name = rb_funcallv(rb_cFile, rb_intern("absolute_path"), 1, &file_name);
|
711
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
712
|
+
std::string cppfname = p1788_rbstring_to_cppstring(file_name);
|
713
|
+
try {
|
714
|
+
f.write_svg(cppfname);
|
715
|
+
} catch (const std::exception &e) {
|
716
|
+
rb_raise(rb_eRuntimeError, "%s", e.what());
|
717
|
+
}
|
718
|
+
return self;
|
719
|
+
}
|
720
|
+
|
721
|
+
/* Generate the figure and return its content as a string in the SVG format.
|
722
|
+
* @return [String]
|
723
|
+
*/
|
724
|
+
static VALUE p1788_figure_to_svg(VALUE self)
|
725
|
+
{
|
726
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
727
|
+
std::string s;
|
728
|
+
try {
|
729
|
+
s = std::move(f.to_svg());
|
730
|
+
} catch (const std::exception &e) {
|
731
|
+
rb_raise(rb_eRuntimeError, "%s", e.what());
|
732
|
+
}
|
733
|
+
return rb_usascii_str_new(s.c_str(), s.size());
|
734
|
+
}
|
735
|
+
#endif
|
736
|
+
|
737
|
+
|
738
|
+
#ifdef CAIRO_HAS_PDF_SURFACE
|
739
|
+
/* Generate the figure and write the output image in PDF format to file _file_name_.
|
740
|
+
* @param file_name [String] name of the file to write the image to.
|
741
|
+
* @return [self]
|
742
|
+
*/
|
743
|
+
static VALUE p1788_figure_write_pdf(VALUE self, VALUE file_name)
|
744
|
+
{
|
745
|
+
file_name = rb_funcallv(file_name, id_to_s, 0, NULL);
|
746
|
+
if (RSTRING_LEN(file_name) < 1)
|
747
|
+
rb_raise(rb_eRuntimeError, "file name is empty");
|
748
|
+
file_name = rb_funcallv(rb_cFile, rb_intern("absolute_path"), 1, &file_name);
|
749
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
750
|
+
std::string cppfname = p1788_rbstring_to_cppstring(file_name);
|
751
|
+
try {
|
752
|
+
f.write_pdf(cppfname);
|
753
|
+
} catch (const std::exception &e) {
|
754
|
+
rb_raise(rb_eRuntimeError, "%s", e.what());
|
755
|
+
}
|
756
|
+
return self;
|
757
|
+
}
|
758
|
+
|
759
|
+
/* Generate the figure and return its content as a string in the PDF format.
|
760
|
+
* @return [String]
|
761
|
+
*/
|
762
|
+
static VALUE p1788_figure_to_pdf(VALUE self)
|
763
|
+
{
|
764
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
765
|
+
std::string s;
|
766
|
+
try {
|
767
|
+
s = std::move(f.to_pdf());
|
768
|
+
} catch (const std::exception &e) {
|
769
|
+
rb_raise(rb_eRuntimeError, "%s", e.what());
|
770
|
+
}
|
771
|
+
return rb_usascii_str_new(s.c_str(), s.size());
|
772
|
+
}
|
773
|
+
#endif
|
774
|
+
|
775
|
+
|
776
|
+
/* Tell the figure to draw new objects (boxes) with a border.
|
777
|
+
* @see stroke_off
|
778
|
+
* @see stroke_width=
|
779
|
+
* @see stroke_color=
|
780
|
+
* @see stroke?
|
781
|
+
* @return [self]
|
782
|
+
*/
|
783
|
+
static VALUE p1788_figure_stroke_on(VALUE self)
|
784
|
+
{
|
785
|
+
p1788_figure_rb2ref(self).cmd_stroke(true);
|
786
|
+
return self;
|
787
|
+
}
|
788
|
+
|
789
|
+
|
790
|
+
/* Tell the figure to draw new objects (boxes) without border.
|
791
|
+
* @see stroke_on
|
792
|
+
* @see stroke?
|
793
|
+
* @return [self]
|
794
|
+
*/
|
795
|
+
static VALUE p1788_figure_stroke_off(VALUE self)
|
796
|
+
{
|
797
|
+
p1788_figure_rb2ref(self).cmd_stroke(false);
|
798
|
+
return self;
|
799
|
+
}
|
800
|
+
|
801
|
+
|
802
|
+
/* Returns _true_ if new objects (boxes) will be drawned with a border.
|
803
|
+
* @see stroke_on
|
804
|
+
* @see stroke_off
|
805
|
+
* @return [Boolean]
|
806
|
+
*/
|
807
|
+
static VALUE p1788_figure_get_stroke_onoff(VALUE self)
|
808
|
+
{
|
809
|
+
return p1788_figure_rb2ref(self).do_stroke() ? Qtrue : Qfalse;
|
810
|
+
}
|
811
|
+
|
812
|
+
|
813
|
+
/* Tell the figure to fill new objects (boxes) with the fill color.
|
814
|
+
* @see fill_off
|
815
|
+
* @see fill_color=
|
816
|
+
* @see fill?
|
817
|
+
* @return [self]
|
818
|
+
*/
|
819
|
+
static VALUE p1788_figure_fill_on(VALUE self)
|
820
|
+
{
|
821
|
+
p1788_figure_rb2ref(self).cmd_fill(true);
|
822
|
+
return self;
|
823
|
+
}
|
824
|
+
|
825
|
+
|
826
|
+
/* Tell the figure not to fill new objects (boxes).
|
827
|
+
* @see fill_on
|
828
|
+
* @see fill?
|
829
|
+
* @return [self]
|
830
|
+
*/
|
831
|
+
static VALUE p1788_figure_fill_off(VALUE self)
|
832
|
+
{
|
833
|
+
p1788_figure_rb2ref(self).cmd_fill(false);
|
834
|
+
return self;
|
835
|
+
}
|
836
|
+
|
837
|
+
|
838
|
+
/* Returns _true_ if new objects (boxes) will be filled.
|
839
|
+
* @see fill_on
|
840
|
+
* @see fill_off
|
841
|
+
* @return [Boolean]
|
842
|
+
*/
|
843
|
+
static VALUE p1788_figure_get_fill_onoff(VALUE self)
|
844
|
+
{
|
845
|
+
return p1788_figure_rb2ref(self).do_fill() ? Qtrue : Qfalse;
|
846
|
+
}
|
847
|
+
|
848
|
+
|
849
|
+
/* Set the line width of the new objects (boxes) that will be drawned.
|
850
|
+
* @see stroke_on
|
851
|
+
* @see stroke_color=
|
852
|
+
* @return [self]
|
853
|
+
*/
|
854
|
+
static VALUE p1788_figure_set_stroke_width(VALUE self, VALUE w)
|
855
|
+
{
|
856
|
+
p1788_figure_rb2ref(self).cmd_stroke_width(NUM2DBL(w));
|
857
|
+
return self;
|
858
|
+
}
|
859
|
+
|
860
|
+
|
861
|
+
/* Returns the current line width used to draw the border of objects (boxes).
|
862
|
+
* @see stroke_width=
|
863
|
+
* @return [Float]
|
864
|
+
*/
|
865
|
+
static VALUE p1788_figure_get_stroke_width(VALUE self)
|
866
|
+
{
|
867
|
+
return DBL2NUM(p1788_figure_rb2ref(self).stroke_width());
|
868
|
+
}
|
869
|
+
|
870
|
+
|
871
|
+
/* Set the border color of the new objects (boxes) that will be drawned.
|
872
|
+
*
|
873
|
+
* The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
|
874
|
+
* for the red, green, blue and alpha channels.
|
875
|
+
*
|
876
|
+
* The color can also be set to a string, like `"#cc000080"`, `"#cc0000.5"`,`"r.5"` or `"W"`.
|
877
|
+
* @param c [Integer, String]
|
878
|
+
* @see stroke_on
|
879
|
+
* @see stroke_width=
|
880
|
+
* @return [self]
|
881
|
+
*/
|
882
|
+
static VALUE p1788_figure_set_stroke_color(VALUE self, VALUE c)
|
883
|
+
{
|
884
|
+
unsigned int n = p1788_figure_parse_color(c);
|
885
|
+
p1788_figure_rb2ref(self).cmd_stroke_color(n);
|
886
|
+
return self;
|
887
|
+
}
|
888
|
+
|
889
|
+
|
890
|
+
/* Returns the current color used to draw the border of objects (boxes).
|
891
|
+
* The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
|
892
|
+
* for the red, green, blue and alpha channels.
|
893
|
+
* @see stroke_color=
|
894
|
+
* @return [Integer]
|
895
|
+
*/
|
896
|
+
static VALUE p1788_figure_get_stroke_color(VALUE self)
|
897
|
+
{
|
898
|
+
return UINT2NUM(p1788_figure_rb2ref(self).stroke_color());
|
899
|
+
}
|
900
|
+
|
901
|
+
|
902
|
+
/* Set the fill color of the new objects (boxes) that will be drawned.
|
903
|
+
*
|
904
|
+
* The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
|
905
|
+
* for the red, green, blue and alpha channels.
|
906
|
+
*
|
907
|
+
* The color can also be set to a string, like `"#cc000080"`, `"#cc0000.5"`,`"r.5"` or `"W"`.
|
908
|
+
* @param c [Integer, String]
|
909
|
+
* @see fill_on
|
910
|
+
* @return [self]
|
911
|
+
*/
|
912
|
+
static VALUE p1788_figure_set_fill_color(VALUE self, VALUE c)
|
913
|
+
{
|
914
|
+
unsigned int n = p1788_figure_parse_color(c);
|
915
|
+
p1788_figure_rb2ref(self).cmd_fill_color(n);
|
916
|
+
return self;
|
917
|
+
}
|
918
|
+
|
919
|
+
|
920
|
+
/* Returns the current color used to fill objects (boxes).
|
921
|
+
* The color is encoded into a 32-bit integer that can be split in hexadecimal as: 0xRRGGBBAA,
|
922
|
+
* for the red, green, blue and alpha channels.
|
923
|
+
* @see fill_color=
|
924
|
+
* @return [Integer]
|
925
|
+
*/
|
926
|
+
static VALUE p1788_figure_get_fill_color(VALUE self)
|
927
|
+
{
|
928
|
+
return UINT2NUM(p1788_figure_rb2ref(self).fill_color());
|
929
|
+
}
|
930
|
+
|
931
|
+
|
932
|
+
static const char *format_regexp = "^((_|([^\\[\\]]+))?(\\[(_|([^\\[\\]]+))?\\])?)$";
|
933
|
+
// match[] 12 3 4 5 6
|
934
|
+
|
935
|
+
|
936
|
+
static void p1788_figure_parse_format(P1788Figure::Figure& f, VALUE str)
|
937
|
+
{
|
938
|
+
if (!RB_TYPE_P(str, T_STRING))
|
939
|
+
rb_raise(rb_eTypeError, "expecting a string as format, not a %" PRIsVALUE,
|
940
|
+
rb_class_name(rb_class_of(str)));
|
941
|
+
VALUE cr = rb_str_new_static(format_regexp, 41);
|
942
|
+
VALUE regexp = rb_class_new_instance(1, &cr, rb_cRegexp);
|
943
|
+
VALUE match = rb_funcallv(str, id_match, 1, ®exp);
|
944
|
+
if (NIL_P(match))
|
945
|
+
rb_raise(rb_eRuntimeError, "cannot parse \"%" PRIsVALUE "\" as a format", str);
|
946
|
+
VALUE m;
|
947
|
+
|
948
|
+
/* Stroke */
|
949
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(2));
|
950
|
+
if (NIL_P(m)) // no stroke
|
951
|
+
f.cmd_stroke(false);
|
952
|
+
else {
|
953
|
+
f.cmd_stroke(true);
|
954
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(3));
|
955
|
+
if (m != Qnil)
|
956
|
+
f.cmd_stroke_color(p1788_figure_parse_color(m));
|
957
|
+
}
|
958
|
+
|
959
|
+
/* Fill */
|
960
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(5));
|
961
|
+
if (NIL_P(m)) // no fill
|
962
|
+
f.cmd_fill(false);
|
963
|
+
else {
|
964
|
+
f.cmd_fill(true);
|
965
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(6));
|
966
|
+
if (m != Qnil)
|
967
|
+
f.cmd_fill_color(p1788_figure_parse_color(m));
|
968
|
+
}
|
969
|
+
}
|
970
|
+
|
971
|
+
|
972
|
+
/* Draw a single box.
|
973
|
+
* @return [self]
|
974
|
+
* @overload draw_box(box, format=nil)
|
975
|
+
* @param box [IntervalVector] an interval vector with at least two elements (for the _x_ and _y_ axis)
|
976
|
+
* @param format [String] an optional string in the form `"border_color[fill_color]"`
|
977
|
+
*/
|
978
|
+
static VALUE p1788_figure_draw_box(int argc, VALUE *argv, VALUE self)
|
979
|
+
{
|
980
|
+
VALUE rbox, rformat;
|
981
|
+
rb_scan_args(argc, argv, "11", &rbox, &rformat);
|
982
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
983
|
+
if (rformat != Qnil)
|
984
|
+
p1788_figure_parse_format(f, rformat);
|
985
|
+
f.cmd_draw_box(p1788_vector_rb2ref(rbox));
|
986
|
+
return self;
|
987
|
+
}
|
988
|
+
|
989
|
+
|
990
|
+
/* Draw multiple boxes at once.
|
991
|
+
* @return [self]
|
992
|
+
* @overload draw_boxes(array_of_boxes, format=nil)
|
993
|
+
* @param array_of_boxes [Array<IntervalVector>] an array of interval vectors each with at least two elements (for the _x_ and _y_ axis)
|
994
|
+
* @param format [String] an optional string in the form `"border_color[fill_color]"`
|
995
|
+
*/
|
996
|
+
static VALUE p1788_figure_draw_boxes(int argc, VALUE *argv, VALUE self)
|
997
|
+
{
|
998
|
+
VALUE rboxes, rformat;
|
999
|
+
rb_scan_args(argc, argv, "11", &rboxes, &rformat);
|
1000
|
+
P1788Figure::Figure& f = p1788_figure_rb2ref(self);
|
1001
|
+
if (!RB_TYPE_P(rboxes, T_ARRAY))
|
1002
|
+
rb_raise(rb_eTypeError, "expecting an array of %" PRIsVALUE ", not a %" PRIsVALUE,
|
1003
|
+
rb_class_name(c_IntervalVector), rb_class_name(rb_class_of(rboxes)));
|
1004
|
+
if (rformat != Qnil)
|
1005
|
+
p1788_figure_parse_format(f, rformat);
|
1006
|
+
const size_t l = rb_array_len(rboxes);
|
1007
|
+
if (l < 1) return self;
|
1008
|
+
std::vector<P1788Figure::Box> bv;
|
1009
|
+
bv.reserve(l);
|
1010
|
+
for (size_t i = 0; i < l; i++) {
|
1011
|
+
VALUE e = rb_ary_entry(rboxes, i);
|
1012
|
+
if (!is_an_interval_vector(e))
|
1013
|
+
rb_raise(rb_eTypeError, "expecting interval vectors in the array, not %" PRIsVALUE,
|
1014
|
+
rb_class_name(rb_class_of(e)));
|
1015
|
+
const IntervalVector& iv = p1788_vector_rb2ref(e);
|
1016
|
+
if (!(iv.size() < 2 || Interval::is_empty(iv[0]) || Interval::is_empty(iv[1])))
|
1017
|
+
bv.emplace_back(iv[0], iv[1]);
|
1018
|
+
}
|
1019
|
+
if (bv.size() > 0)
|
1020
|
+
f.cmd_draw_boxes(std::move(bv));
|
1021
|
+
return self;
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
|
1025
|
+
/* Reset the figure to its default, clearing all boxes, labels, etc.
|
1026
|
+
* After a reset, the figure state is the same than after `Figure.new()`.
|
1027
|
+
* @return [self]
|
1028
|
+
*/
|
1029
|
+
static VALUE p1788_figure_reset(VALUE self)
|
1030
|
+
{
|
1031
|
+
p1788_figure_rb2ref(self).reset();
|
1032
|
+
return self;
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
|
1036
|
+
static const char *extension_regexp = "\\.((png|PNG)|(svg|SVG)|(pdf|PDF))$";
|
1037
|
+
// match[] 12 3 4
|
1038
|
+
|
1039
|
+
|
1040
|
+
/* Generate the figure and write the output image to file _file_name_.
|
1041
|
+
* The output format (either _png_, _svg_ or _pdf_) is deduced from the extension of the file.
|
1042
|
+
* @return [self]
|
1043
|
+
* @param file_name [String] name of the file to write the image to, ending with '.png', '.svg' or '.pdf'.
|
1044
|
+
*/
|
1045
|
+
static VALUE p1788_figure_write(VALUE self, VALUE file_name)
|
1046
|
+
{
|
1047
|
+
file_name = rb_funcallv(file_name, id_to_s, 0, NULL);
|
1048
|
+
if (RSTRING_LEN(file_name) < 1)
|
1049
|
+
rb_raise(rb_eRuntimeError, "file name is empty");
|
1050
|
+
VALUE cr = rb_str_new_static(extension_regexp, 34);
|
1051
|
+
VALUE regexp = rb_class_new_instance(1, &cr, rb_cRegexp);
|
1052
|
+
VALUE match = rb_funcallv(file_name, id_match, 1, ®exp);
|
1053
|
+
if (NIL_P(match))
|
1054
|
+
rb_raise(rb_eRuntimeError, "cannot deduce format from file name \"%" PRIsVALUE "\"", file_name);
|
1055
|
+
VALUE m;
|
1056
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(2));
|
1057
|
+
if (m != Qnil) {
|
1058
|
+
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
1059
|
+
return p1788_figure_write_png(self, file_name);
|
1060
|
+
#else
|
1061
|
+
rb_raise(rb_eRuntimeError, "no support for PNG, sorry");
|
1062
|
+
#endif
|
1063
|
+
}
|
1064
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(3));
|
1065
|
+
if (m != Qnil) {
|
1066
|
+
#ifdef CAIRO_HAS_SVG_SURFACE
|
1067
|
+
return p1788_figure_write_svg(self, file_name);
|
1068
|
+
#else
|
1069
|
+
rb_raise(rb_eRuntimeError, "no support for SVG, sorry");
|
1070
|
+
#endif
|
1071
|
+
}
|
1072
|
+
m = rb_funcall(match, id_brackets, 1, INT2NUM(4));
|
1073
|
+
if (m != Qnil) {
|
1074
|
+
#ifdef CAIRO_HAS_PDF_SURFACE
|
1075
|
+
return p1788_figure_write_pdf(self, file_name);
|
1076
|
+
#else
|
1077
|
+
rb_raise(rb_eRuntimeError, "no support for PDF, sorry");
|
1078
|
+
#endif
|
1079
|
+
}
|
1080
|
+
return self;
|
1081
|
+
}
|
1082
|
+
|
1083
|
+
|
1084
|
+
/* Returns a new {Figure}
|
1085
|
+
* @return [Figure]
|
1086
|
+
* @overload new(width: nil, height: nil, xrange: nil, yrange: nil, with_decorations: true, title: nil, xlabel: nil, ylabel: nil, background_color: 't', decoration_color: 'k', decoration_font: 'Sans', decoration_font_size: 11, decoration_line_width: 1, label_font_size: nil, title_font_size: nil, title_in_bold: false)
|
1087
|
+
* @param width [Integer, nil] Width of the frame of the output image. See {width=}.
|
1088
|
+
* @param height [Integer, nil] Height of the frame of the output image. See {height=}.
|
1089
|
+
* @param xrange [Interval, nil] The horizontal range that will be displayed. See {xrange=}.
|
1090
|
+
* @param yrange [Interval, nil] The vertical range that will be displayed. See {yrange=}.
|
1091
|
+
* @param with_decorations [Boolean, nil] Draw frame, graduations, labels and title around the figure? See {with_decorations=}.
|
1092
|
+
* @param title [String, nil] The title of the figure. See {title=}.
|
1093
|
+
* @param xlabel [String, nil] The label for the horizontal axis. See {xlabel=}.
|
1094
|
+
* @param ylabel [String, nil] The label for the vertical axis. See {ylabel=}.
|
1095
|
+
* @param background_color [Integer, String, nil] Background color of the figure. Default is transparent. See {background_color=}.
|
1096
|
+
* @param decoration_color [Integer, String, nil] Color of the frame, labels and title. Defaults to black. See {decoration_color=}.
|
1097
|
+
* @param decoration_font [Integer, String, nil] Font for labels, title and graduations. Defaults to "Sans". See {decoration_font=}.
|
1098
|
+
* @param decoration_font_size [Float, nil] Font size for the graduations. Defaults to 11. See {decoration_font_size=}.
|
1099
|
+
* @param decoration_line_width [Float, nil] Line width of the frame of the figure. Defaults to 1. See {decoration_line_width=}.
|
1100
|
+
* @param label_font_size [Float, nil] Font size for the labels. Defaults to 1.1 times _decoration_font_size_. See {label_font_size=}.
|
1101
|
+
* @param title_font_size [Float, nil] Font size for the title. Defaults to 1.23 times _decoration_font_size_. See {title_font_size=}.
|
1102
|
+
* @param title_in_bold [Boolean] Draw the title in bold or not?. Defaults to _false_. See {title_in_bold=}.
|
1103
|
+
*/
|
1104
|
+
static VALUE p1788_figure_initialize(int argc, VALUE *argv, VALUE self)
|
1105
|
+
{
|
1106
|
+
const ID kwkeys[] = {
|
1107
|
+
id_width,
|
1108
|
+
id_height,
|
1109
|
+
id_xrange,
|
1110
|
+
id_yrange,
|
1111
|
+
id_with_decorations,
|
1112
|
+
id_title,
|
1113
|
+
id_xlabel,
|
1114
|
+
id_ylabel,
|
1115
|
+
id_background_color,
|
1116
|
+
id_decoration_color,
|
1117
|
+
id_decoration_font,
|
1118
|
+
id_decoration_font_size,
|
1119
|
+
id_decoration_line_width,
|
1120
|
+
id_label_font_size,
|
1121
|
+
id_title_font_size,
|
1122
|
+
id_title_in_bold
|
1123
|
+
};
|
1124
|
+
VALUE kwvalues[] = {Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef, Qundef};
|
1125
|
+
VALUE kw;
|
1126
|
+
|
1127
|
+
rb_scan_args(argc, argv, ":", &kw);
|
1128
|
+
if (NIL_P(kw))
|
1129
|
+
return self;
|
1130
|
+
|
1131
|
+
rb_get_kwargs(kw, kwkeys, 0, 16, kwvalues);
|
1132
|
+
|
1133
|
+
if (kwvalues[0] != Qundef) p1788_figure_set_width(self, kwvalues[0]);
|
1134
|
+
if (kwvalues[1] != Qundef) p1788_figure_set_height(self, kwvalues[1]);
|
1135
|
+
if (kwvalues[2] != Qundef) p1788_figure_set_xrange(self, kwvalues[2]);
|
1136
|
+
if (kwvalues[3] != Qundef) p1788_figure_set_yrange(self, kwvalues[3]);
|
1137
|
+
if (kwvalues[4] != Qundef) p1788_figure_set_with_decorations(self, kwvalues[4]);
|
1138
|
+
if (kwvalues[5] != Qundef) p1788_figure_set_title(self, kwvalues[5]);
|
1139
|
+
if (kwvalues[6] != Qundef) p1788_figure_set_xlabel(self, kwvalues[6]);
|
1140
|
+
if (kwvalues[7] != Qundef) p1788_figure_set_ylabel(self, kwvalues[7]);
|
1141
|
+
if (kwvalues[8] != Qundef) p1788_figure_set_background_color(self, kwvalues[8]);
|
1142
|
+
if (kwvalues[9] != Qundef) p1788_figure_set_decoration_color(self, kwvalues[9]);
|
1143
|
+
if (kwvalues[10] != Qundef) p1788_figure_set_decoration_font(self, kwvalues[10]);
|
1144
|
+
if (kwvalues[11] != Qundef) p1788_figure_set_decoration_font_size(self, kwvalues[11]);
|
1145
|
+
if (kwvalues[12] != Qundef) p1788_figure_set_decoration_line_width(self, kwvalues[12]);
|
1146
|
+
if (kwvalues[13] != Qundef) p1788_figure_set_label_font_size(self, kwvalues[13]);
|
1147
|
+
if (kwvalues[14] != Qundef) p1788_figure_set_title_font_size(self, kwvalues[14]);
|
1148
|
+
if (kwvalues[15] != Qundef) p1788_figure_set_title_in_bold(self, kwvalues[15]);
|
1149
|
+
|
1150
|
+
return self;
|
1151
|
+
}
|
1152
|
+
|
1153
|
+
|
1154
|
+
void Init_p1788_figure()
|
1155
|
+
{
|
1156
|
+
id_width = rb_intern("width");
|
1157
|
+
id_height = rb_intern("height");
|
1158
|
+
id_xrange = rb_intern("xrange");
|
1159
|
+
id_yrange = rb_intern("yrange");
|
1160
|
+
id_with_decorations = rb_intern("with_decorations");
|
1161
|
+
id_title = rb_intern("title");
|
1162
|
+
id_xlabel = rb_intern("xlabel");
|
1163
|
+
id_ylabel = rb_intern("ylabel");
|
1164
|
+
id_background_color = rb_intern("background_color");
|
1165
|
+
id_decoration_color = rb_intern("decoration_color");
|
1166
|
+
id_decoration_font = rb_intern("decoration_font");
|
1167
|
+
id_decoration_font_size = rb_intern("decoration_font_size");
|
1168
|
+
id_decoration_line_width = rb_intern("decoration_line_width");
|
1169
|
+
id_label_font_size = rb_intern("label_font_size");
|
1170
|
+
id_title_font_size = rb_intern("title_font_size");
|
1171
|
+
id_title_in_bold = rb_intern("title_in_bold");
|
1172
|
+
|
1173
|
+
c_Figure = rb_define_class_under(m_P1788, "Figure", rb_cObject);
|
1174
|
+
rb_define_alloc_func(c_Figure, p1788_figure_alloc);
|
1175
|
+
rb_undef_method(rb_class_of(c_Figure), "allocate");
|
1176
|
+
rb_define_method(c_Figure, "initialize", p1788_figure_initialize, -1);
|
1177
|
+
|
1178
|
+
/* Attributes */
|
1179
|
+
rb_define_method(c_Figure, "with_decorations", p1788_figure_get_with_decorations, 0);
|
1180
|
+
rb_define_method(c_Figure, "with_decorations=", p1788_figure_set_with_decorations, 1);
|
1181
|
+
rb_define_method(c_Figure, "decoration_font", p1788_figure_get_decoration_font, 0);
|
1182
|
+
rb_define_method(c_Figure, "decoration_font=", p1788_figure_set_decoration_font, 1);
|
1183
|
+
rb_define_method(c_Figure, "decoration_font_size", p1788_figure_get_decoration_font_size, 0);
|
1184
|
+
rb_define_method(c_Figure, "decoration_font_size=", p1788_figure_set_decoration_font_size, 1);
|
1185
|
+
rb_define_method(c_Figure, "title_font_size", p1788_figure_get_title_font_size, 0);
|
1186
|
+
rb_define_method(c_Figure, "title_font_size=", p1788_figure_set_title_font_size, 1);
|
1187
|
+
rb_define_method(c_Figure, "label_font_size", p1788_figure_get_label_font_size, 0);
|
1188
|
+
rb_define_method(c_Figure, "label_font_size=", p1788_figure_set_label_font_size, 1);
|
1189
|
+
rb_define_method(c_Figure, "decoration_line_width", p1788_figure_get_decoration_line_width, 0);
|
1190
|
+
rb_define_method(c_Figure, "decoration_line_width=", p1788_figure_set_decoration_line_width, 1);
|
1191
|
+
rb_define_method(c_Figure, "decoration_color", p1788_figure_get_decoration_color, 0);
|
1192
|
+
rb_define_method(c_Figure, "decoration_color=", p1788_figure_set_decoration_color, 1);
|
1193
|
+
rb_define_method(c_Figure, "background_color", p1788_figure_get_background_color, 0);
|
1194
|
+
rb_define_method(c_Figure, "background_color=", p1788_figure_set_background_color, 1);
|
1195
|
+
rb_define_method(c_Figure, "title_in_bold", p1788_figure_get_title_in_bold, 0);
|
1196
|
+
rb_define_method(c_Figure, "title_in_bold=", p1788_figure_set_title_in_bold, 1);
|
1197
|
+
rb_define_method(c_Figure, "title", p1788_figure_get_title, 0);
|
1198
|
+
rb_define_method(c_Figure, "title=", p1788_figure_set_title, 1);
|
1199
|
+
rb_define_method(c_Figure, "xlabel", p1788_figure_get_xlabel, 0);
|
1200
|
+
rb_define_method(c_Figure, "xlabel=", p1788_figure_set_xlabel, 1);
|
1201
|
+
rb_define_method(c_Figure, "ylabel", p1788_figure_get_ylabel, 0);
|
1202
|
+
rb_define_method(c_Figure, "ylabel=", p1788_figure_set_ylabel, 1);
|
1203
|
+
rb_define_method(c_Figure, "width", p1788_figure_get_width, 0);
|
1204
|
+
rb_define_method(c_Figure, "width=", p1788_figure_set_width, 1);
|
1205
|
+
rb_define_method(c_Figure, "height", p1788_figure_get_height, 0);
|
1206
|
+
rb_define_method(c_Figure, "height=", p1788_figure_set_height, 1);
|
1207
|
+
rb_define_method(c_Figure, "xrange", p1788_figure_get_xrange, 0);
|
1208
|
+
rb_define_method(c_Figure, "xrange=", p1788_figure_set_xrange, 1);
|
1209
|
+
rb_define_method(c_Figure, "yrange", p1788_figure_get_yrange, 0);
|
1210
|
+
rb_define_method(c_Figure, "yrange=", p1788_figure_set_yrange, 1);
|
1211
|
+
|
1212
|
+
/* Statefull commands */
|
1213
|
+
rb_define_method(c_Figure, "stroke_on", p1788_figure_stroke_on, 0);
|
1214
|
+
rb_define_method(c_Figure, "stroke_off", p1788_figure_stroke_off, 0);
|
1215
|
+
rb_define_method(c_Figure, "stroke?", p1788_figure_get_stroke_onoff, 0);
|
1216
|
+
rb_define_method(c_Figure, "stroke_width=", p1788_figure_set_stroke_width, 1);
|
1217
|
+
rb_define_method(c_Figure, "stroke_width", p1788_figure_get_stroke_width, 0);
|
1218
|
+
rb_define_method(c_Figure, "stroke_color=", p1788_figure_set_stroke_color, 1);
|
1219
|
+
rb_define_method(c_Figure, "stroke_color", p1788_figure_get_stroke_color, 0);
|
1220
|
+
rb_define_method(c_Figure, "fill_on", p1788_figure_fill_on, 0);
|
1221
|
+
rb_define_method(c_Figure, "fill_off", p1788_figure_fill_off, 0);
|
1222
|
+
rb_define_method(c_Figure, "fill?", p1788_figure_get_fill_onoff, 0);
|
1223
|
+
rb_define_method(c_Figure, "fill_color=", p1788_figure_set_fill_color, 1);
|
1224
|
+
rb_define_method(c_Figure, "fill_color", p1788_figure_get_fill_color, 0);
|
1225
|
+
rb_define_method(c_Figure, "draw_box", p1788_figure_draw_box, -1);
|
1226
|
+
rb_define_method(c_Figure, "draw_boxes", p1788_figure_draw_boxes, -1);
|
1227
|
+
rb_define_method(c_Figure, "reset!", p1788_figure_reset, 0);
|
1228
|
+
|
1229
|
+
/* Figure generation and output */
|
1230
|
+
rb_define_method(c_Figure, "allocated_size", p1788_figure_allocated_size, 0);
|
1231
|
+
rb_define_method(c_Figure, "content_range", p1788_figure_content_range, 0);
|
1232
|
+
rb_define_method(c_Figure, "nice_range", p1788_figure_nice_range, 0);
|
1233
|
+
rb_define_method(c_Figure, "write", p1788_figure_write, 1);
|
1234
|
+
rb_define_method(c_Figure, "set_range", p1788_figure_set_range, 1);
|
1235
|
+
#ifdef CAIRO_HAS_PNG_FUNCTIONS
|
1236
|
+
rb_define_method(c_Figure, "write_png", p1788_figure_write_png, 1);
|
1237
|
+
rb_define_method(c_Figure, "to_png", p1788_figure_to_png, 0);
|
1238
|
+
#endif
|
1239
|
+
#ifdef CAIRO_HAS_SVG_SURFACE
|
1240
|
+
rb_define_method(c_Figure, "write_svg", p1788_figure_write_svg, 1);
|
1241
|
+
rb_define_method(c_Figure, "to_svg", p1788_figure_to_svg, 0);
|
1242
|
+
#endif
|
1243
|
+
#ifdef CAIRO_HAS_PDF_SURFACE
|
1244
|
+
rb_define_method(c_Figure, "write_pdf", p1788_figure_write_pdf, 1);
|
1245
|
+
rb_define_method(c_Figure, "to_pdf", p1788_figure_to_pdf, 0);
|
1246
|
+
#endif
|
1247
|
+
}
|
1248
|
+
|
1249
|
+
|