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

« back to all changes in this revision

Viewing changes to src/Maps/FeatureManipulations.cpp

  • 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
#include "Maps/FeatureManipulations.h"
 
2
#include "Command/DocumentCommands.h"
 
3
#include "Command/FeatureCommands.h"
 
4
#include "Command/RoadCommands.h"
 
5
#include "Command/RelationCommands.h"
 
6
#include "Command/TrackPointCommands.h"
 
7
#include "Maps/MapDocument.h"
 
8
#include "Maps/Road.h"
 
9
#include "Maps/Relation.h"
 
10
#include "Maps/TrackPoint.h"
 
11
#include "PropertiesDock.h"
 
12
 
 
13
#include <QtCore/QString>
 
14
 
 
15
#include <algorithm>
 
16
 
 
17
#ifndef _MOBILE
 
18
#include <ggl/ggl.hpp>
 
19
#include <ggl/geometries/cartesian2d.hpp>
 
20
#include <ggl/algorithms/intersection.hpp>
 
21
#endif
 
22
 
 
23
bool canJoin(Road* R1, Road* R2)
 
24
{
 
25
        if ( (R1->size() == 0) || (R2->size() == 0) )
 
26
                return true;
 
27
        MapFeature* Start1 = R1->get(0);
 
28
        MapFeature* End1 = R1->get(R1->size()-1);
 
29
        MapFeature* Start2 = R2->get(0);
 
30
        MapFeature* End2 = R2->get(R2->size()-1);
 
31
        return (Start1 == Start2) ||
 
32
                (Start1 == End2) ||
 
33
                (Start2 == End1) ||
 
34
                (End2 == End1);
 
35
}
 
36
 
 
37
bool canBreak(Road* R1, Road* R2)
 
38
{
 
39
        if ( (R1->size() == 0) || (R2->size() == 0) )
 
40
                return false;
 
41
        for (int i=0; i<R1->size(); i++)
 
42
                for (int j=0; j<R2->size(); j++)
 
43
                        if (R1->get(i) == R2->get(j))
 
44
                                return true;
 
45
        return false;
 
46
}
 
47
 
 
48
bool canJoinRoads(PropertiesDock* theDock)
 
49
{
 
50
        QList<Road*> Input;
 
51
        for (int i=0; i<theDock->size(); ++i)
 
52
                if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
53
                        if (!(R->isClosed()))
 
54
                                Input.push_back(R);
 
55
        for (int i=0; i<Input.size(); ++i)
 
56
                for (int j=i+1; j<Input.size(); ++j)
 
57
                        if (canJoin(Input[i],Input[j]))
 
58
                                return true;
 
59
        return false;
 
60
}
 
61
 
 
62
bool canBreakRoads(PropertiesDock* theDock)
 
63
{
 
64
        QList<Road*> Input;
 
65
        for (int i=0; i<theDock->size(); ++i)
 
66
                if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
67
                        Input.push_back(R);
 
68
        for (int i=0; i<Input.size(); ++i)
 
69
                for (int j=i+1; j<Input.size(); ++j)
 
70
                        if (canBreak(Input[i],Input[j]))
 
71
                                return true;
 
72
        return false;
 
73
}
 
74
 
 
75
bool canDetachNodes(PropertiesDock* theDock)
 
76
{
 
77
        QList<Road*> Roads, Result;
 
78
        QList<TrackPoint*> Points;
 
79
        for (int i=0; i<theDock->size(); ++i)
 
80
                if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
81
                        Roads.push_back(R);
 
82
                else if (TrackPoint* Pt = dynamic_cast<TrackPoint*>(theDock->selection(i)))
 
83
                        Points.push_back(Pt);
 
84
 
 
85
        if (Roads.size() > 1 && Points.size() > 1)
 
86
                return false;
 
87
 
 
88
        if (Roads.size() == 0 && Points.size()) {
 
89
                for (int i=0; i<Points.size(); ++i) {
 
90
                        Road * R = Road::GetSingleParentRoad(Points[i]);
 
91
                        if (R)
 
92
                                return true;
 
93
                }
 
94
                return false;
 
95
        }
 
96
 
 
97
        if (Roads.size() && Points.size() == 1)
 
98
                return true;
 
99
 
 
100
        if (Roads.size() == 1 && Points.size())
 
101
                return true;
 
102
 
 
103
        return false;
 
104
}
 
