source: tags/ms_r18q1/WINDOW/AW_print.cxx

Last change on this file was 17002, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.1 KB
Line 
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
23using namespace AW;
24using 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
35struct Spoolable {
36    virtual ~Spoolable() {}
37
38    virtual const char *text() const  = 0;
39    virtual const AW_rgb *rgb() const = 0;
40};
41
42class SpoolableString : public Spoolable {
43    string s;
44public:
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};
50class SpoolableColor : public Spoolable {
51    AW_rgb color;
52public:
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
59typedef SmartPtr<Spoolable> SpoolablePtr;
60
61// ---------------------
62//      color mapping
63
64static 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
103class 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
109public:
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
130inline double colorDistSquare(const AW_rgb& col1, const AW_rgb& col2) {
131    AW_rgb_diff diff = AW_rgb_normalized(AW_rgb16(col1)) - AW_rgb_normalized(AW_rgb16(col2));
132    return diff.r()*diff.r() + diff.g()*diff.g() + diff.b()*diff.b();
133}
134
135class 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;
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
178public:
179    ColorMap() {
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            size_t erased = color.erase(cheapest);
218
219            aw_assert(erased == 1);
220            --usedColors;
221        }
222
223        aw_assert(color.size() <= allowed); // failed to reduce colors
224
225        vector<AW_rgb> sortedColors;
226        for (ColMap::iterator i = color.begin(); i != color.end(); ++i) {
227            sortedColors.push_back(i->first);
228        }
229        sort(sortedColors.begin(), sortedColors.end(), *this);
230
231        // stupid mapping:
232        int nextIdx = XFIG_USER_COLOR_FIRST;
233        for (ColMap::iterator i = color.begin(); i != color.end(); ++i) {
234            UsedColor& used = i->second;
235            if (!used.isStdColor()) {
236                used.assign(nextIdx++);
237            }
238        }
239    }
240
241    void printUserColorDefinitions(FILE *xout) {
242        const AW_rgb *used[XFIG_USER_COLOR_LAST+1];
243
244        for (int i = 0; i<=XFIG_USER_COLOR_LAST; ++i) {
245            used[i] = NULp;
246        }
247
248        for (ColMap::const_iterator i = color.begin(); i != color.end(); ++i) {
249            const AW_rgb&    rgb  = i->first;
250            const UsedColor& ucol = i->second;
251            aw_assert(rgb != AW_NO_COLOR);
252            aw_assert(ucol.isAssigned());
253
254            int idx   = ucol.getIndex();
255            aw_assert(!used[idx]);
256            used[idx] = &(i->first);
257        }
258
259        // print custom color definitions sorted by index:
260        for (int i = XFIG_USER_COLOR_FIRST; i<=XFIG_USER_COLOR_LAST; ++i) {
261            if (used[i]) {
262                fprintf(xout, "0 %d #%06lx\n", i, *used[i]);
263            }
264        }
265    }
266
267    int rgb2index(AW_rgb rgb) const {
268        ColMap::const_iterator found = color.find(rgb);
269        while (found == color.end()) {
270            Remap::const_iterator remapped = replaced.find(rgb);
271            aw_assert(remapped != replaced.end());
272
273            rgb   = remapped->second;
274            found = color.find(rgb);
275        }
276        return found->second.getIndex();
277    }
278};
279
280// -----------------
281//      SPOOLER
282
283class SPOOLER {
284    // SPOOLER delays output of xfig objects:
285    // 1. collect object code (while tracing information about used colors)
286    // 2. generate color table (probably reduced)
287    // 3. print object code (and remap colors)
288
289    typedef list<SpoolablePtr> Spoolables;
290
291    Spoolables objs;
292
293    void initColors(ColorMap& colmap) {
294        for (Spoolables::const_iterator i = objs.begin(); i != objs.end(); ++i) {
295            const AW_rgb *rgb = (*i)->rgb();
296            if (rgb) colmap.add(*rgb);
297        }
298    }
299
300public:
301    SPOOLER() {}
302
303    void put(const char *str) { objs.push_back(new SpoolableString(str)); }
304    void putColor(AW_rgb rgb) { objs.push_back(new SpoolableColor(rgb)); }
305    void putDefaultColor() { put("-1 "); }
306
307    void spool(FILE *xout) {
308        ColorMap colmap;
309
310        initColors(colmap);
311        colmap.mapColors(XFIG_USER_COLOR_COUNT);
312        colmap.printUserColorDefinitions(xout);
313
314        while (!objs.empty()) {
315            SpoolablePtr next = objs.front();
316            objs.pop_front();
317
318            const char *txt = next->text();
319            if (txt) {
320                fputs(txt, xout);
321            }
322            else {
323                const AW_rgb *rgb = next->rgb();
324                arb_assert(rgb);
325
326                int idx    = colmap.rgb2index(*rgb);
327                fprintf(xout, "%d ", idx);
328            }
329        }
330    }
331
332};
333
334// -------------------------
335//      AW_device_print
336
337const double dpi_screen2printer = double(DPI_PRINTER)/DPI_SCREEN;
338
339inline double screen2printer(double val) { return val*dpi_screen2printer; }
340inline int print_pos(AW_pos screen_pos) { return AW_INT(screen2printer(screen_pos)); }
341
342AW_DEVICE_TYPE AW_device_print::type() { return AW_DEVICE_PRINTER; }
343
344// Note: parameters to spoolf HAVE TO be wrapped in "()"!
345#define spoolf(format)      spooler->put(GBS_global_string format)
346#define spools(str)         spooler->put(str)
347#define spoolColor(rgb)     color_mode ? spooler->putColor(rgb) : spooler->putDefaultColor()
348#define spoolDefaultColor() spooler->putDefaultColor()
349
350bool AW_device_print::line_impl(int gc, const LineVector& Line, AW_bitset filteri) {
351    bool drawflag = false;
352    if (filteri & filter) {
353        LineVector transLine = transform(Line);
354        LineVector clippedLine;
355        drawflag = clip(transLine, clippedLine);
356
357        if (drawflag) {
358            const AW_GC *gcm        = get_common()->map_gc(gc);
359            int          line_width = gcm->get_line_width();
360
361            int    line_mode = 0;
362            double gap_ratio = 0.0;
363            switch (gcm->get_line_style()) {
364                case AW_SOLID: /* use defaults from above*/ break;
365                case AW_DASHED:  line_mode = 1; gap_ratio = 4.0; break;
366                case AW_DOTTED:  line_mode = 2; gap_ratio = 2.0; break;
367            }
368
369            aw_assert(xfig); // file has to be good!
370
371            // type, subtype, style, thickness, pen_color,
372            // fill_color(new), depth, pen_style, area_fill, style_val,
373            // join_style(new), cap_style(new), radius, forward_arrow,
374            // backward_arrow, npoints
375            spoolf(("2 1 %d %d ",
376                    line_mode,
377                    AW_INT(line_width)));
378            spoolColor(gcm->get_last_fg_color());
379            spoolf(("0 0 0 0 %5.3f 0 1 0 0 0 2\n\t%d %d %d %d\n",
380                    gap_ratio,
381                    print_pos(clippedLine.xpos()),
382                    print_pos(clippedLine.ypos()),
383                    print_pos(clippedLine.head().xpos()),
384                    print_pos(clippedLine.head().ypos())));
385        }
386    }
387    return drawflag;
388}
389
390bool AW_device_print::invisible_impl(const AW::Position& pos, AW_bitset filteri) {
391    bool drawflag = false;
392    if (filteri & filter) {
393        Position trans = transform(pos);
394
395        drawflag = !is_outside_clip(trans);
396        if (drawflag) {
397            spoolf(("2 1 0 1 7 7 50 -1 -1 0.000 0 0 -1 0 0 1\n\t%d %d\n",
398                    print_pos(trans.xpos()),
399                    print_pos(trans.ypos())));
400        }
401    }
402    return drawflag;
403}
404
405void AW_device_print::draw_text(int gc, const char *textBuffer, size_t textStart, size_t textLen, const AW::Position& pos) {
406    const AW_GC *gcm = get_common()->map_gc(gc);
407
408    AW::Position POS(transform(pos));
409
410    char *pstr                                = strdup(textBuffer+textStart); // @@@ only copy textLen characters!
411    if (textLen < strlen(pstr)) pstr[textLen] = 0; // @@@ caller asserts textLen <= strlen(pstr)
412    else  textLen                             = strlen(pstr);
413
414    size_t i;
415    for (i=0; i<textLen; i++) {
416        if (pstr[i] < ' ') pstr[i] = '?';
417    }
418
419    int fontnr           = AW_font_2_xfig(gcm->get_fontnr());
420    if (fontnr<0) fontnr = - fontnr;
421    if (textBuffer[0]) { // @@@ incorrect or useless?
422        // 4=string 0=left color depth penstyle font font_size angle
423        // font_flags height length x y string
424        // (font/fontsize and color/depth have been switched from format 2.1 to 3.2)
425
426        SizedCstr sstr(textBuffer); // @@@ shouldn't this use only part of textBuffer??? maybe 'pstr'?
427
428        spools("4 0 ");
429        spoolColor(gcm->get_last_fg_color());
430        spoolf(("0 0 %d %d 0.000 4 %d %d %d %d ",
431                fontnr,
432                gcm->get_fontsize(),
433                (int)gcm->get_font_limits().get_height(),
434                gcm->get_string_size(sstr),
435                print_pos(POS.xpos()),
436                print_pos(POS.ypos())));
437
438        spoolf(("%s\\001\n", pstr));
439    }
440    free(pstr);
441}
442
443GB_ERROR AW_device_print::open(const char *path) {
444    if (xfig) return "You cannot reopen a device";
445
446    xfig = fopen(path, "w");
447    if (!xfig) return GB_IO_error("writing", path);
448
449    fprintf(xfig,
450            "#FIG 3.2\n"   // version
451            "Landscape\n"  // "Portrait"
452            "Center\n"     // "Flush Left"
453            "Metric\n"     // "Inches"
454            "A4\n"         // papersize
455            "100.0\n"      // export&print magnification %
456            "Single\n"     // Single/Multiple Pages
457            "-3\n"         // background = transparent for gif export
458            "%i 2\n"       // dpi, 2  = origin in upper left corner
459            , DPI_PRINTER);
460
461    spooler = new SPOOLER;
462
463    return NULp;
464}
465
466int AW_common::find_data_color_idx(AW_rgb color) const {
467    for (int i=0; i<data_colors_size; i++) {
468        if (color == data_colors[i]) {
469            return i;
470        }
471    }
472    return -1;
473}
474
475int AW_device_print::find_color_idx(AW_rgb color) {
476    int idx = -1;
477    if (color_mode) {
478        idx = get_common()->find_data_color_idx(color);
479        if (idx >= 0) idx += XFIG_USER_COLOR_FIRST;
480    }
481    return idx;
482}
483
484void AW_device_print::close() {
485    arb_assert(correlated(spooler, xfig));
486
487    if (spooler) {
488        spooler->spool(xfig);
489
490        delete spooler;
491        spooler = NULp;
492
493        fclose(xfig);
494        xfig = NULp;
495    }
496}
497
498static 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*/) {
499    DOWNCAST(AW_device_print*, device)->draw_text(gc, textBuffer, textStart, textLen, pos);
500    return true;
501}
502bool AW_device_print::text_impl(int gc, const SizedCstr& cstr, const AW::Position& pos, AW_pos alignment, AW_bitset filteri) {
503    return text_overlay(gc, cstr, pos, alignment, filteri, AW_draw_string_on_printer);
504}
505
506bool AW_device_print::box_impl(int gc, AW::FillStyle filled, const Rectangle& rect, AW_bitset filteri) {
507    bool drawflag = false;
508    if (filter & filteri) {
509        if (filled.somehow()) {
510            Position q[4];
511            q[0] = rect.upper_left_corner();
512            q[1] = rect.upper_right_corner();
513            q[2] = rect.lower_right_corner();
514            q[3] = rect.lower_left_corner();
515
516            drawflag = polygon(gc, filled, 4, q, filteri);
517        }
518        else {
519            drawflag = generic_box(gc, rect, filteri);
520        }
521    }
522    return drawflag;
523}
524
525bool AW_device_print::circle_impl(int gc, AW::FillStyle filled, const Position& center, const AW::Vector& radius, AW_bitset filteri) {
526    bool drawflag = false;
527    if (filteri & filter) {
528        aw_assert(radius.x()>0 && radius.y()>0);
529        Rectangle Box(center-radius, center+radius);
530        Rectangle screen_box = transform(Box);
531        Rectangle clipped_box;
532        drawflag          = box_clip(screen_box, clipped_box);
533        bool half_visible = (clipped_box.surface()*2) > screen_box.surface();
534
535        drawflag = drawflag && half_visible;
536        // @@@ correct behavior would be to draw an arc if only partly visible
537
538        if (drawflag) {
539            const AW_GC *gcm = get_common()->map_gc(gc);
540
541            // force into clipped_box (hack):
542            Position Center        = clipped_box.centroid();
543            Vector   screen_radius = clipped_box.diagonal()/2;
544
545            int cx = print_pos(Center.xpos());
546            int cy = print_pos(Center.ypos());
547            int rx = print_pos(screen_radius.x());
548            int ry = print_pos(screen_radius.y());
549
550            {
551                int subtype = (rx == ry) ? 3 : 1; // 3(circle) 1(ellipse)
552                subtype     = 3; // @@@ remove after refactoring
553                spoolf(("1 %d  ", subtype));  // type + subtype:
554            }
555
556            {
557                int line_width = gcm->get_line_width();
558                spoolf(("%d %d ", AW_SOLID, line_width));   // line_style + line_width
559
560                AW_rgb color = gcm->get_last_fg_color();
561                spoolColor(color); // pen_color
562
563                int area_fill;
564                if (filled.somehow()) {
565                    spoolColor(color); // fill_color
566                    area_fill = AW_INT(20+20*gcm->get_grey_level()); // 20 = full saturation; 40 = white;
567                }
568                else {
569                    spoolDefaultColor(); // fill_color
570                    area_fill = -1;
571                }
572                spoolf(("0 0 %d ", area_fill));             // depth + pen_style + area_fill (20 = full color, 40 = white)
573                spoolf(("0.000 1 0.0000 "));                // style_val + direction + angle (x-axis)
574            }
575
576            spoolf(("%d %d ", cx, cy)); // center
577            spoolf(("%d %d ", rx, ry)); // radius
578            spoolf(("%d %d ", cx, cy)); // start
579            spoolf(("%d %d\n", print_pos(Center.xpos()+screen_radius.x()), cy)); // end
580        }
581    }
582    return drawflag;
583}
584
585bool 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) {
586    bool drawflag = false;
587    if (filteri && filter) {
588        aw_assert(radius.x()>0 && radius.y()>0);
589        Rectangle Box(center-radius, center+radius);
590        Rectangle screen_box = transform(Box);
591        Rectangle clipped_box;
592        drawflag          = box_clip(screen_box, clipped_box);
593        bool half_visible = (clipped_box.surface()*2) > screen_box.surface();
594
595        drawflag = drawflag && half_visible;
596        // @@@ correct behavior would be to draw an arc if only partly visible
597
598        if (drawflag) {
599            const AW_GC *gcm = get_common()->map_gc(gc);
600
601            // force into clipped_box (hack):
602            Position Center        = clipped_box.centroid();
603            Vector   screen_radius = clipped_box.diagonal()/2;
604
605            int cx = print_pos(Center.xpos());
606            int cy = print_pos(Center.ypos());
607            int rx = print_pos(screen_radius.x());
608            int ry = print_pos(screen_radius.y());
609
610            bool use_spline = (rx != ry); // draw interpolated spline for ellipsoid arcs
611
612            spools(use_spline ? "3 4 " : "5 1 ");  // type + subtype:
613
614            {
615                int line_width = gcm->get_line_width();
616                spoolf(("%d %d ", AW_SOLID, line_width));   // line_style + line_width
617
618                AW_rgb color = gcm->get_last_fg_color();
619                spoolColor(color); // pen_color
620
621                int area_fill;
622                if (filled.somehow()) {
623                    spoolColor(color); // fill_color
624                    area_fill = AW_INT(20+20*gcm->get_grey_level()); // 20 = full saturation; 40 = white;
625                }
626                else {
627                    spoolDefaultColor(); // fill_color
628                    area_fill = -1;
629                }
630
631                spoolf(("0 0 %d ", area_fill));             // depth + pen_style + area_fill (20 = full color, 40 = white)
632                spools("0.000 1 ");                         // style_val + cap_style
633                if (!use_spline) spools("1 ");              // direction
634                spools("0 0 ");                             // 2 arrows
635            }
636
637            Angle a0(Angle::deg2rad*start_degrees);
638            Angle a1(Angle::deg2rad*(start_degrees+arc_degrees));
639
640            if (use_spline) {
641                const int MAX_ANGLE_STEP = 45; // degrees
642
643                int steps = (abs(arc_degrees)-1)/MAX_ANGLE_STEP+1;
644                Angle step(Angle::deg2rad*double(arc_degrees)/steps);
645
646                spoolf(("%d\n\t", steps+1)); // npoints
647
648                double rmax, x_factor, y_factor;
649                if (rx>ry) {
650                    rmax     = rx;
651                    x_factor = 1.0;
652                    y_factor = double(ry)/rx;
653                }
654                else {
655                    rmax     = ry;
656                    x_factor = double(rx)/ry;
657                    y_factor = 1.0;
658                }
659
660                for (int n = 0; n <= steps; ++n) {
661                    Vector   toCircle  = a0.normal()*rmax;
662                    Vector   toEllipse(toCircle.x()*x_factor, toCircle.y()*y_factor);
663                    Position onEllipse = Center+toEllipse;
664
665                    int x = print_pos(onEllipse.xpos());
666                    int y = print_pos(onEllipse.ypos());
667
668                    spoolf((" %d %d", x, y));
669
670                    if (n<steps) {
671                        if (n == steps-1) a0 = a1;
672                        else              a0 += step;
673                    }
674                }
675                spools("\n\t");
676                for (int n = 0; n <= steps; ++n) {
677                    // -1 = interpolate; 0 = discontinuity; 1 = approximate
678                    spoolf((" %d", (n == 0 || n == steps) ? 0 : -1));
679                }
680                spools("\n");
681            }
682            else {
683                spoolf(("%d %d ", cx, cy)); // center
684
685                Angle am(Angle::deg2rad*(start_degrees+arc_degrees*0.5));
686
687                double   r  = screen_radius.x();
688                Position p0 = Center+a0.normal()*r;
689                Position pm = Center+am.normal()*r;
690                Position p1 = Center+a1.normal()*r;
691
692                spoolf(("%d %d ",  print_pos(p0.xpos()), print_pos(p0.ypos())));
693                spoolf(("%d %d ",  print_pos(pm.xpos()), print_pos(pm.ypos())));
694                spoolf(("%d %d\n", print_pos(p1.xpos()), print_pos(p1.ypos())));
695            }
696        }
697    }
698    return drawflag;
699}
700
701bool AW_device_print::polygon_impl(int gc, AW::FillStyle filled, int npos, const Position *pos, AW_bitset filteri) {
702    bool drawflag = false;
703    if (filter & filteri) {
704        drawflag = generic_polygon(gc, npos, pos, filteri);
705        if (drawflag) { // line visible -> area fill needed
706            const AW_GC *gcm = get_common()->map_gc(gc);
707
708            short greylevel             = (short)(gcm->get_grey_level()*22);
709            if (greylevel>21) greylevel = 21;
710
711            int line_width = gcm->get_line_width();
712
713            spoolf(("2 3 0 %d ", line_width));
714            spoolColor(gcm->get_last_fg_color());
715            spoolf(("-1 0 0 %d 0.000 0 0 -1 0 0 %d\n", greylevel, npos+1));
716
717            // @@@ method used here for clipping leads to wrong results,
718            // since group border (drawn by generic_polygon() above) is clipped correctly,
719            // but filled content is clipped different.
720            //
721            // fix: clip the whole polygon before drawing border
722
723            for (int i=0; i <= npos; i++) {
724                int j = i == npos ? 0 : i; // print pos[0] after pos[n-1]
725
726                Position transPos = transform(pos[j]);
727                Position clippedPos;
728                ASSERT_RESULT(bool, true, force_into_clipbox(transPos, clippedPos));
729                spoolf(("   %d %d\n", print_pos(clippedPos.xpos()), print_pos(clippedPos.ypos())));
730            }
731        }
732    }
733    return drawflag;
734}
Note: See TracBrowser for help on using the repository browser.