ARB
AW_print.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : AW_print.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include "aw_root.hxx"
12 #include "aw_common.hxx"
13 #include "aw_xfont.hxx"
14 #include "aw_rgb.hxx"
15 
16 #include <arb_msg.h>
17 
18 #include <map>
19 #include <list>
20 #include <vector>
21 #include <string>
22 
23 using namespace AW;
24 using namespace std;
25 
26 #define XFIG_DEFAULT_COLOR_COUNT 32 // colors "hardcoded" in fig format
27 #define XFIG_USER_COLOR_COUNT 512 // restriction defined by fig format
28 
29 #define XFIG_USER_COLOR_FIRST XFIG_DEFAULT_COLOR_COUNT
30 #define XFIG_USER_COLOR_LAST (XFIG_USER_COLOR_FIRST+XFIG_USER_COLOR_COUNT-1)
31 
32 // -------------------
33 // Spoolable
34 
35 struct Spoolable {
36  virtual ~Spoolable() {}
37 
38  virtual const char *text() const = 0;
39  virtual const AW_rgb *rgb() const = 0;
40 };
41 
42 class SpoolableString : public Spoolable {
43  string s;
44 public:
45  SpoolableString(const char *txt) : s(txt) {}
46 
47  const char *text() const OVERRIDE { return s.c_str(); }
48  const AW_rgb *rgb() const OVERRIDE { return NULp; }
49 };
50 class SpoolableColor : public Spoolable {
51  AW_rgb color;
52 public:
53  SpoolableColor(const AW_rgb& color_) : color(color_) {}
54 
55  const char *text() const OVERRIDE { return NULp; }
56  const AW_rgb *rgb() const OVERRIDE { return &color; }
57 };
58 
60 
61 // ---------------------
62 // color mapping
63 
64 static AW_rgb figStdColors[32] = {
65  // color names were taken from xfig color chooser.
66  // corresponding color values were taken from X11 source code:
67  // https://cgit.freedesktop.org/xorg/xserver/tree/os/oscolor.c
68 
69  0x000000, // Black [index 0]
70  0x0000ff, // Blue
71  0x00ff00, // Green
72  0x00ffff, // Cyan
73  0xff0000, // Red
74  0xff00ff, // Magenta
75  0xffff00, // Yellow
76  0xffffff, // White
77  0x00008b, // Blue4
78  0x0000cd, // Blue3
79  0x0000ee, // Blue2
80  0xadd8e6, // LtBlue
81  0x008b00, // Green4
82  0x00cd00, // Green3
83  0x00ee00, // Green2
84  0x008b8b, // Cyan4
85  0x00cdcd, // Cyan3
86  0x00eeee, // Cyan2
87  0x8b0000, // Red4
88  0xcd0000, // Red3
89  0xee0000, // Red2
90  0x8b008b, // Magenta4
91  0xcd00cd, // Magenta3
92  0xee00ee, // Magenta2
93  0x8b2323, // Brown4
94  0xcd3333, // Brown3
95  0xee3b3b, // Brown2
96  0x8b636c, // Pink4
97  0xcd919e, // Pink3
98  0xeea9b8, // Pink2
99  0xffc0cb, // Pink
100  0xffd700, // Gold [index 31]
101 };
102 
103 class UsedColor {
104  int count; // how often color occurred (=weight)
105  int index; // xfig color index (-2 = not assigned; -1 .. 31 = fixed xfig color; 32..543 = user defined color)
106 
107  static const int NOT_ASSIGNED = -2;
108 
109 public:
110  UsedColor() : count(0), index(NOT_ASSIGNED) {}
111  explicit UsedColor(int idx) : count(0), index(idx) {} // used to add figStdColors
112 
113  void inc() { ++count; }
114  void addCount(int toAdd) { count += toAdd; }
115  int getCount() const { return count; }
116 
117  bool isAssigned() const { return index != NOT_ASSIGNED; }
118  bool isStdColor() const { return index>=0 && index<XFIG_USER_COLOR_FIRST; }
119 
120  void assign(int idx) {
121  aw_assert(!isAssigned());
122  aw_assert(idx>=XFIG_USER_COLOR_FIRST && idx<=XFIG_USER_COLOR_LAST); // only allow to assign user colors
123  index = idx;
124  aw_assert(isAssigned());
125  }
126 
127  int getIndex() const { aw_assert(isAssigned()); return index; }
128 };
129 
130 inline double colorDistSquare(const AW_rgb& col1, const AW_rgb& col2) {
132  return diff.r()*diff.r() + diff.g()*diff.g() + diff.b()*diff.b();
133 }
134 
135 class ColorMap {
136  // maps RGB values to xfig color indices
137  typedef map<AW_rgb,UsedColor> ColMap;
138  typedef map<AW_rgb,AW_rgb> Remap; // colors -> replaced by different color
139 
140  ColMap color;
141  Remap replaced;
142 
143  AW_rgb findCheapestReplaceableColor(AW_rgb *replaceBy) {
144  AW_rgb cheapest = AW_NO_COLOR;
145  double penalty = numeric_limits<float>::max();
146 
147  for (ColMap::const_iterator i = color.begin(); i != color.end(); ++i) {
148  const AW_rgb& col1 = i->first;
149  if (i->second.isStdColor()) continue; // do not attempt to replace standard colors
150 
151  const int amount = i->second.getCount();
152  aw_assert(amount>0); // otherwise color should not appear in table
153 
154  for (ColMap::const_iterator j = color.begin(); j != color.end(); ++j) {
155  const AW_rgb& col2 = j->first;
156 
157  if (&col1 != &col2) {
158  double currPenalty = amount*colorDistSquare(col1, col2);
159 #if defined(DEBUG) && 0
160  fprintf(stderr, "replace %s ", AW_rgb16(col1).ascii());
161  fprintf(stderr, "by %s (amount=%i) -> penalty = %f\n", AW_rgb16(col2).ascii(), amount, currPenalty);
162 #endif
163 
164  if (currPenalty<penalty) {
165  penalty = currPenalty;
166  cheapest = col1;
167  *replaceBy = col2;
168  }
169  }
170  }
171  }
172 
173  aw_assert(penalty<numeric_limits<float>::max()); // no color found
174  aw_assert(penalty>0); // should not occur!
175  return cheapest;
176  }
177 
178 public:
180  // add fig standard colors to ColMap [=color indices 0..31]
181  for (int i = 0; i<XFIG_DEFAULT_COLOR_COUNT; ++i) {
182  color[figStdColors[i]] = UsedColor(i);
183  }
184  }
185 
186  void add(AW_rgb rgb) { color[rgb].inc(); }
187 
188  bool operator()(const AW_rgb& c1, const AW_rgb& c2) const {
189  // operator to sort colors (often used colors first; strict order)
190  ColMap::const_iterator f1 = color.find(c1);
191  ColMap::const_iterator f2 = color.find(c2);
192 
193  aw_assert(f1 != color.end());
194  aw_assert(f2 != color.end());
195 
196  int cmp = f1->second.getCount() - f2->second.getCount();
197  if (!cmp) cmp = c1-c2; // define strict order using rgb value
198  return cmp>0;
199  }
200 
201  void mapColors(size_t allowed) {
202  size_t usedColors = color.size(); // with std-colors
203 
204  allowed += XFIG_DEFAULT_COLOR_COUNT;
205 
206  // reduce colors if too many colors in map:
207  while (usedColors>allowed) {
208  AW_rgb replaceBy;
209  AW_rgb cheapest = findCheapestReplaceableColor(&replaceBy);
210 
211  aw_assert(!color[cheapest].isStdColor());
212 
213  // @@@ if amount of 'cheapest' and 'replaceBy' is (nearly) the same -> create mixed color and replace both?
214 
215  replaced[cheapest] = replaceBy; // store color replacement
216  color[replaceBy].addCount(color[cheapest].getCount()); // add occurrences of removed color to replacement color
217 
218  IF_ASSERTION_USED(size_t erased = )color.erase(cheapest);
219  aw_assert(erased == 1);
220 
221  --usedColors;
222  }
223 
224  aw_assert(color.size() <= allowed); // failed to reduce colors
225 
226  vector<AW_rgb> sortedColors;
227  for (ColMap::iterator i = color.begin(); i != color.end(); ++i) {
228  sortedColors.push_back(i->first);
229  }
230  sort(sortedColors.begin(), sortedColors.end(), *this);
231 
232  // stupid mapping:
233  int nextIdx = XFIG_USER_COLOR_FIRST;
234  for (ColMap::iterator i = color.begin(); i != color.end(); ++i) {
235  UsedColor& used = i->second;
236  if (!used.isStdColor()) {
237  used.assign(nextIdx++);
238  }
239  }
240  }
241 
242  void printUserColorDefinitions(FILE *xout) {
243  const AW_rgb *used[XFIG_USER_COLOR_LAST+1];
244 
245  for (int i = 0; i<=XFIG_USER_COLOR_LAST; ++i) {
246  used[i] = NULp;
247  }
248 
249  for (ColMap::const_iterator i = color.begin(); i != color.end(); ++i) {
250 #if defined(ASSERTION_USED)
251  const AW_rgb& rgb = i->first;
252  aw_assert(rgb != AW_NO_COLOR);
253 #endif
254  const UsedColor& ucol = i->second;
255  aw_assert(ucol.isAssigned());
256 
257  int idx = ucol.getIndex();
258  aw_assert(!used[idx]);
259  used[idx] = &(i->first);
260  }
261 
262  // print custom color definitions sorted by index:
263  for (int i = XFIG_USER_COLOR_FIRST; i<=XFIG_USER_COLOR_LAST; ++i) {
264  if (used[i]) {
265  fprintf(xout, "0 %d #%06lx\n", i, *used[i]);
266  }
267  }
268  }
269 
270  int rgb2index(AW_rgb rgb) const {
271  ColMap::const_iterator found = color.find(rgb);
272  while (found == color.end()) {
273  Remap::const_iterator remapped = replaced.find(rgb);
274  aw_assert(remapped != replaced.end());
275 
276  rgb = remapped->second;
277  found = color.find(rgb);
278  }
279  return found->second.getIndex();
280  }
281 };
282 
283 // -----------------
284 // SPOOLER
285 
286 class SPOOLER {
287  // SPOOLER delays output of xfig objects:
288  // 1. collect object code (while tracing information about used colors)
289  // 2. generate color table (probably reduced)
290  // 3. print object code (and remap colors)
291 
292  typedef list<SpoolablePtr> Spoolables;
293 
294  Spoolables objs;
295 
296  void initColors(ColorMap& colmap) {
297  for (Spoolables::const_iterator i = objs.begin(); i != objs.end(); ++i) {
298  const AW_rgb *rgb = (*i)->rgb();
299  if (rgb) colmap.add(*rgb);
300  }
301  }
302 
303 public:
304  SPOOLER() {}
305 
306  void put(const char *str) { objs.push_back(new SpoolableString(str)); }
307  void putColor(AW_rgb rgb) { objs.push_back(new SpoolableColor(rgb)); }
308  void putDefaultColor() { put("-1 "); }
309 
310  void spool(FILE *xout) {
311  ColorMap colmap;
312 
313  initColors(colmap);
315  colmap.printUserColorDefinitions(xout);
316 
317  while (!objs.empty()) {
318  SpoolablePtr next = objs.front();
319  objs.pop_front();
320 
321  const char *txt = next->text();
322  if (txt) {
323  fputs(txt, xout);
324  }
325  else {
326  const AW_rgb *rgb = next->rgb();
327  arb_assert(rgb);
328 
329  int idx = colmap.rgb2index(*rgb);
330  fprintf(xout, "%d ", idx);
331  }
332  }
333  }
334 
335 };
336 
337 // -------------------------
338 // AW_device_print
339 
341 
342 inline double screen2printer(double val) { return val*dpi_screen2printer; }
343 inline int print_pos(AW_pos screen_pos) { return AW_INT(screen2printer(screen_pos)); }
344 
346 
347 // Note: parameters to spoolf HAVE TO be wrapped in "()"!
348 #define spoolf(format) spooler->put(GBS_global_string format)
349 #define spools(str) spooler->put(str)
350 #define spoolColor(rgb) color_mode ? spooler->putColor(rgb) : spooler->putDefaultColor()
351 #define spoolDefaultColor() spooler->putDefaultColor()
352 
353 bool AW_device_print::line_impl(int gc, const LineVector& Line, AW_bitset filteri) {
354  bool drawflag = false;
355  if (filteri & filter) {
356  LineVector transLine = transform(Line);
357  LineVector clippedLine;
358  drawflag = clip(transLine, clippedLine);
359 
360  if (drawflag) {
361  const AW_GC *gcm = get_common()->map_gc(gc);
362  int line_width = gcm->get_line_width();
363 
364  int line_mode = 0;
365  double gap_ratio = 0.0;
366  switch (gcm->get_line_style()) {
367  case AW_SOLID: /* use defaults from above*/ break;
368  case AW_DASHED: line_mode = 1; gap_ratio = 4.0; break;
369  case AW_DOTTED: line_mode = 2; gap_ratio = 2.0; break;
370  }
371 
372  aw_assert(xfig); // file has to be good!
373 
374  // type, subtype, style, thickness, pen_color,
375  // fill_color(new), depth, pen_style, area_fill, style_val,
376  // join_style(new), cap_style(new), radius, forward_arrow,
377  // backward_arrow, npoints
378  spoolf(("2 1 %d %d ",
379  line_mode,
380  AW_INT(line_width)));
382  spoolf(("0 0 0 0 %5.3f 0 1 0 0 0 2\n\t%d %d %d %d\n",
383  gap_ratio,
384  print_pos(clippedLine.xpos()),
385  print_pos(clippedLine.ypos()),
386  print_pos(clippedLine.head().xpos()),
387  print_pos(clippedLine.head().ypos())));
388  }
389  }
390  return drawflag;
391 }
392 
393 bool AW_device_print::invisible_impl(const AW::Position& pos, AW_bitset filteri) {
394  bool drawflag = false;
395  if (filteri & filter) {
396  Position trans = transform(pos);
397 
398  drawflag = !is_outside_clip(trans);
399  if (drawflag) {
400  spoolf(("2 1 0 1 7 7 50 -1 -1 0.000 0 0 -1 0 0 1\n\t%d %d\n",
401  print_pos(trans.xpos()),
402  print_pos(trans.ypos())));
403  }
404  }
405  return drawflag;
406 }
407 
408 void AW_device_print::draw_text(int gc, const char *textBuffer, size_t textStart, size_t textLen, const AW::Position& pos) {
409  const AW_GC *gcm = get_common()->map_gc(gc);
410 
411  AW::Position POS(transform(pos));
412 
413  char *pstr = strdup(textBuffer+textStart); // @@@ only copy textLen characters!
414  if (textLen < strlen(pstr)) pstr[textLen] = 0; // @@@ caller asserts textLen <= strlen(pstr)
415  else textLen = strlen(pstr);
416 
417  size_t i;
418  for (i=0; i<textLen; i++) {
419  if (pstr[i] < ' ') pstr[i] = '?';
420  }
421 
422  int fontnr = AW_font_2_xfig(gcm->get_fontnr());
423  if (fontnr<0) fontnr = - fontnr;
424  if (textBuffer[0]) { // @@@ incorrect or useless?
425  // 4=string 0=left color depth penstyle font font_size angle
426  // font_flags height length x y string
427  // (font/fontsize and color/depth have been switched from format 2.1 to 3.2)
428 
429  SizedCstr sstr(textBuffer); // @@@ shouldn't this use only part of textBuffer??? maybe 'pstr'?
430 
431  spools("4 0 ");
433  spoolf(("0 0 %d %d 0.000 4 %d %d %d %d ",
434  fontnr,
435  gcm->get_fontsize(),
436  (int)gcm->get_font_limits().get_height(),
437  gcm->get_string_size(sstr),
438  print_pos(POS.xpos()),
439  print_pos(POS.ypos())));
440 
441  spoolf(("%s\\001\n", pstr));
442  }
443  free(pstr);
444 }
445 
446 GB_ERROR AW_device_print::open(const char *path) {
447  if (xfig) return "You cannot reopen a device";
448 
449  xfig = fopen(path, "w");
450  if (!xfig) return GB_IO_error("writing", path);
451 
452  fprintf(xfig,
453  "#FIG 3.2\n" // version
454  "Landscape\n" // "Portrait"
455  "Center\n" // "Flush Left"
456  "Metric\n" // "Inches"
457  "A4\n" // papersize
458  "100.0\n" // export&print magnification %
459  "Single\n" // Single/Multiple Pages
460  "-3\n" // background = transparent for gif export
461  "%i 2\n" // dpi, 2 = origin in upper left corner
462  , DPI_PRINTER);
463 
464  spooler = new SPOOLER;
465 
466  return NULp;
467 }
468 
470  for (int i=0; i<data_colors_size; i++) {
471  if (color == data_colors[i]) {
472  return i;
473  }
474  }
475  return -1;
476 }
477 
478 int AW_device_print::find_color_idx(AW_rgb color) {
479  int idx = -1;
480  if (color_mode) {
481  idx = get_common()->find_data_color_idx(color);
482  if (idx >= 0) idx += XFIG_USER_COLOR_FIRST;
483  }
484  return idx;
485 }
486 
487 void AW_device_print::close() {
488  arb_assert(correlated(spooler, xfig));
489 
490  if (spooler) {
491  spooler->spool(xfig);
492 
493  delete spooler;
494  spooler = NULp;
495 
496  fclose(xfig);
497  xfig = NULp;
498  }
499 }
500 
501 static bool AW_draw_string_on_printer(AW_device *device, int gc, const char *textBuffer, size_t textStart, size_t textLen, const AW::Position& pos, AW_CL /*cduser*/) {
502  DOWNCAST(AW_device_print*, device)->draw_text(gc, textBuffer, textStart, textLen, pos);
503  return true;
504 }
505 bool AW_device_print::text_impl(int gc, const SizedCstr& cstr, const AW::Position& pos, AW_pos alignment, AW_bitset filteri) {
506  return text_overlay(gc, cstr, pos, alignment, filteri, AW_draw_string_on_printer);
507 }
508 
509 bool AW_device_print::box_impl(int gc, AW::FillStyle filled, const Rectangle& rect, AW_bitset filteri) {
510  bool drawflag = false;
511  if (filter & filteri) {
512  if (filled.somehow()) {
513  Position q[4];
514  q[0] = rect.upper_left_corner();
515  q[1] = rect.upper_right_corner();
516  q[2] = rect.lower_right_corner();
517  q[3] = rect.lower_left_corner();
518 
519  drawflag = polygon(gc, filled, 4, q, filteri);
520  }
521  else {
522  drawflag = generic_box(gc, rect, filteri);
523  }
524  }
525  return drawflag;
526 }
527 
528 AW_device::Fill_Style AW_device_print::detectFillstyleForGreylevel(int gc, AW::FillStyle filled) { // @@@ directly pass greylevel (or AW_GC?)
529  // @@@ DRY code here vs setFillstyleForGreylevel
530 
531  switch (filled.get_style()) {
532  case AW::FillStyle::SOLID: return FS_SOLID;
533  case AW::FillStyle::EMPTY: return FS_EMPTY;
534 
537  break; // detect using greylevel
538  }
539 
540  AW_grey_level greylevel = get_grey_level(gc);
541 
542  static const float PART = 1.0/22; // exact for color_mode==false
543 
544  if (greylevel<PART) return FS_EMPTY;
545  if (greylevel>(1.0-PART)) return FS_SOLID;
546 
547  return FS_GREY;
548 }
549 
550 int AW_device_print::calcAreaFill(AW_device::Fill_Style fillStyle, AW_grey_level grey_level) {
551  int area_fill = -1;
552  if (fillStyle == FS_SOLID) { // @@@ use switch here
553  area_fill = 20;
554  }
555  else if (fillStyle != FS_EMPTY) {
556  aw_assert(grey_level>=0.0 && grey_level<=1.0);
557  if (color_mode) {
558  area_fill = AW_INT(40-20*grey_level); // 20 = full saturation; 40 = white
559  aw_assert(area_fill != 40); // @@@ should better use fillStyle==FS_EMPTY in that case
560  }
561  else {
562  area_fill = AW_INT(20*grey_level); // 1=light 19=dark 20=solid
563  aw_assert(area_fill != 0); // @@@ should better use fillStyle==FS_EMPTY in that case
564  }
565  aw_assert(area_fill != 20); // @@@ should better use fillStyle==FS_SOLID in that case
566  }
567  return area_fill;
568 }
569 
570 bool AW_device_print::circle_impl(int gc, AW::FillStyle filled, const Position& center, const AW::Vector& radius, AW_bitset filteri) {
571  bool drawflag = false;
572  if (filteri & filter) {
573  aw_assert(radius.x()>0 && radius.y()>0);
574  Rectangle Box(center-radius, center+radius);
575  Rectangle screen_box = transform(Box);
576  Rectangle clipped_box;
577  drawflag = box_clip(screen_box, clipped_box);
578  bool half_visible = (clipped_box.surface()*2) > screen_box.surface();
579 
580  drawflag = drawflag && half_visible;
581  // @@@ correct behavior would be to draw an arc if only partly visible
582 
583  if (drawflag) {
584  const AW_GC *gcm = get_common()->map_gc(gc);
585 
586  // force into clipped_box (hack):
587  Position Center = clipped_box.centroid();
588  Vector screen_radius = clipped_box.diagonal()/2;
589 
590  int cx = print_pos(Center.xpos());
591  int cy = print_pos(Center.ypos());
592  int rx = print_pos(screen_radius.x());
593  int ry = print_pos(screen_radius.y());
594 
595  {
596  int subtype = (rx == ry) ? 3 : 1; // 3(circle) 1(ellipse)
597  subtype = 3; // @@@ remove after refactoring
598  spoolf(("1 %d ", subtype)); // type + subtype:
599  }
600 
601  {
602  int line_width = gcm->get_line_width();
603  spoolf(("%d %d ", AW_SOLID, line_width)); // line_style + line_width
604 
605  {
606  AW_rgb color = gcm->get_last_fg_color();
607  Fill_Style fillStyle = detectFillstyleForGreylevel(gc, filled);
608  int area_fill = calcAreaFill(fillStyle, gcm->get_grey_level());
609 
610  spoolColor(color); // pen_color
611  if (area_fill == -1) {
612  spoolDefaultColor(); // fill color
613  }
614  else {
615  spoolColor(color); // fill color
616  }
617  spoolf(("0 0 %d ", area_fill)); // depth + pen_style + area_fill
618  }
619  spoolf(("0.000 1 0.0000 ")); // style_val + direction + angle (x-axis)
620  }
621 
622  spoolf(("%d %d ", cx, cy)); // center
623  spoolf(("%d %d ", rx, ry)); // radius
624  spoolf(("%d %d ", cx, cy)); // start
625  spoolf(("%d %d\n", print_pos(Center.xpos()+screen_radius.x()), cy)); // end
626  }
627  }
628  return drawflag;
629 }
630 
631 bool AW_device_print::arc_impl(int gc, AW::FillStyle filled, const AW::Position& center, const AW::Vector& radius, int start_degrees, int arc_degrees, AW_bitset filteri) {
632  bool drawflag = false;
633  if (filteri && filter) {
634  aw_assert(radius.x()>0 && radius.y()>0);
635  Rectangle Box(center-radius, center+radius);
636  Rectangle screen_box = transform(Box);
637  Rectangle clipped_box;
638  drawflag = box_clip(screen_box, clipped_box);
639  bool half_visible = (clipped_box.surface()*2) > screen_box.surface();
640 
641  drawflag = drawflag && half_visible;
642  // @@@ correct behavior would be to draw an arc if only partly visible
643 
644  UNCOVERED(); // @@@ AW_device_print::arc_impl not triggered from test code.
645  // Uses via method arc():
646  // - from SECEDIT to draw '~'-bonds (may be saved to xfig)
647  // - from EDIT4 to mark protein codon triples (NEVER saved to xfig)
648  // AW_device_Xm version is used indirectly via method circle_impl().
649 
650  if (drawflag) {
651  const AW_GC *gcm = get_common()->map_gc(gc);
652 
653  // force into clipped_box (hack):
654  Position Center = clipped_box.centroid();
655  Vector screen_radius = clipped_box.diagonal()/2;
656 
657  int cx = print_pos(Center.xpos());
658  int cy = print_pos(Center.ypos());
659  int rx = print_pos(screen_radius.x());
660  int ry = print_pos(screen_radius.y());
661 
662  bool use_spline = (rx != ry); // draw interpolated spline for ellipsoid arcs
663 
664  spools(use_spline ? "3 4 " : "5 1 "); // type + subtype:
665 
666  {
667  int line_width = gcm->get_line_width();
668  spoolf(("%d %d ", AW_SOLID, line_width)); // line_style + line_width
669 
670  {
671  AW_rgb color = gcm->get_last_fg_color();
672  Fill_Style fillStyle = detectFillstyleForGreylevel(gc, filled);
673  int area_fill = calcAreaFill(fillStyle, gcm->get_grey_level());
674 
675  spoolColor(color); // pen_color
676  if (area_fill == -1) {
677  spoolDefaultColor(); // fill color
678  }
679  else {
680  spoolColor(color); // fill color
681  }
682  spoolf(("0 0 %d ", area_fill)); // depth + pen_style + area_fill
683 #if defined(UNIT_TESTS)
684  if (area_fill != -1) { UNCOVERED(); } // @@@ filled arcs not tested
685  else { UNCOVERED(); } // @@@ unfilled arcs not tested
686 #endif
687  }
688  spools("0.000 1 "); // style_val + cap_style
689  if (!use_spline) spools("1 "); // direction
690  spools("0 0 "); // 2 arrows
691  }
692 
693  Angle a0(Angle::deg2rad*start_degrees);
694  Angle a1(Angle::deg2rad*(start_degrees+arc_degrees));
695 
696  if (use_spline) {
697  const int MAX_ANGLE_STEP = 45; // degrees
698 
699  int steps = (abs(arc_degrees)-1)/MAX_ANGLE_STEP+1;
700  Angle step(Angle::deg2rad*double(arc_degrees)/steps);
701 
702  spoolf(("%d\n\t", steps+1)); // npoints
703 
704  double rmax, x_factor, y_factor;
705  if (rx>ry) {
706  rmax = rx;
707  x_factor = 1.0;
708  y_factor = double(ry)/rx;
709  }
710  else {
711  rmax = ry;
712  x_factor = double(rx)/ry;
713  y_factor = 1.0;
714  }
715 
716  for (int n = 0; n <= steps; ++n) {
717  Vector toCircle = a0.normal()*rmax;
718  Vector toEllipse(toCircle.x()*x_factor, toCircle.y()*y_factor);
719  Position onEllipse = Center+toEllipse;
720 
721  int x = print_pos(onEllipse.xpos());
722  int y = print_pos(onEllipse.ypos());
723 
724  spoolf((" %d %d", x, y));
725 
726  if (n<steps) {
727  if (n == steps-1) a0 = a1;
728  else a0 += step;
729  }
730  }
731  spools("\n\t");
732  for (int n = 0; n <= steps; ++n) {
733  // -1 = interpolate; 0 = discontinuity; 1 = approximate
734  spoolf((" %d", (n == 0 || n == steps) ? 0 : -1));
735  }
736  spools("\n");
737  }
738  else {
739  spoolf(("%d %d ", cx, cy)); // center
740 
741  Angle am(Angle::deg2rad*(start_degrees+arc_degrees*0.5));
742 
743  double r = screen_radius.x();
744  Position p0 = Center+a0.normal()*r;
745  Position pm = Center+am.normal()*r;
746  Position p1 = Center+a1.normal()*r;
747 
748  spoolf(("%d %d ", print_pos(p0.xpos()), print_pos(p0.ypos())));
749  spoolf(("%d %d ", print_pos(pm.xpos()), print_pos(pm.ypos())));
750  spoolf(("%d %d\n", print_pos(p1.xpos()), print_pos(p1.ypos())));
751  }
752  }
753  }
754  return drawflag;
755 }
756 
757 bool AW_device_print::polygon_impl(int gc, AW::FillStyle filled, int npos, const Position *pos, AW_bitset filteri) {
758  bool drawflag = false;
759  if (filter & filteri) {
760  drawflag = generic_polygon(gc, npos, pos, filteri);
761  if (drawflag) { // line visible -> area fill needed
762  const AW_GC *gcm = get_common()->map_gc(gc);
763 
764  int line_width = gcm->get_line_width();
765 
766  spools("2 3 ");
767  spoolf(("%d %d ", AW_SOLID, line_width));
768 
769  {
770  AW_rgb color = gcm->get_last_fg_color();
771  Fill_Style fillStyle = detectFillstyleForGreylevel(gc, filled);
772  int area_fill = calcAreaFill(fillStyle, gcm->get_grey_level());
773 
774  spoolColor(color); // pen_color
775  if (area_fill == -1) {
776  spoolDefaultColor(); // fill color
777  }
778  else {
779  spoolColor(color); // fill color
780  }
781  spoolf(("0 0 %d ", area_fill)); // depth + pen_style + area_fill
782  }
783 
784  spools("0.000 0 0 -1 0 0 ");
785 
786  spoolf(("%d\n", npos+1));
787 
788  // @@@ method used here for clipping leads to wrong results,
789  // since group border (drawn by generic_polygon() above) is clipped correctly,
790  // but filled content is clipped different.
791  //
792  // fix: clip the whole polygon before drawing border
793 
794  for (int i=0; i <= npos; i++) {
795  int j = i == npos ? 0 : i; // print pos[0] after pos[n-1]
796 
797  Position transPos = transform(pos[j]);
798  Position clippedPos;
799  ASSERT_RESULT(bool, true, force_into_clipbox(transPos, clippedPos));
800  spoolf((" %d %d\n", print_pos(clippedPos.xpos()), print_pos(clippedPos.ypos())));
801  }
802  }
803  }
804  return drawflag;
805 }
float g() const
Definition: aw_rgb.hxx:111
#define arb_assert(cond)
Definition: arb_assert.h:245
long AW_bitset
Definition: aw_base.hxx:44
float r() const
Definition: aw_rgb.hxx:110
GB_TYPES type
AW_rgb get_last_fg_color() const
Definition: aw_common.hxx:151
AW_linestyle get_line_style() const
Definition: aw_common.hxx:59
int rgb2index(AW_rgb rgb) const
Definition: AW_print.cxx:270
void putColor(AW_rgb rgb)
Definition: AW_print.cxx:307
#define XFIG_DEFAULT_COLOR_COUNT
Definition: AW_print.cxx:26
const AW_rgb * rgb() const OVERRIDE
Definition: AW_print.cxx:48
short get_height() const
int get_string_size(long textlen) const
Definition: AW_device.cxx:403
Position centroid() const
static char * y[maxsp+1]
float b() const
Definition: aw_rgb.hxx:112
void spool(FILE *xout)
Definition: AW_print.cxx:310
short get_line_width() const
Definition: aw_common.hxx:58
static bool AW_draw_string_on_printer(AW_device *device, int gc, const char *textBuffer, size_t textStart, size_t textLen, const AW::Position &pos, AW_CL)
Definition: AW_print.cxx:501
const char * text() const OVERRIDE
Definition: AW_print.cxx:47
int getIndex() const
Definition: AW_print.cxx:127
void add(AW_rgb rgb)
Definition: AW_print.cxx:186
int find_data_color_idx(AW_rgb color) const
Definition: AW_print.cxx:469
UsedColor(int idx)
Definition: AW_print.cxx:111
#define ASSERT_RESULT(Type, Expected, Expr)
Definition: arb_assert.h:336
GB_ERROR GB_IO_error(const char *action, const char *filename)
Definition: arb_msg.cxx:285
SpoolableString(const char *txt)
Definition: AW_print.cxx:45
int AW_font_2_xfig(AW_font font_nr)
Definition: AW_xfont.cxx:724
STL namespace.
unsigned long AW_rgb
Definition: aw_base.hxx:51
#define spoolColor(rgb)
Definition: AW_print.cxx:350
double screen2printer(double val)
Definition: AW_print.cxx:342
static AW_rgb figStdColors[32]
Definition: AW_print.cxx:64
bool operator()(const AW_rgb &c1, const AW_rgb &c2) const
Definition: AW_print.cxx:188
const char * text() const OVERRIDE
Definition: AW_print.cxx:55
#define DOWNCAST(totype, expr)
Definition: downcast.h:141
SmartPtr< Spoolable > SpoolablePtr
Definition: AW_print.cxx:59
#define XFIG_USER_COLOR_FIRST
Definition: AW_print.cxx:29
static int diff(int v1, int v2, int v3, int v4, int st, int en)
Definition: ClustalV.cxx:534
double AW_pos
Definition: aw_base.hxx:29
#define spools(str)
Definition: AW_print.cxx:349
static const double deg2rad
bool somehow() const
Definition: aw_position.hxx:70
double surface() const
bool isAssigned() const
Definition: AW_print.cxx:117
const double & ypos() const
const AW_rgb * rgb() const OVERRIDE
Definition: AW_print.cxx:56
Generic smart pointer.
Definition: smartptr.h:149
Style get_style() const
Definition: aw_position.hxx:66
AW_font get_fontnr() const
Definition: aw_common.hxx:175
#define aw_assert(bed)
Definition: aw_position.hxx:29
Position lower_left_corner() const
bool isStdColor() const
Definition: AW_print.cxx:118
const Position & upper_left_corner() const
void putDefaultColor()
Definition: AW_print.cxx:308
AW_grey_level get_grey_level() const
Definition: aw_common.hxx:51
const double & y() const
short get_fontsize() const
Definition: aw_common.hxx:174
#define cmp(h1, h2)
Definition: admap.cxx:50
void printUserColorDefinitions(FILE *xout)
Definition: AW_print.cxx:242
const double & ypos() const
float AW_grey_level
Definition: aw_base.hxx:46
const Vector & diagonal() const
#define DPI_PRINTER
Definition: aw_device.hxx:32
#define spoolf(format)
Definition: AW_print.cxx:348
void mapColors(size_t allowed)
Definition: AW_print.cxx:201
Definition: CT_part.hxx:62
fputs(TRACE_PREFIX, stderr)
void inc()
Definition: AW_print.cxx:113
#define XFIG_USER_COLOR_COUNT
Definition: AW_print.cxx:27
#define IF_ASSERTION_USED(x)
Definition: arb_assert.h:308
void put(const char *str)
Definition: AW_print.cxx:306
long AW_CL
Definition: cb.h:21
#define XFIG_USER_COLOR_LAST
Definition: AW_print.cxx:30
double colorDistSquare(const AW_rgb &col1, const AW_rgb &col2)
Definition: AW_print.cxx:130
#define OVERRIDE
Definition: cxxforward.h:112
void assign(int idx)
Definition: AW_print.cxx:120
Position upper_right_corner() const
int getCount() const
Definition: AW_print.cxx:115
#define abs(x)
Definition: f2c.h:151
Position head() const
const double dpi_screen2printer
Definition: AW_print.cxx:340
virtual ~Spoolable()
Definition: AW_print.cxx:36
void addCount(int toAdd)
Definition: AW_print.cxx:114
const double & xpos() const
#define NULp
Definition: cxxforward.h:116
int print_pos(AW_pos screen_pos)
Definition: AW_print.cxx:343
AW_DEVICE_TYPE
Definition: aw_device.hxx:48
#define DPI_SCREEN
Definition: aw_device.hxx:31
#define AW_NO_COLOR
Definition: aw_base.hxx:50
Position lower_right_corner() const
const AW_font_limits & get_font_limits() const
Definition: aw_common.hxx:133
SpoolableColor(const AW_rgb &color_)
Definition: AW_print.cxx:53
const double & x() const
#define spoolDefaultColor()
Definition: AW_print.cxx:351
#define UNCOVERED()
Definition: arb_assert.h:380
const double & xpos() const
#define max(a, b)
Definition: f2c.h:154
GB_write_int const char s
Definition: AW_awar.cxx:154