105
 
 
106
void reversePoints(MapDocument* theDocument, CommandList* theList, Road* R)
 
107
{
 
108
        QList<TrackPoint*> Pts;
 
109
        for (int i=R->size(); i; --i)
 
110
        {
 
111
                TrackPoint* Pt = R->getNode(i-1);
 
112
                Pts.push_back(Pt);
 
113
        }
 
114
        for (int i=0; i<Pts.size(); ++i)
 
115
                theList->add(new RoadRemoveTrackPointCommand(R,Pts[i],theDocument->getDirtyOrOriginLayer(R->layer())));
 
116
        for (int i=0; i<Pts.size(); ++i)
 
117
                theList->add(new RoadAddTrackPointCommand(R,Pts[i],theDocument->getDirtyOrOriginLayer(R->layer())));
 
118
}
 
119
 
 
120
static void appendPoints(MapDocument* theDocument, CommandList* L, Road* Dest, Road* Src)
 
121
{
 
122
        L->add(new RoadRemoveTrackPointCommand(Src,(int)0,theDocument->getDirtyOrOriginLayer(Src->layer())));
 
123
        while (Src->size())
 
124
        {
 
125
                TrackPoint* Pt = Src->getNode(0);
 
126
                L->add(new RoadRemoveTrackPointCommand(Src,(int)0,theDocument->getDirtyOrOriginLayer(Src->layer())));
 
127
                L->add(new RoadAddTrackPointCommand(Dest,Pt,theDocument->getDirtyOrOriginLayer(Src->layer())));
 
128
        }
 
129
}
 
130
 
 
131
static Road* join(MapDocument* theDocument, CommandList* L, Road* R1, Road* R2)
 
132
{
 
133
        QList<MapFeature*> Alternatives;
 
134
        if (R1->size() == 0)
 
135
        {
 
136
                MapFeature::mergeTags(theDocument,L,R2,R1);
 
137
                L->add(new RemoveFeatureCommand(theDocument,R1,Alternatives));
 
138
                return R2;
 
139
        }
 
140
        if (R2->size() == 0)
 
141
        {
 
142
                MapFeature::mergeTags(theDocument,L,R1,R2);
 
143
                L->add(new RemoveFeatureCommand(theDocument,R2,Alternatives));
 
144
                return R1;
 
145
        }
 
146
        MapFeature* Start1 = R1->get(0);
 
147
        MapFeature* End1 = R1->get(R1->size()-1);
 
148
        MapFeature* Start2 = R2->get(0);
 
149
        MapFeature* End2 = R2->get(R2->size()-1);
 
150
        if ( (Start1 == Start2) || (Start1 == End2) )
 
151
                reversePoints(theDocument,L,R1);
 
152
        if ( (End1 == End2) || (Start1 == End2) )
 
153
                reversePoints(theDocument,L,R2);
 
154
        appendPoints(theDocument,L,R1,R2);
 
155
        MapFeature::mergeTags(theDocument,L,R1,R2);
 
156
        L->add(new RemoveFeatureCommand(theDocument,R2,Alternatives));
 
157
        return R1;
 
158
}
 
