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
@@ -26,7 +26,7 @@ void Init_Font_Dictionary(void) {
26
26
  int i, num_fonts = num_pdf_standard_fonts;
27
27
  Font_Dictionary *font_info;
28
28
  for (i = 0; i < num_fonts; i++) {
29
- font_info = ALLOC(Font_Dictionary);
29
+ font_info = (Font_Dictionary *)calloc(1,sizeof(Font_Dictionary));
30
30
  font_info->afm = &afm_array[i];
31
31
  font_info->font_num = font_info->afm->font_num;
32
32
  font_info->in_use = false;
@@ -104,7 +104,7 @@ static void Record_Font_In_Use(Font_Dictionary *font_info, int font_number)
104
104
 
105
105
  #define DEBUG 0
106
106
  #define MAXSTR 100
107
- static Font_Dictionary *GetFontDict(char *font_name, int font_number) {
107
+ static Font_Dictionary *GetFontDict(char *font_name, int font_number, int *ierr) {
108
108
  Font_Dictionary *font_info;
109
109
  for (font_info = font_dictionaries; font_info != NULL; font_info = font_info->next) {
110
110
  if (strcmp(font_name, font_info->afm->font_name) == 0) {
@@ -112,23 +112,22 @@ static Font_Dictionary *GetFontDict(char *font_name, int font_number) {
112
112
  return font_info;
113
113
  }
114
114
  }
115
- rb_raise(rb_eArgError, "Sorry: invalid font name (%s)", font_name);
115
+ RAISE_ERROR_s("Sorry: invalid font name (%s)", font_name, ierr);
116
116
  return NULL;
117
117
  }
118
118
 
119
- static Font_Dictionary *GetFontInfo(int font_number)
119
+ static Font_Dictionary *GetFontInfo(int font_number, int *ierr)
120
120
  {
121
121
  Font_Dictionary *f;
122
122
  for (f = font_dictionaries; f != NULL; f = f->next) {
123
123
  if (f->font_num == font_number) { Record_Font_In_Use(f, font_number); return f; }
124
124
  }
125
125
  if (font_number > 0 && font_number <= num_predefined_fonts)
126
- return GetFontDict(predefined_Fonts[font_number], font_number);
126
+ return GetFontDict(predefined_Fonts[font_number], font_number, ierr);
127
127
  return NULL;
128
128
  }
129
129
 
130
- static int c_register_font(char *font_name)
131
- {
130
+ OBJ_PTR c_register_font(OBJ_PTR fmkr, FM *p, char *font_name, int *ierr) {
132
131
  Font_Dictionary *f;
133
132
  int i;
134
133
  for (f = font_dictionaries; f != NULL; f = f->next) {
@@ -136,22 +135,17 @@ static int c_register_font(char *font_name)
136
135
  }
137
136
  for (i = 1; i <= num_predefined_fonts; i++) {
138
137
  if (strcmp(predefined_Fonts[i], font_name)==0) {
139
- f = GetFontDict(font_name, i);
140
- if (f == NULL) rb_raise(rb_eArgError, "Error in reading font metrics for %s", font_name);
138
+ f = GetFontDict(font_name, i, ierr);
139
+ if (f == NULL) RAISE_ERROR_s("Error in reading font metrics for %s", font_name, ierr);
141
140
  return i;
142
141
  }
143
142
  }
144
- f = GetFontDict(font_name, next_available_font_number);
145
- if (f == NULL) rb_raise(rb_eArgError, "Error in reading font metrics for %s", font_name);
146
- return next_available_font_number++;
143
+ f = GetFontDict(font_name, next_available_font_number, ierr);
144
+ if (f == NULL) RAISE_ERROR_s("Error in reading font metrics for %s", font_name, ierr);
145
+ next_available_font_number++;
146
+ return Integer_New(next_available_font_number);
147
147
  }
148
148
 
149
- VALUE FM_register_font(VALUE fmkr, VALUE font_name)
150
- {
151
- font_name = rb_String(font_name);
152
- int font_num = c_register_font(RSTRING_PTR(font_name));
153
- return INT2FIX(font_num);
154
- }
155
149
 
156
150
  bool Used_Any_Fonts(void)
157
151
  {
@@ -221,10 +215,11 @@ void Write_Font_Dictionaries(void)
221
215
  }
222
216
 
223
217
  static void GetStringInfo(FM *p, int font_number, unsigned char *text, double ft_ht,
224
- double *llx_ptr, double *lly_ptr, double *urx_ptr, double *ury_ptr, double *width_ptr) {
225
- Font_Dictionary *fontinfo = GetFontInfo(font_number);
226
- if (fontinfo == NULL)
227
- rb_raise(rb_eArgError, "Sorry: invalid font number (%i): must register font before use it.", font_number);
218
+ double *llx_ptr, double *lly_ptr, double *urx_ptr, double *ury_ptr, double *width_ptr, int *ierr) {
219
+ Font_Dictionary *fontinfo = GetFontInfo(font_number, ierr);
220
+ if (*ierr != 0) return;
221
+ if (fontinfo == NULL) {
222
+ RAISE_ERROR_i("Sorry: invalid font number (%i): must register font before use it.", font_number, ierr); return; }
228
223
  unsigned char *c_ptr = text, c;
229
224
  double width = 0, llx, lly, urx, ury;
230
225
  if (fontinfo == NULL || text == NULL || text[0] == '\0') {
@@ -242,52 +237,50 @@ static void GetStringInfo(FM *p, int font_number, unsigned char *text, double ft
242
237
  }
243
238
  urx = llx + width;
244
239
  *width_ptr = width * ft_ht * 1e-3;
245
- *llx_ptr = llx * ft_ht * 1e-3;
246
- *lly_ptr = lly * ft_ht * 1e-3;
247
- *urx_ptr = urx * ft_ht * 1e-3;
248
- *ury_ptr = ury * ft_ht * 1e-3;
240
+ *llx_ptr = ft_ht * 1e-3 * llx;
241
+ *lly_ptr = ft_ht * 1e-3 * lly;
242
+ *ury_ptr = ft_ht * 1e-3 * ury;
243
+ *urx_ptr = ft_ht * 1e-3 * (urx-70.0); // adjust for extra white space on right
249
244
  }
250
245
 
251
- VALUE FM_marker_string_info(VALUE fmkr, VALUE font_number, VALUE string, VALUE scale)
252
- { // [ width, llx, lly, urx, ury ] in figure coords
253
- FM *p = Get_FM(fmkr);
254
- font_number = rb_Integer(font_number);
255
- string = rb_String(string);
256
- unsigned char *text = (unsigned char *)(RSTRING_PTR(string));
257
- scale = rb_Float(scale);
258
- double ft_ht = p->default_text_scale * NUM2DBL(scale) * p->default_font_size * ENLARGE;
246
+ OBJ_PTR c_marker_string_info(OBJ_PTR fmkr, FM *p, int fnt, unsigned char *text, double scale, int *ierr) {
247
+ double ft_ht = p->default_text_scale * scale * p->default_font_size * ENLARGE;
259
248
  int ft_height = ROUND(ft_ht);
260
249
  ft_ht = ft_height;
261
250
  double llx, lly, urx, ury, width;
262
- int fnt = NUM2INT(font_number);
263
- GetStringInfo(p, fnt, text, ft_ht, &llx, &lly, &urx, &ury, &width);
264
- VALUE result = rb_ary_new2(5);
251
+ GetStringInfo(p, fnt, text, ft_ht, &llx, &lly, &urx, &ury, &width, ierr);
252
+ if (*ierr != 0) RETURN_NIL;
253
+ OBJ_PTR result = Array_New(5);
265
254
  width = convert_output_to_figure_dx(p,width);
266
255
  llx = convert_output_to_figure_dx(p,llx);
267
256
  urx = convert_output_to_figure_dx(p,urx);
268
257
  lly = convert_output_to_figure_dy(p,lly);
269
258
  ury = convert_output_to_figure_dy(p,ury);
270
- rb_ary_store(result, 0, rb_float_new(width));
271
- rb_ary_store(result, 1, rb_float_new(llx));
272
- rb_ary_store(result, 2, rb_float_new(lly));
273
- rb_ary_store(result, 3, rb_float_new(urx));
274
- rb_ary_store(result, 4, rb_float_new(ury));
259
+ Array_Store(result, 0, Float_New(width), ierr);
260
+ Array_Store(result, 1, Float_New(llx), ierr);
261
+ Array_Store(result, 2, Float_New(lly), ierr);
262
+ Array_Store(result, 3, Float_New(urx), ierr);
263
+ Array_Store(result, 4, Float_New(ury), ierr);
264
+
275
265
  return result;
276
266
  }
277
267
 
278
268
  #define TRANSFORM_VEC(dx,dy) tmp = dx; dx = (dx) * a + (dy) * c; dy = tmp * b + (dy) * d;
279
269
 
280
- void c_rotated_string_at_points(FM *p, double rotation, int font_number, unsigned char *text, double scale,
281
- int n, double *xs, double *ys, int alignment, int justification, double horizontal_scaling, double vertical_scaling,
282
- double italic_angle, double ascent_angle)
270
+ static void c_rotated_string_at_points(
271
+ OBJ_PTR fmkr, FM *p, double rotation, int font_number, unsigned char *text, double scale,
272
+ int n, double *xs, double *ys, int alignment, int just,
273
+ double horizontal_scaling, double vertical_scaling,
274
+ double italic_angle, double ascent_angle, int *ierr)
283
275
  {
284
276
  double ft_ht = p->default_text_scale * scale * p->default_font_size * ENLARGE;
285
- int i, ft_height = ROUND(ft_ht);
277
+ int i, ft_height = ROUND(ft_ht), justification = just-1;
286
278
  ft_ht = ft_height;
287
- if (constructing_path) rb_raise(rb_eArgError, "Sorry: must not be constructing a path when show marker");
279
+ if (constructing_path) { RAISE_ERROR("Sorry: must not be constructing a path when show marker", ierr); return; }
288
280
  double llx, lly, urx, ury, width, shiftx, shifty, tmp;
289
281
  double a=horizontal_scaling, b=0.0, c=0.0, d=vertical_scaling; // the initial transform
290
- GetStringInfo(p, font_number, text, ft_ht, &llx, &lly, &urx, &ury, &width);
282
+ GetStringInfo(p, font_number, text, ft_ht, &llx, &lly, &urx, &ury, &width, ierr);
283
+ if (*ierr != 0) return;
291
284
  // translate according to justification and alignment
292
285
  // note that we use the bbox to calculate shifts so 'center' means center of bbox
293
286
  if (italic_angle != 0) {
@@ -315,14 +308,18 @@ void c_rotated_string_at_points(FM *p, double rotation, int font_number, unsigne
315
308
  shiftx *= 0.9;
316
309
  }
317
310
  break;
318
- default: rb_raise(rb_eArgError, "Sorry: invalid setting for marker justification (%i)", justification);
311
+ default:
312
+ RAISE_ERROR_i("Sorry: invalid setting for marker justification (%i)", justification, ierr);
313
+ return;
319
314
  }
320
315
  switch (alignment) {
321
316
  case ALIGNED_AT_TOP: shifty = -ury; break;
322
317
  case ALIGNED_AT_MIDHEIGHT: shifty = -(ury+lly)/2; break;
323
318
  case ALIGNED_AT_BASELINE: shifty = 0; break;
324
319
  case ALIGNED_AT_BOTTOM: shifty = -lly; break;
325
- default: rb_raise(rb_eArgError, "Sorry: invalid setting for marker alignment (%i)", alignment);
320
+ default:
321
+ RAISE_ERROR_i("Sorry: invalid setting for marker alignment (%i)", alignment, ierr);
322
+ return;
326
323
  }
327
324
  // transform the bbox
328
325
  double llx2 = llx, lly2 = lly, urx2 = urx, ury2 = ury; // if we're rotated we'll need all 4 corners of bbox
@@ -350,12 +347,14 @@ void c_rotated_string_at_points(FM *p, double rotation, int font_number, unsigne
350
347
  update_bbox(p,x+llx2, y+ury2);
351
348
  update_bbox(p,x+urx2, y+lly2);
352
349
  dx = x - prev_x; dy = y - prev_y;
353
- idx = ROUND(dx); idy = ROUND(dy);
354
- prev_x = prev_x + idx; prev_y = prev_y + idy;
350
+ //idx = ROUND(dx); idy = ROUND(dy);
351
+ //prev_x = prev_x + idx; prev_y = prev_y + idy;
352
+ prev_x = prev_x + dx; prev_y = prev_y + dy;
355
353
  if (b == 0 && c == 0 && a == 1 && d == 1) {
356
- fprintf(TF, "%i %i Td (", idx, idy);
354
+ //fprintf(TF, "%i %i Td (", idx, idy);
355
+ fprintf(TF, "%0.6f %0.6f Td (", dx, dy);
357
356
  } else { // need high precision when doing rotations
358
- fprintf(TF, "%0.6f %0.6f %0.6f %0.6f %0.6f %0.6f Tm (", a, b, c, d, dx, dy);
357
+ fprintf(TF, "%0.6f %0.6f %0.6f %0.6f %0.6f %0.6f Tm (", a, b, c, d, x, y);
359
358
  }
360
359
  while ((char_code = *cp++) != '\0') {
361
360
  if (char_code == '\\')
@@ -370,71 +369,94 @@ void c_rotated_string_at_points(FM *p, double rotation, int font_number, unsigne
370
369
  fprintf(TF, "ET\n");
371
370
  }
372
371
 
373
- VALUE FM_private_show_marker(VALUE fmkr, VALUE integer_args, VALUE stroke_width, VALUE string,
374
- VALUE x, VALUE y, VALUE x_vec, VALUE y_vec,
375
- VALUE h_scale, VALUE v_scale, VALUE scale, VALUE it_angle, VALUE ascent_angle, VALUE angle,
376
- VALUE fill_color, VALUE stroke_color)
377
- {
378
- FM *p = Get_FM(fmkr);
379
- int int_args, c, alignment, justification, fnt_num, n, mode;
372
+ void c_private_show_marker(
373
+ OBJ_PTR fmkr, FM *p, int int_args, OBJ_PTR stroke_width, OBJ_PTR string,
374
+ OBJ_PTR x, OBJ_PTR y, OBJ_PTR x_vec, OBJ_PTR y_vec,
375
+ double h_scale, double v_scale, double scale, double it_angle, double ascent_angle, double angle,
376
+ OBJ_PTR fill_color, OBJ_PTR stroke_color, int *ierr) {
377
+ int c, alignment, justification, fnt_num, n, mode;
380
378
  unsigned char *text = NULL, buff[2];
381
379
  double *xs, *ys, xloc, yloc, prev_line_width = -1;
382
380
  bool restore_fill_color = false, restore_stroke_color = false;
383
- VALUE prev_fill_color = Qnil, prev_stroke_color = Qnil;
384
- integer_args = rb_Integer(integer_args);
385
- int_args = NUM2INT(integer_args);
381
+ double stroke_color_R=0.0, stroke_color_G=0.0, stroke_color_B=0.0;
382
+ double prev_stroke_color_R, prev_stroke_color_G, prev_stroke_color_B;
383
+ double fill_color_R=0.0, fill_color_G=0.0, fill_color_B=0.0;
384
+ double prev_fill_color_R, prev_fill_color_G, prev_fill_color_B;
386
385
  c = int_args / 100000; int_args -= c * 100000;
387
386
  fnt_num = int_args / 1000; int_args -= fnt_num * 1000;
388
387
  mode = int_args / 100; int_args -= mode * 100;
389
388
  alignment = int_args / 10; int_args -= alignment * 10;
390
389
  justification = int_args;
391
- if (string == Qnil) {
392
- if (c < 0 || c > 255)
393
- rb_raise(rb_eArgError, "Sorry: invalid character code (%i) : must be between 0 and 255", c);
390
+ if (string == OBJ_NIL) {
391
+ if (c < 0 || c > 255) {
392
+ RAISE_ERROR_i("Sorry: invalid character code (%i) : must be between 0 and 255", c, ierr);
393
+ return;
394
+ }
394
395
  text = buff; text[0] = c; text[1] = '\0';
395
- if (stroke_width != Qnil) {
396
- stroke_width = rb_Float(stroke_width);
397
- double width = NUM2DBL(stroke_width);
396
+ if (stroke_width != OBJ_NIL) {
397
+ double width = Number_to_double(stroke_width, ierr);
398
+ if (*ierr != 0) return;
398
399
  prev_line_width = p->line_width; // restore it later
399
400
  fprintf(TF, "%0.6f w\n", width * ENLARGE);
400
401
  }
401
402
  } else {
402
- string = rb_String(string);
403
- text = (unsigned char *)(RSTRING_PTR(string));
403
+ text = (unsigned char *)(String_Ptr(string,ierr));
404
+ if (*ierr != 0) return;
404
405
  }
405
406
  fprintf(TF, "%d Tr\n", mode);
406
- if (stroke_color != Qnil && stroke_color != p->stroke_color &&
407
- (mode == STROKE || mode == FILL_AND_STROKE || mode == STROKE_AND_CLIP || mode == FILL_STROKE_AND_CLIP)) {
408
- prev_stroke_color = p->stroke_color; restore_stroke_color = true;
409
- FM_stroke_color_set(fmkr, stroke_color);
407
+ if (stroke_color != OBJ_NIL &&
408
+ (mode == STROKE || mode == FILL_AND_STROKE ||
409
+ mode == STROKE_AND_CLIP || mode == FILL_STROKE_AND_CLIP)) {
410
+ Unpack_RGB(stroke_color, &stroke_color_R, &stroke_color_G, &stroke_color_B, ierr);
411
+ if (*ierr != 0) return;
412
+ if (stroke_color_R != p->stroke_color_R ||
413
+ stroke_color_G != p->stroke_color_G ||
414
+ stroke_color_B != p->stroke_color_B) {
415
+ prev_stroke_color_R = p->stroke_color_R;
416
+ prev_stroke_color_G = p->stroke_color_G;
417
+ prev_stroke_color_B = p->stroke_color_B;
418
+ restore_stroke_color = true;
419
+ c_stroke_color_set_RGB(fmkr, p, stroke_color_R, stroke_color_G, stroke_color_B, ierr);
420
+ if (*ierr != 0) return;
421
+ }
410
422
  }
411
- if (fill_color != Qnil && fill_color != p->fill_color &&
412
- (mode == FILL || mode == FILL_AND_STROKE || mode == FILL_AND_CLIP || mode == FILL_STROKE_AND_CLIP)) {
413
- prev_fill_color = p->fill_color; restore_fill_color = true;
414
- FM_fill_color_set(fmkr, fill_color);
423
+ if (fill_color != OBJ_NIL &&
424
+ (mode == FILL || mode == FILL_AND_STROKE ||
425
+ mode == FILL_AND_CLIP || mode == FILL_STROKE_AND_CLIP)) {
426
+ Unpack_RGB(fill_color, &fill_color_R, &fill_color_G, &fill_color_B, ierr);
427
+ if (*ierr != 0) return;
428
+ if (fill_color_R != p->fill_color_R ||
429
+ fill_color_G != p->fill_color_G ||
430
+ fill_color_B != p->fill_color_B) {
431
+ prev_fill_color_R = p->fill_color_R;
432
+ prev_fill_color_G = p->fill_color_G;
433
+ prev_fill_color_B = p->fill_color_B;
434
+ restore_fill_color = true;
435
+ c_fill_color_set_RGB(fmkr, p, fill_color_R, fill_color_G, fill_color_B, ierr);
436
+ if (*ierr != 0) return;
437
+ }
415
438
  }
416
- h_scale = rb_Float(h_scale);
417
- v_scale = rb_Float(v_scale);
418
- scale = rb_Float(scale);
419
- it_angle = rb_Float(it_angle);
420
- ascent_angle = rb_Float(ascent_angle);
421
- angle = rb_Float(angle);
422
- if (x == Qnil) {
439
+ if (x == OBJ_NIL) {
423
440
  long xlen, ylen;
424
- xs = Dvector_Data_for_Read(x_vec, &xlen);
425
- ys = Dvector_Data_for_Read(y_vec, &ylen);
426
- if (xlen != ylen) rb_raise(rb_eArgError, "Sorry: must have same number xs and ys for showing markers");
427
- if (xlen <= 0) return fmkr;
441
+ xs = Vector_Data_for_Read(x_vec, &xlen, ierr);
442
+ if (*ierr != 0) return;
443
+ ys = Vector_Data_for_Read(y_vec, &ylen, ierr);
444
+ if (*ierr != 0) return;
445
+ if (xlen != ylen) {
446
+ RAISE_ERROR("Sorry: must have same number xs and ys for showing markers", ierr); return; }
447
+ if (xlen <= 0) return;
428
448
  n = xlen;
429
449
  } else {
430
- x = rb_Float(x); xloc = NUM2DBL(x); xs = &xloc;
431
- y = rb_Float(y); yloc = NUM2DBL(y); ys = &yloc;
450
+ xloc = Number_to_double(x, ierr); xs = &xloc;
451
+ yloc = Number_to_double(y, ierr); ys = &yloc;
452
+ if (*ierr != 0) return;
432
453
  n = 1;
433
454
  }
434
- c_rotated_string_at_points(p, NUM2DBL(angle), fnt_num, text, NUM2DBL(scale), n, xs, ys,
435
- alignment, justification, NUM2DBL(h_scale), NUM2DBL(v_scale), NUM2DBL(it_angle), NUM2DBL(ascent_angle));
436
- if (prev_line_width >= 0) c_line_width_set(p, prev_line_width);
437
- if (restore_fill_color) FM_fill_color_set(fmkr, prev_fill_color);
438
- if (restore_stroke_color) FM_stroke_color_set(fmkr, prev_stroke_color);
439
- return fmkr;
455
+ c_rotated_string_at_points(fmkr, p, angle, fnt_num, text, scale, n, xs, ys,
456
+ alignment, justification, h_scale, v_scale, it_angle, ascent_angle, ierr);
457
+ if (prev_line_width >= 0) c_line_width_set(fmkr, p, prev_line_width, ierr);
458
+ if (restore_fill_color)
459
+ c_fill_color_set_RGB(fmkr, p, prev_fill_color_R, prev_fill_color_G, prev_fill_color_B, ierr);
460
+ if (restore_stroke_color)
461
+ c_stroke_color_set_RGB(fmkr, p, prev_stroke_color_R, prev_stroke_color_G, prev_stroke_color_B, ierr);
440
462
  }
@@ -0,0 +1,524 @@
1
+ /* texout.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
+
24
+ #define RADIANS_TO_DEGREES (180.0 / PI)
25
+
26
+ static FILE *fp; // for the TeX file
27
+
28
+ /* TeX text */
29
+
30
+ void c_rescale_text(OBJ_PTR fmkr, FM *p, double scaling_factor, int *ierr) {
31
+ double scale = scaling_factor * p->default_text_scale;
32
+ if (scaling_factor <= 0) { RAISE_ERROR("Sorry: text scaling must be positive", ierr); return; }
33
+ p->default_text_height_dx *= scaling_factor;
34
+ p->default_text_height_dy *= scaling_factor;
35
+ p->default_text_scale = scale;
36
+ }
37
+
38
+ static int String_Is_Blank(char *str) {
39
+ char c;
40
+ if (str == NULL) return 1;
41
+ while (1) {
42
+ c = *str++;
43
+ if (c == '\0') return 1;
44
+ if (!isspace(c)) break;
45
+ }
46
+ return 0;
47
+ }
48
+
49
+ static OBJ_PTR Get_Measure_Hash(OBJ_PTR fmkr, OBJ_PTR measure_name)
50
+ {
51
+ OBJ_PTR value;
52
+ int i;
53
+ OBJ_PTR measures_info = Obj_Attr_Get(fmkr, measures_info_ID, &i);
54
+ if(measure_name == OBJ_NIL) {
55
+ return OBJ_NIL;
56
+ }
57
+ if(! Hash_Has_Key_Obj(measures_info, measure_name)) {
58
+ value = Hash_New();
59
+ Hash_Set_Obj_Obj(measures_info, measure_name, value);
60
+ }
61
+ else
62
+ value = Hash_Get_Obj_Obj(measures_info, measure_name);
63
+ return value;
64
+ }
65
+
66
+
67
+ static void tex_show_rotated_text(OBJ_PTR fmkr, FM *p, char *text,
68
+ double x, double y, double scale,
69
+ double angle, int justification,
70
+ int alignment, OBJ_PTR measure_name)
71
+ { // x and y are the device coords for the reference point of the text
72
+ char ref, jst;
73
+ double ft_ht, sz;
74
+ int dummy;
75
+ OBJ_PTR measures = Get_Measure_Hash(fmkr, measure_name);
76
+ if (String_Is_Blank(text)) return; /* blank strings break TeX! */
77
+ scale *= p->default_text_scale;
78
+ ft_ht = scale * p->default_font_size;
79
+ sz = ft_ht * ENLARGE;
80
+ ref = (alignment == ALIGNED_AT_BASELINE)? 'B' :
81
+ (alignment == ALIGNED_AT_BOTTOM)? 'b' :
82
+ (alignment == ALIGNED_AT_TOP)? 't' : 'c';
83
+ if (justification == 0) jst = 'c';
84
+ else if (justification > 0) jst = 'r';
85
+ else jst = 'l';
86
+ bbox_llx = MIN(bbox_llx, x - sz);
87
+ bbox_lly = MIN(bbox_lly, y - sz);
88
+ bbox_urx = MAX(bbox_urx, x + sz);
89
+ bbox_ury = MAX(bbox_ury, y + sz);
90
+ if (angle != 0.0)
91
+ fprintf(fp,"\\put(%d,%d){\\rotatebox{%.1f}{\\scalebox{%.2f}{\\makebox(0,0)[%c%c]{",
92
+ ROUND(x), ROUND(y), angle, scale, jst, ref);
93
+ else
94
+ fprintf(fp,"\\put(%d,%d){\\scalebox{%.2f}{\\makebox(0,0)[%c%c]{",
95
+ ROUND(x), ROUND(y), scale, jst, ref);
96
+ if(measure_name != OBJ_NIL)
97
+ fprintf(fp, "{\\tiogameasure{%s}{\\tiogasetfont{}",
98
+ CString_Ptr(measure_name,&dummy));
99
+ else
100
+ fprintf(fp, "{{\\tiogasetfont{}");
101
+
102
+ /* Moving the \BS out of the potential \tiogameasure input, so it does
103
+ not disturb the measure.
104
+ */
105
+ fprintf(fp, (alignment == ALIGNED_AT_BASELINE)? "%s}\\BS" : "%s}", text);
106
+ fprintf(fp, angle != 0? "}}}}}\n" : "}}}}\n");
107
+
108
+ /* Now, we save measures informations if applicable*/
109
+ if(measures != OBJ_NIL) {
110
+ Hash_Set_Double(measures, "scale", scale);
111
+ /* [xy]anchor are saved in postscript points */
112
+ Hash_Set_Double(measures, "xanchor", ROUND(x) / ENLARGE);
113
+ Hash_Set_Double(measures, "yanchor", ROUND(y) / ENLARGE);
114
+ Hash_Set_Double(measures, "angle", angle);
115
+ Hash_Set_Double(measures, "just", justification);
116
+ Hash_Set_Double(measures, "align", alignment);
117
+ }
118
+ }
119
+
120
+ static void Convert_Frame_Text_Position_To_Output_Location(FM *p, int frame_side, double offset,
121
+ double fraction, double *xp, double *yp, double *base_angle, char *text, int *ierr)
122
+ {
123
+ double page_x, page_y;
124
+ switch (frame_side) {
125
+ case LEFT:
126
+ page_x = p->page_width * p->frame_left - offset;
127
+ page_y = p->page_height * (p->frame_bottom + fraction * p->frame_height);
128
+ *base_angle = 90;
129
+ break;
130
+ case RIGHT:
131
+ page_x = p->page_width * p->frame_right + offset;
132
+ page_y = p->page_height * (p->frame_bottom + fraction * p->frame_height);
133
+ *base_angle = 90;
134
+ break;
135
+ case AT_X_ORIGIN:
136
+ if (0.0 > p->bounds_xmax || 0.0 < p->bounds_xmin) {
137
+ RAISE_ERROR_s("Sorry: x origin is not part of plot for (%s)", text, ierr); return; }
138
+ page_x = convert_figure_to_output_x(p, 0.0);
139
+ if (p->xaxis_reversed) offset = -offset;
140
+ page_x += offset;
141
+ page_y = p->page_height * (p->frame_bottom + fraction * p->frame_height);
142
+ *base_angle = 90;
143
+ break;
144
+ case TOP:
145
+ page_y = p->page_height * p->frame_top + offset;
146
+ page_x = p->page_width * (p->frame_left + fraction * p->frame_width);
147
+ *base_angle = 0;
148
+ break;
149
+ case BOTTOM:
150
+ page_y = p->page_height * p->frame_bottom - offset;
151
+ page_x = p->page_width * (p->frame_left + fraction * p->frame_width);
152
+ *base_angle = 0;
153
+ break;
154
+ case AT_Y_ORIGIN:
155
+ if (0.0 > p->bounds_ymax || 0.0 < p->bounds_ymin) {
156
+ RAISE_ERROR_s("Sorry: y origin is not part of plot for (%s)", text, ierr); return; }
157
+ page_y = convert_figure_to_output_y(p, 0.0);
158
+ if (p->yaxis_reversed) offset = -offset;
159
+ page_y += offset;
160
+ page_x = p->page_width * (p->frame_left + fraction * p->frame_width);
161
+ *base_angle = 0;
162
+ break;
163
+ default:
164
+ RAISE_ERROR_s("Sorry: invalid parameter for frame side in show text (%s)", text, ierr);
165
+ return;
166
+ }
167
+ *xp = p->page_left + page_x; *yp = p->page_bottom + page_y;
168
+ }
169
+
170
+ void c_show_rotated_text(OBJ_PTR fmkr, FM *p, char *text, int frame_side, double shift, double fraction,
171
+ double scale, double angle, int justification, int alignment, OBJ_PTR measure_name, int *ierr) {
172
+ double x, y, base_angle, ft_ht = p->default_text_scale * scale * p->default_font_size;
173
+ Convert_Frame_Text_Position_To_Output_Location(p, frame_side, shift*ft_ht*ENLARGE, fraction, &x, &y, &base_angle, text, ierr);
174
+ tex_show_rotated_text(fmkr, p, text, x, y, scale, angle + base_angle, justification, alignment, measure_name);
175
+ }
176
+
177
+
178
+ void c_show_rotated_label(OBJ_PTR fmkr, FM *p, char *text,
179
+ double xloc, double yloc, double scale, double angle, int justification, int alignment, OBJ_PTR measure_name, int *ierr) {
180
+ tex_show_rotated_text(fmkr, p, text, convert_figure_to_output_x(p, xloc), convert_figure_to_output_y(p, yloc),
181
+ scale, angle, justification, alignment, measure_name);
182
+ }
183
+
184
+ OBJ_PTR c_check_label_clip(OBJ_PTR fmkr, FM *p, double x, double y, int *ierr) {
185
+ x = convert_figure_to_frame_x(p,x);
186
+ y = convert_figure_to_frame_y(p,y);
187
+ if (x < p->label_left_margin || y < p->label_bottom_margin ||
188
+ 1.0 - x < p->label_right_margin || 1.0 - y < p->label_top_margin) RETURN_FALSE;
189
+ RETURN_TRUE;
190
+ }
191
+
192
+ /* TeX File Management */
193
+
194
+ static long cur_pos;
195
+
196
+ static void Get_tex_name(char *ofile, char *filename, int maxlen)
197
+ {
198
+ char *dot;
199
+ strncpy(ofile, filename, maxlen);
200
+ dot = strrchr(ofile,'.');
201
+ if (dot != NULL) dot[0] = '\0';
202
+ strcat(ofile, "_figure.txt");
203
+ }
204
+
205
+ void Open_tex(OBJ_PTR fmkr, char *filename, bool quiet_mode, int *ierr)
206
+ {
207
+ char ofile[300];
208
+ Get_tex_name(ofile, filename, 300);
209
+ fp = fopen(ofile, "w");
210
+ fprintf(fp,"\\setlength{\\unitlength}{%fbp}%%\n", 1.0/ENLARGE);
211
+ cur_pos = ftell(fp);
212
+ fprintf(fp,"\\begin{picture}(xxxxxx,xxxxxx) %% (width,height)(xoffset,yoffset) -- Adjust the 2nd pair for registration adjustments\n"); /* this line is rewritten at the end */
213
+ fprintf(fp,"\\def\\BS{\\phantom{\\Huge\\scalebox{0}[2]{\\hbox{\\rotatebox{180}{O}O}}}}\n");
214
+ // graphicx seems to vertically align baseline (B) like center (c),
215
+ // so we add BS (Big Strut) to make them look the same
216
+ }
217
+
218
+ void Close_tex(OBJ_PTR fmkr, bool quiet_mode, int *ierr)
219
+ {
220
+ double x, y, xoff, yoff;
221
+ x = bbox_urx - bbox_llx; if (x < 0) x = bbox_urx = bbox_llx = 0;
222
+ y = bbox_ury - bbox_lly; if (y < 0) y = bbox_ury = bbox_lly = 0;
223
+ xoff = bbox_llx + Get_tex_xoffset(fmkr,ierr)*ENLARGE;
224
+ yoff = bbox_lly + Get_tex_yoffset(fmkr,ierr)*ENLARGE;
225
+ fprintf(fp,"\\end{picture}");
226
+ fseek(fp, cur_pos, SEEK_SET);
227
+ fprintf(fp,"\\begin{picture}(%03d,%03d)(%02d,%d)", ROUND(x), ROUND(y), ROUND(xoff), ROUND(yoff));
228
+ fclose(fp);
229
+ }
230
+
231
+
232
+ static void Write_preview_header(OBJ_PTR fmkr, FILE *file, int *ierr) {
233
+ fprintf(file, "\\documentclass{%s}\n\n", Get_tex_preview_documentclass(fmkr,ierr));
234
+ /* we print out the preamble generated from tioga.sty.in */
235
+ fprintf(file, "%% Tioga preamble generated from tioga.sty.in\n");
236
+ fprintf(file, "%s\n", Get_tex_preview_generated_preamble(fmkr,ierr));
237
+ fprintf(file, "%% User-specified preamble\n");
238
+ fprintf(file, "%s\n\n", Get_tex_preamble(fmkr,ierr));
239
+ fprintf(file, "%% Command to format numeric labels on xaxis\n");
240
+ fprintf(file, "\\newcommand{\\tiogaxaxisnumericlabel}[1]{%s}\n\n", Get_xaxis_numeric_label_tex(fmkr,ierr));
241
+ fprintf(file, "%% Command to format numeric labels on yaxis\n");
242
+ fprintf(file, "\\newcommand{\\tiogayaxisnumericlabel}[1]{%s}\n\n", Get_yaxis_numeric_label_tex(fmkr,ierr));
243
+ fprintf(file, "%% Color constants definitions\n");
244
+ fprintf(file, "%s\n\n", CString_Ptr(COLOR_PREAMBLE(fmkr,ierr),ierr));
245
+ fprintf(file, "%% Set page margins, page size and orientation.\n");
246
+ fprintf(file, "\t\\usepackage[pdftex,tmargin=0pt,lmargin=0pt,"
247
+ "rmargin=0pt,bmargin=0pt,\n");
248
+ fprintf(file, "\tpaperwidth=%s,paperheight=%s,\n",
249
+ Get_tex_preview_paper_width(fmkr,ierr),
250
+ Get_tex_preview_paper_height(fmkr,ierr));
251
+ fprintf(file, "\thoffset=%s,voffset=%s\n",
252
+ Get_tex_preview_hoffset(fmkr,ierr),
253
+ Get_tex_preview_voffset(fmkr,ierr));
254
+ fprintf(file, "\t]{geometry}\n");
255
+
256
+ fprintf(file, "\n%% We need the graphicx package and the calc package.\n");
257
+ fprintf(file, "\t\\usepackage{graphicx}\n");
258
+ fprintf(file, "\t\\usepackage{calc}\n\n");
259
+ fprintf(file, "\t%% This is necessary to avoid getting the picture on the second page\n");
260
+ fprintf(file, "\t\\topskip=0pt\n\n");
261
+
262
+ /* now, the commands to customize the font used */
263
+ fprintf(file, "\\settiogafontsize[10pt]{%s}\n", Get_tex_fontsize(fmkr,ierr));
264
+ fprintf(file, "\\settiogafontfamily{\\%s}\n", Get_tex_fontfamily(fmkr,ierr));
265
+ fprintf(file, "\\settiogafontseries{\\%s}\n", Get_tex_fontseries(fmkr,ierr));
266
+ fprintf(file, "\\settiogafontshape{\\%s}\n", Get_tex_fontshape(fmkr,ierr));
267
+ }
268
+
269
+
270
+ static void Write_figure_command(OBJ_PTR fmkr, char *simple_name, FILE *file, int *ierr) {
271
+ char *minwhitespace;
272
+
273
+ if (Get_tex_preview_fullpage(fmkr,ierr)) {
274
+ minwhitespace = Get_tex_preview_minwhitespace(fmkr,ierr);
275
+ if (minwhitespace == NULL) {
276
+ fprintf(file, "\\tiogafigurefullpage{%s}\n", simple_name);
277
+ } else {
278
+ fprintf(file, "\\tiogafigurefullpage[%s]{%s}\n", minwhitespace, simple_name);
279
+ }
280
+ } else {
281
+ const char * command = Get_tex_preview_tiogafigure_command(fmkr,ierr);
282
+ if(strcmp(command, "tiogafigureshow")) {
283
+ fprintf(file, "\\%s{%s}{%s}{%s}\n", Get_tex_preview_tiogafigure_command(fmkr,ierr), simple_name,
284
+ Get_tex_preview_figure_width(fmkr,ierr), Get_tex_preview_figure_height(fmkr,ierr));
285
+ } else { /* no need for extra arguments for tiogafigureshow */
286
+ fprintf(file, "\\%s{%s}\n", Get_tex_preview_tiogafigure_command(fmkr,ierr), simple_name);
287
+ }
288
+ }
289
+ }
290
+
291
+
292
+ void Create_wrapper(OBJ_PTR fmkr, char *fname, bool quiet_mode, int *ierr)
293
+ { // create the wrapper TeX file to combine the text and graphics to make a figure
294
+ char *dot;
295
+ char tex_fname[100], base_name[100], simple_name[100];
296
+ FILE *file;
297
+ if ((dot=strrchr(fname,'.')) != NULL) {
298
+ strncpy(base_name, fname, dot-fname); base_name[dot-fname] = '\0';
299
+ snprintf(tex_fname, sizeof(tex_fname), "%s.tex", base_name);
300
+ }
301
+ else {
302
+ strcpy(base_name, fname);
303
+ snprintf(tex_fname, sizeof(tex_fname), "%s.tex", fname);
304
+ }
305
+ if ((dot=strrchr(base_name,'/')) != NULL) {
306
+ strcpy(simple_name, dot+1);
307
+ }
308
+ else {
309
+ strcpy(simple_name, base_name);
310
+ }
311
+ file = fopen(tex_fname, "w");
312
+ fprintf(file, "%% Tioga preview LaTeX file for %s_figure.pdf and %s_figure.txt\n\n", base_name, base_name);
313
+
314
+ Write_preview_header(fmkr, file, ierr);
315
+
316
+ fprintf(file, "\n%% Here's the page with the figure.\n");
317
+ fprintf(file, "\\begin{document}\n");
318
+ fprintf(file, "\\pagestyle{%s}\n", Get_tex_preview_pagestyle(fmkr,ierr));
319
+ /* necessary to get the position right */
320
+ fprintf(file, "\\noindent");
321
+ Write_figure_command(fmkr, simple_name, file, ierr);
322
+ fprintf(file, "\\end{document}\n");
323
+ fclose(file);
324
+ }
325
+
326
+ void Init_tex(int *ierr)
327
+ {
328
+ }
329
+
330
+ void Rename_tex(char *oldname, char *newname, int *ierr)
331
+ {
332
+ char old_ofile[300], new_ofile[300];
333
+ Get_tex_name(old_ofile, oldname, 300);
334
+ Get_tex_name(new_ofile, newname, 300);
335
+ rename(old_ofile, new_ofile); // from stdio.h
336
+ }
337
+
338
+ void private_make_portfolio(char *name, OBJ_PTR fignums, OBJ_PTR fignames, int *ierr)
339
+ {
340
+ FILE *file;
341
+ int i, len, numfigs, j;
342
+ char tex_fname[256];
343
+ snprintf(tex_fname, sizeof(tex_fname), "%s.tex", name);
344
+ file = fopen(tex_fname, "w");
345
+ if (file == NULL) {
346
+ RAISE_ERROR_s("Sorry: can't open %s.\n", tex_fname, ierr); return; }
347
+ fprintf(file, "%% Tioga Portfolio %s\n\n", name);
348
+ fprintf(file, "\\documentclass{article}\n");
349
+ fprintf(file, "\\usepackage{pdfpages}\n");
350
+ fprintf(file, "\\begin{document}\n");
351
+ fprintf(file, "%% Start of figures, one per page\n\n");
352
+ len = Array_Len(fignames,ierr);
353
+ if (fignums == OBJ_NIL) {
354
+ for (i=0; i < len; i++) {
355
+ fprintf(file, "\\includepdf{%s.pdf}\n", Get_String(fignames, i, ierr));
356
+ if (*ierr != 0) return;
357
+ }
358
+ } else {
359
+ numfigs = Array_Len(fignums,ierr);
360
+ if (*ierr != 0) return;
361
+ for (i=0; i < numfigs; i++) {
362
+ OBJ_PTR n = Array_Entry(fignums,i,ierr);
363
+ if (*ierr != 0) return;
364
+ j = Number_to_int(n,ierr);
365
+ if (j >= 0 && j < len) {
366
+ fprintf(file, "\\includepdf{%s.pdf}\n", Get_String(fignames, j, ierr));
367
+ if (*ierr != 0) return;
368
+ }
369
+ else {
370
+ fclose(file);
371
+ RAISE_ERROR("Requested figure numbers must be >= 0 and < num_figures.", ierr);
372
+ return;
373
+ }
374
+ }
375
+ }
376
+ fprintf(file, "\n\\end{document}\n");
377
+ fclose(file);
378
+ }
379
+
380
+
381
+ /*
382
+ Stores and transforms measures as printed by pdflatex.
383
+
384
+ Takes sizes in bp.
385
+
386
+ */
387
+ void c_save_measure(OBJ_PTR fmkr, OBJ_PTR measure_name,
388
+ double width, double height, double depth)
389
+ {
390
+ double angle, scale;
391
+ int just, align;
392
+ /* Page coordinates in bp before applying rotation ! */
393
+ double xl,xr,yt,yb;
394
+ double xa,ya;
395
+ OBJ_PTR measures = Get_Measure_Hash(fmkr, measure_name);
396
+ int dummy;
397
+
398
+ /* The following really should not happen */
399
+ if(measures == OBJ_NIL) {
400
+ fprintf(stderr, "Warning: got hash = OBJ_NIL in %s, line %d\n",
401
+ __FILE__, __LINE__);
402
+ return;
403
+ }
404
+
405
+ /* Storing measured sizes */
406
+ Hash_Set_Double(measures, "tex_measured_width", width);
407
+ Hash_Set_Double(measures, "tex_measured_height", height);
408
+ Hash_Set_Double(measures, "tex_measured_depth", depth);
409
+
410
+ angle = Hash_Get_Double(measures, "angle");
411
+ scale = Hash_Get_Double(measures, "scale");
412
+ just = Hash_Get_Double(measures, "just");
413
+ align = Hash_Get_Double(measures, "align");
414
+
415
+ /* Setting the appropriate scale */
416
+ width *= scale;
417
+ height *= scale;
418
+ depth *= scale;
419
+ /* Now setting the width and height in */
420
+ Hash_Set_Double(measures, "width", width);
421
+ Hash_Set_Double(measures, "height", height);
422
+ Hash_Set_Double(measures, "depth", depth);
423
+
424
+ xa = Hash_Get_Double(measures, "xanchor");
425
+ ya = Hash_Get_Double(measures, "yanchor");
426
+
427
+ /* Now, we try to compute the precise position of
428
+ the points of the box surrounding the text.
429
+ */
430
+
431
+ /* First, before rotation: */
432
+ switch(just) {
433
+ case 1: /* Right-justified */
434
+ xr = xa;
435
+ xl = xa - width;
436
+ break;
437
+ case 0: /* Centered */
438
+ xr = xa + width/2;
439
+ xl = xa - width/2;
440
+ break;
441
+ case -1: /* Left-justified */
442
+ xl = xa;
443
+ xr = xa + width;
444
+ break;
445
+ default:
446
+ fprintf(stderr, "Invalid justification = %d at %s, line %d\n",
447
+ just, __FILE__, __LINE__);
448
+ xl = xa;
449
+ xr = xa + width/2;
450
+ }
451
+
452
+ /* First, before rotation: */
453
+ switch(align) {
454
+ case ALIGNED_AT_BASELINE:
455
+ yt = ya + height;
456
+ yb = ya - depth;
457
+ break;
458
+ case ALIGNED_AT_BOTTOM:
459
+ yt = ya + height + depth;
460
+ yb = ya;
461
+ break;
462
+ case ALIGNED_AT_TOP:
463
+ yb = ya - height - depth;
464
+ yt = ya;
465
+ break;
466
+ default: /* Centered */
467
+ yb = ya - 0.5*(height + depth);
468
+ yt = ya + 0.5*(height + depth);
469
+ }
470
+
471
+ /* Now, rotation */
472
+ if(angle == 0.0) {
473
+ /* xbl = x of 'bottom left' */
474
+ Hash_Set_Double(measures, "xbl", xl);
475
+ Hash_Set_Double(measures, "ybl", yb);
476
+ Hash_Set_Double(measures, "xtl", xl);
477
+ Hash_Set_Double(measures, "ytl", yt);
478
+ Hash_Set_Double(measures, "xbr", xr);
479
+ Hash_Set_Double(measures, "ybr", yb);
480
+ Hash_Set_Double(measures, "xtr", xr);
481
+ Hash_Set_Double(measures, "ytr", yt);
482
+ }
483
+ else {
484
+ double s = - sin(angle * PI/180);
485
+ double c = cos(angle * PI/180);
486
+ Hash_Set_Double(measures, "xbl",
487
+ xa + (xl-xa)*c + (yb - ya) * s);
488
+ Hash_Set_Double(measures, "ybl",
489
+ ya - (xl-xa)*s + (yb - ya) * c);
490
+ Hash_Set_Double(measures, "xtl",
491
+ xa + (xl-xa)*c + (yt - ya) * s);
492
+ Hash_Set_Double(measures, "ytl",
493
+ ya - (xl-xa)*s + (yt - ya) * c);
494
+ Hash_Set_Double(measures, "xbr",
495
+ xa + (xr-xa)*c + (yb - ya) * s);
496
+ Hash_Set_Double(measures, "ybr",
497
+ ya - (xr-xa)*s + (yb - ya) * c);
498
+ Hash_Set_Double(measures, "xtr",
499
+ xa + (xr-xa)*c + (yt - ya) * s);
500
+ Hash_Set_Double(measures, "ytr",
501
+ ya - (xr-xa)*s + (yt - ya) * c);
502
+ }
503
+
504
+ /* We transform coordinates into an array
505
+ (topleft, topright, botright, botleft)
506
+ of arrays (xy) of doubles
507
+ */
508
+ OBJ_PTR points = Array_New(0);
509
+ OBJ_PTR current_point;
510
+ int i;
511
+ for(i = 0; i < 8; i++) {
512
+ char buf[4];
513
+ if(! (i % 2)) {
514
+ current_point = Array_New(0);
515
+ Array_Push(points, current_point, &dummy);
516
+ }
517
+ snprintf(buf, sizeof(buf), "%c%c%c",
518
+ (i%2 ? 'y' : 'x'),
519
+ (i/4 ? 't' : 'b'),
520
+ ((i >= 2) && (i < 6) ? 'r' : 'l'));
521
+ Array_Push(current_point, Hash_Get_Obj(measures, buf), &dummy);
522
+ }
523
+ Hash_Set_Obj(measures, "points", points);
524
+ }