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
@@ -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
+ }