159
 
 
160
void joinRoads(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
161
{
 
162
        QList<Road*> Input;
 
163
        for (int i=0; i<theDock->size(); ++i)
 
164
                if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
165
                        if (!(R->area() > 0.0))
 
166
                                Input.push_back(R);
 
167
        while (Input.size() > 1)
 
168
        {
 
169
                int Break = true;
 
170
                for (int i=0; i<Input.size(); ++i)
 
171
                        for (int j=i+1; j<Input.size(); ++j)
 
172
                                if (canJoin(Input[i],Input[j]))
 
173
                                {
 
174
                                        Road* R = join(theDocument, theList,Input[i],Input[j]);
 
175
                                        Input.erase(Input.begin()+j);
 
176
                                        Input[i] = R;
 
177
                                        i=j=Input.size();
 
178
                                        Break = false;
 
179
                                }
 
180
                if (Break)
 
181
                        break;
 
182
        }
 
183
        theDock->setSelection(Input);
 
184
}
 
185
 
 
186
static void splitRoad(MapDocument* theDocument, CommandList* theList, Road* In, const QList<TrackPoint*>& Points, QList<Road*>& Result)
 
187
{
 
188
        int pos;
 
189
        if (In->isClosed()) {  // Special case: If area, rotate the area so that the start node is the first point of splitting
 
190
 
 
191
                QList<TrackPoint*> Target;
 
192
                for (int i=0; i < Points.size(); i++)
 
193
                        if ((pos = In->find(Points[i])) != In->size()) {
 
194
                                for (int j=pos+1; j<In->size(); ++j)
 
195
                                        Target.push_back(In->getNode(j));
 
196
                                for (int j=1; j<= pos; ++j)
 
197
                                        Target.push_back(In->getNode(j));
 
198
                                break;
 
199
                        }
 
200
                if (pos == In->size())
 
201
                        return;
 
202
 
 
203
                if (Points.size() == 1) // Special case: For a 1 point area splitting, de-close the road, i.e. duplicate the selected node 
 
204
                {
 
205
                        TrackPoint* N = new TrackPoint(*(In->getNode(pos)));
 
206
                        theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(In->layer()),N,true));
 
207
 
 
208
                        Target.prepend(N);
 
209
                } else // otherwise, just close the modified area
 
210
                        Target.prepend(In->getNode(pos));
 
211
 
 
212
                // Now, reconstruct the road/area
 
213
                while (In->size())
 
214
                        theList->add(new RoadRemoveTrackPointCommand(In,(int)0,theDocument->getDirtyOrOriginLayer(In->layer())));
 
215
 
 
216
                for (int i=0; i<Target.size(); ++i)
 
217
                        theList->add(new RoadAddTrackPointCommand(In,Target[i],theDocument->getDirtyOrOriginLayer(In->layer())));
 
218
 
 
219
                if (Points.size() == 1) {  // For 1-point, we are done
 
220
                        Result.push_back(In);
 
221
                        return;
 
222
                }
 
223
        }
 
224
 
 
225
        Road* FirstPart = In;
 
226
        Result.push_back(FirstPart);
 
227
        for (int i=1; (i+1)<FirstPart->size(); ++i)
 
228
        {
 
229
                if (std::find(Points.begin(),Points.end(),FirstPart->get(i)) != Points.end())
 
230
                {
 
231
                        Road* NextPart = new Road;
 
232
                        copyTags(NextPart,FirstPart);
 
233
                        theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(In->layer()),NextPart,true));
 
234
                        theList->add(new RoadAddTrackPointCommand(NextPart, FirstPart->getNode(i), theDocument->getDirtyOrOriginLayer(In->layer())));
 
235
            for (int j=0; j < In->sizeParents(); j++) {
 
236
                                Relation* L = CAST_RELATION(In->getParent(j));
 
237
                                theList->add(new RelationAddFeatureCommand(L, L->getRole(L->find(In)), NextPart, theDocument->getDirtyOrOriginLayer(In->layer())));
 
238
            }
 
239
                        while ( (i+1) < FirstPart->size() )
 
240
                        {
 
241
                                theList->add(new RoadAddTrackPointCommand(NextPart, FirstPart->getNode(i+1), theDocument->getDirtyOrOriginLayer(In->layer())));
 
242
                                theList->add(new RoadRemoveTrackPointCommand(FirstPart,i+1,theDocument->getDirtyOrOriginLayer(In->layer())));
 
243
                        }
 
244
                        Result.push_back(NextPart);
 
245
                        FirstPart = NextPart;
 
246
                        i=0;
 
247
                }
 
248
        }
 
249
}
 
250
 
 
251
void splitRoads(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
252
{
 
253
        QList<Road*> Roads, Result;
 
254
        QList<TrackPoint*> Points;
 
255
        for (int i=0; i<theDock->size(); ++i)
 
256
                if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
257
                        Roads.push_back(R);
 
258
                else if (TrackPoint* Pt = dynamic_cast<TrackPoint*>(theDock->selection(i)))
 
259
                        Points.push_back(Pt);
 
260
 
 
261
        if (Roads.size() == 0 && Points.size() == 1)
 
262
        {
 
263
                Road * R = Road::GetSingleParentRoadInner(Points[0]);
 
264
                if (R)
 
265
                        Roads.push_back(R);
 
266
        }
 
267
 
 
268
        for (int i=0; i<Roads.size(); ++i)
 
269
                splitRoad(theDocument, theList,Roads[i],Points, Result);
 
270
        theDock->setSelection(Result);
 
271
}
 
272
 
 
273
static void breakRoad(MapDocument* theDocument, CommandList* theList, Road* R, TrackPoint* Pt)
 
274
{
 
275
        for (int i=0; i<R->size(); ++i)
 
276
                if (R->get(i) == Pt)
 
277
                {
 
278
                        TrackPoint* New = new TrackPoint(*Pt);
 
279
                        copyTags(New,Pt);
 
280
                        theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(R->layer()),New,true));
 
281
                        theList->add(new RoadRemoveTrackPointCommand(R,i,theDocument->getDirtyOrOriginLayer(R->layer())));
 
282
                        theList->add(new RoadAddTrackPointCommand(R,New,i,theDocument->getDirtyOrOriginLayer(R->layer())));
 
283
                }
 
