~ubuntu-branches/ubuntu/saucy/merkaartor/saucy

« back to all changes in this revision

Viewing changes to Utils/LineF.h

  • Committer: Bazaar Package Importer
  • Author(s): Bernd Zeimetz
  • Date: 2009-09-13 00:52:12 UTC
  • mto: (1.2.7 upstream) (0.1.3 upstream) (3.1.7 sid)
  • mto: This revision was merged to the branch mainline in revision 10.
  • Revision ID: james.westby@ubuntu.com-20090913005212-pjecal8zxm07x0fj
ImportĀ upstreamĀ versionĀ 0.14+svnfixes~20090912

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#ifndef MERKAARTOR_LINEF_
2
 
#define MERKAARTOR_LINEF_
3
 
 
4
 
#include "Map/Coord.h"
5
 
 
6
 
#include <QtCore/QPointF>
7
 
 
8
 
#include <math.h>
9
 
#ifndef M_PI
10
 
#define M_PI        3.14159265358979323846
11
 
#endif
12
 
#ifndef M_PI_2
13
 
#define M_PI_2          1.57079632679489661923
14
 
#endif
15
 
 
16
 
inline double distance(const QPointF& A, const QPointF& B)
17
 
{
18
 
        double dx = A.x()-B.x();
19
 
        double dy = A.y()-B.y();
20
 
        return sqrt( dx*dx+dy*dy );
21
 
}
22
 
 
23
 
inline double length(const QPointF& A)
24
 
{
25
 
        return sqrt(A.x()*A.x()+A.y()*A.y());
26
 
}
27
 
 
28
 
inline double angle(const QPointF& A, const QPointF& B)
29
 
{
30
 
        double d = A.x()*B.x()+A.y()*B.y();
31
 
        double x = A.x()*B.y()-A.y()*B.x();
32
 
        // numerical stability : in extreme cases the argument of asin gets slightly larger than 1
33
 
        if (fabs(d) < 0.00001)
34
 
                return (x>0)?M_PI_2:-M_PI;
35
 
        x = asin(x/(length(A)*length(B)));
36
 
        if (d<0)
37
 
        {
38
 
                if (x > 0)
39
 
                        x = M_PI - x;
40
 
                else
41
 
                        x = -M_PI - x;
42
 
        }
43
 
        return x;
44
 
 
45
 
}
46
 
 
47
 
inline double angle(const QPointF& A)
48
 
{
49
 
        return atan2(A.y(),A.x());
50
 
}
51
 
 
52
 
inline QPointF toQt(const Coord& C)
53
 
{
54
 
        return QPointF(C.lat(),C.lon());
55
 
}
56
 
 
57
 
inline Coord toCoord(const QPointF& F)
58
 
{
59
 
        return Coord(int(F.x()),int(F.y()));
60
 
}
61
 
 
62
 
class LineF
63
 
