source: tags/svn.1.5.4/WINDOW/AW_print.cxx

Last change on this file was 7768, checked in by westram, 13 years ago

merge from dev [7671] [7672]

  • AW_device
    • device invisible
      • made invisible_impl pure virtual (like other impls)
      • added generic_invisible and use in AW_device_Xm::invisible_impl
      • removed unused parameter 'gc'
        • removed flavor of invisible() not using position - prototype clashed and outdated anyway
    • privat_reset
      • made pure virtual in AW_device
      • renamed to specific_reset
  • swapped order for diff in display test
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.4 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
14#include <arb_msg.h>
15
16using namespace AW;
17
18const double dpi_screen2printer = double(DPI_PRINTER)/DPI_SCREEN;
19
20inline double screen2printer(double val) { return val*dpi_screen2printer; }
21inline int print_pos(AW_pos screen_pos) { return AW_INT(screen2printer(screen_pos)); }
22
23AW_DEVICE_TYPE AW_device_print::type() { return AW_DEVICE_PRINTER; }
24
25bool AW_device_print::line_impl(int gc, const LineVector& Line, AW_bitset filteri) {
26    bool drawflag = false;
27    if (filteri & filter) {
28        LineVector transLine = transform(Line);
29        LineVector clippedLine;
30        drawflag = clip(transLine, clippedLine);
31
32        if (drawflag) {
33            const AW_GC *gcm        = get_common()->map_gc(gc);
34            int          line_width = gcm->get_line_width();
35
36            int    line_mode = 0;
37            double gap_ratio = 0.0;
38            switch (gcm->get_line_style()) {
39                case AW_SOLID: /* use defaults from above*/ break;
40                case AW_DASHED:  line_mode = 1; gap_ratio = 4.0; break;
41                case AW_DOTTED:  line_mode = 2; gap_ratio = 2.0; break;
42            }
43
44            aw_assert(out);     // file has to be good!
45
46            // type, subtype, style, thickness, pen_color,
47            // fill_color(new), depth, pen_style, area_fill, style_val,
48            // join_style(new), cap_style(new), radius, forward_arrow,
49            // backward_arrow, npoints
50            fprintf(out, "2 1 %d %d %d 0 0 0 0 %5.3f 0 1 0 0 0 2\n\t%d %d %d %d\n",
51                    line_mode,
52                    AW_INT(line_width),
53                    find_color_idx(gcm->get_last_fg_color()),
54                    gap_ratio, 
55                    print_pos(clippedLine.xpos()),
56                    print_pos(clippedLine.ypos()),
57                    print_pos(clippedLine.head().xpos()),
58                    print_pos(clippedLine.head().ypos()));
59        }
60    }
61    return drawflag;
62}
63
64bool AW_device_print::invisible_impl(const AW::Position& pos, AW_bitset filteri) {
65    bool drawflag = false;
66    if (filteri & filter) {
67        Position trans = transform(pos);
68
69        drawflag = !is_outside_clip(trans);
70        if (drawflag) {
71            fprintf(out, "2 1 0 1 7 7 50 -1 -1 0.000 0 0 -1 0 0 1\n\t%d %d\n",
72                    print_pos(trans.xpos()),
73                    print_pos(trans.ypos()));
74        }
75    }
76    return drawflag;
77}
78
79static bool AW_draw_string_on_printer(AW_device *devicei, int gc, const char *str, size_t /* opt_strlen */, size_t start, size_t size,
80                                      AW_pos x, AW_pos y, AW_pos /*opt_ascent*/, AW_pos /*opt_descent*/,
81                                      AW_CL /*cduser*/)
82{
83    AW_pos           X, Y;
84    AW_device_print *device = (AW_device_print *)devicei;
85    AW_common       *common = device->get_common();
86    const AW_GC     *gcm    = common->map_gc(gc);
87
88    device->transform(x, y, X, Y);
89    char *pstr = strdup(str+start);
90    if (size < strlen(pstr)) pstr[size] = 0;
91    else size  = strlen(pstr);
92    size_t i;
93    for (i=0; i<size; i++) {
94        if (pstr[i] < ' ') pstr[i] = '?';
95    }
96    int fontnr = AW_font_2_xfig(gcm->get_fontnr());
97    if (fontnr<0) fontnr = - fontnr;
98    if (str[0]) {
99        // 4=string 0=left color depth penstyle font font_size angle
100        // font_flags height length x y string
101        // (font/fontsize and color/depth have been switched from format
102        // 2.1 to 3.2
103        fprintf(device->get_FILE(), "4 0 %d 0 0 %d %d 0.000 4 %d %d %d %d ",
104                device->find_color_idx(gcm->get_last_fg_color()),
105                fontnr,
106                gcm->get_fontsize(),
107                (int)gcm->get_font_limits().height,
108                device->get_string_size(gc, str, 0),
109                print_pos(X),
110                print_pos(Y));
111        char *p;
112        for (p = pstr; *p; p++) {
113            if (*p >= 32) putc(*p, device->get_FILE());
114        }
115        fprintf(device->get_FILE(), "\\001\n");
116    }
117    free(pstr);
118    return true;
119}
120
121#define DATA_COLOR_OFFSET 32
122
123GB_ERROR AW_device_print::open(const char *path) {
124    if (out) return "You cannot reopen a device";
125
126    out = fopen(path, "w");
127    if (!out) return GB_IO_error("writing", path);
128
129    fprintf(out,
130            "#FIG 3.2\n"   // version
131            "Landscape\n"  // "Portrait"
132            "Center\n"     // "Flush Left"
133            "Metric\n"     // "Inches"
134            "A4\n"         // papersize
135            "100.0\n"      // export&print magnification %
136            "Single\n"     // Single/Multiple Pages
137            "-3\n"         // background = transparent for gif export
138            "%i 2\n"       // dpi, 2  = origin in upper left corner
139            , DPI_PRINTER);
140
141    if (color_mode) {
142        for (int i=0; i<get_common()->get_data_color_size(); i++) {
143            unsigned long col = get_common()->get_data_color(i);
144            if (col != (unsigned long)AW_NO_COLOR) fprintf(out, "0 %d #%06lx\n", i+DATA_COLOR_OFFSET, col);
145        }
146    }
147
148    return 0;
149}
150
151int AW_common::find_data_color_idx(AW_rgb color) const {
152    for (int i=0; i<data_colors_size; i++) {
153        if (color == data_colors[i]) {
154            return i;
155        }
156    }
157    return -1;
158}
159
160int AW_device_print::find_color_idx(AW_rgb color) {
161    int idx = -1;
162    if (color_mode) {
163        idx = get_common()->find_data_color_idx(color);
164        if (idx >= 0) idx += DATA_COLOR_OFFSET;
165    }
166    return idx;
167}
168
169void AW_device_print::set_color_mode(bool mode) {
170    color_mode=mode;
171}
172
173void AW_device_print::close() {
174    if (out) fclose(out);
175    out = 0;
176}
177
178
179bool AW_device_print::text_impl(int gc, const char *str, const Position& pos, AW_pos alignment, AW_bitset filteri, long opt_strlen) {
180    return text_overlay(gc, str, opt_strlen, pos, alignment, filteri, (AW_CL)this, 0.0, 0.0, AW_draw_string_on_printer);
181}
182
183bool AW_device_print::box_impl(int gc, bool filled, const Rectangle& rect, AW_bitset filteri) {
184    bool drawflag = false;
185    if (filter & filteri) {
186        if (filled) {
187            Position q[4];
188            q[0] = rect.upper_left_corner();
189            q[1] = rect.upper_right_corner();
190            q[2] = rect.lower_right_corner();
191            q[3] = rect.lower_left_corner();
192
193            drawflag = filled_area(gc, 4, q, filteri);
194        }
195        else {
196            drawflag = generic_box(gc, false, rect, filteri);
197        }
198    }
199    return drawflag;
200}
201
202bool AW_device_print::circle_impl(int gc, bool filled, const Position& center, const AW::Vector& radius, AW_bitset filteri) {
203    bool drawflag = false;
204    if (filteri & filter) {
205        aw_assert(radius.x()>0 && radius.y()>0);
206        Rectangle Box(center-radius, center+radius);
207        Rectangle screen_box = transform(Box);
208        Rectangle clipped_box;
209        drawflag          = box_clip(screen_box, clipped_box);
210        bool half_visible = (clipped_box.surface()*2) > screen_box.surface();
211
212        drawflag = drawflag && half_visible;
213        // @@@ correct behavior would be to draw an arc if only partly visible
214
215        if (drawflag) {
216            const AW_GC *gcm = get_common()->map_gc(gc);
217
218            // force into clipped_box (hack):
219            Position Center        = clipped_box.centroid();
220            Vector   screen_radius = clipped_box.diagonal()/2;
221
222            int cx = print_pos(Center.xpos());
223            int cy = print_pos(Center.ypos());
224            int rx = print_pos(screen_radius.x());
225            int ry = print_pos(screen_radius.y());
226
227            {
228                int subtype = (rx == ry) ? 3 : 1; // 3(circle) 1(ellipse)
229                subtype     = 3; // @@@ remove after refactoring
230                fprintf(out, "1 %d  ", subtype);  // type + subtype:
231            }
232
233            {
234                int colorIdx = find_color_idx(gcm->get_last_fg_color());
235                int fill_color, area_fill;
236                if (filled) {
237                    fill_color = colorIdx;
238                    area_fill  = AW_INT(20+20*gcm->get_grey_level());    // 20 = full saturation; 40 = white;
239                }
240                else {
241                    fill_color = area_fill = -1;
242                }
243                int line_width = gcm->get_line_width();
244
245                fprintf(out, "%d %d ", AW_SOLID, line_width);   // line_style + line_width
246                fprintf(out, "%d %d 0 ", colorIdx, fill_color); // pen_color + fill_color + depth
247                fprintf(out, "0 %d ", area_fill);               // pen_style + area_fill (20 = full color, 40 = white)
248                fputs("0.000 1 0.0000 ", out);                  // style_val + direction + angle (x-axis)
249            }
250
251            fprintf(out, "%d %d ", cx, cy); // center
252            fprintf(out, "%d %d ", rx, ry); // radius
253            fprintf(out, "%d %d ", cx, cy); // start
254            fprintf(out, "%d %d\n", print_pos(Center.xpos()+screen_radius.x()), cy); // end
255        }
256    }
257    return drawflag;
258}
259
260bool AW_device_print::arc_impl(int gc, bool filled, const AW::Position& center, const AW::Vector& radius, int start_degrees, int arc_degrees, AW_bitset filteri) {
261    bool drawflag = false;
262    if (filteri && filter) {
263        aw_assert(radius.x()>0 && radius.y()>0);
264        Rectangle Box(center-radius, center+radius);
265        Rectangle screen_box = transform(Box);
266        Rectangle clipped_box;
267        drawflag          = box_clip(screen_box, clipped_box);
268        bool half_visible = (clipped_box.surface()*2) > screen_box.surface();
269
270        drawflag = drawflag && half_visible;
271        // @@@ correct behavior would be to draw an arc if only partly visible
272
273        if (drawflag) {
274            const AW_GC *gcm = get_common()->map_gc(gc);
275
276            // force into clipped_box (hack):
277            Position Center        = clipped_box.centroid();
278            Vector   screen_radius = clipped_box.diagonal()/2;
279
280            int cx = print_pos(Center.xpos());
281            int cy = print_pos(Center.ypos());
282            int rx = print_pos(screen_radius.x());
283            int ry = print_pos(screen_radius.y());
284
285            bool use_spline = (rx != ry); // draw interpolated spline for ellipsoid arcs
286
287            // fputs(use_spline ? "3 2 " : "5 1 ", out);  // type + subtype:
288            fputs(use_spline ? "3 4 " : "5 1 ", out);  // type + subtype:
289
290            {
291                int colorIdx = find_color_idx(gcm->get_last_fg_color());
292                int fill_color, area_fill;
293
294                if (filled) {
295                    fill_color = colorIdx;
296                    area_fill  = AW_INT(20+20*gcm->get_grey_level());    // 20 = full saturation; 40 = white;
297                }
298                else {
299                    fill_color = area_fill = -1;
300                }
301                int line_width = gcm->get_line_width();
302
303                fprintf(out, "%d %d ", AW_SOLID, line_width);   // line_style + line_width
304                fprintf(out, "%d %d 0 ", colorIdx, fill_color); // pen_color + fill_color + depth
305                fprintf(out, "0 %d ", area_fill);               // pen_style + area_fill (20 = full color, 40 = white)
306                fputs("0.000 1 ", out);                         // style_val + cap_style
307                if (!use_spline) fputs("1 ", out);              // direction
308                fputs("0 0 ", out);                             // 2 arrows
309            }
310
311            Angle a0(Angle::deg2rad*start_degrees);
312            Angle a1(Angle::deg2rad*(start_degrees+arc_degrees));
313
314            if (use_spline) {
315                const int MAX_ANGLE_STEP = 45; // degrees
316
317                int steps = (abs(arc_degrees)-1)/MAX_ANGLE_STEP+1;
318                Angle step(Angle::deg2rad*double(arc_degrees)/steps);
319
320                fprintf(out, "%d\n\t", steps+1); // npoints
321
322                double rmax, x_factor, y_factor;
323                if (rx>ry) {
324                    rmax     = rx;
325                    x_factor = 1.0;
326                    y_factor = double(ry)/rx;
327                }
328                else {
329                    rmax     = ry;
330                    x_factor = double(rx)/ry;
331                    y_factor = 1.0;
332                }
333
334                for (int n = 0; n <= steps; ++n) {
335                    Vector   toCircle  = a0.normal()*rmax;
336                    Vector   toEllipse(toCircle.x()*x_factor, toCircle.y()*y_factor);
337                    Position onEllipse = Center+toEllipse;
338
339                    int x = print_pos(onEllipse.xpos());
340                    int y = print_pos(onEllipse.ypos());
341
342                    fprintf(out, " %d %d", x, y);
343
344                    if (n<steps) {
345                        if (n == steps-1) a0 = a1;
346                        else              a0 += step;
347                    }
348                }
349                fputs("\n\t", out);
350                for (int n = 0; n <= steps; ++n) {
351                    // -1 = interpolate; 0 = discontinuity; 1 = approximate
352                    fprintf(out, " %d", (n == 0 || n == steps) ? 0 : -1);
353                }
354                fputc('\n', out);
355            }
356            else {
357                fprintf(out, "%d %d ", cx, cy); // center
358
359                Angle am(Angle::deg2rad*(start_degrees+arc_degrees*0.5));
360
361                double   r  = screen_radius.x();
362                Position p0 = Center+a0.normal()*r;
363                Position pm = Center+am.normal()*r;
364                Position p1 = Center+a1.normal()*r;
365
366                fprintf(out, "%d %d ",  print_pos(p0.xpos()), print_pos(p0.ypos()));
367                fprintf(out, "%d %d ",  print_pos(pm.xpos()), print_pos(pm.ypos()));
368                fprintf(out, "%d %d\n", print_pos(p1.xpos()), print_pos(p1.ypos()));
369            }
370        }
371    }
372    return drawflag;
373}
374
375bool AW_device_print::filled_area_impl(int gc, int npos, const Position *pos, AW_bitset filteri) {
376    bool drawflag = false;
377    if (filter & filteri) {
378        drawflag = generic_filled_area(gc, npos, pos, filteri);
379        if (drawflag) { // line visible -> area fill needed
380            const AW_GC *gcm = get_common()->map_gc(gc);
381
382            short greylevel             = (short)(gcm->get_grey_level()*22);
383            if (greylevel>21) greylevel = 21;
384
385            int line_width = gcm->get_line_width();
386
387            fprintf(out, "2 3 0 %d %d -1 0 0 %d 0.000 0 0 -1 0 0 %d\n",
388                    line_width, find_color_idx(gcm->get_last_fg_color()), greylevel, npos+1);
389
390            // @@@ method used here for clipping leads to wrong results,
391            // since group border (drawn by generic_filled_area() above) is clipped correctly,
392            // but filled content is clipped different.
393            //
394            // fix: clip the whole polygon before drawing border
395
396            for (int i=0; i <= npos; i++) {
397                int j = i == npos ? 0 : i; // print pos[0] after pos[n-1]
398
399                Position transPos = transform(pos[j]);
400                Position clippedPos;
401                ASSERT_RESULT(bool, true, force_into_clipbox(transPos, clippedPos)); 
402                fprintf(out, "   %d %d\n", print_pos(clippedPos.xpos()), print_pos(clippedPos.ypos()));
403            }
404        }
405    }
406    return drawflag;
407}
Note: See TracBrowser for help on using the repository browser.