284
                if (!Pt->sizeParents())
 
285
                        theList->add(new RemoveFeatureCommand(theDocument,Pt));
 
286
}
 
287
 
 
288
void breakRoads(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
289
{
 
290
        QList<Road*> Roads, Result;
 
291
        QList<TrackPoint*> Points;
 
292
        for (int i=0; i<theDock->size(); ++i)
 
293
                if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
294
                        Roads.push_back(R);
 
295
                else if (TrackPoint* Pt = dynamic_cast<TrackPoint*>(theDock->selection(i)))
 
296
                        Points.push_back(Pt);
 
297
 
 
298
        if (Roads.size() == 0 && Points.size() == 1)
 
299
        {
 
300
                for (int i=0; i<Points[0]->sizeParents() ; ++i) {
 
301
                        Road * R = dynamic_cast<Road*>(Points[0]->getParent(i));
 
302
                        if (R)
 
303
                                Roads.push_back(R);
 
304
                }
 
305
        }
 
306
 
 
307
        if (Roads.size() == 1 && Points.size() ) {
 
308
                splitRoad(theDocument, theList,Roads[0],Points, Result);
 
309
                if (Roads[0]->area() > 0.0) {
 
310
                        for (int i=0; i<Points.size(); ++i)
 
311
                                breakRoad(theDocument, theList, Roads[0],Points[i]);
 
312
                } else {
 
313
                        Roads = Result;
 
314
                }
 
315
        } 
 
316
 
 
317
        for (int i=0; i<Roads.size(); ++i)
 
318
                for (int j=0; j<Roads[i]->size(); ++j)
 
319
                        for (int k=i+1; k<Roads.size(); ++k)
 
320
                                breakRoad(theDocument, theList, Roads[k],dynamic_cast<TrackPoint*>(Roads[i]->get(j)));
 
321
}
 
322
 
 
323
bool canCreateJunction(PropertiesDock* theDock)
 
324
{
 
325
        return createJunction(NULL, NULL, theDock, false);
 
326
}
 
327
 
 
328
int createJunction(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock, bool doIt)
 
329
{
 
330
        int numInter = 0;
 
331
 
 
332
        //TODO test that the junction do not already exists!
 
333
        typedef ggl::point_2d P;
 
334
 
 
335
        QList<Road*> Roads, Result;
 
336
        for (int i=0; i<theDock->size(); ++i)
 
337
                if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
338
                        Roads.push_back(R);
 
339
 
 
340
        if (Roads.size() < 2)
 
341
                return 0;
 
342
 
 
343
        Road* R1 = Roads[0];
 
344
        Road* R2 = Roads[1];
 
345
 
 
346
        for (int i=0; i<R1->size()-1; ++i) {
 
347
                P a(R1->getNode(i)->position().lon(), R1->getNode(i)->position().lat());
 
348
                P b(R1->getNode(i+1)->position().lon(), R1->getNode(i+1)->position().lat());
 
349
        ggl::segment<P> s1(a, b);
 
350
 
 
351
                for (int j=0; j<R2->size()-1; ++j) {
 
352
                        P c(R2->getNode(j)->position().lon(), R2->getNode(j)->position().lat());
 
353
                        P d(R2->getNode(j+1)->position().lon(), R2->getNode(j+1)->position().lat());
 
354
                        ggl::segment<P> s2(c, d);
 
355
 
 
356
                        std::vector<ggl::point_2d> intersected;
 
357
//                      ggl::intersection < ggl::point_2d, ggl::segment, ggl::segment, std::back_insert_iterator< std::vector<ggl::point_2d> > >
 
358
//                              (s1, s2, std::back_inserter(intersected));
 
359
                        ggl::intersection<ggl::point_2d>(s1, s2, std::back_inserter(intersected));
 
360
 
 
361
                        if (intersected.size()) {
 
362
                                numInter++;
 
363
                                if (doIt) {
 
364
                                        TrackPoint* pt = new TrackPoint(Coord(qRound(intersected[0].y()), qRound(intersected[0].x())));
 
365
                                        theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(R1->layer()),pt,true));
 
366
                                        theList->add(new RoadAddTrackPointCommand(R1,pt,i+1,theDocument->getDirtyOrOriginLayer(R1->layer())));
 
367
                                        theList->add(new RoadAddTrackPointCommand(R2,pt,j+1,theDocument->getDirtyOrOriginLayer(R2->layer())));
 
368
                                }
 
369
                                ++i; ++j;
 
370
                        }
 
371
                }
 
372
        }
 
