tioga 1.6 → 1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/Tioga_README +35 -10
  2. data/split/Dvector/dvector.c +264 -22
  3. data/split/Dvector/lib/Dvector_extras.rb +30 -2
  4. data/split/Flate/extconf.rb +1 -1
  5. data/split/Function/function.c +112 -2
  6. data/split/Tioga/figures.c +76 -77
  7. data/split/Tioga/figures.h +375 -490
  8. data/split/Tioga/generic.c +254 -0
  9. data/split/Tioga/generic.h +236 -0
  10. data/split/Tioga/init.c +434 -320
  11. data/split/Tioga/lib/Creating_Paths.rb +11 -1
  12. data/split/Tioga/lib/FigMkr.rb +263 -65
  13. data/split/Tioga/lib/Legends.rb +4 -2
  14. data/split/Tioga/lib/Markers.rb +3 -2
  15. data/split/Tioga/lib/Special_Paths.rb +22 -23
  16. data/split/Tioga/lib/TeX_Text.rb +79 -1
  17. data/split/Tioga/lib/TexPreamble.rb +14 -0
  18. data/split/Tioga/lib/Utils.rb +5 -1
  19. data/split/Tioga/pdfs.h +7 -45
  20. data/split/Tioga/{axes.c → shared/axes.c} +210 -197
  21. data/split/Tioga/{makers.c → shared/makers.c} +442 -211
  22. data/split/Tioga/{pdf_font_dicts.c → shared/pdf_font_dicts.c} +0 -0
  23. data/split/Tioga/shared/pdfcolor.c +628 -0
  24. data/split/Tioga/shared/pdfcoords.c +443 -0
  25. data/split/Tioga/{pdffile.c → shared/pdffile.c} +56 -52
  26. data/split/Tioga/{pdfimage.c → shared/pdfimage.c} +103 -211
  27. data/split/Tioga/shared/pdfpath.c +766 -0
  28. data/split/Tioga/{pdftext.c → shared/pdftext.c} +121 -99
  29. data/split/Tioga/shared/texout.c +524 -0
  30. data/split/Tioga/wrappers.c +489 -0
  31. data/split/Tioga/wrappers.h +259 -0
  32. data/split/extconf.rb +4 -0
  33. data/split/mkmf2.rb +12 -1
  34. data/tests/benchmark_dvector_reads.rb +112 -0
  35. data/tests/tc_Dvector.rb +35 -3
  36. data/tests/tc_Function.rb +32 -0
  37. metadata +65 -52
  38. data/split/Tioga/pdfcolor.c +0 -486
  39. data/split/Tioga/pdfcoords.c +0 -523
  40. data/split/Tioga/pdfpath.c +0 -913
  41. data/split/Tioga/texout.c +0 -380
