source: branches/profile/WINDOW/aw_position.hxx

Last change on this file was 11454, checked in by westram, 10 years ago
  • use is_nan etc
  • 'infinite' is now invalid as coordinate or angle
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.2 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : aw_position.hxx                                   //
4//   Purpose   : Positions, Vectors and Angles                     //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in July 2007      //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#ifndef AW_POSITION_HXX
13#define AW_POSITION_HXX
14
15#ifndef AW_BASE_HXX
16#include "aw_base.hxx"
17#endif
18#ifndef ARB_ASSERT_H
19#include <arb_assert.h>
20#endif
21#ifndef ARBTOOLS_H
22#include <arbtools.h>
23#endif
24#ifndef _GLIBCXX_CMATH
25#include <cmath>
26#endif
27
28#ifndef aw_assert
29#define aw_assert(bed) arb_assert(bed)
30#endif
31
32// ------------------------
33//      validity checks
34
35#if defined(DEBUG)
36
37#define ISVALID(a) aw_assert((a).valid())
38
39inline const double& NONAN(const double& d) {
40    aw_assert(d == d);
41    return d;
42}
43
44#else
45#define ISVALID(a)
46#define NONAN(d)   (d)
47#endif // DEBUG
48
49namespace AW {
50
51    const double EPSILON = 0.001; // how equal is nearly equal
52
53    inline bool nearlyEqual(const double& val1, const double& val2) { return std::abs(val1-val2) < EPSILON; }
54    inline bool nearlyZero(const double& val) { return nearlyEqual(val, 0.0); }
55    inline double centroid(const double& val1, const double& val2) { return (val1+val2)*0.5; }
56
57    // -------------------------------------------------------
58    //      class Position represents 2-dimensional positions
59
60    // Note: orientation of drawn canvases is like shown in this figure:
61    //
62    //        __________________\ +x
63    //       |                  /                       .
64    //       |
65    //       |
66    //       |
67    //       |
68    //       |
69    //       |
70    //      \|/
71    //    +y
72    //
73    // i.e. rotating an angle by 90 degrees, means rotating it 3 hours in clockwise direction
74
75    class Vector;
76
77    class Position {
78        double x, y;
79
80        static bool is_between(const double& coord1, const double& between, const double& coord2) {
81            return ((coord1-between)*(between-coord2)) >= 0.0;
82        }
83
84    public:
85
86        bool valid() const { return !is_nan_or_inf(x) && !is_nan_or_inf(y); }
87
88        Position(double X, double Y) : x(X), y(Y) { ISVALID(*this); }
89        // Position(const Position& other) : x(other.x), y(other.y) { ISVALID(*this); }
90        Position() : x(NAN), y(NAN) {} // default is no position
91        ~Position() {}
92
93        inline Position& operator += (const Vector& v);
94        inline Position& operator -= (const Vector& v);
95
96        const double& xpos() const { return x; }
97        const double& ypos() const { return y; }
98
99        void setx(const double& X) { x = NONAN(X); }
100        void sety(const double& Y) { y = NONAN(Y); }
101
102        void movex(const double& X) { x += NONAN(X); }
103        void movey(const double& Y) { y += NONAN(Y); }
104
105        void move(const Vector& movement) { *this += movement; }
106        void moveTo(const Position& pos) { *this = pos; }
107
108        inline bool is_between(const Position& p1, const Position& p2) const {
109            return is_between(p1.x, x, p2.x) && is_between(p1.y, y, p2.y);
110        }
111    };
112
113    extern const Position Origin;
114
115    inline bool nearlyEqual(const Position& p1, const Position& p2) {
116        return
117            nearlyEqual(p1.xpos(), p2.xpos()) && 
118            nearlyEqual(p1.ypos(), p2.ypos()); 
119    }
120   
121    // -------------------------------
122    //      a 2D vector
123
124    class Vector {
125        Position       end;                         // endpoint of vector (vector starts at Position::origin)
126        mutable double len;                         // once calculated, length of vector is stored here (negative value means "not calculated")
127
128    public:
129        bool valid() const { return end.valid() && !is_nan(len); } // infinite len is allowed (but untested)
130
131        Vector()                                         : len(NAN) {} // default is not a vector
132        Vector(const double& X, const double& Y)         : end(X, Y), len(-1) { ISVALID(*this); } // vector (0,0)->(X,Y)
133        Vector(const double& X, const double& Y, const double& Length) : end(X, Y), len(Length) { ISVALID(*this); } // same with known length
134        explicit Vector(const Position& to)              : end(to), len(-1) { ISVALID(*this); } // vector origin->to
135        Vector(const Position& from, const Position& to) : end(to.xpos()-from.xpos(), to.ypos()-from.ypos()), len(-1) { ISVALID(*this); } // vector from->to
136        ~Vector() {}
137
138        const double& x() const { return end.xpos(); }
139        const double& y() const { return end.ypos(); }
140        const Position& endpoint() const { return end; }
141
142        Vector& set(const double& X, const double& Y, double Length = -1) { end = Position(X, Y); len = Length; return *this; }
143        Vector& setx(const double& X) { end.setx(X); len = -1; return *this; }
144        Vector& sety(const double& Y) { end.sety(Y); len = -1; return *this; }
145
146        const double& length() const {
147            if (len<0.0) len = sqrt(x()*x() + y()*y());
148            return len;
149        }
150
151        // length-modifying members:
152
153        Vector& operator *= (const double& factor)  { return set(x()*factor, y()*factor, length()*std::abs(factor)); }
154        Vector& operator /= (const double& divisor) { return operator *= (1.0/divisor); }
155
156        Vector& operator += (const Vector& other)  { return set(x()+other.x(), y()+other.y()); }
157        Vector& operator -= (const Vector& other)  { return set(x()-other.x(), y()-other.y()); }
158
159        Vector& normalize() {
160            aw_assert(length()>0); // cannot normalize zero-Vector!
161            return *this /= length();
162        }
163        bool is_normalized() const { return nearlyEqual(length(), 1); }
164        bool has_length() const { return !nearlyEqual(length(), 0); }
165
166        Vector& set_length(double new_length) {
167            double factor  = new_length/length();
168            return (*this  *= factor);
169        }
170
171        // length-constant members:
172
173        Vector& neg()  { end = Position(-x(), -y()); return *this; }
174        Vector& negx() { end.setx(-x()); return *this; }
175        Vector& negy() { end.sety(-y()); return *this; }
176
177        Vector& flipxy() { end = Position(y(), x()); return *this; }
178
179        Vector& rotate90deg()  { return negy().flipxy(); }
180        Vector& rotate180deg() { return neg(); }
181        Vector& rotate270deg() { return negx().flipxy(); }
182
183        Vector& rotate45deg();
184        Vector& rotate135deg() { return rotate45deg().rotate90deg(); }
185        Vector& rotate225deg() { return rotate45deg().rotate180deg(); }
186        Vector& rotate315deg() { return rotate45deg().rotate270deg(); }
187
188        Vector operator-() const { return Vector(-x(), -y(), len); } // unary minus
189    };
190
191    extern const Vector ZeroVector;
192
193    inline bool nearlyEqual(const Vector& v1, const Vector& v2) { return nearlyEqual(v1.endpoint(), v2.endpoint()); }
194   
195    // -----------------------------------------
196    //      inline Position members
197
198    inline Position& Position::operator += (const Vector& v) { x += v.x(); y += v.y(); ISVALID(*this); return *this; }
199    inline Position& Position::operator -= (const Vector& v) { x -= v.x(); y -= v.y(); ISVALID(*this); return *this; }
200
201    // ------------------------------------------
202    //      basic Position / Vector functions
203
204    // Difference between Positions
205    inline Vector operator-(const Position& to, const Position& from) { return Vector(from, to); }
206
207    // Position +- Vector -> new Position
208    inline Position operator+(const Position& p, const Vector& v) { return Position(p) += v; }
209    inline Position operator+(const Vector& v, const Position& p) { return Position(p) += v; }
210    inline Position operator-(const Position& p, const Vector& v) { return Position(p) -= v; }
211
212    // Vector addition
213    inline Vector operator+(const Vector& v1, const Vector& v2) { return Vector(v1) += v2; }
214    inline Vector operator-(const Vector& v1, const Vector& v2) { return Vector(v1) -= v2; }
215
216    // stretch/shrink Vector
217    inline Vector operator*(const Vector& v, const double& f) { return Vector(v) *= f; }
218    inline Vector operator*(const double& f, const Vector& v) { return Vector(v) *= f; }
219    inline Vector operator/(const Vector& v, const double& d) { return Vector(v) /= d; }
220
221    inline Position centroid(const Position& p1, const Position& p2) { return Position(centroid(p1.xpos(), p2.xpos()), centroid(p1.ypos(), p2.ypos())); }
222
223    inline double Distance(const Position& from, const Position& to) { return Vector(from, to).length(); }
224    inline double scalarProduct(const Vector& v1, const Vector& v2) { return v1.x()*v2.x() + v1.y()*v2.y(); }
225
226    inline bool are_distinct(const Position& p1, const Position& p2) { return Vector(p1, p2).has_length(); }
227
228    inline bool is_vertical(const Vector& v) { return nearlyZero(v.x()) && !nearlyZero(v.y()); }
229    inline bool is_horizontal(const Vector& v) { return !nearlyZero(v.x()) && nearlyZero(v.y()); }
230
231    inline Vector orthogonal_projection(const Vector& projectee, const Vector& target) {
232        //! returns the orthogonal projection of 'projectee' onto 'target'
233        double tlen = target.length();
234        return target * (scalarProduct(projectee, target) / (tlen*tlen));
235    }
236    inline Vector normalized(const Vector& v) {
237        //! returns the normalized Vector of 'v', i.e. a Vector with same orientation, but length 1
238        return Vector(v).normalize();
239    }
240    inline bool are_parallel(const Vector& v1, const Vector& v2) {
241        //! returns true, if two vectors have the same orientation
242        Vector diff = normalized(v1)-normalized(v2);
243        return !diff.has_length();
244    }
245    //! returns true, if two vectors have opposite orientations
246    inline bool are_antiparallel(const Vector& v1, const Vector& v2) { return are_parallel(v1, -v2); }
247
248    // -------------------------------------------------
249    //      a positioned vector, representing a line
250
251    enum AW_screen_area_conversion_mode { INCLUSIVE_OUTLINE, UPPER_LEFT_OUTLINE };
252
253    class LineVector {
254        Position Start;         // start point
255        Vector   ToEnd;         // vector to end point
256
257    protected:
258        void standardize();
259
260    public:
261        bool valid() const { return Start.valid() && ToEnd.valid(); }
262
263        LineVector(const Position& startpos, const Position& end) : Start(startpos), ToEnd(startpos, end) { ISVALID(*this); }
264        LineVector(const Position& startpos, const Vector& to_end) : Start(startpos), ToEnd(to_end) { ISVALID(*this); }
265        LineVector(double X1, double Y1, double X2, double Y2) : Start(X1, Y1), ToEnd(X2-X1, Y2-Y1) { ISVALID(*this); }
266        explicit LineVector(const AW_screen_area& r, AW_screen_area_conversion_mode mode) {
267            switch (mode) {
268                case INCLUSIVE_OUTLINE:
269                    Start = Position(r.l, r.t);
270                    ToEnd = Vector(r.r-r.l+1, r.b-r.t+1);
271                    break;
272                case UPPER_LEFT_OUTLINE: 
273                    Start = Position(r.l, r.t);
274                    ToEnd = Vector(r.r-r.l, r.b-r.t);
275                    break;
276            }
277            ISVALID(*this);
278        }
279        explicit LineVector(const AW_world& r) : Start(r.l, r.t), ToEnd(r.r-r.l, r.b-r.t) { ISVALID(*this); }
280        LineVector() {}
281
282        const Vector& line_vector() const { return ToEnd; }
283        const Position& start() const { return Start; }
284        Position head() const { return Start+ToEnd; }
285
286        Position centroid() const { return Start+ToEnd*0.5; }
287        double length() const { return line_vector().length(); }
288        bool has_length() const { return line_vector().has_length(); }
289
290        const double& xpos() const { return Start.xpos(); }
291        const double& ypos() const { return Start.ypos(); }
292
293        void move(const Vector& movement) { Start += movement; }
294        void moveTo(const Position& pos) { Start = pos; }
295
296        LineVector reverse() const { return LineVector(head(), Vector(ToEnd).neg()); }
297    };
298
299    Position crosspoint(const LineVector& l1, const LineVector& l2, double& factor_l1, double& factor_l2);
300    Position nearest_linepoint(const Position& pos, const LineVector& line, double& factor);
301    inline Position nearest_linepoint(const Position& pos, const LineVector& line) { double dummy; return nearest_linepoint(pos, line, dummy); }
302    inline double Distance(const Position& pos, const LineVector& line) { return Distance(pos, nearest_linepoint(pos, line)); }
303
304    inline bool is_vertical(const LineVector& line) { return is_vertical(line.line_vector()); }
305    inline bool is_horizontal(const LineVector& line) { return is_horizontal(line.line_vector()); }
306    inline bool nearlyEqual(const LineVector& L1, const LineVector& L2) {
307        return
308            nearlyEqual(L1.line_vector(), L2.line_vector()) &&
309            nearlyEqual(L1.start(), L2.start());
310    }
311   
312    // ---------------------
313    //      a rectangle
314
315    class Rectangle : public LineVector { // the LineVector describes one corner and the diagonal
316    public:
317        explicit Rectangle(const LineVector& Diagonal) : LineVector(Diagonal) { standardize(); }
318        Rectangle(const Position& corner, const Position& opposite_corner) : LineVector(corner, opposite_corner) { standardize(); }
319        Rectangle(const Position& corner, const Vector& to_opposite_corner) : LineVector(corner, to_opposite_corner) { standardize(); }
320        Rectangle(double X1, double Y1, double X2, double Y2) : LineVector(X1, Y1, X2, Y2) { standardize(); }
321        explicit Rectangle(const AW_screen_area& r, AW_screen_area_conversion_mode mode) : LineVector(r, mode) { standardize(); }
322        explicit Rectangle(const AW_world& r) : LineVector(r) { standardize(); }
323        Rectangle() {};
324
325        const Vector& diagonal() const { return line_vector(); }
326
327        const Position& upper_left_corner() const { return start(); }
328        Position lower_left_corner()        const { return Position(start().xpos(),                   start().ypos()+line_vector().y()); }
329        Position upper_right_corner()       const { return Position(start().xpos()+line_vector().x(), start().ypos()); }
330        Position lower_right_corner()       const { return head(); }
331
332        double left()   const { return upper_left_corner().xpos(); }
333        double top()    const { return upper_left_corner().ypos(); }
334        double right()  const { return lower_right_corner().xpos(); }
335        double bottom() const { return lower_right_corner().ypos(); }
336
337        double width() const { return diagonal().x(); }
338        double height() const { return diagonal().y(); }
339
340        LineVector upper_edge() const { return LineVector(start(), Vector(line_vector().x(),  0)); }
341        LineVector left_edge()  const { return LineVector(start(), Vector(0,                  line_vector().y())); }
342        LineVector lower_edge() const { return LineVector(head(),  Vector(-line_vector().x(), 0)); }
343        LineVector right_edge() const { return LineVector(head(),  Vector(0,                  -line_vector().y())); }
344
345        LineVector horizontal_extent() const { return LineVector(left_edge().centroid(), Vector(width(), 0.0)); }
346        LineVector vertical_extent() const { return LineVector(upper_edge().centroid(), Vector(0.0, height())); }
347
348        LineVector bigger_extent() const { return width()>height() ? horizontal_extent() : vertical_extent(); }
349        LineVector smaller_extent() const { return width()<height() ? horizontal_extent() : vertical_extent(); }
350
351        void standardize() { LineVector::standardize(); }
352
353        bool contains(const Position& pos) const { return pos.is_between(upper_left_corner(), lower_right_corner()); }
354        bool contains(const LineVector& lvec) const { return contains(lvec.start()) && contains(lvec.head()); }
355
356        bool distinct_from(const Rectangle& rect) const {
357            // returns false for adjacent rectangles (even if they only share one corner)
358            return
359                top()       > rect.bottom() ||
360                rect.top()  > bottom()      ||
361                left()      > rect.right()  ||
362                rect.left() > right();
363        }
364        bool overlaps_with(const Rectangle& rect) const { return !distinct_from(rect); }
365
366        Rectangle intersect_with(const Rectangle& rect) const {
367            aw_assert(overlaps_with(rect));
368            return Rectangle(Rectangle(upper_left_corner(), rect.upper_left_corner()).lower_right_corner(),
369                             Rectangle(lower_right_corner(), rect.lower_right_corner()).upper_left_corner());
370        }
371
372        Rectangle bounding_box(const Rectangle& rect) const {
373            return Rectangle(Rectangle(upper_left_corner(), rect.upper_left_corner()).upper_left_corner(),
374                             Rectangle(lower_right_corner(), rect.lower_right_corner()).lower_right_corner());
375        }
376        Rectangle bounding_box(const Position& pos) const {
377            return Rectangle(Rectangle(upper_left_corner(), pos).upper_left_corner(),
378                             Rectangle(lower_right_corner(), pos).lower_right_corner());
379        }
380
381        double surface() const { return width()*height(); }
382    };
383
384    inline Rectangle bounding_box(const Rectangle& r1, const Rectangle& r2) { return r1.bounding_box(r2); }
385
386    inline Rectangle bounding_box(const Rectangle& rect, const LineVector& line) { return rect.bounding_box(Rectangle(line)); }
387    inline Rectangle bounding_box(const LineVector& line, const Rectangle& rect) { return rect.bounding_box(Rectangle(line)); }
388
389    inline Rectangle bounding_box(const LineVector& l1, const LineVector& l2) { return Rectangle(l1).bounding_box(Rectangle(l2)); }
390
391    inline Rectangle bounding_box(const Rectangle& rect, const Position& pos) { return rect.bounding_box(pos); }
392    inline Rectangle bounding_box(const Position& pos, const Rectangle& rect) { return rect.bounding_box(pos); }
393
394    inline Rectangle bounding_box(const LineVector& line, const Position& pos) { return Rectangle(line).bounding_box(pos); }
395    inline Rectangle bounding_box(const Position& pos, const LineVector& line) { return Rectangle(line).bounding_box(pos); }
396   
397    inline Rectangle bounding_box(const Position& p1, const Position& p2) { return Rectangle(p1, p2); }
398
399
400    // ------------------------------------------------------------------
401    //      class angle represents an angle using a normalized vector
402
403    class Angle {
404        mutable Vector Normal;  // the normal vector representing the angle (x = cos(angle), y = sin(angle))
405        mutable double Radian;  // the radian of the angle
406
407        void recalcRadian() const;
408        void recalcNormal() const;
409
410    public:
411        bool valid() const { return Normal.valid() && !is_nan_or_inf(Radian); }
412
413        static const double rad2deg;
414        static const double deg2rad;
415
416        explicit Angle(double Radian_) : Radian(Radian_) { recalcNormal(); ISVALID(*this); }
417        Angle(double x, double y) : Normal(x, y) { Normal.normalize(); recalcRadian(); ISVALID(*this); }
418        explicit Angle(const Vector& v) : Normal(v) { Normal.normalize(); recalcRadian(); ISVALID(*this); }
419        Angle(const Vector& n, double r) : Normal(n), Radian(r) { aw_assert(n.is_normalized()); ISVALID(*this); }
420        Angle(const Position& p1, const Position& p2) : Normal(p1, p2) { Normal.normalize(); recalcRadian(); ISVALID(*this); }
421        Angle() : Radian(NAN) {}  // default is not an angle
422
423        Angle& operator = (const Angle& other) { Normal = other.Normal; Radian = other.Radian; return *this; }
424        Angle& operator = (const Vector& vec) { Normal = vec; Normal.normalize(); recalcRadian(); return *this; }
425
426        void fixRadian() const { // force radian into range [0, 2*M_PI[
427            while (Radian<0.0) Radian       += 2*M_PI;
428            while (Radian >= 2*M_PI) Radian -= 2*M_PI;
429        }
430
431        const double& radian() const { fixRadian(); return Radian; }
432        double degrees() const { fixRadian(); return rad2deg*Radian; }
433        const Vector& normal() const { return Normal; }
434
435        const double& sin() const { return Normal.y(); }
436        const double& cos() const { return Normal.x(); }
437
438        Angle& operator += (const Angle& o) {
439            Radian += o.Radian;
440
441            double norm = normal().length()*o.normal().length();
442            if (nearlyEqual(norm, 1)) {  // fast method
443                Vector newNormal(cos()*o.cos() - sin()*o.sin(),
444                                 sin()*o.cos() + cos()*o.sin());
445                aw_assert(newNormal.is_normalized());
446                Normal = newNormal;
447            }
448            else {
449                recalcNormal();
450            }
451            return *this;
452        }
453        Angle& operator -= (const Angle& o) {
454            Radian -= o.Radian;
455
456            double norm = normal().length()*o.normal().length();
457            if (nearlyEqual(norm, 1)) { // fast method
458                Vector newNormal(cos()*o.cos() + sin()*o.sin(),
459                                 sin()*o.cos() - cos()*o.sin());
460                aw_assert(newNormal.is_normalized());
461
462                Normal = newNormal;
463            }
464            else {
465                recalcNormal();
466            }
467            return *this;
468        }
469
470        Angle& operator *= (const double& fact) {
471            fixRadian();
472            Radian *= fact;
473            recalcNormal();
474            return *this;
475        }
476
477        Angle& rotate90deg()   { Normal.rotate90deg();  Radian += 0.5*M_PI; return *this; }
478        Angle& rotate180deg()  { Normal.rotate180deg(); Radian +=     M_PI; return *this; }
479        Angle& rotate270deg()  { Normal.rotate270deg(); Radian += 1.5*M_PI; return *this; }
480
481        Angle operator-() const { return Angle(Vector(Normal).negy(), 2*M_PI-Radian); } // unary minus
482    };
483
484    inline Angle operator+(const Angle& a1, const Angle& a2) { return Angle(a1) += a2; }
485    inline Angle operator-(const Angle& a1, const Angle& a2) { return Angle(a1) -= a2; }
486
487    inline Angle operator*(const Angle& a, const double& fact) { return Angle(a) *= fact; }
488    inline Angle operator/(const Angle& a, const double& divi) { return Angle(a) *= (1.0/divi); }
489
490    // ---------------------
491    //      some helpers
492
493    // pythagoras:
494
495    inline double hypotenuse(double cath1, double cath2) { return sqrt(cath1*cath1 + cath2*cath2); }
496    inline double cathetus(double hypotenuse, double cathetus) {
497        aw_assert(hypotenuse>cathetus);
498        return sqrt(hypotenuse*hypotenuse - cathetus*cathetus);
499    }
500
501#if defined(DEBUG)
502    // don't use these in release code - they are only approximations!
503
504    // test whether two doubles are "equal" (slow - use for assertions only!)
505    inline bool are_equal(const double& d1, const double& d2) {
506        double diff = std::abs(d1-d2);
507        return diff < 0.000001;
508    }
509
510    inline bool are_orthographic(const Vector& v1, const Vector& v2) { // orthogonal (dt.)
511        return are_equal(scalarProduct(v1, v2), 0);
512    }
513
514#endif // DEBUG
515
516    inline bool isOrigin(const Position& p) {
517        return p.xpos() == 0 && p.ypos() == 0;
518    }
519
520#if defined(DEBUG)
521    inline void aw_dump(const double& p, const char *varname) {
522        fprintf(stderr, "%s=%f", varname, p);
523    }
524    inline void aw_dump(const Position& p, const char *varname) {
525        fprintf(stderr, "Position %s={ ", varname);
526        aw_dump(p.xpos(), "x"); fputs(", ", stderr);
527        aw_dump(p.ypos(), "y"); fputs(" }", stderr);
528    }
529    inline void aw_dump(const Vector& v, const char *varname) {
530        fprintf(stderr, "Vector %s={ ", varname);
531        aw_dump(v.x(), "x"); fputs(", ", stderr);
532        aw_dump(v.y(), "y"); fputs(" }", stderr);
533    }
534    inline void aw_dump(const LineVector& v, const char *varname) {
535        fprintf(stderr, "LineVector %s={ ", varname);
536        aw_dump(v.start(), "start"); fputs(", ", stderr);
537        aw_dump(v.line_vector(), "line_vector"); fputs(" }", stderr);
538       
539    }
540    inline void aw_dump(const Rectangle& r, const char *varname) {
541        fprintf(stderr, "Rectangle %s={ ", varname);
542        aw_dump(r.upper_left_corner(), "upper_left_corner"); fputs(", ", stderr);
543        aw_dump(r.lower_right_corner(), "lower_right_corner"); fputs(" }", stderr);
544    }
545
546#define AW_DUMP(x) do { aw_dump(x, #x); fputc('\n', stderr); } while(0)
547   
548#endif
549
550};
551
552#else
553#error aw_position.hxx included twice
554#endif // AW_POSITION_HXX
Note: See TracBrowser for help on using the repository browser.