373
 
 
374
        return numInter;
 
375
 
 
376
 
 
377
//      QList<Road*> Roads, Result;
 
378
//      for (int i=0; i<theDock->size(); ++i)
 
379
//              if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
380
//                      Roads.push_back(R);
 
381
//
 
382
//      if (Roads.size() < 2)
 
383
//              return false;
 
384
//
 
385
//      Road* R1 = Roads[0];
 
386
//      Road* R2 = Roads[1];
 
387
//
 
388
//      std::vector<ggl::point_2d> intersected;
 
389
//      ggl::intersection <std::vector<ggl::point_2d>, std::vector<TrackPointPtr>, std::vector<TrackPointPtr>, std::back_insert_iterator <std::vector<ggl::point_2d> > >
 
390
//                      (R1->getNodes(), R2->getNodes(), std::back_inserter(intersected));
 
391
//
 
392
//      if (!doIt)
 
393
//              return intersected.size();
 
394
//
 
395
//      for (int i=0; i<intersected.size()-1; ++i) {
 
396
//              TrackPoint* pt = new TrackPoint(Coord(qRound(intersected[i].y()), qRound(intersected[i].x())));
 
397
//              theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(R1->layer()),pt,true));
 
398
//              theList->add(new RoadAddTrackPointCommand(R1,pt,i+1,theDocument->getDirtyOrOriginLayer(R1->layer())));
 
399
//              theList->add(new RoadAddTrackPointCommand(R2,pt,j+1,theDocument->getDirtyOrOriginLayer(R2->layer())));
 
400
//      }
 
401
//
 
402
//      return intersected.size();
 
403
}
 
404
 
 
405
#define STREET_NUMBERS_LENGTH 1500.0
 
406
#define STREET_NUMBERS_ANGLE 30.0
 
407
 
 
408
void createStreetNumbers(MapDocument* theDocument, CommandList* theList, Road* theRoad, bool Left)
 
409
{
 
410
        QString streetName = theRoad->tagValue("name", "");
 
411
        QLineF l, l2, nv;
 
412
 
 
413
        TrackPoint* N;
 
414
        Road* R = new Road;
 
415
        theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(),R,true));
 
416
        theList->add(new SetTagCommand(R, "addr:interpolation", ""));
 
417
        theList->add(new SetTagCommand(R, "addr:street", streetName));
 
418
        QPointF prevPoint;
 
