source: branches/help/WINDOW/AW_clipable.cxx

Last change on this file was 16873, checked in by westram, 7 years ago
  • fix typos ("neither")
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_clipable.cxx                                   //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "aw_window.hxx"
12#include "aw_root.hxx"
13#include "aw_common_xm.hxx"
14
15#include <arb_msg.h>
16
17using namespace AW;
18
19inline AW_pos clip_in_range(AW_pos low, AW_pos val, AW_pos high) {
20    if (val <= low) return low;
21    if (val >= high) return high;
22    return val;
23}
24
25bool AW_clipable::box_clip(AW_pos x0, AW_pos y0, AW_pos x1, AW_pos y1, AW_pos& x0out, AW_pos& y0out, AW_pos& x1out, AW_pos& y1out) {
26    // clip coordinates of a box
27
28    aw_assert(x0 <= x1);
29    aw_assert(y0 <= y1);
30
31    if (x1<clip_rect.l || x0>clip_rect.r) return false;
32    if (y1<clip_rect.t || y0>clip_rect.b) return false;
33
34    if (completely_clipped()) return false;
35
36    x0out = clip_in_range(clip_rect.l, x0, clip_rect.r);
37    x1out = clip_in_range(clip_rect.l, x1, clip_rect.r);
38    y0out = clip_in_range(clip_rect.t, y0, clip_rect.b);
39    y1out = clip_in_range(clip_rect.t, y1, clip_rect.b);
40
41    return true;
42}
43
44bool AW_clipable::box_clip(const Rectangle& rect, Rectangle& clippedRect) { // @@@ maybe return clippedRect as AW_screen_area
45    if (completely_clipped()) return false;
46
47    Rectangle clipRect(clip_rect, UPPER_LEFT_OUTLINE);
48    if (rect.distinct_from(clipRect))
49        return false;
50
51    clippedRect = rect.intersect_with(clipRect);
52    return true;
53}
54
55inline Position rect_corner(const Rectangle& rect, int n) {
56    if (n == 0) return rect.upper_left_corner();
57    if (n == 1) return rect.upper_right_corner();
58    if (n == 2) return rect.lower_right_corner();
59    return rect.lower_left_corner();
60}
61
62bool AW_clipable::need_extra_clip_position(const AW::Position& p1, const AW::Position& p2, AW::Position& extra) {
63    // calculates one extra needed position
64    //
65    // (may be caused by clipping, e.g. if a Position is clipped and the two adjacent lines cross different
66    //  sides of the clipping rectangle)
67    //
68    // Note:
69    // - needs to be called until it returns false! (use 'extra' of 1st call as 'p1' for 2nd call, ...)
70    // - returns corner of clipping rectangle adjacent to p1
71
72    bool yequal = nearlyEqual(p1.ypos(), p2.ypos());
73    if (!yequal) {
74        bool xequal = nearlyEqual(p1.xpos(), p2.xpos());
75        if (!xequal) {
76            Rectangle clipRect(clip_rect, UPPER_LEFT_OUTLINE);
77
78            for (int c = 0; c<4; ++c) {
79                Position corner = rect_corner(clipRect, c);
80                if (nearlyEqual(p1.xpos(), corner.xpos()) && nearlyEqual(p2.ypos(), corner.ypos())) {
81                    extra = corner;
82                    return true;
83                }
84                if (nearlyEqual(p1.ypos(), corner.ypos()) && nearlyEqual(p2.xpos(), corner.xpos())) {
85                    extra = corner;
86                    return true;
87                }
88            }
89
90            // fprintf(stderr, "Failed to find extra needed position:\n");
91            // AW_DUMP(p1);
92            // AW_DUMP(p2);
93            // AW_DUMP(clipRect);
94
95            // happens rarely, no display bugs seen -> ignore
96        }
97    }
98    return false;
99}
100
101bool AW_clipable::box_clip(int npos, const Position *pos, int& nclippedPos, Position*& clippedPos) {
102    aw_assert(!clippedPos);
103
104    bool is_visible = false;    // indicates whether part of the polygon is visible
105
106    nclippedPos            = 0;
107    const int MAX_POSS_POS = npos*2;
108    clippedPos             = new Position[MAX_POSS_POS];
109
110    for (int i = 0; i<npos; ++i) {
111        int j = i+1;
112        if (j == npos) j = 0;
113
114        LineVector v(pos[i], pos[j]);
115        LineVector vclipped;
116        if (clip(v, vclipped)) { // drawn
117            is_visible = true;
118            if (!nclippedPos) { // first entry
119                clippedPos[nclippedPos++] = vclipped.start();
120                clippedPos[nclippedPos++] = vclipped.head();
121            }
122            else {
123                if (nearlyEqual(clippedPos[nclippedPos-1], vclipped.start())) { // neither current nor last line was clipped at 'start'
124                    clippedPos[nclippedPos++] = vclipped.head();
125                }
126                else {
127                    Position extra;
128                    if (need_extra_clip_position(clippedPos[nclippedPos-1], vclipped.start(), extra)) {
129                        clippedPos[nclippedPos++] = extra;
130                    }
131                    clippedPos[nclippedPos++] = vclipped.start();
132                    clippedPos[nclippedPos++] = vclipped.head();
133                }
134            }
135        }
136        if (j == 0 && nclippedPos>0) { // last line
137            Position extra;
138            if (need_extra_clip_position(clippedPos[nclippedPos-1], clippedPos[0], extra)) {
139                clippedPos[nclippedPos++] = extra;
140            }
141        }
142    }
143
144    aw_assert(nclippedPos<=MAX_POSS_POS);
145
146    return is_visible;
147}
148
149bool AW_clipable::clip(AW_pos x0, AW_pos y0, AW_pos x1, AW_pos y1, AW_pos& x0out, AW_pos& y0out, AW_pos& x1out, AW_pos& y1out) {
150    // clip coordinates of a line
151
152    int    outcodeout;
153    AW_pos x = 0;
154    AW_pos y = 0;
155
156    bool is_visible = false;    // indicates whether part of line is visible
157    bool done       = false;    // true soon as line is completely inside or outside rectangle
158
159    while (!done) {
160        int outcode0 = compoutcode(x0, y0);
161        int outcode1 = compoutcode(x1, y1);
162
163        if ((outcode0 | outcode1) == 0) { // line is inside the rectangle
164            x0out = x0; y0out = y0; // clipped coordinates of line
165            x1out = x1; y1out = y1;
166
167            done    = true;
168            is_visible = true;
169        }
170        else if ((outcode0 & outcode1) != 0) { // line is outside the rectangle
171            done = true;
172        }
173        else { // line overlaps with at least one rectangle border
174            outcodeout = outcode0>0 ? outcode0 : outcode1;
175
176            if ((outcodeout & 8) != 0) { // overlap at top
177                x = x0+(x1-x0)*(clip_rect.t-y0)/(y1-y0);
178                y = clip_rect.t;
179            }
180            else if ((outcodeout & 4) != 0) { // overlap at bottom
181                x = x0+(x1-x0)*(clip_rect.b-y0)/(y1-y0);
182                y = clip_rect.b;
183            }
184            else if ((outcodeout & 2) != 0) { // overlap at right side
185                y = y0+(y1-y0)*(clip_rect.r-x0)/(x1-x0);
186                x = clip_rect.r;
187            }
188            else if ((outcodeout & 1) != 0) {
189                y = y0+(y1-y0)*(clip_rect.l-x0)/(x1-x0); // overlap at left side
190                x = clip_rect.l;
191            }
192
193            // set corrected point and iterate :
194            if (outcode0 > 0) {
195                x0 = x;
196                y0 = y;
197            }
198            else {
199                x1 = x;
200                y1 = y;
201            }
202        }
203    }
204
205    return is_visible;
206}
207
208bool AW_clipable::clip(const LineVector& line, LineVector& clippedLine) {
209    AW_pos x0, y0, x1, y1;
210    bool   drawflag = clip(line.start().xpos(), line.start().ypos(), line.head().xpos(), line.head().ypos(),
211                           x0, y0, x1, y1);
212    if (drawflag) clippedLine = LineVector(x0, y0, x1, y1);
213    return drawflag;
214}
215void AW_clipable::set_bottom_clip_border(int bottom, bool allow_oversize) {
216    clip_rect.b = bottom;
217    if (!allow_oversize) {
218        if (clip_rect.b > get_screen().b) clip_rect.b = get_screen().b;
219    }
220    else {
221        set_bottom_font_overlap(true); // added 21.6.02 --ralf
222    }
223}
224
225void AW_clipable::set_left_clip_border(int left, bool allow_oversize) {
226    clip_rect.l = left;
227    if (!allow_oversize) {
228        if (clip_rect.l < get_screen().l) clip_rect.l = get_screen().l;
229    }
230    else {
231        set_left_font_overlap(true); // added 21.6.02 --ralf
232    }
233}
234
235void AW_clipable::set_right_clip_border(int right, bool allow_oversize) {
236    clip_rect.r = right;
237    if (!allow_oversize) {
238        if (clip_rect.r > get_screen().r) clip_rect.r = get_screen().r;
239    }
240    else {
241        set_right_font_overlap(true); // added to correct problem with last char skipped (added 21.6.02 --ralf)
242    }
243}
244
245void AW_clipable::set_top_clip_border(int top, bool allow_oversize) {
246    clip_rect.t = top;
247    if (!allow_oversize) {
248        if (clip_rect.t < get_screen().t) clip_rect.t = get_screen().t;
249    }
250    else {
251        set_top_font_overlap(true); // added 21.6.02 --ralf
252    }
253}
254
255
256int AW_clipable::reduceClipBorders(int top, int bottom, int left, int right) {
257    // return 0 if no clipping area left
258    if (top    > clip_rect.t) clip_rect.t = top;
259    if (bottom < clip_rect.b) clip_rect.b = bottom;
260    if (left   > clip_rect.l) clip_rect.l = left;
261    if (right  < clip_rect.r) clip_rect.r = right;
262
263    return !(clip_rect.b<clip_rect.t || clip_rect.r<clip_rect.l);
264}
265
266void AW_clipable::set_cliprect_oversize(const AW_screen_area& rect, bool allow_oversize) {
267    clip_rect = rect;
268
269    const AW_screen_area& screen = get_screen();
270    if (!allow_oversize) {
271        if (clip_rect.t < screen.t) clip_rect.t = screen.t;
272        if (clip_rect.b > screen.b) clip_rect.b = screen.b;
273        if (clip_rect.l < screen.l) clip_rect.l = screen.l;
274        if (clip_rect.r > screen.r) clip_rect.r = screen.r;
275    }
276
277    set_font_overlap(false);
278
279    if (allow_oversize) { // added 21.6.02 --ralf
280        if (clip_rect.t < screen.t) set_top_font_overlap(true);
281        if (clip_rect.b > screen.b) set_bottom_font_overlap(true);
282        if (clip_rect.l < screen.l) set_left_font_overlap(true);
283        if (clip_rect.r > screen.r) set_right_font_overlap(true);
284    }
285}
286
287void AW_clipable::reduce_top_clip_border(int top) {
288    if (top > clip_rect.t) clip_rect.t = top;
289}
290void AW_clipable::reduce_bottom_clip_border(int bottom) {
291    if (bottom < clip_rect.b)     clip_rect.b = bottom;
292}
293void AW_clipable::reduce_left_clip_border(int left) {
294    if (left > clip_rect.l)clip_rect.l = left;
295}
296void AW_clipable::reduce_right_clip_border(int right) {
297    if (right < clip_rect.r)    clip_rect.r = right;
298}
299
300void AW_clipable::set_bottom_clip_margin(int bottom, bool allow_oversize) {
301    clip_rect.b -= bottom;
302    if (!allow_oversize) {
303        if (clip_rect.b > get_screen().b) clip_rect.b = get_screen().b;
304    }
305    else {
306        set_bottom_font_overlap(true); // added 21.6.02 --ralf
307    }
308}
309bool AW_clipable::force_into_clipbox(const Position& pos, Position& forcedPos) {
310    // force 'pos' inside 'clip_rect'
311    if (completely_clipped()) return false;
312
313    forcedPos.setx(clip_in_range(clip_rect.l, pos.xpos(), clip_rect.r));
314    forcedPos.sety(clip_in_range(clip_rect.t, pos.ypos(), clip_rect.b));
315    return true;
316}
317
Note: See TracBrowser for help on using the repository browser.