source: branches/help/WINDOW/aw_position.hxx

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