419
 
 
420
        for (int j=0; j < theRoad->size(); j++) {
 
421
                if (j == 0) {
 
422
                        l2 = QLineF(theRoad->getNode(j)->position().toPointF(), theRoad->getNode(j+1)->position().toPointF());
 
423
                        l = l2;
 
424
                        l.setAngle(l2.angle() + 180.);
 
425
                        prevPoint = l.p2();
 
426
                } else 
 
427
                if (j == theRoad->size()-1) {
 
428
                        l = QLineF(theRoad->getNode(j)->position().toPointF(), theRoad->getNode(j-1)->position().toPointF());
 
429
                        l2 = l;
 
430
                        l2.setAngle(l.angle() + 180.);
 
431
                } else {
 
432
                        l = QLineF(theRoad->getNode(j)->position().toPointF(), theRoad->getNode(j-1)->position().toPointF());
 
433
                        l2 = QLineF(theRoad->getNode(j)->position().toPointF(), theRoad->getNode(j+1)->position().toPointF());
 
434
                }
 
435
                nv = l.normalVector().unitVector();
 
436
 
 
437
                double theAngle = (l.angle() - l2.angle());
 
438
                if (theAngle < 0.0) theAngle = 360. + theAngle;
 
439
                theAngle /= 2.;
 
440
                nv.setAngle(l2.angle() + theAngle);
 
441
                nv.setLength(STREET_NUMBERS_LENGTH/sin(angToRad(theAngle)));
 
442
                if (Left)
 
443
                        nv.setAngle(nv.angle() + 180.0);
 
444
 
 
445
                QLineF lto(prevPoint, nv.p2());
 
446
                lto.setLength(lto.length()+STREET_NUMBERS_LENGTH);
 
447
                QPointF pto;
 
448
 
 
449
                bool intersectedTo = false;
 
450
                for (int k=0; k < theRoad->getNode(j)->sizeParents(); ++k) {
 
451
                        Road* I = CAST_WAY(theRoad->getNode(j)->getParent(k));
 
452
                        if (!I || I == theRoad)
 
453
                                continue;
 
454
 
 
455
                        for (int m=0; m < I->size()-1; ++m) {
 
456
                                QLineF l3 = QLineF(I->getNode(m)->position().toPointF(), I->getNode(m+1)->position().toPointF());
 
457
                                QPointF theIntersection;
 
458
                                if (lto.intersect(l3, &theIntersection) == QLineF::BoundedIntersection) {
 
459
                                        intersectedTo = true;
 
460
                                        QLineF lt = QLineF(prevPoint, theIntersection);
 
461
                                        if (lt.length() < lto.length())
 
462
                                                lto = lt;
 
463
                                }
 
464
                        }
 
465
                }
 
466
 
 
467
                if (j != 0) {
 
468
                        QLineF lfrom = QLineF(nv.p2(), prevPoint);
 
469
                        lfrom.setLength(lfrom.length()*2.);
 
470
                        QPointF pfrom;
 
471
 
 
472
                        bool intersectedFrom = false;
 
473
                        for (int k=0; k < theRoad->getNode(j-1)->sizeParents(); ++k) {
 
474
                                Road* I = CAST_WAY(theRoad->getNode(j-1)->getParent(k));
 
475
                                if (!I || I == theRoad)
 
476
                                        continue;
 
477
 
 
478
                                for (int m=0; m < I->size()-1; ++m) {
 
479
                                        QLineF l3 = QLineF(I->getNode(m)->position().toPointF(), I->getNode(m+1)->position().toPointF());
 
480
                                        QPointF theIntersection;
 
481
                                        if (lfrom.intersect(l3, &theIntersection) == QLineF::BoundedIntersection) {
 
482
                                                intersectedFrom = true;
 
483
                                                QLineF lt = QLineF(nv.p2(), theIntersection);
 
484
                                                if (lt.length() < lfrom.length())
 
485
                                                        lfrom = lt;
 
486
                                        }
 
487
                                }
 
488
                        }
 
489
                        if (intersectedFrom) {
 
490
                                lfrom.setLength(lfrom.length() - STREET_NUMBERS_LENGTH);
 
491
                                pfrom = lfrom.p2();
 
492
 
 
493
                                R = new Road;
 
494
                                theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(),R,true));
 
495
                                theList->add(new SetTagCommand(R, "addr:interpolation", ""));
 
496
                                theList->add(new SetTagCommand(R, "addr:street", streetName));
 
497
 
 
498
                                N = new TrackPoint(Coord(pfrom));
 
499
                                theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(),N,true));
 
500
                                theList->add(new RoadAddTrackPointCommand(R, N, theDocument->getDirtyOrOriginLayer(R->layer())));
 
501
                                theList->add(new SetTagCommand(N, "addr:housenumber", ""));
 
502
                        } else {
 
503
                                pfrom = prevPoint;
 
504
                        }
 
505
                }
 
506
 
 
507
                if (intersectedTo) {
 
508
                        if (j != 0) {
 
509
                                lto.setLength(lto.length() - STREET_NUMBERS_LENGTH);
 
510
                                pto = lto.p2();
 
511
 
 
512
                                N = new TrackPoint(Coord(pto));
 
513
                                theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(),N,true));
 
514
                                theList->add(new RoadAddTrackPointCommand(R, N, theDocument->getDirtyOrOriginLayer(R->layer())));
 
515
                                theList->add(new SetTagCommand(N, "addr:housenumber", ""));
 
516
                        }
 
517
                } else {
 
518
                        if (theAngle < 85. || theAngle > 95. || j== 0 || j == theRoad->size()-1) {
 
519
                                N = new TrackPoint(Coord(nv.p2()));
 
520
                                theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(),N,true));
 