{
64
 
public:
65
 
        LineF(const QPointF& aP1, const QPointF& aP2)
66
 
                : P1(aP1), P2(aP2), Valid(true)
67
 
        {
68
 
                init();
69
 
        }
70
 
 
71
 
        LineF(const QPoint& aP1, const QPoint& aP2)
72
 
                : P1(aP1), P2(aP2), Valid(true)
73
 
        {
74
 
                init();
75
 
        }
76
 
 
77
 
        LineF(const Coord& aP1, const Coord& aP2)
78
 
                : P1(aP1.lat(),aP1.lon()), P2(aP2.lat(),aP2.lon()), Valid(true)
79
 
        {
80
 
                init();
81
 
        }
82
 
 
83
 
        void init()
84
 
        {
85
 
                A = P2.y()-P1.y();
86
 
                B = -P2.x()+P1.x();
87
 
                C = -P1.y()*B-P1.x()*A;
88
 
                double F = sqrt(A*A+B*B);
89
 
                if (F<0.00000001)
90
 
                        Valid=false;
91
 
                else
92
 
                {
93
 
                        A/=F;
94
 
                        B/=F;
95
 
                        C/=F;
96
 
                }
97
 
        }
98
 
 
99
 
        void slide(double d)
100
 
        {
101
 
                C += d*sqrt(A*A+B*B);
102
 
        }
103
 
 
104
 
        double distance(const QPointF& P) const
105
 
        {
106
 
                if (Valid)
107
 
                        return fabs(A*P.x()+B*P.y()+C);
108
 
                else
109
 
                        return sqrt( (P.x()-P1.x())*(P.x()-P1.x()) + (P.y()-P1.y())*(P.y()-P1.y()) );
110
 
        }
111
 
 
112
 
        //double capDistance(const QPointF& P) const
113
 
        //{
114
 
        //      if (Valid)
115
 
        //      {
116
 
        //              double dx = P2.x()-P1.x();
117
 
        //              double dy = P2.y()-P1.y();
118
 
        //              double px = P.x()-P1.x();
119
 
        //              double py = P.y()-P1.y();
120
 
        //              if ( (dx*px+dy*py) < 0)
121
 
        //                      return ::distance(P,P1);
122
 
        //              px = P.x()-P2.x();
123
 
        //              py = P.y()-P2.y();
124
 
        //              if ( (dx*px+dy*py) > 0)
125
 
        //                      return ::distance(P,P2);
126
 
        //              return fabs(A*P.x()+B*P.y()+C);
127
 
        //      }
128
 
        //      else
129
 
        //              return sqrt( (P.x()-A)*(P.x()-A) + (P.y()-B)*(P.y()-B) );
130
 
        //}
131
 
 
132
 
        double capDistance(const Coord& cd)
133
 
        {
134
 
                QPointF P(cd.lat(), cd.lon());
135
 
                if (Valid)
136
 
                {
137
 
                        double dx = P2.x()-P1.x();
138
 
                        double dy = P2.y()-P1.y();
139
 
                        double px = P.x()-P1.x();
140
 
                        double py = P.y()-P1.y();
141
 
                        if ( (dx*px+dy*py) < 0)
142
 
                                return ::distance(P,P1);
143
 
                        px = P.x()-P2.x();
144
 
                        py = P.y()-P2.y();
145
 
                        if ( (dx*px+dy*py) > 0)
146
 
                                return ::distance(P,P2);
147
 
                        return fabs(A*P.x()+B*P.y()+C);
148
 
                }
149
 
                else
150
 
                        return sqrt( (P.x()-A)*(P.x()-A) + (P.y()-B)*(P.y()-B) );
151
 
                //return capDistance(QPointF(P.lat(),P.lon()));
152
 
        }
153
 
 
154
 
        Coord project(const Coord& P)
155
 
        {
156
 
                if (Valid)
157
 
                {
158
 
                        double SD = A*P.lat()+B*P.lon()+C;
159
 
                        return Coord(int(P.lat()-A*SD),int(P.lon()-B*SD));
160
 
                }
161
 
                return Coord(int(P1.x()),int(P1.y()));
162
 
        }
163
 
        QPointF project(const QPointF& P)
164
 
        {
165
 
                if (Valid)
166
 
                {
167
 
                        double SD = A*P.x()+B*P.y()+C;
168
 
                        return QPointF(P.x()-A*SD,P.y()-B*SD);
169
 
                }
170
 
                return P1;
171
 
        }
172
 
        QPointF project(const QPoint& P)
173
 
        {
174
 
                return project(QPointF(P));
175
 
        }
176
 
 
177
 
        bool intersectsWith(const CoordBox& C) const
178
 
        {
179
 
                QPointF intersection;
180
 
                if ( QLineF(P1, P2).intersect( QLineF( C.topLeft().toPointF(), C.topRight().toPointF() ), &intersection) == QLineF::BoundedIntersection ) return true;
181
 
                if ( QLineF(P1, P2).intersect( QLineF( C.topRight().toPointF(), C.bottomRight().toPointF() ), &intersection) == QLineF::BoundedIntersection ) return true;
182
 
                if ( QLineF(P1, P2).intersect( QLineF( C.bottomRight().toPointF(), C.bottomLeft().toPointF() ), &intersection) == QLineF::BoundedIntersection ) return true;
183
 
                if ( QLineF(P1, P2).intersect( QLineF( C.bottomLeft().toPointF(), C.topLeft().toPointF() ), &intersection) == QLineF::BoundedIntersection ) return true;
184
 
                return false;
185
 
        }
186
 
 
187
 
        void intersectionWith(const CoordBox& C, Coord* C1, Coord* C2) const
188
 
        {
189
 
                QPointF intersection;
190
 
                bool hasC1 = false;
191
 
 
192
 
                if ( QLineF(P1, P2).intersect( QLineF( C.topLeft().toPointF(), C.topRight().toPointF() ), &intersection) == QLineF::BoundedIntersection ) {
193
 
                        *C1 = intersection;
194
 
                        hasC1 = true;
195
 
                }
196
 
                if ( QLineF(P1, P2).intersect( QLineF( C.topRight().toPointF(), C.bottomRight().toPointF() ), &intersection) == QLineF::BoundedIntersection ) {
197
 
                        if (hasC1) {
198
 
                                *C2 = intersection;
199
 
                                return;
200
 
                        } else {
201
 
                                *C1 = intersection;
202
 
                                hasC1 = true;
203
 
                        }
204
 
                }
205
 
                if ( QLineF(P1, P2).intersect( QLineF( C.bottomRight().toPointF(), C.bottomLeft().toPointF() ), &intersection) == QLineF::BoundedIntersection ) {
206
 
                        if (hasC1) {
207
 
                                *C2 = intersection;
208
 
                                return;
209
 
                        } else {
210
 
                                *C1 = intersection;
211
 
                                hasC1 = true;
212
 
                        }
213
 
                }
214
 
                if ( QLineF(P1, P2).intersect( QLineF( C.bottomLeft().toPointF(), C.topLeft().toPointF() ), &intersection) == QLineF::BoundedIntersection ) {
215
 
                        if (hasC1) {
216
 
                                *C2 = intersection;
217
 
                                return;
218
 
                        } else {
219
 
                                *C1 = intersection;
220
 
                                hasC1 = true;
221
 
                        }
222
 
                }
223
 
        }
224
 
 
225
 
        QPointF intersectionWith(const LineF& L)
226
 
        {
227
 
                double D = A*L.B - L.A*B;
228
 
                if (fabs(D) < 0.00001)
229
 
                        return P2;
230
 
                double x = B*L.C - L.B*C;
231
 
                double y = L.A*C - A*L.C;
232
 
                return QPointF(x/D,y/D);
233
 
        }
234
 
 
235
 
        bool segmentContains(const QPointF& X)
236
 
        {
237
 
                return
238
 
                        ( ((P1.x() <= X.x()) && (X.x() <= P2.x())) ||
239
 
                          ((P1.x() >= X.x()) && (X.x() >= P2.x())) ) &&
240
 
                        ( ((P1.y() <= X.y()) && (X.y() <= P2.y())) ||
241
 
                          ((P1.y() >= X.y()) && (X.y() >= P2.y())) );
242
 
        }
243
 
 
244
 
 
245
 
private:
246
 
        QPointF P1, P2;
247
 
        bool Valid;
248
 
        double A,B,C;
249
 
};
250
 
 
251
 