@@ -1,913 +0,0 @@
1
- /* pdfpath.c */
2
- /*
3
- Copyright (C) 2005 Bill Paxton
4
-
5
- This file is part of Tioga.
6
-
7
- Tioga is free software; you can redistribute it and/or modify
8
- it under the terms of the GNU General Library Public License as published
9
- by the Free Software Foundation; either version 2 of the License, or
10
- (at your option) any later version.
11
-
12
- Tioga is distributed in the hope that it will be useful,
13
- but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- GNU Library General Public License for more details.
16
-
17
- You should have received a copy of the GNU Library General Public License
18
- along with Tioga; if not, write to the Free Software
19
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
- */
21
-
22
- #include "figures.h"
23
- #include "pdfs.h"
24
-
25
- bool have_current_point, constructing_path, writing_file;
26
- double bbox_llx, bbox_lly, bbox_urx, bbox_ury;
27
-
28
- /* emits a warning on nonok numbers if croak_on_nonok_numbers is true */
29
- static void croak_on_nonok(FM *p, const char * function)
30
- {
31
- if(p->croak_on_nonok_numbers)
32
- rb_warn("Illegal coordinates in function %s, element suppressed",
33
- function);
34
- }
35
-
36
- /* small macro to check if a number is ok to be output */
37
-
38
- #define CROAK_ON_NONOK(p) croak_on_nonok(p, __FUNCTION__)
39
- #define ARE_OK_NUMBERS(x,y) if(! is_okay_number(x) || ! is_okay_number(y)) {\
40
- CROAK_ON_NONOK(p); return;}
41
-
42
-
43
- /* PDF graphics */
44
-
45
- /* graphics attributes */
46
-
47
- void Unpack_RGB(VALUE rgb, double *rp, double *gp, double *bp)
48
- {
49
- if (rgb == Qnil) { *rp = *gp = *bp = 0.0; return; }
50
- rgb = rb_Array(rgb);
51
- if (RARRAY(rgb)->len != 3) rb_raise(rb_eArgError, "Sorry: invalid rgb array for setting color: must have 3 entries");
52
- VALUE entry = rb_ary_entry(rgb, 0);
53
- entry = rb_Float(entry);
54
- double r = NUM2DBL(entry);
55
- entry = rb_ary_entry(rgb, 1);
56
- entry = rb_Float(entry);
57
- double g = NUM2DBL(entry);
58
- entry = rb_ary_entry(rgb, 2);
59
- entry = rb_Float(entry);
60
- double b = NUM2DBL(entry);
61
- if (r < 0.0 || r > 1.0) rb_raise(rb_eArgError, "Sorry: invalid red (%g) for color: must be between 0 and 1", r);
62
- if (g < 0.0 || g > 1.0) rb_raise(rb_eArgError, "Sorry: invalid green (%g) for color: must be between 0 and 1", g);
63
- if (b < 0.0 || b > 1.0) rb_raise(rb_eArgError, "Sorry: invalid blue (%g) for color: must be between 0 and 1", b);
64
- *rp = r; *gp = g; *bp = b;
65
- }
66
-
67
- void c_stroke_color_set(FM *p, double r, double g, double b)
68
- {
69
- if (writing_file) fprintf(TF, "%0.3f %0.3f %0.3f RG\n", r, g, b);
70
- }
71
-
72
- VALUE FM_stroke_color_set(VALUE fmkr, VALUE value) // value is array of [r, g, b] intensities from 0 to 1
73
- { // r g b RG
74
- FM *p = Get_FM(fmkr);
75
- double r, g, b;
76
- Unpack_RGB(value, &r, &g, &b);
77
- c_stroke_color_set(p, r, g, b);
78
- p->stroke_color = value;
79
- return value;
80
- }
81
-
82
- VALUE FM_fill_color_set(VALUE fmkr, VALUE value) // value is array of [r, g, b] intensities from 0 to 1
83
- { // r g b rg
84
- FM *p = Get_FM(fmkr);
85
- double r, g, b;
86
- Unpack_RGB(value, &r, &g, &b);
87
- if (writing_file) fprintf(TF, "%0.3f %0.3f %0.3f rg\n", r, g, b);
88
- p->fill_color = value;
89
- return value;
90
- }
91
-
92
- void c_line_width_set(FM *p, double line_width)
93
- {
94
- if (line_width < 0.0) rb_raise(rb_eArgError, "Sorry: invalid line width (%g points): must be positive", line_width);
95
- if (line_width > 1e3) rb_raise(rb_eArgError, "Sorry: too large line width (%g points)", line_width);
96
- if (writing_file) fprintf(TF, "%0.3f w\n", line_width * ENLARGE * p->default_line_scale);
97
- p->line_width = line_width;
98
- }
99
-
100
- VALUE FM_line_width_set(VALUE fmkr, VALUE value) // value is thickness in points
101
- { // w
102
- FM *p = Get_FM(fmkr);
103
- value = rb_Float(value);
104
- c_line_width_set(p, NUM2DBL(value));
105
- return value;
106
- }
107
-
108
- void c_line_scale_set(FM *p, double new_scale)
109
- {
110
- if (new_scale <= 0) rb_raise(rb_eArgError, "Sorry: line scale must be positive");
111
- p->default_line_scale = new_scale;
112
- c_line_width_set(p, p->line_width);
113
- }
114
-
115
- VALUE FM_rescale_lines(VALUE fmkr, VALUE scaling_factor)
116
- {
117
- FM *p = Get_FM(fmkr);
118
- scaling_factor = rb_Float(scaling_factor);
119
- c_line_scale_set(p, NUM2DBL(scaling_factor) * p->default_line_scale);
120
- return fmkr;
121
- }
122
-
123
- void c_line_cap_set(FM *p, int line_cap)
124
- {
125
- if (line_cap < 0 || line_cap > 3) rb_raise(rb_eArgError, "Sorry: invalid arg for setting line_cap (%i)", line_cap);
126
- if (writing_file) fprintf(TF, "%d J\n", line_cap);
127
- p->line_cap = line_cap;
128
- }
129
-
130
- VALUE FM_line_cap_set(VALUE fmkr, VALUE value)
131
- { // J
132
- FM *p = Get_FM(fmkr);
133
- value = rb_Integer(value);
134
- c_line_cap_set(p, NUM2INT(value));
135
- return value;
136
- }
137
-
138
- void c_line_join_set(FM *p, int line_join)
139
- {
140
- if (line_join < 0 || line_join > 3) rb_raise(rb_eArgError, "Sorry: invalid arg for setting line_join (%i)", line_join);
141
- if (writing_file) fprintf(TF, "%d j\n", line_join);
142
- p->line_join = line_join;
143
- }
144
-
145
- VALUE FM_line_join_set(VALUE fmkr, VALUE value)
146
- { // j
147
- FM *p = Get_FM(fmkr);
148
- value = rb_Integer(value);
149
- c_line_join_set(p, NUM2INT(value));
150
- return value;
151
- }
152
-
153
- void c_miter_limit_set(FM *p, double miter_limit)
154
- {
155
- if (miter_limit < 0.0)
156
- rb_raise(rb_eArgError,
157
- "Sorry: invalid miter limit (%g): must be positive ratio for max miter length to line width", miter_limit);
158
- if (writing_file) fprintf(TF, "%0.3f M\n", miter_limit);
159
- p->miter_limit = miter_limit;
160
- }
161
-
162
- VALUE FM_miter_limit_set(VALUE fmkr, VALUE value) // value is max ratio of miter length to line width
163
- { // M
164
- FM *p = Get_FM(fmkr);
165
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must not be constructing a path when change miter limit");
166
- value = rb_Float(value);
167
- c_miter_limit_set(p, NUM2DBL(value));
168
- return value;
169
- }
170
-
171
- VALUE FM_line_type_set(VALUE fmkr, VALUE line_type)
172
- { // array phase d (distances given in points)
173
- FM *p = Get_FM(fmkr);
174
- double sz;
175
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must not be constructing a path when change line_type");
176
- if (line_type == Qnil) {
177
- fprintf(TF, "[] 0 d\n");
178
- } else {
179
- line_type = rb_Array(line_type);
180
- if (writing_file) {
181
- if (RARRAY(line_type)->len != 2)
182
- rb_raise(rb_eArgError, "Sorry: invalid line_type. Must be [ [dash pattern] dash phase ]");
183
- VALUE dashArray = rb_ary_entry(line_type, 0), dashPhase = rb_ary_entry(line_type, 1);
184
- fprintf(TF, "[ ");
185
- if (dashArray != Qnil) {
186
- dashArray = rb_Array(dashArray);
187
- long i, len = RARRAY(dashArray)->len;
188
- for (i=0; i < len; i++) {
189
- VALUE entry = rb_ary_entry(dashArray, i);
190
- entry = rb_Float(entry);
191
- sz = NUM2DBL(entry);
192
- if (sz < 0.0) rb_raise(rb_eArgError, "Sorry: invalid dash array entry (%g): must be positive", sz);
193
- fprintf(TF, "%0.3f ", sz * ENLARGE);
194
- }
195
- }
196
- dashPhase = rb_Float(dashPhase);
197
- sz = NUM2DBL(dashPhase);
198
- if (sz < 0.0) rb_raise(rb_eArgError, "Sorry: invalid dash phase (%g): must be positive", sz);
199
- fprintf(TF, "] %0.3f d\n", sz * ENLARGE);
200
- }
201
- }
202
- p->line_type = line_type;
203
- return fmkr;
204
- }
205
-
206
-
207
- /* Path construction operators */
208
-
209
- /* all locations and vectors are in figure coordinates */
210
-
211
- long c_round_dev(FM *p, double v) { // make sure that we don't get too far out or can overflow!
212
- if (v > MAX_DEV_COORD_ALLOWED) {
213
- //if (p->debug_verbosity_level > 0) printf("c_round_dev clipping %g\n", v);
214
- return iMAX_DEV_COORD_ALLOWED;
215
- }
216
- if (v < -MAX_DEV_COORD_ALLOWED) {
217
- //if (p->debug_verbosity_level > 0) printf("c_round_dev clipping %g\n", v);
218
- return -iMAX_DEV_COORD_ALLOWED;
219
- }
220
- return ROUND(v);
221
- }
222
-
223
- void update_bbox(FM *p, double x, double y)
224
- {
225
- if (x >= p->clip_left && x < bbox_llx) bbox_llx = x;
226
- if (y >= p->clip_bottom && y < bbox_lly) bbox_lly = y;
227
- if (x <= p->clip_right && x > bbox_urx) bbox_urx = x;
228
- if (y <= p->clip_top && y > bbox_ury) bbox_ury = y;
229
- }
230
-
231
- VALUE FM_update_bbox(VALUE fmkr, VALUE x, VALUE y)
232
- {
233
- FM *p = Get_FM(fmkr);
234
- x = rb_Float(x);
235
- y = rb_Float(y);
236
- update_bbox(p, convert_figure_to_output_x(p,NUM2DBL(x)), convert_figure_to_output_y(p,NUM2DBL(y)));
237
- return fmkr;
238
- }
239
-
240
-
241
- VALUE FM_bbox_left(VALUE fmkr)
242
- {
243
- return rb_float_new(bbox_llx);
244
- }
245
-
246
- VALUE FM_bbox_right(VALUE fmkr)
247
- {
248
- return rb_float_new(bbox_urx);
249
- }
250
-
251
- VALUE FM_bbox_top(VALUE fmkr)
252
- {
253
- return rb_float_new(bbox_ury);
254
- }
255
-
256
- VALUE FM_bbox_bottom(VALUE fmkr)
257
- {
258
- return rb_float_new(bbox_lly);
259
- }
260
-
261
-
262
-
263
- void c_moveto(FM *p, double x, double y)
264
- {
265
- ARE_OK_NUMBERS(x,y);
266
- if (writing_file) fprintf(TF, "%ld %ld m\n", c_round_dev(p,x), c_round_dev(p,y));
267
- update_bbox(p, x, y);
268
- have_current_point = constructing_path = true;
269
- }
270
-
271
- VALUE FM_move_to_point(VALUE fmkr, VALUE x, VALUE y)
272
- {
273
- FM *p = Get_FM(fmkr);
274
- x = rb_Float(x);
275
- y = rb_Float(y);
276
- double dev_x = convert_figure_to_output_x(p,NUM2DBL(x)), dev_y = convert_figure_to_output_y(p,NUM2DBL(y));
277
- c_moveto(p, dev_x, dev_y);
278
- return fmkr;
279
- }
280
-
281
- void c_lineto(FM *p, double x, double y)
282
- {
283
- ARE_OK_NUMBERS(x,y);
284
- if (!constructing_path) rb_raise(rb_eArgError, "Sorry: must start path with moveto before call lineto");
285
- if (writing_file) fprintf(TF, "%ld %ld l\n", c_round_dev(p,x), c_round_dev(p,y));
286
- update_bbox(p, x, y);
287
- }
288
-
289
- VALUE FM_append_point_to_path(VALUE fmkr, VALUE x, VALUE y)
290
- {
291
- FM *p = Get_FM(fmkr);
292
- x = rb_Float(x);
293
- y = rb_Float(y);
294
- double dev_x = convert_figure_to_output_x(p,NUM2DBL(x)), dev_y = convert_figure_to_output_y(p,NUM2DBL(y));
295
- c_lineto(p, dev_x, dev_y);
296
- return fmkr;
297
- }
298
-
299
- void c_curveto(FM *p, double x1, double y1, double x2, double y2, double x3, double y3)
300
- {
301
- ARE_OK_NUMBERS(x1,y1);
302
- ARE_OK_NUMBERS(x2,y2);
303
- ARE_OK_NUMBERS(x3,y3);
304
- if (!constructing_path) rb_raise(rb_eArgError, "Sorry: must start path with moveto before call curveto");
305
- if (writing_file) fprintf(TF, "%ld %ld %ld %ld %ld %ld c\n",
306
- c_round_dev(p,x1), c_round_dev(p,y1), c_round_dev(p,x2), c_round_dev(p,y2), c_round_dev(p,x3), c_round_dev(p,y3));
307
- update_bbox(p, x1, y1);
308
- update_bbox(p, x2, y2);
309
- update_bbox(p, x3, y3);
310
- }
311
-
312
- VALUE FM_append_curve_to_path(VALUE fmkr, VALUE x1, VALUE y1, VALUE x2, VALUE y2, VALUE x3, VALUE y3)
313
- {
314
- FM *p = Get_FM(fmkr);
315
- x1 = rb_Float(x1);
316
- y1 = rb_Float(y1);
317
- x2 = rb_Float(x2);
318
- y2 = rb_Float(y2);
319
- x3 = rb_Float(x3);
320
- y3 = rb_Float(y3);
321
- double dev_x1 = convert_figure_to_output_x(p,NUM2DBL(x1)), dev_y1 = convert_figure_to_output_y(p,NUM2DBL(y1));
322
- double dev_x2 = convert_figure_to_output_x(p,NUM2DBL(x2)), dev_y2 = convert_figure_to_output_y(p,NUM2DBL(y2));
323
- double dev_x3 = convert_figure_to_output_x(p,NUM2DBL(x3)), dev_y3 = convert_figure_to_output_y(p,NUM2DBL(y3));
324
- c_curveto(p, dev_x1, dev_y1, dev_x2, dev_y2, dev_x3, dev_y3);
325
- return fmkr;
326
- }
327
-
328
- void c_closepath(FM *p)
329
- {
330
- if (!constructing_path) rb_raise(rb_eArgError, "Sorry: must be constructing path when call closepath");
331
- if (writing_file) fprintf(TF, "h\n");
332
- have_current_point = false;
333
- p = NULL;
334
- }
335
-
336
- VALUE FM_close_path(VALUE fmkr)
337
- {
338
- c_closepath(Get_FM(fmkr));
339
- return fmkr;
340
- }
341
-
342
- void c_append_arc(FM *p, double x_start, double y_start, double x_corner, double y_corner,
343
- double x_end, double y_end, double radius)
344
- {
345
- ARE_OK_NUMBERS(x_start,y_start);
346
- ARE_OK_NUMBERS(x_corner,y_corner);
347
- ARE_OK_NUMBERS(x_end,y_end);
348
-
349
- double x0, y0, x1, y1, x2, y2, x3, y3, udx, udy, vdx, vdy, wdx, wdy, len, x_center, y_center, tmp;
350
- double psi, sin_psi, cos_psi, theta, cos_alpha, sin_alpha;
351
- udx = x_start - x_corner; udy = y_start - y_corner;
352
- vdx = x_end - x_corner; vdy = y_end - y_corner;
353
- len = sqrt(udx*udx + udy*udy); udx /= len; udy /= len; // u is unit vector from corner to start
354
- len = sqrt(vdx*vdx + vdy*vdy); vdx /= len; vdy /= len; // v is unit vector from corner to end
355
- cos_psi = udx*vdx + udy*vdy; sin_psi = udy * vdx - udx * vdy;
356
- psi = atan2(sin_psi, cos_psi); // psi is angle between u and v
357
- if (psi > PI) psi = 2*PI - psi;
358
- theta = PI - psi; // theta is opening angle for the arc
359
- while (theta < 0) theta += 2*PI;
360
- if (theta >= PI) rb_raise(rb_eArgError, "Sorry: invalid control point for arc");
361
- // first compute control points for arc of opening theta with unit radius, bisected by positive x axis
362
- // based on note by Richard DeVeneza, "How to determine the control points of a Bezier curve that
363
- // approximates a small circular arc", Nov 2004.
364
- x0 = cos(theta/2); y0 = sin(theta/2); x3 = x0; y3 = -y0;
365
- x1 = (4-x0)/3; y1 = (1-x0)*(3-x0)/(3*y0); x2 = x1; y2 = -y1;
366
- if (sin_psi > 0) { y0 = -y0; y1 = -y1; y2 = -y2; y3 = -y3; }
367
- wdx = udx + vdx; wdy = udy + vdy;
368
- len = sqrt(wdx*wdx + wdy*wdy); wdx /= len; wdy /= len; // w is unit vector bisecting the corner angle
369
- cos_alpha = -wdx; sin_alpha = -wdy; // need to rotate the arc by alpha
370
- x_center = x_corner + radius * wdx / x0;
371
- y_center = y_corner + radius * wdy / x0;
372
- // then translate arc to x_center, y_center
373
- tmp = x0; x0 = x0*cos_alpha - y0*sin_alpha; y0 = y0*cos_alpha + tmp*sin_alpha;
374
- tmp = x1; x1 = x1*cos_alpha - y1*sin_alpha; y1 = y1*cos_alpha + tmp*sin_alpha;
375
- tmp = x2; x2 = x2*cos_alpha - y2*sin_alpha; y2 = y2*cos_alpha + tmp*sin_alpha;
376
- tmp = x3; x3 = x3*cos_alpha - y3*sin_alpha; y3 = y3*cos_alpha + tmp*sin_alpha;
377
- x0 *= radius; y0 *= radius;
378
- x1 *= radius; y1 *= radius;
379
- x2 *= radius; y2 *= radius;
380
- x3 *= radius; y3 *= radius;
381
- x0 += x_center; y0 += y_center;
382
- x1 += x_center; y1 += y_center;
383
- x2 += x_center; y2 += y_center;
384
- x3 += x_center; y3 += y_center;
385
- if (have_current_point) c_lineto(p,x0,y0);
386
- else c_moveto(p,x0,y0);
387
- c_curveto(p,x1,y1,x2,y2,x3,y3);
388
- }
389
-
390
- double Get_Arc_Radius(FM *p, VALUE dx, VALUE dy)
391
- {
392
- dx = rb_Float(dx);
393
- dy = rb_Float(dy);
394
- double rx = NUM2DBL(dx), ry = NUM2DBL(dy);
395
- rx = convert_figure_to_output_dx(p,rx);
396
- ry = convert_figure_to_output_dy(p,ry);
397
- if (rx < 0) rx = -rx;
398
- if (ry < 0) ry = -ry;
399
- return MIN(rx,ry);
400
- }
401
-
402
- VALUE FM_append_arc_to_path(VALUE fmkr, VALUE x_start, VALUE y_start, VALUE x_corner, VALUE y_corner,
403
- VALUE x_end, VALUE y_end, VALUE dx, VALUE dy)
404
- {
405
- FM *p = Get_FM(fmkr);
406
- x_start = rb_Float(x_start);
407
- y_start = rb_Float(y_start);
408
- x_corner = rb_Float(x_corner);
409
- y_corner = rb_Float(y_corner);
410
- x_end = rb_Float(x_end);
411
- y_end = rb_Float(y_end);
412
- c_append_arc(p,
413
- convert_figure_to_output_x(p,NUM2DBL(x_start)), convert_figure_to_output_y(p,NUM2DBL(y_start)),
414
- convert_figure_to_output_x(p,NUM2DBL(x_corner)), convert_figure_to_output_y(p,NUM2DBL(y_corner)),
415
- convert_figure_to_output_x(p,NUM2DBL(x_end)), convert_figure_to_output_y(p,NUM2DBL(y_end)),
416
- Get_Arc_Radius(p,dx,dy));
417
- return fmkr;
418
- }
419
-
420
- void c_append_rect(FM *p, double x, double y, double width, double height)
421
- {
422
- c_moveto(p,x,y);
423
- c_lineto(p,x+width,y);
424
- c_lineto(p,x+width,y+height);
425
- c_lineto(p,x,y+height);
426
- c_closepath(p);
427
- }
428
-
429
- VALUE FM_append_rect_to_path(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height)
430
- {
431
- FM *p = Get_FM(fmkr);
432
- x = rb_Float(x);
433
- y = rb_Float(y);
434
- width = rb_Float(width);
435
- height = rb_Float(height);
436
- c_append_rect(p,
437
- convert_figure_to_output_x(p,NUM2DBL(x)), convert_figure_to_output_y(p,NUM2DBL(y)),
438
- convert_figure_to_output_dx(p,NUM2DBL(width)), convert_figure_to_output_dy(p,NUM2DBL(height)));
439
- return fmkr;
440
- }
441
-
442
- void c_append_rounded_rect(FM *p, double x, double y, double width, double height, double radius)
443
- {
444
- double xc = x + width/2, yc = y + height/2, xp = x + width, yp = y + height;
445
- c_moveto(p,xc,y);
446
- c_append_arc(p,xc,y, xp,y, xp,yc, radius);
447
- c_append_arc(p,xp,yc, xp,yp, xc,yp, radius);
448
- c_append_arc(p,xc,yp, x,yp, x,yc, radius);
449
- c_append_arc(p,x,yc, x,y, xc,y, radius);
450
- c_closepath(p);
451
- }
452
-
453
- VALUE FM_append_rounded_rect_to_path(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height, VALUE dx, VALUE dy)
454
- {
455
- FM *p = Get_FM(fmkr);
456
- x = rb_Float(x);
457
- y = rb_Float(y);
458
- width = rb_Float(width);
459
- height = rb_Float(height);
460
- c_append_rounded_rect(p,
461
- convert_figure_to_output_x(p,NUM2DBL(x)), convert_figure_to_output_y(p,NUM2DBL(y)),
462
- convert_figure_to_output_dx(p,NUM2DBL(width)), convert_figure_to_output_dy(p,NUM2DBL(height)),
463
- Get_Arc_Radius(p,dx,dy));
464
- return fmkr;
465
- }
466
-
467
- #define ROTATE90(x,y) tmp = x; x = y; y = -tmp;
468
- #define TRANSFORM(xp,yp,x,y) xp = a*(x)+c*(y)+e; yp = b*(x)+d*(y)+f;
469
-
470
- void c_append_oval(FM *p, double x, double y, double dx, double dy, double angle)
471
- {
472
- double cs = cos(angle/RADIANS_TO_DEGREES), sn = sin(angle/RADIANS_TO_DEGREES);
473
- double a = cs*dx, b = sn*dx, c = -sn*dy, d = cs*dy, e = x, f = y;
474
- double x0, y0, x1, y1, x2, y2, x3, y3, x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p, tmp;
475
- int i;
476
- x0 = 0.707107; y0 = 0.707107; x3 = x0; y3 = -y0;
477
- x1 = 1.09763; y1 = 0.316582; x2 = x1; y2 = -y1;
478
- TRANSFORM(x0p,y0p,x0,y0)
479
- TRANSFORM(x1p,y1p,x1,y1)
480
- TRANSFORM(x2p,y2p,x2,y2)
481
- TRANSFORM(x3p,y3p,x3,y3)
482
- c_moveto(p,x0p,y0p);
483
- c_curveto(p,x1p,y1p,x2p,y2p,x3p,y3p);
484
- for (i = 0; i < 3; i++) {
485
- ROTATE90(x0,y0)
486
- ROTATE90(x1,y1)
487
- ROTATE90(x2,y2)
488
- ROTATE90(x3,y3)
489
- TRANSFORM(x0p,y0p,x0,y0)
490
- TRANSFORM(x1p,y1p,x1,y1)
491
- TRANSFORM(x2p,y2p,x2,y2)
492
- TRANSFORM(x3p,y3p,x3,y3)
493
- c_curveto(p,x1p,y1p,x2p,y2p,x3p,y3p);
494
- }
495
- c_closepath(p);
496
- }
497
-
498
- VALUE FM_append_oval_to_path(VALUE fmkr, VALUE x, VALUE y, VALUE dx, VALUE dy, VALUE angle)
499
- {
500
- FM *p = Get_FM(fmkr);
501
- x = rb_Float(x);
502
- y = rb_Float(y);
503
- dx = rb_Float(dx);
504
- dy = rb_Float(dy);
505
- angle = rb_Float(angle);
506
- c_append_oval(p,
507
- convert_figure_to_output_x(p,NUM2DBL(x)), convert_figure_to_output_y(p,NUM2DBL(y)),
508
- convert_figure_to_output_dx(p,NUM2DBL(dx)), convert_figure_to_output_dy(p,NUM2DBL(dy)),
509
- NUM2DBL(angle));
510
- return fmkr;
511
- }
512
-
513
- VALUE FM_append_circle_to_path(VALUE fmkr, VALUE x, VALUE y, VALUE dx)
514
- {
515
- FM *p = Get_FM(fmkr);
516
- x = rb_Float(x);
517
- y = rb_Float(y);
518
- dx = rb_Float(dx);
519
- double s = convert_figure_to_output_dx(p,NUM2DBL(dx));
520
- c_append_oval(p,
521
- convert_figure_to_output_x(p,NUM2DBL(x)), convert_figure_to_output_y(p,NUM2DBL(y)),
522
- s, s, 0.0);
523
- return fmkr;
524
- }
525
-
526
- VALUE FM_append_points_to_path(VALUE fmkr, VALUE x_vec, VALUE y_vec)
527
- {
528
- FM *p = Get_FM(fmkr);
529
- long xlen, ylen, i;
530
- double x0, y0;
531
- double *xs = Dvector_Data_for_Read(x_vec, &xlen);
532
- double *ys = Dvector_Data_for_Read(y_vec, &ylen);
533
- if (xlen != ylen) rb_raise(rb_eArgError, "Sorry: must have same number xs and ys for append_points");
534
- if (xlen <= 0) return fmkr;
535
- x0 = convert_figure_to_output_x(p,xs[0]); y0 = convert_figure_to_output_y(p,ys[0]);
536
- if (have_current_point) c_lineto(p,x0,y0);
537
- else c_moveto(p,x0,y0);
538
- for (i=1; i<xlen; i++)
539
- c_lineto(p,convert_figure_to_output_x(p,xs[i]), convert_figure_to_output_y(p,ys[i]));
540
- return fmkr;
541
- }
542
-
543
- VALUE FM_private_append_points_with_gaps_to_path(VALUE fmkr, VALUE x_vec, VALUE y_vec, VALUE gaps, VALUE close_gaps)
544
- // where there's a gap, do a moveto instead of a lineto
545
- {
546
- if (gaps == Qnil) return FM_append_points_to_path(fmkr, x_vec, y_vec);
547
- FM *p = Get_FM(fmkr);
548
- long xlen, ylen, glen, i, j;
549
- double x0, y0;
550
- double *xs = Dvector_Data_for_Read(x_vec, &xlen);
551
- double *ys = Dvector_Data_for_Read(y_vec, &ylen);
552
- double *gs = Dvector_Data_for_Read(gaps, &glen);
553
- bool do_close = (close_gaps == Qtrue);
554
- if (xlen != ylen) rb_raise(rb_eArgError, "Sorry: must have same number xs and ys for append_points_with_gaps");
555
- if (xlen <= 0) return fmkr;
556
- x0 = convert_figure_to_output_x(p,xs[0]); y0 = convert_figure_to_output_y(p,ys[0]);
557
- if (have_current_point) c_lineto(p,x0,y0);
558
- else c_moveto(p,x0,y0);
559
- for (i = 1, j = 0; j < glen; j++) {
560
- int gap_start = ROUND(gs[j]);
561
- if (gap_start == xlen) break;
562
- if (gap_start > xlen)
563
- rb_raise(rb_eArgError, "Sorry: gap value (%i) too large for vectors of length (%i)", gap_start, xlen);
564
- while (i < gap_start) {
565
- c_lineto(p,convert_figure_to_output_x(p,xs[i]), convert_figure_to_output_y(p,ys[i]));
566
- i++;
567
- }
568
- if (do_close) c_closepath(p);
569
- c_moveto(p,convert_figure_to_output_x(p,xs[i]), convert_figure_to_output_y(p,ys[i]));
570
- i++;
571
- }
572
- while (i < xlen) {
573
- c_lineto(p,convert_figure_to_output_x(p,xs[i]), convert_figure_to_output_y(p,ys[i]));
574
- i++;
575
- }
576
- if (do_close) c_closepath(p);
577
- return fmkr;
578
- }
579
-
580
- /* Path painting operators */
581
-
582
- VALUE FM_stroke(VALUE fmkr)
583
- {
584
- if (!constructing_path) return fmkr;
585
- if (writing_file) fprintf(TF, "S\n");
586
- have_current_point = constructing_path = false;
587
- return fmkr;
588
- }
589
-
590
- VALUE FM_close_and_stroke(VALUE fmkr)
591
- {
592
- if (!constructing_path) return fmkr;
593
- if (writing_file) fprintf(TF, "s\n");
594
- have_current_point = constructing_path = false;
595
- return fmkr;
596
- }
597
-
598
- VALUE FM_fill(VALUE fmkr)
599
- {
600
- if (!constructing_path) return fmkr;
601
- if (writing_file) fprintf(TF, "f\n");
602
- have_current_point = constructing_path = false;
603
- return fmkr;
604
- }
605
-
606
- VALUE FM_discard_path(VALUE fmkr)
607
- {
608
- if (!constructing_path) return fmkr;
609
- if (writing_file) fprintf(TF, "n\n");
610
- have_current_point = constructing_path = false;
611
- return fmkr;
612
- }
613
-
614
- VALUE FM_eofill(VALUE fmkr)
615
- {
616
- if (!constructing_path) return fmkr;
617
- if (writing_file) fprintf(TF, "f*\n");
618
- have_current_point = constructing_path = false;
619
- return fmkr;
620
- }
621
-
622
- VALUE FM_fill_and_stroke(VALUE fmkr)
623
- {
624
- if (!constructing_path) return fmkr;
625
- if (writing_file) fprintf(TF, "B\n");
626
- have_current_point = constructing_path = false;
627
- return fmkr;
628
- }
629
-
630
- VALUE FM_eofill_and_stroke(VALUE fmkr)
631
- {
632
- if (!constructing_path) return fmkr;
633
- if (writing_file) fprintf(TF, "B*\n");
634
- have_current_point = constructing_path = false;
635
- return fmkr;
636
- }
637
-
638
- VALUE FM_close_fill_and_stroke(VALUE fmkr)
639
- {
640
- if (!constructing_path) return fmkr;
641
- if (writing_file) fprintf(TF, "b\n");
642
- have_current_point = constructing_path = false;
643
- return fmkr;
644
- }
645
-
646
- VALUE FM_close_eofill_and_stroke(VALUE fmkr)
647
- {
648
- if (!constructing_path) return fmkr;
649
- if (writing_file) fprintf(TF, "b*\n");
650
- have_current_point = constructing_path = false;
651
- return fmkr;
652
- }
653
-
654
- void c_clip(FM *p)
655
- {
656
- if (!constructing_path) return;
657
- if (writing_file) fprintf(TF, "W n\n");
658
- have_current_point = constructing_path = false;
659
- p = NULL;
660
- }
661
-
662
- VALUE FM_clip(VALUE fmkr)
663
- {
664
- c_clip(Get_FM(fmkr));
665
- return fmkr;
666
- }
667
-
668
- VALUE FM_eoclip(VALUE fmkr)
669
- {
670
- if (!constructing_path) return fmkr;
671
- if (writing_file) fprintf(TF, "W* n\n");
672
- have_current_point = constructing_path = false;
673
- return fmkr;
674
- }
675
-
676
- VALUE FM_fill_and_clip(VALUE fmkr)
677
- {
678
- if (!constructing_path) return fmkr;
679
- if (writing_file) fprintf(TF, "q f Q\n");
680
- c_clip(Get_FM(fmkr));
681
- return fmkr;
682
- }
683
-
684
- VALUE FM_stroke_and_clip(VALUE fmkr)
685
- {
686
- if (!constructing_path) return fmkr;
687
- if (writing_file) fprintf(TF, "q S Q\n");
688
- c_clip(Get_FM(fmkr));
689
- return fmkr;
690
- }
691
-
692
- VALUE FM_fill_stroke_and_clip(VALUE fmkr)
693
- {
694
- if (!constructing_path) return fmkr;
695
- if (writing_file) fprintf(TF, "q B Q\n");
696
- c_clip(Get_FM(fmkr));
697
- return fmkr;
698
- }
699
-
700
- /* Combination Path Constructing and Using */
701
-
702
- VALUE FM_stroke_line(VALUE fmkr, VALUE x1, VALUE y1, VALUE x2, VALUE y2)
703
- {
704
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling stroke_line");
705
- FM_move_to_point(fmkr, x1, y1);
706
- FM_append_point_to_path(fmkr, x2, y2);
707
- FM_stroke(fmkr);
708
- return fmkr;
709
- }
710
-
711
- VALUE FM_fill_rect(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height)
712
- {
713
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_rect");
714
- FM_append_rect_to_path(fmkr, x, y, width, height);
715
- FM_fill(fmkr);
716
- return fmkr;
717
- }
718
-
719
- VALUE FM_stroke_rect(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height)
720
- {
721
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling stroke_rect");
722
- FM_append_rect_to_path(fmkr, x, y, width, height);
723
- FM_stroke(fmkr);
724
- return fmkr;
725
- }
726
-
727
- VALUE FM_fill_and_stroke_rect(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height)
728
- {
729
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_and_stroke_rect");
730
- FM_append_rect_to_path(fmkr, x, y, width, height);
731
- FM_fill_and_stroke(fmkr);
732
- return fmkr;
733
- }
734
-
735
- void c_clip_rect(FM *p, double x, double y, double width, double height) // in output coords
736
- {
737
- double clip_left=x, clip_right, clip_top, clip_bottom=y, clip_width=width, clip_height=height;
738
- if (clip_width < 0.0) { clip_right = clip_left; clip_width = -clip_width; clip_left -= clip_width; }
739
- else clip_right = clip_left + clip_width;
740
- if (clip_height < 0.0) { clip_top = clip_bottom; clip_height = -clip_height; clip_bottom -= clip_height; }
741
- else clip_top = clip_bottom + clip_height;
742
- c_append_rect(p, clip_left, clip_bottom, clip_width, clip_height);
743
- c_clip(p);
744
- if (clip_left > p->clip_left) p->clip_left = clip_left;
745
- if (clip_bottom > p->clip_bottom) p->clip_bottom = clip_bottom;
746
- if (clip_right < p->clip_right) p->clip_right = clip_right;
747
- if (clip_top < p->clip_top) p->clip_top = clip_top;
748
- }
749
-
750
- VALUE FM_clip_rect(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height)
751
- {
752
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling clip_rect");
753
- FM *p = Get_FM(fmkr);
754
- x = rb_Float(x);
755
- y = rb_Float(y);
756
- width = rb_Float(width);
757
- height = rb_Float(height);
758
- c_clip_rect(p,
759
- convert_figure_to_output_x(p,NUM2DBL(x)), convert_figure_to_output_y(p,NUM2DBL(y)),
760
- convert_figure_to_output_dx(p,NUM2DBL(width)), convert_figure_to_output_dy(p,NUM2DBL(height)));
761
- return fmkr;
762
- }
763
-
764
- VALUE FM_clip_oval(VALUE fmkr, VALUE x, VALUE y, VALUE dx, VALUE dy, VALUE angle)
765
- {
766
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling clip_oval");
767
- FM_append_oval_to_path(fmkr, x, y, dx, dy, angle);
768
- FM_clip(fmkr);
769
- return fmkr;
770
- }
771
-
772
- VALUE FM_fill_oval(VALUE fmkr, VALUE x, VALUE y, VALUE dx, VALUE dy, VALUE angle)
773
- {
774
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_oval");
775
- FM_append_oval_to_path(fmkr, x, y, dx, dy, angle);
776
- FM_fill(fmkr);
777
- return fmkr;
778
- }
779
-
780
- VALUE FM_stroke_oval(VALUE fmkr, VALUE x, VALUE y, VALUE dx, VALUE dy, VALUE angle)
781
- {
782
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling stroke_oval");
783
- FM_append_oval_to_path(fmkr, x, y, dx, dy, angle);
784
- FM_stroke(fmkr);
785
- return fmkr;
786
- }
787
-
788
- VALUE FM_fill_and_stroke_oval(VALUE fmkr, VALUE x, VALUE y, VALUE dx, VALUE dy, VALUE angle)
789
- {
790
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_and_stroke_oval");
791
- FM_append_oval_to_path(fmkr, x, y, dx, dy, angle);
792
- FM_fill_and_stroke(fmkr);
793
- return fmkr;
794
- }
795
-
796
- VALUE FM_clip_rounded_rect(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height, VALUE dx, VALUE dy)
797
- {
798
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling clip_rounded_rect");
799
- FM_append_rounded_rect_to_path(fmkr, x, y, width, height, dx, dy);
800
- FM_clip(fmkr);
801
- return fmkr;
802
- }
803
-
804
- VALUE FM_fill_rounded_rect(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height, VALUE dx, VALUE dy)
805
- {
806
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_rounded_rect");
807
- FM_append_rounded_rect_to_path(fmkr, x, y, width, height, dx, dy);
808
- FM_fill(fmkr);
809
- return fmkr;
810
- }
811
-
812
- VALUE FM_stroke_rounded_rect(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height, VALUE dx, VALUE dy)
813
- {
814
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling stroke_rounded_rect");
815
- FM_append_rounded_rect_to_path(fmkr, x, y, width, height, dx, dy);
816
- FM_stroke(fmkr);
817
- return fmkr;
818
- }
819
-
820
- VALUE FM_fill_and_stroke_rounded_rect(VALUE fmkr, VALUE x, VALUE y, VALUE width, VALUE height, VALUE dx, VALUE dy)
821
- {
822
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_and_stroke_rounded_rect");
823
- FM_append_rounded_rect_to_path(fmkr, x, y, width, height, dx, dy);
824
- FM_fill_and_stroke(fmkr);
825
- return fmkr;
826
- }
827
-
828
- VALUE FM_clip_circle(VALUE fmkr, VALUE x, VALUE y, VALUE dx)
829
- {
830
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling clip_circle");
831
- FM_append_circle_to_path(fmkr, x, y, dx);
832
- FM_clip(fmkr);
833
- return fmkr;
834
- }
835
-
836
- VALUE FM_fill_circle(VALUE fmkr, VALUE x, VALUE y, VALUE dx)
837
- {
838
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_circle");
839
- FM_append_circle_to_path(fmkr, x, y, dx);
840
- FM_fill(fmkr);
841
- return fmkr;
842
- }
843
-
844
- VALUE FM_stroke_circle(VALUE fmkr, VALUE x, VALUE y, VALUE dx)
845
- {
846
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling stroke_circle");
847
- FM_append_circle_to_path(fmkr, x, y, dx);
848
- FM_stroke(fmkr);
849
- return fmkr;
850
- }
851
-
852
- VALUE FM_fill_and_stroke_circle(VALUE fmkr, VALUE x, VALUE y, VALUE dx)
853
- {
854
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_and_stroke_circle");
855
- FM_append_circle_to_path(fmkr, x, y, dx);
856
- FM_fill_and_stroke(fmkr);
857
- return fmkr;
858
- }
859
-
860
- static void c_append_frame(FM *p, bool clip)
861
- {
862
- double frame_left = convert_page_to_output_x(p, p->frame_left);
863
- double frame_bottom = convert_page_to_output_y(p, p->frame_bottom);
864
- double frame_width = convert_page_to_output_dx(p, p->frame_width);
865
- double frame_height = convert_page_to_output_dy(p, p->frame_height);
866
- double frame_right = frame_left + frame_width;
867
- double frame_top = frame_bottom + frame_height;
868
- c_append_rect(p, frame_left, frame_bottom, frame_width, frame_height);
869
- if (!clip) return;
870
- if (frame_left > p->clip_left) p->clip_left = frame_left;
871
- if (frame_bottom > p->clip_bottom) p->clip_bottom = frame_bottom;
872
- if (frame_right < p->clip_right) p->clip_right = frame_right;
873
- if (frame_top < p->clip_top) p->clip_top = frame_top;
874
- }
875
-
876
- VALUE FM_append_frame_to_path(VALUE fmkr)
877
- {
878
- FM *p = Get_FM(fmkr);
879
- c_append_frame(p, false);
880
- return fmkr;
881
- }
882
-
883
- VALUE FM_fill_frame(VALUE fmkr)
884
- {
885
- FM *p = Get_FM(fmkr);
886
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_frame");
887
- c_append_frame(p, false); FM_fill(fmkr);
888
- return fmkr;
889
- }
890
-
891
- VALUE FM_stroke_frame(VALUE fmkr)
892
- {
893
- FM *p = Get_FM(fmkr);
894
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling stroke_frame");
895
- c_append_frame(p, false); FM_stroke(fmkr);
896
- return fmkr;
897
- }
898
-
899
- VALUE FM_fill_and_stroke_frame(VALUE fmkr)
900
- {
901
- FM *p = Get_FM(fmkr);
902
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling fill_and_stroke_frame");
903
- c_append_frame(p, false); FM_fill_and_stroke(fmkr);
904
- return fmkr;
905
- }
906
-
907
- VALUE FM_clip_to_frame(VALUE fmkr)
908
- {
909
- FM *p = Get_FM(fmkr);
910
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must finish with current path before calling clip_to_frame");
911
- c_append_frame(p, true); FM_clip(fmkr);
912
- return fmkr;
913
- }