521
                                theList->add(new RoadAddTrackPointCommand(R, N, theDocument->getDirtyOrOriginLayer(R->layer())));
 
522
                                theList->add(new SetTagCommand(N, "addr:housenumber", ""));
 
523
                        }
 
524
 
 
525
                        pto = nv.p2();
 
526
                }
 
527
                prevPoint = nv.p2();
 
528
        }
 
529
}
 
530
 
 
531
void addStreetNumbers(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
532
{
 
533
        QList<Road*> Roads;
 
534
        for (int i=0; i<theDock->size(); ++i)
 
535
                if (Road* R = CAST_WAY(theDock->selection(i)))
 
536
                        Roads.push_back(R);
 
537
 
 
538
        if (Roads.isEmpty())
 
539
                return;
 
540
 
 
541
        QList<Road*>::const_iterator it = Roads.constBegin();
 
542
        for (;it != Roads.constEnd(); ++it) {
 
543
                if((*it)->size() < 2)
 
544
                        continue;
 
545
 
 
546
                createStreetNumbers(theDocument, theList, (*it), false);
 
547
                createStreetNumbers(theDocument, theList, (*it), true);
 
548
        }
 
549
 
 
550
        if (Roads.size() == 1)
 
551
                theList->setFeature(Roads.at(0));
 
552
}
 
553
 
 
554
void alignNodes(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
555
{
 
556
        if (theDock->size() < 3) //thre must be at least 3 nodes to align something
 
557
                return;
 
558
        
 
559
        //We build a list of selected nodes
 
560
        QList<TrackPoint*> Nodes;
 
561
        for (int i=0; i<theDock->size(); ++i)
 
562
                if (TrackPoint* N = dynamic_cast<TrackPoint*>(theDock->selection(i)))
 
563
                        Nodes.push_back(N);
 
564
 
 
565
        //we check that we have at least 3 nodes and the first two can give a line
 
566
        if(Nodes.size() < 3)
 
567
                return;
 
568
        if(Nodes[0]->position() == Nodes[1]->position())
 
569
                return;
 
570
 
 
571
        //we do the alignement
 
572
        Coord pos(0,0);
 
573
        const Coord p1(Nodes[0]->position());
 
574
        const Coord p2(Nodes[1]->position()-p1);
 
575
        for (int i=2; i<Nodes.size(); ++i) {
 
576
                pos=Nodes[i]->position()-p1;
 
577
                rotate(pos,-angle(p2));
 
578
                pos.setLat(0);
 
579
                rotate(pos,angle(p2));
 
580
                pos=pos+p1;
 
581
                theList->add(new MoveTrackPointCommand( Nodes[i], pos, theDocument->getDirtyOrOriginLayer(Nodes[i]->layer()) ));
 
582
        }
 
583
}
 
584
 
 
585
void mergeNodes(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
586
{
 
587
        if (theDock->size() <= 1)
 
588
                return;
 
589
        QList<TrackPoint*> Nodes;
 
590
        QList<MapFeature*> alt;
 
591
        for (int i=0; i<theDock->size(); ++i)
 
592
                if (TrackPoint* N = dynamic_cast<TrackPoint*>(theDock->selection(i)))
 
593
                        Nodes.push_back(N);
 
594
        TrackPoint* merged = Nodes[0];
 
595
        alt.push_back(merged);
 
596
        for (int i=1; i<Nodes.size(); ++i) {
 
597
                MapFeature::mergeTags(theDocument, theList, merged, Nodes[i]);
 
598
                theList->add(new RemoveFeatureCommand(theDocument, Nodes[i], alt));
 
599
        }
 
600
}
 
601
 
 
602
void detachNode(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
603
{
 
604
        QList<Road*> Roads, Result;
 
605
        QList<TrackPoint*> Points;
 
606
        for (int i=0; i<theDock->size(); ++i)
 
607
                if (Road* R = dynamic_cast<Road*>(theDock->selection(i)))
 
608
                        Roads.push_back(R);
 
609
                else if (TrackPoint* Pt = dynamic_cast<TrackPoint*>(theDock->selection(i)))
 
610
                        Points.push_back(Pt);
 
611
 
 
612
        if (Roads.size() > 1 && Points.size() > 1)
 
613
                return;
 
614
 
 
615
        if (Roads.size() == 0 && Points.size())
 
616
        {
 
617
                for (int i=0; i<Points.size(); ++i) {
 
618
                        Road * R = Road::GetSingleParentRoad(Points[i]);
 
619
                        if (R)
 
620
                                theList->add(new RoadRemoveTrackPointCommand(R, Points[i],
 
621
                                        theDocument->getDirtyOrOriginLayer(R)));
 
622
                }
 
623
        }
 
624
 
 
625
        if (Roads.size() > 1 && Points.size() == 1)
 
626
        {
 
627
                for (int i=0; i<Roads.size(); ++i) {
 
628
                        if (Roads[i]->find(Points[0]) < Roads[i]->size())
 
629
                                theList->add(new RoadRemoveTrackPointCommand(Roads[i], Points[0],
 
630
                                        theDocument->getDirtyOrOriginLayer(Roads[i])));
 
631
                }
 
632
        }
 
633
 
 
634
        if (Roads.size() == 1 && Points.size())
 
635
        {
 
636
                for (int i=0; i<Points.size(); ++i) {
 
637
                        if (Roads[0]->find(Points[i]) < Roads[0]->size())
 
638
                                theList->add(new RoadRemoveTrackPointCommand(Roads[0], Points[i],
 
639
                                        theDocument->getDirtyOrOriginLayer(Roads[0])));
 
640
                }
 
641
        }
 
642
}
 
643
 
 
644
void commitFeatures(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
645
{
 
646
        QList<MapFeature*> alt;
 
647
        QList<MapFeature*> Features;
 
648
 
 
649
        for (int i=0; i<theDock->size(); ++i)
 
650
                if (!theDock->selection(i)->isDirty())
 
651
                        Features.push_back(theDock->selection(i));
 
652
        for (int i=0; i<Features.size(); ++i) {
 
653
                if (TrackPoint* N = dynamic_cast<TrackPoint *>(Features[i])) {
 
654
                        theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(),N,true));
 
655
                }
 
656
                if (Road* R = dynamic_cast<Road *>(Features[i])) {
 
657
                        theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(),R,true));
 
658
                        for (int j=0; j < R->size(); ++j) {
 
659
                                if (!Features.contains(R->get(j))) {
 
660
                                        theList->add(new AddFeatureCommand(theDocument->getDirtyOrOriginLayer(),R->get(j),true));
 
661
                                }
 
662
                        }
 
663
                }
 
664
        }
 
665
}
 
666
 
 
667
void addRelationMember(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
668
{
 
669
        Relation* theRelation = NULL;
 
670
        QList<MapFeature*> Features;
 
671
        for (int i=0; i<theDock->size(); ++i)
 
672
                if ((theDock->selection(i)->getClass() == "Relation") && !theRelation)
 
673
                        theRelation = dynamic_cast<Relation*>(theDock->selection(i));
 
674
                else 
 
675
                        Features.push_back(theDock->selection(i));
 
676
 
 
677
        if (!(theRelation && Features.size())) return;
 
678
 
 
679
        for (int i=0; i<Features.size(); ++i) {
 
680
                theList->add(new RelationAddFeatureCommand(theRelation, "", Features[i], theDocument->getDirtyOrOriginLayer(theRelation->layer()))); 
 
681
        }
 
682
}
 
683
 
 
684
void removeRelationMember(MapDocument* theDocument, CommandList* theList, PropertiesDock* theDock)
 
685
{
 
686
        Relation* theRelation = NULL;
 
687
        QList<MapFeature*> Features;
 
688
        for (int i=0; i<theDock->size(); ++i)
 
689
                if ((theDock->selection(i)->getClass() == "Relation") && !theRelation)
 
690
                        theRelation = dynamic_cast<Relation*>(theDock->selection(i));
 
691
                else 
 
692
                        Features.push_back(theDock->selection(i));
 
693
 
 
694
        if (!theRelation && Features.size() == 1)
 
695
                theRelation = MapFeature::GetSingleParentRelation(Features[0]);
 
696
        if (!(theRelation && Features.size())) return;
 
697
 
 
698
        int idx;
 
699
        for (int i=0; i<Features.size(); ++i) {
 
700
                if ((idx = theRelation->find(Features[i])) != theRelation->size())
 
701
                        theList->add(new RelationRemoveFeatureCommand(theRelation, idx, theDocument->getDirtyOrOriginLayer(theRelation->layer()))); 
 
702
        }
 
703
}
 
704