ARB
AW_clipable.cxx
Go to the documentation of this file.
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 
17 using namespace AW;
18 
19 inline 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 
25 bool 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 
44 bool 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 
55 inline 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 
62 bool 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 
101 bool 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 
149 bool 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 
208 bool 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 }
215 void 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 
225 void 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 
235 void 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 
245 void 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 
256 int 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 
266 void 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 
288  if (top > clip_rect.t) clip_rect.t = top;
289 }
291  if (bottom < clip_rect.b) clip_rect.b = bottom;
292 }
294  if (left > clip_rect.l)clip_rect.l = left;
295 }
297  if (right < clip_rect.r) clip_rect.r = right;
298 }
299 
300 void 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 }
309 bool 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 
Position rect_corner(const Rectangle &rect, int n)
Definition: AW_clipable.cxx:55
bool 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)
Definition: AW_clipable.cxx:25
static char * y[maxsp+1]
void reduce_bottom_clip_border(int bottom)
bool nearlyEqual(const double &val1, const double &val2)
Definition: aw_position.hxx:75
void set_left_clip_border(int left, bool allow_oversize=false)
int reduceClipBorders(int top, int bottom, int left, int right)
void reduce_left_clip_border(int left)
void reduce_top_clip_border(int top)
void reduce_right_clip_border(int right)
AW_pos clip_in_range(AW_pos low, AW_pos val, AW_pos high)
Definition: AW_clipable.cxx:19
void set_top_clip_border(int top, bool allow_oversize=false)
bool 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)
bool distinct_from(const Rectangle &rect) const
void sety(const double &Y)
const Position & start() const
double AW_pos
Definition: aw_base.hxx:29
const double & ypos() const
Rectangle intersect_with(const Rectangle &rect) const
void set_bottom_clip_border(int bottom, bool allow_oversize=false)
#define aw_assert(bed)
Definition: aw_position.hxx:29
Position lower_left_corner() const
const Position & upper_left_corner() const
void set_bottom_clip_margin(int bottom, bool allow_oversize=false)
void setx(const double &X)
void set_right_clip_border(int right, bool allow_oversize=false)
Position upper_right_corner() const
Position head() const
const double & xpos() const
static int line
Definition: arb_a2ps.c:296
Position lower_right_corner() const
bool force_into_clipbox(const AW::Position &pos, AW::Position &forcedPos)