tioga 1.6 → 1.7

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.
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
@@ -0,0 +1,766 @@
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
+ GIVE_WARNING("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(OBJ_PTR rgb, double *rp, double *gp, double *bp, int *ierr)
48
+ {
49
+ if (rgb == OBJ_NIL) { *rp = *gp = *bp = 0.0; return; }
50
+ int len = Array_Len(rgb, ierr);
51
+ if (*ierr != 0) return;
52
+ if (len != 3) { RAISE_ERROR("Sorry: invalid rgb array for setting color: must have 3 entries", ierr); return; }
53
+ OBJ_PTR entry = Array_Entry(rgb, 0, ierr);; if (*ierr != 0) return;
54
+ double r = Number_to_double(entry, ierr); if (*ierr != 0) return;
55
+ entry = Array_Entry(rgb, 1, ierr);; if (*ierr != 0) return;
56
+ double g = Number_to_double(entry, ierr); if (*ierr != 0) return;
57
+ entry = Array_Entry(rgb, 2, ierr);; if (*ierr != 0) return;
58
+ double b = Number_to_double(entry, ierr); if (*ierr != 0) return;
59
+ if (r < 0.0 || r > 1.0) RAISE_ERROR_g("Sorry: invalid red (%g) for color: must be between 0 and 1", r, ierr);
60
+ if (g < 0.0 || g > 1.0) RAISE_ERROR_g("Sorry: invalid green (%g) for color: must be between 0 and 1", g, ierr);
61
+ if (b < 0.0 || b > 1.0) RAISE_ERROR_g("Sorry: invalid blue (%g) for color: must be between 0 and 1", b, ierr);
62
+ if (*ierr != 0) return;
63
+ *rp = r; *gp = g; *bp = b;
64
+ }
65
+
66
+ void c_stroke_color_set_RGB(OBJ_PTR fmkr, FM *p, double r, double g, double b, int *ierr) {
67
+ if (writing_file) fprintf(TF, "%0.3f %0.3f %0.3f RG\n", r, g, b);
68
+ p->stroke_color_R = r;
69
+ p->stroke_color_G = g;
70
+ p->stroke_color_B = b;
71
+ }
72
+
73
+ void c_stroke_color_set(OBJ_PTR fmkr, FM *p, OBJ_PTR value, int *ierr) { // value is array of [r, g, b] intensities from 0 to 1
74
+ double r, g, b;
75
+ Unpack_RGB(value, &r, &g, &b, ierr);
76
+ if (*ierr != 0) return;
77
+ c_stroke_color_set_RGB(fmkr, p, r, g, b, ierr);
78
+ }
79
+
80
+
81
+ OBJ_PTR c_stroke_color_get(OBJ_PTR fmkr, FM *p, int *ierr) { // OBJ_PTR is array of [r, g, b] intensities from 0 to 1
82
+ double r, g, b;
83
+ r = p->stroke_color_R;
84
+ g = p->stroke_color_G;
85
+ b = p->stroke_color_B;
86
+ OBJ_PTR result = Array_New(3);
87
+ Array_Store(result, 0, Float_New(r), ierr);
88
+ Array_Store(result, 1, Float_New(g), ierr);
89
+ Array_Store(result, 2, Float_New(b), ierr);
90
+ return result;
91
+ }
92
+
93
+
94
+ void c_fill_color_set_RGB(OBJ_PTR fmkr, FM *p, double r, double g, double b, int *ierr) {
95
+ if (writing_file) fprintf(TF, "%0.3f %0.3f %0.3f rg\n", r, g, b);
96
+ p->fill_color_R = r;
97
+ p->fill_color_G = g;
98
+ p->fill_color_B = b;
99
+ }
100
+
101
+ void c_fill_color_set(OBJ_PTR fmkr, FM *p, OBJ_PTR value, int *ierr) {
102
+ double r, g, b;
103
+ Unpack_RGB(value, &r, &g, &b, ierr);
104
+ if (*ierr != 0) return;
105
+ c_fill_color_set_RGB(fmkr, p, r, g, b, ierr);
106
+ }
107
+
108
+
109
+ OBJ_PTR c_fill_color_get(OBJ_PTR fmkr, FM *p, int *ierr) { // OBJ_PTR is array of [r, g, b] intensities from 0 to 1
110
+ double r, g, b;
111
+ r = p->fill_color_R;
112
+ g = p->fill_color_G;
113
+ b = p->fill_color_B;
114
+ OBJ_PTR result = Array_New(3);
115
+ Array_Store(result, 0, Float_New(r), ierr);
116
+ Array_Store(result, 1, Float_New(g), ierr);
117
+ Array_Store(result, 2, Float_New(b), ierr);
118
+ return result;
119
+ }
120
+
121
+
122
+ void c_line_width_set(OBJ_PTR fmkr, FM *p, double line_width, int *ierr) {
123
+ if (line_width < 0.0) { RAISE_ERROR_g("Sorry: invalid line width (%g points): must be positive", line_width, ierr); return; }
124
+ if (line_width > 1e3) { RAISE_ERROR_g("Sorry: too large line width (%g points)", line_width, ierr); return; }
125
+ if (writing_file) fprintf(TF, "%0.3f w\n", line_width * ENLARGE * p->default_line_scale);
126
+ p->line_width = line_width;
127
+ }
128
+
129
+
130
+ void c_rescale_lines(OBJ_PTR fmkr, FM *p, double scaling_factor, int *ierr) {
131
+ double new_scale = scaling_factor * p->default_line_scale;
132
+ if (new_scale <= 0) { RAISE_ERROR("Sorry: line scale must be positive", ierr); return; }
133
+ p->default_line_scale = new_scale;
134
+ c_line_width_set(fmkr, p, p->line_width, ierr);
135
+ }
136
+
137
+
138
+ void c_line_cap_set(OBJ_PTR fmkr, FM *p, int line_cap, int *ierr) {
139
+ if (line_cap < 0 || line_cap > 3) { RAISE_ERROR_i("Sorry: invalid arg for setting line_cap (%i)", line_cap, ierr); return; }
140
+ if (writing_file) fprintf(TF, "%d J\n", line_cap);
141
+ p->line_cap = line_cap;
142
+ }
143
+
144
+
145
+ void c_line_join_set(OBJ_PTR fmkr, FM *p, int line_join, int *ierr) {
146
+ if (line_join < 0 || line_join > 3) { RAISE_ERROR_i("Sorry: invalid arg for setting line_join (%i)", line_join, ierr); return; }
147
+ if (writing_file) fprintf(TF, "%d j\n", line_join);
148
+ p->line_join = line_join;
149
+ }
150
+
151
+
152
+ void c_miter_limit_set(OBJ_PTR fmkr, FM *p, double miter_limit, int *ierr) {
153
+ if (constructing_path) { RAISE_ERROR("Sorry: must not be constructing a path when change miter limit", ierr); return; }
154
+ if (miter_limit < 0.0) {
155
+ RAISE_ERROR_g(
156
+ "Sorry: invalid miter limit (%g): must be positive ratio for max miter length to line width", miter_limit, ierr);
157
+ return; }
158
+ if (writing_file) fprintf(TF, "%0.3f M\n", miter_limit);
159
+ p->miter_limit = miter_limit;
160
+ }
161
+
162
+
163
+ void c_line_type_set(OBJ_PTR fmkr, FM *p, OBJ_PTR line_type, int *ierr) { // array phase d (distances given in points)
164
+ double sz;
165
+ if (constructing_path) {
166
+ RAISE_ERROR("Sorry: must not be constructing a path when change line_type", ierr);
167
+ return;
168
+ }
169
+ if (line_type == OBJ_NIL) {
170
+ fprintf(TF, "[] 0 d\n");
171
+ } else {
172
+ if (writing_file) {
173
+ int len = Array_Len(line_type, ierr);
174
+ if (*ierr != 0) return;
175
+ if (len != 2) {
176
+ RAISE_ERROR("Sorry: invalid line_type. Must be [ [dash pattern] dash phase ]", ierr);
177
+ return;
178
+ }
179
+ OBJ_PTR dashArray = Array_Entry(line_type, 0, ierr);
180
+ if (*ierr != 0) return;
181
+ OBJ_PTR dashPhase = Array_Entry(line_type, 1, ierr);
182
+ if (*ierr != 0) return;
183
+ fprintf(TF, "[ ");
184
+ if (dashArray != OBJ_NIL) {
185
+ long i, len = Array_Len(dashArray, ierr);
186
+ if (*ierr != 0) return;
187
+ for (i=0; i < len; i++) {
188
+ OBJ_PTR entry = Array_Entry(dashArray, i, ierr);
189
+ if (*ierr != 0) return;
190
+ sz = Number_to_double(entry, ierr);
191
+ if (*ierr != 0) return;
192
+ if (sz < 0.0) {
193
+ RAISE_ERROR_g("Sorry: invalid dash array entry (%g): must be positive", sz, ierr);
194
+ return;
195
+ }
196
+ fprintf(TF, "%0.3f ", sz * ENLARGE);
197
+ }
198
+ }
199
+ sz = Number_to_double(dashPhase, ierr);
200
+ if (*ierr != 0) return;
201
+ if (sz < 0.0) {
202
+ RAISE_ERROR_g("Sorry: invalid dash phase (%g): must be positive", sz, ierr);
203
+ return;
204
+ }
205
+ fprintf(TF, "] %0.3f d\n", sz * ENLARGE);
206
+ }
207
+ }
208
+ Set_line_type(fmkr, line_type, ierr);
209
+ }
210
+
211
+
212
+ /* Path construction operators */
213
+
214
+ /* all locations and vectors are in figure coordinates */
215
+
216
+ static long c_round_dev(FM *p, double v) { // make sure that we don't get too far out or can overflow!
217
+ if (v > MAX_DEV_COORD_ALLOWED) {
218
+ //if (p->debug_verbosity_level > 0) printf("c_round_dev clipping %g\n", v);
219
+ return iMAX_DEV_COORD_ALLOWED;
220
+ }
221
+ if (v < -MAX_DEV_COORD_ALLOWED) {
222
+ //if (p->debug_verbosity_level > 0) printf("c_round_dev clipping %g\n", v);
223
+ return -iMAX_DEV_COORD_ALLOWED;
224
+ }
225
+ return ROUND(v);
226
+ }
227
+
228
+ void update_bbox(FM *p, double x, double y)
229
+ {
230
+ if (x >= p->clip_left && x < bbox_llx) bbox_llx = x;
231
+ if (y >= p->clip_bottom && y < bbox_lly) bbox_lly = y;
232
+ if (x <= p->clip_right && x > bbox_urx) bbox_urx = x;
233
+ if (y <= p->clip_top && y > bbox_ury) bbox_ury = y;
234
+ }
235
+
236
+ void c_update_bbox(OBJ_PTR fmkr, FM *p, double x, double y, int *ierr) {
237
+ update_bbox(p, convert_figure_to_output_x(p,x), convert_figure_to_output_y(p,y));
238
+ }
239
+
240
+
241
+ OBJ_PTR c_bbox_left(OBJ_PTR fmkr, FM *p, int *ierr) { return Float_New(bbox_llx); }
242
+
243
+ OBJ_PTR c_bbox_right(OBJ_PTR fmkr, FM *p, int *ierr) { return Float_New(bbox_urx); }
244
+
245
+ OBJ_PTR c_bbox_top(OBJ_PTR fmkr, FM *p, int *ierr) { return Float_New(bbox_ury); }
246
+
247
+ OBJ_PTR c_bbox_bottom(OBJ_PTR fmkr, FM *p, int *ierr) { return Float_New(bbox_lly); }
248
+
249
+
250
+ void c_move_to_point(OBJ_PTR fmkr, FM *p, double x, double y, int *ierr) {
251
+ x = convert_figure_to_output_x(p,x);
252
+ y = convert_figure_to_output_y(p,y);
253
+ c_moveto(fmkr,p,x,y,ierr);
254
+ }
255
+ void c_moveto(OBJ_PTR fmkr, FM *p, double x, double y, int *ierr) {
256
+ ARE_OK_NUMBERS(x,y);
257
+ if (writing_file) fprintf(TF, "%ld %ld m\n", c_round_dev(p,x), c_round_dev(p,y));
258
+ update_bbox(p, x, y);
259
+ have_current_point = constructing_path = true;
260
+ }
261
+
262
+
263
+ void c_append_point_to_path(OBJ_PTR fmkr, FM *p, double x, double y, int *ierr) {
264
+ x = convert_figure_to_output_x(p,x);
265
+ y = convert_figure_to_output_y(p,y);
266
+ c_lineto(fmkr, p, x, y, ierr);
267
+ }
268
+ void c_lineto(OBJ_PTR fmkr, FM *p, double x, double y, int *ierr) {
269
+ ARE_OK_NUMBERS(x,y);
270
+ if (!constructing_path) { RAISE_ERROR("Sorry: must start path with moveto before call lineto", ierr); return; }
271
+ if (writing_file) fprintf(TF, "%ld %ld l\n", c_round_dev(p,x), c_round_dev(p,y));
272
+ update_bbox(p, x, y);
273
+ }
274
+
275
+
276
+ OBJ_PTR c_bezier_control_points(OBJ_PTR fmkr, FM *p,
277
+ double x0, double y0, double delta_x, double a, double b, double c, int *ierr) {
278
+ double data[6];
279
+ double x1, y1, x2, y2, x3, y3;
280
+ double cx = delta_x, ay = a * delta_x * delta_x * delta_x, by = b * delta_x * delta_x, cy = c * delta_x;
281
+ x1 = x0 + cx/3.0; x2 = x1 + cx/3.0; x3 = x0 + delta_x;
282
+ y1 = y0 + cy/3.0; y2 = y1 + (cy + by)/3.0; y3 = y0 + ay + by + cy;
283
+ data[0] = x1; data[1] = y1; data[2] = x2; data[3] = y2; data[4] = x3; data[5] = y3;
284
+ return Vector_New(6,data);
285
+ }
286
+
287
+
288
+ void c_append_curve_to_path(OBJ_PTR fmkr, FM *p,
289
+ double x1, double y1, double x2, double y2, double x3, double y3, int *ierr) {
290
+ x1 = convert_figure_to_output_x(p,x1);
291
+ y1 = convert_figure_to_output_y(p,y1);
292
+ x2 = convert_figure_to_output_x(p,x2);
293
+ y2 = convert_figure_to_output_y(p,y2);
294
+ x3 = convert_figure_to_output_x(p,x3);
295
+ y3 = convert_figure_to_output_y(p,y3);
296
+ c_curveto(fmkr, p, x1, y1, x2, y2, x3, y3, ierr);
297
+ }
298
+ void c_curveto(OBJ_PTR fmkr, FM *p,
299
+ double x1, double y1, double x2, double y2, double x3, double y3, int *ierr) {
300
+ ARE_OK_NUMBERS(x1,y1);
301
+ ARE_OK_NUMBERS(x2,y2);
302
+ ARE_OK_NUMBERS(x3,y3);
303
+ if (!constructing_path) { RAISE_ERROR("Sorry: must start path with moveto before call curveto", ierr); return; }
304
+ if (writing_file) fprintf(TF, "%ld %ld %ld %ld %ld %ld c\n",
305
+ 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));
306
+ update_bbox(p, x1, y1);
307
+ update_bbox(p, x2, y2);
308
+ update_bbox(p, x3, y3);
309
+ }
310
+
311
+
312
+ void c_close_path(OBJ_PTR fmkr, FM *p, int *ierr) {
313
+ if (!constructing_path) { RAISE_ERROR("Sorry: must be constructing path when call closepath", ierr); return; }
314
+ if (writing_file) fprintf(TF, "h\n");
315
+ have_current_point = false;
316
+ }
317
+
318
+
319
+ static double Get_Arc_Radius(FM *p, double rx, double ry) {
320
+ rx = convert_figure_to_output_dx(p,rx);
321
+ ry = convert_figure_to_output_dy(p,ry);
322
+ if (rx < 0) rx = -rx;
323
+ if (ry < 0) ry = -ry;
324
+ return MIN(rx,ry);
325
+ }
326
+
327
+
328
+ void c_append_arc_to_path(OBJ_PTR fmkr, FM *p, double x_start, double y_start, double x_corner, double y_corner,
329
+ double x_end, double y_end, double dx, double dy, int *ierr) {
330
+ x_start = convert_figure_to_output_x(p,x_start);
331
+ y_start = convert_figure_to_output_y(p,y_start);
332
+ x_corner = convert_figure_to_output_x(p,x_corner);
333
+ y_corner = convert_figure_to_output_y(p,y_corner);
334
+ x_end = convert_figure_to_output_x(p,x_end);
335
+ y_end = convert_figure_to_output_y(p,y_end);
336
+ c_append_arc(fmkr, p, x_start, y_start, x_corner, y_corner, x_end, y_end, Get_Arc_Radius(p,dx,dy), ierr);
337
+ }
338
+
339
+ void c_append_arc(OBJ_PTR fmkr, FM *p, double x_start, double y_start, double x_corner, double y_corner,
340
+ double x_end, double y_end, double radius, int *ierr) {
341
+ ARE_OK_NUMBERS(x_start,y_start);
342
+ ARE_OK_NUMBERS(x_corner,y_corner);
343
+ ARE_OK_NUMBERS(x_end,y_end);
344
+ double x0, y0, x1, y1, x2, y2, x3, y3, udx, udy, vdx, vdy, wdx, wdy, len, x_center, y_center, tmp;
345
+ double psi, sin_psi, cos_psi, theta, cos_alpha, sin_alpha;
346
+ udx = x_start - x_corner; udy = y_start - y_corner;
347
+ vdx = x_end - x_corner; vdy = y_end - y_corner;
348
+ len = sqrt(udx*udx + udy*udy); udx /= len; udy /= len; // u is unit vector from corner to start
349
+ len = sqrt(vdx*vdx + vdy*vdy); vdx /= len; vdy /= len; // v is unit vector from corner to end
350
+ cos_psi = udx*vdx + udy*vdy; sin_psi = udy * vdx - udx * vdy;
351
+ psi = atan2(sin_psi, cos_psi); // psi is angle between u and v
352
+ if (psi > PI) psi = 2*PI - psi;
353
+ theta = PI - psi; // theta is opening angle for the arc
354
+ while (theta < 0) theta += 2*PI;
355
+ if (theta >= PI) { RAISE_ERROR("Sorry: invalid control point for arc", ierr); return; }
356
+ // first compute control points for arc of opening theta with unit radius, bisected by positive x axis
357
+ // based on note by Richard DeVeneza, "How to determine the control points of a Bezier curve that
358
+ // approximates a small circular arc", Nov 2004.
359
+ x0 = cos(theta/2); y0 = sin(theta/2); x3 = x0; y3 = -y0;
360
+ x1 = (4-x0)/3; y1 = (1-x0)*(3-x0)/(3*y0); x2 = x1; y2 = -y1;
361
+ if (sin_psi > 0) { y0 = -y0; y1 = -y1; y2 = -y2; y3 = -y3; }
362
+ wdx = udx + vdx; wdy = udy + vdy;
363
+ len = sqrt(wdx*wdx + wdy*wdy); wdx /= len; wdy /= len; // w is unit vector bisecting the corner angle
364
+ cos_alpha = -wdx; sin_alpha = -wdy; // need to rotate the arc by alpha
365
+ x_center = x_corner + radius * wdx / x0;
366
+ y_center = y_corner + radius * wdy / x0;
367
+ // then translate arc to x_center, y_center
368
+ tmp = x0; x0 = x0*cos_alpha - y0*sin_alpha; y0 = y0*cos_alpha + tmp*sin_alpha;
369
+ tmp = x1; x1 = x1*cos_alpha - y1*sin_alpha; y1 = y1*cos_alpha + tmp*sin_alpha;
370
+ tmp = x2; x2 = x2*cos_alpha - y2*sin_alpha; y2 = y2*cos_alpha + tmp*sin_alpha;
371
+ tmp = x3; x3 = x3*cos_alpha - y3*sin_alpha; y3 = y3*cos_alpha + tmp*sin_alpha;
372
+ x0 *= radius; y0 *= radius;
373
+ x1 *= radius; y1 *= radius;
374
+ x2 *= radius; y2 *= radius;
375
+ x3 *= radius; y3 *= radius;
376
+ x0 += x_center; y0 += y_center;
377
+ x1 += x_center; y1 += y_center;
378
+ x2 += x_center; y2 += y_center;
379
+ x3 += x_center; y3 += y_center;
380
+ if (have_current_point) c_lineto(fmkr,p,x0,y0,ierr);
381
+ else c_moveto(fmkr,p,x0,y0, ierr);
382
+ c_curveto(fmkr,p,x1,y1,x2,y2,x3,y3,ierr);
383
+ }
384
+
385
+ void c_append_rect_to_path(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, int *ierr) {
386
+ x = convert_figure_to_output_x(p,x);
387
+ y = convert_figure_to_output_y(p,y);
388
+ width = convert_figure_to_output_dx(p,width);
389
+ height = convert_figure_to_output_dy(p,height);
390
+ c_append_rect(fmkr, p, x, y, width, height, ierr);
391
+ }
392
+
393
+ void c_append_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, int *ierr) {
394
+ c_moveto(fmkr,p,x,y, ierr);
395
+ c_lineto(fmkr,p,x+width,y, ierr);
396
+ c_lineto(fmkr,p,x+width,y+height, ierr);
397
+ c_lineto(fmkr,p,x,y+height, ierr);
398
+ c_close_path(fmkr,p, ierr);
399
+ }
400
+
401
+
402
+ void c_append_rounded_rect_to_path(OBJ_PTR fmkr, FM *p,
403
+ double x, double y, double width, double height, double dx, double dy, int *ierr) {
404
+ x = convert_figure_to_output_x(p,x);
405
+ y = convert_figure_to_output_y(p,y);
406
+ width = convert_figure_to_output_dx(p,width);
407
+ height = convert_figure_to_output_dy(p,height);
408
+ double radius = Get_Arc_Radius(p,dx,dy);
409
+ c_append_rounded_rect(fmkr, p, x, y, width, height, radius, ierr);
410
+ }
411
+
412
+ void c_append_rounded_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, double radius, int *ierr)
413
+ {
414
+ double xc = x + width/2, yc = y + height/2, xp = x + width, yp = y + height;
415
+ c_moveto(fmkr,p,xc,y, ierr);
416
+ c_append_arc(fmkr,p,xc,y,xp,y,xp,yc,radius, ierr);
417
+ c_append_arc(fmkr,p,xp,yc,xp,yp,xc,yp,radius, ierr);
418
+ c_append_arc(fmkr,p,xc,yp,x,yp,x,yc,radius, ierr);
419
+ c_append_arc(fmkr,p,x,yc,x,y,xc,y,radius, ierr);
420
+ c_close_path(fmkr,p, ierr);
421
+ }
422
+
423
+
424
+ #define ROTATE90(x,y) tmp = x; x = y; y = -tmp;
425
+ #define TRANSFORM(xp,yp,x,y) xp = a*(x)+c*(y)+e; yp = b*(x)+d*(y)+f;
426
+
427
+ void c_append_oval_to_path(OBJ_PTR fmkr, FM *p, double x, double y, double dx, double dy, double angle, int *ierr) {
428
+ x = convert_figure_to_output_x(p,x);
429
+ y = convert_figure_to_output_y(p,y);
430
+ dx = convert_figure_to_output_dx(p,dx);
431
+ dy = convert_figure_to_output_dy(p,dy);
432
+ c_append_oval(fmkr, p, x, y, dx, dy, angle, ierr); }
433
+
434
+ void c_append_oval(OBJ_PTR fmkr, FM *p, double x, double y, double dx, double dy, double angle, int *ierr) {
435
+ double cs = cos(angle/RADIANS_TO_DEGREES), sn = sin(angle/RADIANS_TO_DEGREES);
436
+ double a = cs*dx, b = sn*dx, c = -sn*dy, d = cs*dy, e = x, f = y;
437
+ double x0, y0, x1, y1, x2, y2, x3, y3, x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p, tmp;
438
+ int i;
439
+ x0 = 0.707107; y0 = 0.707107; x3 = x0; y3 = -y0;
440
+ x1 = 1.09763; y1 = 0.316582; x2 = x1; y2 = -y1;
441
+ TRANSFORM(x0p,y0p,x0,y0)
442
+ TRANSFORM(x1p,y1p,x1,y1)
443
+ TRANSFORM(x2p,y2p,x2,y2)
444
+ TRANSFORM(x3p,y3p,x3,y3)
445
+ c_moveto(fmkr,p,x0p,y0p,ierr);
446
+ if (*ierr != 0) return;
447
+ c_curveto(fmkr,p,x1p,y1p,x2p,y2p,x3p,y3p,ierr);
448
+ if (*ierr != 0) return;
449
+ for (i = 0; i < 3; i++) {
450
+ ROTATE90(x0,y0)
451
+ ROTATE90(x1,y1)
452
+ ROTATE90(x2,y2)
453
+ ROTATE90(x3,y3)
454
+ TRANSFORM(x0p,y0p,x0,y0)
455
+ TRANSFORM(x1p,y1p,x1,y1)
456
+ TRANSFORM(x2p,y2p,x2,y2)
457
+ TRANSFORM(x3p,y3p,x3,y3)
458
+ c_curveto(fmkr,p,x1p,y1p,x2p,y2p,x3p,y3p,ierr);
459
+ if (*ierr != 0) return;
460
+ }
461
+ c_close_path(fmkr,p, ierr);
462
+ }
463
+
464
+
465
+ void c_append_circle_to_path(OBJ_PTR fmkr, FM *p, double x, double y, double dx, int *ierr) {
466
+ double s = convert_figure_to_output_dx(p,dx);
467
+ c_append_oval(fmkr, p, convert_figure_to_output_x(p,x), convert_figure_to_output_y(p,y), s, s, 0.0, ierr);
468
+ }
469
+
470
+ void c_append_points_to_path(OBJ_PTR fmkr, FM *p, OBJ_PTR x_vec, OBJ_PTR y_vec, int *ierr) {
471
+ long xlen, ylen, i;
472
+ double *xs = Vector_Data_for_Read(x_vec, &xlen, ierr);
473
+ if (*ierr != 0) return;
474
+ double *ys = Vector_Data_for_Read(y_vec, &ylen, ierr);
475
+ if (*ierr != 0) return;
476
+ if (xlen != ylen) { RAISE_ERROR("Sorry: must have same number xs and ys for append_points", ierr); return; }
477
+ if (xlen <= 0) return;
478
+ if (have_current_point) c_append_point_to_path(fmkr,p,xs[0],ys[0], ierr);
479
+ else c_move_to_point(fmkr,p,xs[0],ys[0], ierr);
480
+ for (i=1; i<xlen; i++) c_append_point_to_path(fmkr,p,xs[i],ys[i], ierr);
481
+ }
482
+
483
+ void c_private_append_points_with_gaps_to_path(OBJ_PTR fmkr, FM *p,
484
+ OBJ_PTR x_vec, OBJ_PTR y_vec, OBJ_PTR gaps, bool do_close, int *ierr) {
485
+ // where there's a gap, do a moveto instead of a lineto
486
+ if (gaps == OBJ_NIL) return c_append_points_to_path(fmkr, p, x_vec, y_vec, ierr);
487
+ long xlen, ylen, glen, i, j;
488
+ double *xs = Vector_Data_for_Read(x_vec, &xlen, ierr);
489
+ if (*ierr != 0) return;
490
+ double *ys = Vector_Data_for_Read(y_vec, &ylen, ierr);
491
+ if (*ierr != 0) return;
492
+ double *gs = Vector_Data_for_Read(gaps, &glen, ierr);
493
+ if (*ierr != 0) return;
494
+ if (xlen != ylen) { RAISE_ERROR("Sorry: must have same number xs and ys for append_points_with_gaps", ierr); return; }
495
+ if (xlen <= 0) return;
496
+ if (have_current_point) c_append_point_to_path(fmkr,p,xs[0],ys[0], ierr);
497
+ else c_move_to_point(fmkr,p,xs[0],ys[0], ierr);
498
+ for (i = 1, j = 0; j < glen; j++) {
499
+ int gap_start = ROUND(gs[j]);
500
+ if (gap_start == xlen) break;
501
+ if (gap_start > xlen) {
502
+ RAISE_ERROR_ii("Sorry: gap value (%i) too large for vectors of length (%i)", gap_start, xlen, ierr);
503
+ return; }
504
+ while (i < gap_start) {
505
+ c_append_point_to_path(fmkr,p,xs[i],ys[i], ierr);
506
+ i++;
507
+ }
508
+ if (do_close) c_close_path(fmkr,p, ierr);
509
+ c_move_to_point(fmkr,p,xs[i],ys[i], ierr);
510
+ i++;
511
+ }
512
+ while (i < xlen) {
513
+ c_append_point_to_path(fmkr,p,xs[i],ys[i], ierr);
514
+ i++;
515
+ }
516
+ if (do_close) c_close_path(fmkr,p, ierr);
517
+ }
518
+
519
+ /* Path painting operators */
520
+
521
+ void c_stroke(OBJ_PTR fmkr, FM *p, int *ierr) {
522
+ if (!constructing_path) return;
523
+ if (writing_file) fprintf(TF, "S\n");
524
+ have_current_point = constructing_path = false;
525
+ }
526
+
527
+ void c_close_and_stroke(OBJ_PTR fmkr, FM *p, int *ierr) {
528
+ if (!constructing_path) return;
529
+ if (writing_file) fprintf(TF, "s\n");
530
+ have_current_point = constructing_path = false;
531
+ }
532
+
533
+ void c_fill(OBJ_PTR fmkr, FM *p, int *ierr) {
534
+ if (!constructing_path) return;
535
+ if (writing_file) fprintf(TF, "f\n");
536
+ have_current_point = constructing_path = false;
537
+ }
538
+
539
+ void c_discard_path(OBJ_PTR fmkr, FM *p, int *ierr) {
540
+ if (!constructing_path) return;
541
+ if (writing_file) fprintf(TF, "n\n");
542
+ have_current_point = constructing_path = false;
543
+ }
544
+
545
+ void c_eofill(OBJ_PTR fmkr, FM *p, int *ierr) {
546
+ if (!constructing_path) return;
547
+ if (writing_file) fprintf(TF, "f*\n");
548
+ have_current_point = constructing_path = false;
549
+ }
550
+
551
+ void c_fill_and_stroke(OBJ_PTR fmkr, FM *p, int *ierr) {
552
+ if (!constructing_path) return;
553
+ if (writing_file) fprintf(TF, "B\n");
554
+ have_current_point = constructing_path = false;
555
+ }
556
+
557
+ void c_eofill_and_stroke(OBJ_PTR fmkr, FM *p, int *ierr) {
558
+ if (!constructing_path) return;
559
+ if (writing_file) fprintf(TF, "B*\n");
560
+ have_current_point = constructing_path = false;
561
+ }
562
+
563
+ void c_close_fill_and_stroke(OBJ_PTR fmkr, FM *p, int *ierr) {
564
+ if (!constructing_path) return;
565
+ if (writing_file) fprintf(TF, "b\n");
566
+ have_current_point = constructing_path = false;
567
+ }
568
+
569
+ void c_close_eofill_and_stroke(OBJ_PTR fmkr, FM *p, int *ierr) {
570
+ if (!constructing_path) return;
571
+ if (writing_file) fprintf(TF, "b*\n");
572
+ have_current_point = constructing_path = false;
573
+ }
574
+
575
+ void c_clip(OBJ_PTR fmkr, FM *p, int *ierr) {
576
+ if (!constructing_path) return;
577
+ if (writing_file) fprintf(TF, "W n\n");
578
+ have_current_point = constructing_path = false;
579
+ }
580
+
581
+
582
+ void c_eoclip(OBJ_PTR fmkr, FM *p, int *ierr) {
583
+ if (!constructing_path) return;
584
+ if (writing_file) fprintf(TF, "W* n\n");
585
+ have_current_point = constructing_path = false;
586
+ }
587
+
588
+ void c_fill_and_clip(OBJ_PTR fmkr, FM *p, int *ierr) {
589
+ if (!constructing_path) return;
590
+ if (writing_file) fprintf(TF, "q f Q\n");
591
+ c_clip(fmkr,p, ierr);
592
+ }
593
+
594
+ void c_stroke_and_clip(OBJ_PTR fmkr, FM *p, int *ierr) {
595
+ if (!constructing_path) return;
596
+ if (writing_file) fprintf(TF, "q S Q\n");
597
+ c_clip(fmkr,p, ierr);
598
+ }
599
+
600
+ void c_fill_stroke_and_clip(OBJ_PTR fmkr, FM *p, int *ierr) {
601
+ if (!constructing_path) return;
602
+ if (writing_file) fprintf(TF, "q B Q\n");
603
+ c_clip(fmkr,p, ierr);
604
+ }
605
+
606
+ /* Combination Path Constructing and Using */
607
+
608
+ void c_stroke_line(OBJ_PTR fmkr, FM *p, double x1, double y1, double x2, double y2, int *ierr) {
609
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling stroke_line", ierr); return; }
610
+ c_move_to_point(fmkr, p, x1, y1, ierr);
611
+ c_append_point_to_path(fmkr, p, x2, y2, ierr);
612
+ c_stroke(fmkr, p, ierr);
613
+ }
614
+
615
+ void c_fill_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, int *ierr) {
616
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_rect", ierr); return; }
617
+ c_append_rect_to_path(fmkr, p, x, y, width, height, ierr);
618
+ c_fill(fmkr,p, ierr);
619
+ }
620
+
621
+ void c_stroke_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, int *ierr) {
622
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling stroke_rect", ierr); return; }
623
+ c_append_rect_to_path(fmkr, p, x, y, width, height, ierr);
624
+ c_stroke(fmkr,p, ierr);
625
+ }
626
+
627
+ void c_fill_and_stroke_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, int *ierr) {
628
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_and_stroke_rect", ierr); return; }
629
+ c_append_rect_to_path(fmkr, p, x, y, width, height, ierr);
630
+ c_fill_and_stroke(fmkr,p, ierr);
631
+ }
632
+
633
+ void c_clip_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, int *ierr) {
634
+ return c_clip_dev_rect(fmkr, p,
635
+ convert_figure_to_output_x(p,x), convert_figure_to_output_y(p,y),
636
+ convert_figure_to_output_dx(p,width), convert_figure_to_output_dy(p,height), ierr); }
637
+ void c_clip_dev_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, int *ierr) { // in output coords
638
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling clip_rect", ierr); return; }
639
+ double clip_left=x, clip_right, clip_top, clip_bottom=y, clip_width=width, clip_height=height;
640
+ if (clip_width < 0.0) { clip_right = clip_left; clip_width = -clip_width; clip_left -= clip_width; }
641
+ else clip_right = clip_left + clip_width;
642
+ if (clip_height < 0.0) { clip_top = clip_bottom; clip_height = -clip_height; clip_bottom -= clip_height; }
643
+ else clip_top = clip_bottom + clip_height;
644
+ c_append_rect(fmkr, p, clip_left, clip_bottom, clip_width, clip_height, ierr);
645
+ c_clip(fmkr,p, ierr);
646
+ if (clip_left > p->clip_left) p->clip_left = clip_left;
647
+ if (clip_bottom > p->clip_bottom) p->clip_bottom = clip_bottom;
648
+ if (clip_right < p->clip_right) p->clip_right = clip_right;
649
+ if (clip_top < p->clip_top) p->clip_top = clip_top;
650
+ }
651
+
652
+
653
+ void c_clip_oval(OBJ_PTR fmkr, FM *p, double x, double y, double dx, double dy, double angle, int *ierr) {
654
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling clip_oval", ierr); return; }
655
+ c_append_oval_to_path(fmkr, p, x, y, dx, dy, angle, ierr);
656
+ c_clip(fmkr,p, ierr);
657
+ }
658
+
659
+ void c_fill_oval(OBJ_PTR fmkr, FM *p, double x, double y, double dx, double dy, double angle, int *ierr) {
660
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_oval", ierr); return; }
661
+ c_append_oval_to_path(fmkr, p, x, y, dx, dy, angle, ierr);
662
+ c_fill(fmkr,p, ierr);
663
+ }
664
+
665
+ void c_stroke_oval(OBJ_PTR fmkr, FM *p, double x, double y, double dx, double dy, double angle, int *ierr) {
666
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling stroke_oval", ierr); return; }
667
+ c_append_oval_to_path(fmkr, p, x, y, dx, dy, angle, ierr);
668
+ c_stroke(fmkr,p, ierr);
669
+ }
670
+
671
+ void c_fill_and_stroke_oval(OBJ_PTR fmkr, FM *p, double x, double y, double dx, double dy, double angle, int *ierr) {
672
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_and_stroke_oval", ierr); return; }
673
+ c_append_oval_to_path(fmkr, p, x, y, dx, dy, angle, ierr);
674
+ c_fill_and_stroke(fmkr,p, ierr);
675
+ }
676
+
677
+ void c_clip_rounded_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, double dx, double dy, int *ierr) {
678
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling clip_rounded_rect", ierr); return; }
679
+ c_append_rounded_rect_to_path(fmkr, p, x, y, width, height, dx, dy, ierr);
680
+ c_clip(fmkr,p, ierr);
681
+ }
682
+
683
+ void c_fill_rounded_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, double dx, double dy, int *ierr) {
684
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_rounded_rect", ierr); return; }
685
+ c_append_rounded_rect_to_path(fmkr, p, x, y, width, height, dx, dy, ierr);
686
+ c_fill(fmkr,p, ierr);
687
+ }
688
+
689
+ void c_stroke_rounded_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, double dx, double dy, int *ierr) {
690
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling stroke_rounded_rect", ierr); return; }
691
+ c_append_rounded_rect_to_path(fmkr, p, x, y, width, height, dx, dy, ierr);
692
+ c_stroke(fmkr,p, ierr);
693
+ }
694
+
695
+ void c_fill_and_stroke_rounded_rect(OBJ_PTR fmkr, FM *p, double x, double y, double width, double height, double dx, double dy, int *ierr) {
696
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_and_stroke_rounded_rect", ierr); return; }
697
+ c_append_rounded_rect_to_path(fmkr, p, x, y, width, height, dx, dy, ierr);
698
+ c_fill_and_stroke(fmkr,p, ierr);
699
+ }
700
+
701
+ void c_clip_circle(OBJ_PTR fmkr, FM *p, double x, double y, double dx, int *ierr) {
702
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling clip_circle", ierr); return; }
703
+ c_append_circle_to_path(fmkr, p, x, y, dx, ierr);
704
+ c_clip(fmkr, p, ierr);
705
+ }
706
+
707
+ void c_fill_circle(OBJ_PTR fmkr, FM *p, double x, double y, double dx, int *ierr) {
708
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_circle", ierr); return; }
709
+ c_append_circle_to_path(fmkr, p, x, y, dx, ierr);
710
+ c_fill(fmkr, p, ierr);
711
+ }
712
+
713
+ void c_stroke_circle(OBJ_PTR fmkr, FM *p, double x, double y, double dx, int *ierr) {
714
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling stroke_circle", ierr); return; }
715
+ c_append_circle_to_path(fmkr, p, x, y, dx, ierr);
716
+ c_stroke(fmkr, p, ierr);
717
+ }
718
+
719
+ void c_fill_and_stroke_circle(OBJ_PTR fmkr, FM *p, double x, double y, double dx, int *ierr) {
720
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_and_stroke_circle", ierr); return; }
721
+ c_append_circle_to_path(fmkr, p, x, y, dx, ierr);
722
+ c_fill_and_stroke(fmkr, p, ierr);
723
+ }
724
+
725
+ void c_append_frame(OBJ_PTR fmkr, FM *p, bool clip, int *ierr) {
726
+ double frame_left = convert_page_to_output_x(p, p->frame_left);
727
+ double frame_bottom = convert_page_to_output_y(p, p->frame_bottom);
728
+ double frame_width = convert_page_to_output_dx(p, p->frame_width);
729
+ double frame_height = convert_page_to_output_dy(p, p->frame_height);
730
+ double frame_right = frame_left + frame_width;
731
+ double frame_top = frame_bottom + frame_height;
732
+ c_append_rect(fmkr, p, frame_left, frame_bottom, frame_width, frame_height, ierr);
733
+ if (!clip) return;
734
+ if (frame_left > p->clip_left) p->clip_left = frame_left;
735
+ if (frame_bottom > p->clip_bottom) p->clip_bottom = frame_bottom;
736
+ if (frame_right < p->clip_right) p->clip_right = frame_right;
737
+ if (frame_top < p->clip_top) p->clip_top = frame_top;
738
+ }
739
+
740
+ void c_append_frame_to_path(OBJ_PTR fmkr, FM *p, int *ierr) {
741
+ c_append_frame(fmkr, p, false, ierr);
742
+ }
743
+
744
+ void c_fill_frame(OBJ_PTR fmkr, FM *p, int *ierr) {
745
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_frame", ierr); return; }
746
+ c_append_frame(fmkr, p, false, ierr);
747
+ c_fill(fmkr ,p, ierr);
748
+ }
749
+
750
+ void c_stroke_frame(OBJ_PTR fmkr, FM *p, int *ierr) {
751
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling stroke_frame", ierr); return; }
752
+ c_append_frame(fmkr, p, false, ierr);
753
+ c_stroke(fmkr, p, ierr);
754
+ }
755
+
756
+ void c_fill_and_stroke_frame(OBJ_PTR fmkr, FM *p, int *ierr) {
757
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling fill_and_stroke_frame", ierr); return; }
758
+ c_append_frame(fmkr, p, false, ierr);
759
+ c_fill_and_stroke(fmkr, p, ierr);
760
+ }
761
+
762
+ void c_clip_to_frame(OBJ_PTR fmkr, FM *p, int *ierr) {
763
+ if (constructing_path) { RAISE_ERROR("Sorry: must finish with current path before calling clip_to_frame", ierr); return; }
764
+ c_append_frame(fmkr, p, true, ierr);
765
+ c_clip(fmkr, p, ierr);
766
+ }