class BezierF
252
 
{
253
 
        public:
254
 
                BezierF(const QPointF& aA, const QPointF& aB, const QPointF& aC, const QPointF& aD)
255
 
                        : A(aA), B(aB), C(aC), D(aD)
256
 
                {
257
 
                }
258
 
                BezierF(const QPoint& aA, const QPoint& aB, const QPoint& aC, const QPoint& aD)
259
 
                        : A(aA), B(aB), C(aC), D(aD)
260
 
                {
261
 
                }
262
 
 
263
 
                BezierF(const Coord& aA, const Coord& aB, const Coord& aC, const Coord& aD)
264
 
                        : A(toQt(aA)), B(toQt(aB)), C(toQt(aC)), D(toQt(aD))
265
 
                {
266
 
                }
267
 
 
268
 
                double distance(const QPointF& T) const
269
 
                {
270
 
                        double LowestZ = ::distance(A,T);
271
 
                        for (qreal t=0;t<1.0125; t+=0.025)
272
 
                        {
273
 
                                QPointF P = A*(1-t)*(1-t)*(1-t) + 3*B*(1-t)*(1-t)*t + 3*C*(1-t)*t*t + D*t*t*t;
274
 
                                double z = ::distance(P,T);
275
 
                                if (z < LowestZ)
276
 
                                        LowestZ = z;
277
 
                        }
278
 
                        return LowestZ;
279
 
                }
280
 
 
281
 
                QPointF project(const QPointF& T) const
282
 
                {
283
 
                        double LowestZ = ::distance(A,T);
284
 
                        QPointF ClosestP(A);
285
 
                        for (qreal t=0;t<1.0125; t+=0.025)
286
 
                        {
287
 
                                QPointF P = A*(1-t)*(1-t)*(1-t) + 3*B*(1-t)*(1-t)*t + 3*C*(1-t)*t*t + D*t*t*t;
288
 
                                double z = ::distance(P,T);
289
 
                                if (z < LowestZ)
290
 
                                {
291
 
                                        LowestZ = z;
292
 
                                        ClosestP = P;
293
 
                                }
294
 
                        }
295
 
                        return ClosestP;
296
 
                }
297
 
 
298
 
 
299
 
        private:
300
 
                QPointF A,B,C,D;
301
 
};
302
 
 
303
 
#endif
304
 
 
305