source: subversion/applications/editors/potlatch/way.as @ 15001

Last change on this file since 15001 was 14979, checked in by richard, 10 years ago

a few small fixes

File size: 43.1 KB
Line 
1
2        // =====================================================================================
3        // OOP classes - OSMWay
4
5        // ---- Initialise
6       
7        function OSMWay() {
8                this.resetBBox();
9                this.path=new Array();                  // list of nodes
10                this.attr=new Array();                  // hash of tags
11                this.mergedways=new Array();    // list of ways merged into this
12                this.deletednodes=new Object(); // hash of nodes deleted from this
13        };
14
15        OSMWay.prototype=new MovieClip();
16        OSMWay.prototype.clean=true;                            // altered since last upload?
17        OSMWay.prototype.uploading=false;                       // currently uploading?
18        OSMWay.prototype.locked=false;                          // locked against upload?
19        OSMWay.prototype.version=0;                                     // version number?
20        OSMWay.prototype.historic=false;                        // is this an undeleted, not-uploaded way?
21        OSMWay.prototype.checkconnections=false;        // check shared nodes on reload
22
23        // ---- Load from remote server
24
25        OSMWay.prototype.load=function() {
26                responder = function() { };
27                responder.onResult = function(result) {
28                        _root.waysreceived+=1;
29                        var w=result[0];
30                        if (length(result[1])==0) { removeMovieClip(_root.map.ways[w]); 
31                                                                                removeMovieClip(_root.map.areas[w]); return; }
32                        var i,id,x,y,prepoint;
33                        _root.map.ways[w].clean=true;
34                        _root.map.ways[w].locked=false;
35                        _root.map.ways[w].historic=false;
36                        _root.map.ways[w].version=result[3];
37                        _root.map.ways[w].removeNodeIndex();
38                        _root.map.ways[w].path=[];
39                        _root.map.ways[w].resetBBox();
40                        for (i=0; i<result[1].length; i++) {
41                                x =result[1][i][0];
42                                y =result[1][i][1];
43                                id=result[1][i][2];
44                                _root.map.ways[w].updateBBox(x,y);
45                                x=long2coord(x); y=lat2coord(y);
46                                if (nodes[id]) {
47                                        // already exists: move node in other ways if required
48                                        // ** maybe we should take out 'w'? not sure
49                                        if (_root.map.ways[w].checkconnections) { nodes[id].moveTo(x,y,w); }
50                                } else {
51                                        // doesn't exist, so create new node
52                                        _root.nodes[id]=new Node(id,x,y,result[1][i][3],result[1][i][4]);
53                                        _root.nodes[id].clean=true;
54                                        if (id==prenode) { prepoint=i; }
55                                }
56                                _root.map.ways[w].path.push(_root.nodes[id]);
57                                _root.nodes[id].addWay(w);
58                        }
59                        _root.map.ways[w].attr=result[2];
60                        _root.map.ways[w].redraw();
61                        if (w==preway) { _root.map.ways[w].select(); preway=undefined; }
62                        if (prepoint)  { _root.map.ways[w].select(); 
63                                                         _root.map.anchors[prepoint].select();
64                                                         prenode=prepoint=undefined; }
65                        _root.map.ways[w].clearPOIs();
66                        _root.map.ways[w].checkconnections=false;
67                };
68                remote_read.call('getway',responder,Math.floor(this._name));
69        };
70
71        OSMWay.prototype.loadFromDeleted=function(timestamp) {
72                delresponder=function() { };
73                delresponder.onResult=function(result) {
74                        var code=result.shift(); if (code) { handleError(code,result); return; }
75                        var i,id,n;
76                        var w=_root.map.ways[result[0]];
77                        if (result[4]) { w.historic=false; w.clean=true;  }
78                                  else { w.historic=true;  w.clean=false; }
79                        w.version=result[3];
80                        w.removeNodeIndex();
81                        w.path=[];
82                        w.resetBBox();
83                        for (i=0; i<result[1].length; i++) {
84                                n=result[1][i];
85                                x=n[0]; y=n[1]; id=n[2];                                        // 3:current version, 4:tags, 5:reuse?
86                                if (id<0) { id=--_root.newnodeid; }                     // assign negative IDs to anything moved
87                                w.updateBBox(x,y);
88                                x=long2coord(x); y=lat2coord(y);
89                                if (nodes[id]) {
90                                        if (x!=nodes[id].x || y!=nodes[id].y) {
91                                                // ** also needs to check that tags haven't changed
92                                                nodes[id].moveTo(x,y,w);
93                                                nodes[id].attr=n[4];
94                                                nodes[id].version=n[3];
95                                                w.clean=false;
96                                        }
97                                        if (n[5]) { nodes[id].clean=true; }             // is visible and current version
98                                } else {
99                                        _root.nodes[id]=new Node(id,x,y,n[4],n[3]);
100                                }
101                                w.path.push(_root.nodes[id]);
102                                _root.nodes[id].addWay(result[0]);
103                        }
104                        w.attr=result[2];
105                        if (w==ws) { w.select(); }
106                                  else { w.locked=true; }
107                        w.redraw();
108                        w.clearPOIs();
109                };
110                remote_read.call('getway_old',delresponder,Number(this._name),timestamp);
111        };
112
113        OSMWay.prototype.clearPOIs=function() {
114                // check if any way nodes are POIs, delete the POIs if so
115                var i,z;
116                z=this.path;
117                for (i in z) {
118                        if (_root.map.pois[this.path[i].id]) { removeMovieClip(_root.map.pois[this.path[i].id]); }
119                }
120        };
121
122        // ---- Draw line
123
124        OSMWay.prototype.redraw=function(skip) {
125                this.createEmptyMovieClip("taggednodes",2);
126
127                if (skip) {
128                        // We're at the same scale as previously, so don't redraw
129                        // ** will refactor this when we do proper POI icons
130                        for (var i=1; i<this.path.length; i+=1) {
131                                if (this.path[i].tagged) {
132                                        this.taggednodes.attachMovie("poiinway",i,i);
133                                        this.taggednodes[i]._x=this.path[i].x;
134                                        this.taggednodes[i]._y=this.path[i].y;
135                                        this.taggednodes[i]._xscale=this.taggednodes[i]._yscale=taggedscale;
136                                }
137                        }
138                } else {
139
140                        // Either the line has changed, or we've changed scale
141                        this.createEmptyMovieClip("line",1);                                    // clear line
142                        var linealpha=100; // -50*(this.locked==true);
143                        var casingx=1.5; var casingcol=0;
144       
145                        // Set stroke
146       
147                        if              (this.locked)                                    { this.line.lineStyle(linewidth,0xFF0000,linealpha,false,"none"); }
148                        else if (colours[this.attr["highway"]])  { this.line.lineStyle(linewidth,colours[this.attr["highway" ]],linealpha,false,"none"); }
149                        else if (colours[this.attr["waterway"]]) { this.line.lineStyle(linewidth,colours[this.attr["waterway"]],linealpha,false,"none"); }
150                        else if (colours[this.attr["railway"]])  { this.line.lineStyle(linewidth,colours[this.attr["railway" ]],linealpha,false,"none"); }
151                        else {
152                                var c=0xAAAAAA; var z=this.attr;
153                                for (var i in z) { if (i!='created_by' && this.attr[i]!='' && this.attr[i].substr(0,6)!='(type ') { c=0x707070; } }
154                                this.line.lineStyle(linewidth,c,linealpha,false,"none");
155                        }
156                       
157                        // Draw fill/casing
158       
159                        var f=this.getFill();
160                        if (preferences.data.noname && this.attr["highway"] && (!this.attr["name"] || this.attr["name"].substr(0,6)=='(type ')) {
161                                casingx=2; casingcol=0xFF0000;
162                        } else if (this.attr["bridge"] && this.attr["bridge"]!="no") { casingx=2; }
163       
164                        if ((f>-1 || casing[this.attr['highway']]) && !this.locked) {
165                                if (!_root.map.areas[this._name]) { _root.map.areas.createEmptyMovieClip(this._name,++areadepth); }
166                                with (_root.map.areas[this._name]) {
167                                        clear();
168                                        enabled=false;
169                                        moveTo(this.path[0].x,this.path[0].y); 
170                                        if (f>-1) { beginFill(f,20); }
171                                                 else { lineStyle(linewidth*casingx,casingcol,100,false,"none"); }
172                                        for (var i=1; i<this.path.length; i+=1) {
173                                                lineTo(this.path[i].x,this.path[i].y);
174                                        }
175                                        if (f>-1) { endFill(); }
176                                };
177                        } else if (_root.map.areas[this._name]) {
178                                removeMovieClip(_root.map.areas[this._name]);
179                        }
180       
181                        // Draw line and tagged nodes
182       
183                        this.line.moveTo(this.path[0].x,this.path[0].y);
184                        for (var i=0; i<this.path.length; i+=1) {
185                                if (i>0) { this.line.lineTo(this.path[i].x,this.path[i].y); }
186                                if (this.path[i].tagged) {
187                                        // **** attach correct icon:
188                                        // if (this.path[i].attr['frog']) {
189                                        // this.taggednodes.attachMovie("poi_22",i,i);
190                                        // ...probably don't have to do _root.map.pois[point].__proto__=undefined;
191                                        //    because clicks are handled by the way movieclip
192                                        this.taggednodes.attachMovie("poiinway",i,i);
193                                        this.taggednodes[i]._x=this.path[i].x;
194                                        this.taggednodes[i]._y=this.path[i].y;
195                                        this.taggednodes[i]._xscale=this.taggednodes[i]._yscale=taggedscale;
196                                }
197                        }
198
199                        // Draw relations
200
201                        var z=_root.wayrels[this._name];
202                        for (var rel in z) { _root.map.relations[rel].redraw(); }
203                }
204        };
205
206        OSMWay.prototype.getFill=function() {
207                var f=-1; 
208                if (this.path[this.path.length-1]==this.path[0] && this.path.length>2) {
209                        if (this.attr['area']) { f='0x777777'; }
210                        var z=this.attr;
211                        for (var i in z) { if (areas[i] && this.attr[i]!='' && this.attr[i]!='coastline') { f=areas[i]; } }
212                }
213                return f;
214        };
215
216        // ---- Show direction
217
218        OSMWay.prototype.direction=function() {
219                if (this.path.length<2) {
220                        _root.panel.i_clockwise._visible=false;
221                        _root.panel.i_anticlockwise._visible=false;
222                        _root.panel.i_direction._visible=true;
223                        _root.panel.i_direction._alpha=50;
224                } else {
225                        var dx=this.path[this.path.length-1].x-this.path[0].x;
226                        var dy=this.path[this.path.length-1].y-this.path[0].y;
227                        if (dx!=0 || dy!=0) {
228                                // Non-circular
229                                _root.panel.i_direction._rotation=180-Math.atan2(dx,dy)*(180/Math.PI)-45;
230                                _root.panel.i_direction._alpha=100;
231                                _root.panel.i_direction._visible=true;
232                                _root.panel.i_clockwise._visible=false;
233                                _root.panel.i_anticlockwise._visible=false;
234                        } else {
235                                // Circular
236                                _root.panel.i_direction._visible=false;
237                                // Find lowest rightmost point
238                                // cf http://geometryalgorithms.com/Archive/algorithm_0101/
239                                var lowest=0;
240                                var xmax=-999999; var ymin=-999999;
241                                for (var i=0; i<this.path.length; i++) {
242                                        if      (this.path[i].y> ymin) { lowest=i; xmin=this.path[i].x; ymin=this.path[i].y; }
243                                        else if (this.path[i].y==ymin
244                                                  && this.path[i].x> xmax) { lowest=i; xmin=this.path[i].x; ymin=this.path[i].y; }
245                                }
246                                var clockwise=(this.onLeft(lowest)>0);
247                                _root.panel.i_clockwise._visible=clockwise;
248                                _root.panel.i_anticlockwise._visible=!clockwise;
249                        }
250                }
251        };
252
253        OSMWay.prototype.onLeft=function(j) {
254                var left=0;
255                if (this.path.length>=3) {
256                        var i=j-1; if (i==-1) { i=this.path.length-2; }
257                        var k=j+1; if (k==this.path.length) { k=1; }
258                        left=((this.path[j].x-this.path[i].x) * (this.path[k].y-this.path[i].y) -
259                                  (this.path[k].x-this.path[i].x) * (this.path[j].y-this.path[i].y));
260                }
261                return left;
262        };
263       
264
265
266        // ---- Remove from server
267       
268        OSMWay.prototype.remove=function() {
269                clearFloater();
270                memberDeleted('Way', this._name);
271                var cp=new Object; cp[this._name]=true;
272                var z=this.path; for (var i in z) {
273                        if (z[i].numberOfWays()==1) { memberDeleted('Node', z[i].id); }
274                }
275                uploadDirtyRelations();
276
277                this.deleteMergedWays();
278                this.removeNodeIndex();
279
280                if (this._name>=0 && !_root.sandbox && !this.historic && !this.locked) {
281                        deleteresponder = function() { };
282                        deleteresponder.onResult = function(result) {
283                                var code=result.shift(); if (code) { handleError(code,result); return; }
284//                              if (wayselected==result[0]) { deselectAll(); }
285//                              removeMovieClip(_root.map.ways[result[0]]);
286//                              removeMovieClip(_root.map.areas[result[0]]);
287                                _root.writesrequested--;
288                        };
289                        _root.writesrequested++;
290                        var z=shallowCopy(this.path); this.path=new Array();
291                        for (var i in z) { this.markAsDeleted(z[i]); }
292                        remote_write.call('deleteway',deleteresponder,_root.usertoken,_root.changeset,Number(this._name),Number(this.version),this.deletednodes);
293                } // else {
294                if (this._name==wayselected) { stopDrawing(); deselectAll(); }
295                removeMovieClip(_root.map.areas[this._name]);
296                removeMovieClip(this);
297                // }
298        };
299
300        // ---- Variant with confirmation if any nodes have tags
301       
302        OSMWay.prototype.removeWithConfirm=function() {
303                var c=true;
304                var z=this.path;
305                for (var i in z) {
306                        if (this.path[i].tagged && hashLength(this.path[i].ways)==1) { c=false; }
307                }
308                if (c) {
309                        _root.ws.saveUndo(iText("deleting",'deleting'));
310                        this.remove();
311                } else {
312                        _root.windows.attachMovie("modal","confirm",++windowdepth);
313                        _root.windows.confirm.init(275,80,new Array(iText('Cancel','cancel'),iText('Delete','delete')),
314                                function(choice) {
315                                        if (choice==iText('Delete','delete')) { _root.ws.saveUndo(iText("deleting",'deleting')); _root.ws.remove(); }
316                                });
317                        _root.windows.confirm.box.createTextField("prompt",2,7,9,250,100);
318                        writeText(_root.windows.confirm.box.prompt,iText("Some of the points on this way are tagged. Really delete?",'prompt_taggedpoints'));
319                }
320        };
321
322        // ---- Upload to server
323       
324        OSMWay.prototype.upload=function() {
325                putresponder=function() { };
326                putresponder.onResult=function(result) {
327                        var code=result.shift(); if (code) { handleError(code,result); return; }
328
329                        // ** needs to renumber versions as well as nodes
330                        var i,r,z,nw,ow;
331                        ow=result[0];                   // old way ID
332                        nw=result[1];                   // new way ID
333                        if (ow!=nw) {                   // renumber way?
334                                _root.map.ways[ow].renumberNodeIndex(nw);
335                                wayrels[nw]=wayrels[ow]; delete wayrels[ow];
336                                _root.map.ways[ow]._name=nw;
337                                renumberMemberOfRelation('Way', result[0], nw);
338                                if (_root.map.areas[ow]) { _root.map.areas[ow]._name=nw; }
339                                if (_root.panel.t_details.text==ow) { _root.panel.t_details.text=nw; _root.panel.t_details.setTextFormat(plainText); }
340                                if (wayselected==ow) { selectWay(nw); }
341                        }
342                        // ** used to have bbox code here, but don't think we need it
343                        _root.map.ways[nw].uploading=false;
344                        _root.map.ways[nw].historic=false;
345                        _root.map.ways[nw].version=result[3];
346                       
347                        // renumber nodes (and any relations/ways they're in)
348                        z=result[2];
349                        for (var oid in z) {
350                                var nid = result[2][oid];
351                                nodes[oid].renumberTo(nid);
352                                nodes[nid].addWay(nw);
353                                renumberMemberOfRelation('Node', oid, nid);
354                        }
355                        for (var oid in z) { delete _root.nodes[oid]; } // delete -ve nodes
356                       
357                        // set versions, clean, not uploading
358                        z=result[4]; for (var nid in z) { nodes[nid].version=result[4][nid]; nodes[nid].uploading=false; nodes[nid].clean=true; }
359
360                        // remove deleted nodes
361                        z=result[5]; for (var nid in z) { c=_root.map.ways[nw]; delete c.deletednodes[nid]; }
362                       
363                        _root.map.ways[nw].clearPOIs();
364                        uploadDirtyRelations();
365                        _root.map.ways[nw].deleteMergedWays();
366                        _root.writesrequested--;
367                        uploadDirtyWays();                      // make sure dependencies are uploaded
368                };
369
370                if (!this.uploading && !this.hasDependentNodes() && !this.locked && !_root.sandbox && this.path.length>1) {
371                        this.deleteMergedWays();
372
373                        // Assemble list of changed nodes, and send
374                        this.uploading=true;
375                        var sendpath =new Array();
376                        var sendnodes=new Array();
377                        for (i=0; i<this.path.length; i++) {
378                                sendpath.push(this.path[i].id);
379                                if (!this.path[i].clean && !this.path[i].uploading) {
380                                        sendnodes.push(new Array(coord2long(this.path[i].x),
381                                                                                         coord2lat (this.path[i].y),
382                                                                                         this.path[i].id,this.path[i].version,
383                                                                                         deepCopy  (this.path[i].attr)));
384                                        this.path[i].uploading=true;
385                                }
386                        }
387                        _root.writesrequested++;
388                        remote_write.call('putway',putresponder,_root.usertoken,_root.changeset,this.version,Number(this._name),sendpath,this.attr,sendnodes,this.deletednodes);
389                        this.clean=true;
390                }
391        };
392
393        // ---- Delete any ways merged into this one
394
395        OSMWay.prototype.deleteMergedWays=function() {
396                while (this.mergedways.length>0) {
397                        var i=this.mergedways.shift();
398                        _root.map.ways.attachMovie("way",i[0],++waydepth);      // can't remove unless the movieclip exists!
399                        _root.map.ways[i[0]].version=i[1];                                      //  |
400                        _root.map.ways[i[2]].deletednodes=i[2];                         //  |
401                        _root.map.ways[i[0]].remove();
402                }
403        };
404
405        // ---- Revert to copy in database
406       
407        OSMWay.prototype.reload=function() {
408                _root.waysrequested+=1;
409                while (this.mergedways.length>0) {
410                        var i=this.mergedways.shift();
411                        _root.waysrequested+=1;
412                        _root.map.ways.attachMovie("way",i[0],++waydepth);
413                        _root.map.ways[i[0]].load();
414                }
415                this.checkconnections=true;
416                this.load();
417        };
418       
419        // ---- Save for undo
420
421        OSMWay.prototype.saveUndo=function(str) {
422                _root.undo.append(UndoStack.prototype.undo_deleteway,
423                                                  new Array(this._name,this._x,this._y,
424                                                                        deepCopy(this.attr),
425                                                                        deepCopy(this.path)),iText("$1 a way",'a_way',str));
426        };
427
428
429        // ---- Click handling 
430
431        OSMWay.prototype.onRollOver=function() {
432                if (this._name!=_root.wayselected && _root.drawpoint>-1) {
433                        this.highlightPoints(5001,"anchorhint");
434                        setPointer('penplus');
435                } else if (_root.drawpoint>-1) { setPointer('penplus'); }
436                                                                  else { setPointer(''); }
437                if (this._name!=_root.wayselected) { var a=getName(this.attr,nodenames); if (a) { setFloater(a); } }
438        };
439       
440        OSMWay.prototype.onRollOut=function() {
441                if (_root.wayselected) { setPointer(''   ); }
442                                                  else { setPointer('pen'); }
443                _root.map.anchorhints.removeMovieClip();
444                clearFloater();
445        };
446       
447        OSMWay.prototype.onPress=function() {
448                removeWelcome(true);
449                if (Key.isDown(Key.SHIFT) && this._name==_root.wayselected && _root.drawpoint==-1) {
450                        // shift-click current way: insert point
451                        this.insertAnchorPointAtMouse();
452                } else if (Key.isDown(Key.SHIFT) && _root.wayselected && this.name!=_root.wayselected && _root.drawpoint==-1) {
453                        if (_root.ws.hitTest(_root._xmouse,_root._ymouse,true)) {
454                                // shift-click other way (at intersection with current): make intersection
455                                this.insertAnchorPointAtMouse();
456                        } else {
457                                // shift-click other way: merge two ways
458                                this.mergeAtCommonPoint(_root.ws);
459                                _root.ws.redraw();
460                                _root.ws.select();
461//                              _root.ws.upload();
462//                              _root.map.ways[this._name ].remove(wayselected);
463                        }
464                } else if (_root.drawpoint>-1) {
465                        // click other way while drawing: insert point as junction
466                        if (!this.historic) {
467                                if (this._name==_root.wayselected && _root.drawpoint>0) {
468                                        _root.drawpoint+=1;     // inserting node earlier into the way currently being drawn
469                                }
470                                _root.newnodeid--;
471                                _root.nodes[newnodeid]=new Node(newnodeid,0,0,new Object(),0);
472                                this.insertAnchorPoint(_root.nodes[newnodeid]);
473                                this.highlightPoints(5001,"anchorhint");
474                                addEndPoint(_root.nodes[newnodeid]);
475                        }
476                        _root.junction=true;
477                        restartElastic();
478                } else {
479                        // click way: select
480                        _root.panel.properties.saveAttributes();
481                        this.select();
482                        clearTooltip();
483                        _root.clicktime=new Date();
484                        // was the click on a tagged node? if so, select directly
485                        var n;
486                        for (var i=0; i<this.path.length; i+=1) {
487                                if (this.taggednodes[i].hitTest(_root._xmouse,_root._ymouse,true)) { n=i; }
488                        }
489                        if (n) { _root.map.anchors[n].beginDrag();
490                                         _root.map.anchors[n].select(); }
491                          else { this.beginDrag(); }
492                }
493        };
494
495        OSMWay.prototype.beginDrag=function() {
496                this.onMouseMove=function() { this.trackDrag(); };
497                this.onMouseUp  =function() { this.endDrag();   };
498                this.dragged=false;
499                this.held=true;
500                _root.firstxmouse=_root.map._xmouse;
501                _root.firstymouse=_root.map._ymouse;
502        };
503
504        OSMWay.prototype.trackDrag=function() {
505                var t=new Date();
506                var longclick=(t.getTime()-_root.clicktime)>1000;
507                var xdist=Math.abs(_root.map._xmouse-_root.firstxmouse);
508                var ydist=Math.abs(_root.map._ymouse-_root.firstymouse);
509                // Don't enable drag unless way held for a while after click
510                if ((xdist>=tolerance   || ydist>=tolerance  ) &&
511                        (t.getTime()-_root.clicktime)<300 &&
512                        lastwayselected!=wayselected) { this.held=false; }
513                // Move way if dragged a long way, or dragged a short way after a while
514                if ((xdist>=tolerance*4 || ydist>=tolerance*4) ||
515                   ((xdist>=tolerance/4 || ydist>=tolerance/4) && longclick) &&
516                   this.held) {
517                        this.dragged=true;
518                }
519                if (this.dragged) {
520                        _root.map.anchors._x=_root.map.areas[this._name]._x=_root.map.highlight._x=this._x=_root.map._xmouse-_root.firstxmouse;
521                        _root.map.anchors._y=_root.map.areas[this._name]._y=_root.map.highlight._y=this._y=_root.map._ymouse-_root.firstymouse;
522                }
523        };
524       
525        OSMWay.prototype.endDrag=function() {
526                delete this.onMouseMove;
527                delete this.onMouseUp;
528                _root.map.anchors._x=_root.map.areas[this._name]._x=_root.map.highlight._x=this._x=0;
529                _root.map.anchors._y=_root.map.areas[this._name]._y=_root.map.highlight._y=this._y=0;
530                if (this.dragged) {
531                        this.moveNodes(_root.map._xmouse-_root.firstxmouse,_root.map._ymouse-_root.firstymouse);
532                        setAdvice(false,iText("Way dragged (Z to undo)",'advice_waydragged'));
533                        this.redraw();
534                        this.select();
535                        _root.undo.append(UndoStack.prototype.undo_movenodes,
536                                                          new Array(this,_root.map._xmouse-_root.firstxmouse,
537                                                                                         _root.map._ymouse-_root.firstymouse),
538                                                          iText("moving a way",'action_moveway'));
539                }
540        };
541       
542        // ---- Select/highlight
543       
544        OSMWay.prototype.select=function() {
545                _root.panel.properties.tidy();
546                if (_root.wayselected!=this._name || _root.poiselected!=0) { uploadSelected(); }
547//              _root.panel.properties.saveAttributes();
548                selectWay(this._name);
549                _root.pointselected=-2;
550                _root.poiselected=0;
551                this.highlightPoints(5000,"anchor");
552                removeMovieClip(_root.map.anchorhints);
553                this.highlight();
554                setTypeText(iText("Way",'way'),this._name);
555                _root.panel.properties.init('way',getPanelColumns(),4);
556                _root.panel.presets.init(_root.panel.properties);
557                updateButtons();
558                updateScissors(false);
559        };
560       
561        OSMWay.prototype.highlight=function() {
562                _root.map.createEmptyMovieClip("highlight",5);
563                if (_root.pointselected>-2) {
564                        highlightSquare(_root.map.anchors[pointselected]._x,_root.map.anchors[pointselected]._y,8/Math.pow(2,Math.min(_root.scale,17)-13));
565                } else {
566                        var linecolour=0xFFFF00; if (this.locked) { var linecolour=0x00FFFF; }
567                        _root.map.highlight.lineStyle(linewidth*1.5+8,linecolour,80,false,"none");
568                        _root.map.highlight.moveTo(this.path[0].x,this.path[0].y);
569                        for (var i=1; i<this.path.length; i+=1) {
570                                _root.map.highlight.lineTo(this.path[i].x,this.path[i].y);
571                        }
572                }
573                this.direction();
574        };
575
576        OSMWay.prototype.highlightPoints=function(d,atype) {
577                var enlarge=1;
578                var anchorsize=120/Math.pow(2,_root.scale-13);
579                if (preferences.data.thinlines) { enlarge=0.5; }
580                if (_root.scale>15) {
581                        switch (_root.scale) {
582                                case 15: anchorsize+=10*enlarge; break;
583                                case 16: anchorsize+=7 *enlarge; break;
584                                case 17: anchorsize+=5 *enlarge; break;
585                                case 18: anchorsize+=6 *enlarge; break;
586                                case 19: anchorsize+=6 *enlarge; break;
587                        }
588                }
589                var group=atype+"s";
590                _root.map.createEmptyMovieClip(group,d);
591                for (var i=0; i<this.path.length; i+=1) {
592                        _root.map[group].attachMovie(atype,i,i);
593                        _root.map[group][i]._x=this.path[i].x;
594                        _root.map[group][i]._y=this.path[i].y;
595                        _root.map[group][i]._xscale=anchorsize;
596                        _root.map[group][i]._yscale=anchorsize;
597                        _root.map[group][i].node=this.path[i].id;
598                        _root.map[group][i].way=this;
599                        if (this.path[i].tagged) {
600                                // anchor point should be black if it has tags
601                                _root.map[group][i].blacken=new Color(_root.map[group][i]);
602                                _root.map[group][i].blacken.setTransform(to_black);
603                        }
604                }
605        };
606
607        // ---- Split, merge, reverse
608
609        OSMWay.prototype.splitWay=function(point,newattr) {
610                var i,z;
611                if (point>0 && point<(this.path.length-1) && !this.historic) {
612                        _root.newwayid--;                                                                                       // create new way
613                        _root.map.ways.attachMovie("way",newwayid,++waydepth);          //  |
614                        _root.map.ways[newwayid].path=shallowCopy(this.path);           // deep copy path array
615                        this.removeNodeIndex();
616
617                        if (newattr) { _root.map.ways[newwayid].attr=newattr; }
618                                        else { _root.map.ways[newwayid].attr=deepCopy(this.attr); }
619
620                        z=_root.wayrels[this._name];                                                            // copy relations
621                        for (i in z) {                                                                                          //  |
622                                _root.map.relations[i].setWayRole(newwayid,z[i]);               //  |
623                        }                                                                                                                       //  |
624
625                        this.path.splice(Math.floor(point)+1);                                          // current way
626                        this.redraw();                                                                                          //  |
627                        this.createNodeIndex();
628
629                        _root.map.ways[newwayid].path.splice(0,point);                          // new way
630                        _root.map.ways[newwayid].locked=this.locked;                            //  |
631                        _root.map.ways[newwayid].redraw();                                                      //  |
632                        _root.map.ways[newwayid].clean=false;                                           //  | - in case it doesn't upload
633                        _root.map.ways[newwayid].upload();                                                      //  |
634                        _root.map.ways[newwayid].createNodeIndex();                                     //  |
635
636                        this.clean=false;                                                                                       // upload current way
637                        this.upload();                                                                                          //  |
638                        this.select();                                                                                          //  |
639                        uploadDirtyRelations();
640                        _root.undo.append(UndoStack.prototype.undo_splitway,
641                                                          new Array(this,_root.map.ways[newwayid]),
642                                                          iText("splitting a way",'action_splitway'));
643                };
644        };
645
646        //              Merge (start/end of this way,other way object,start/end of other way)
647
648        OSMWay.prototype.mergeWay=function(topos,otherway,frompos) {
649                var i,z;
650                var conflict=false;
651                if (this.historic || otherway.historic) { return; }
652
653                var mergepoint=this.path.length;
654                if (topos==0) {
655                        _root.undo.append(UndoStack.prototype.undo_mergeways,
656                                                          new Array(this,deepCopy(otherway.attr),deepCopy(this.attr),frompos),
657                                                          iText("merging two ways",'action_mergeways'));
658                } else {
659                        _root.undo.append(UndoStack.prototype.undo_mergeways,
660                                                          new Array(this,deepCopy(this.attr),deepCopy(otherway.attr),topos),
661                                                          iText("merging two ways",'action_mergeways'));
662                }
663                if (frompos==0) { for (i=0; i<otherway.path.length;    i+=1) { this.addPointFrom(topos,otherway,i); } }
664                                   else { for (i=otherway.path.length-1; i>=0; i-=1) { this.addPointFrom(topos,otherway,i); } }
665
666                // Merge attributes
667                z=otherway.attr;
668                for (i in z) {
669                        if (otherway.attr[i].substr(0,6)=='(type ') { otherway.attr[i]=null; }
670                        if (this.attr[i].substr(0,6)=='(type ') { this.attr[i]=null; }
671                        if (this.attr[i]) {
672                                if (this.attr[i]!=otherway.attr[i] && otherway.attr[i]) { this.attr[i]+='; '+otherway.attr[i]; conflict=true; }
673                        } else {
674                                this.attr[i]=otherway.attr[i];
675                        }
676                        if (!this.attr[i]) { delete this.attr[i]; }
677                }
678
679                // Merge relations
680                z=_root.wayrels[otherway._name];                                                // copy relations
681                for (i in z) {                                                                                  //  |
682                        if (!_root.wayrels[this._name][i]) {                            //  |
683                                _root.map.relations[i].setWayRole(this._name,z[i]);     
684                        }                                                                                                       //  |
685                }                                                                                                               //  |
686                memberDeleted('Way', otherway._name);                                   // then remove old way from them
687                z=otherway.deletednodes;                                                                //  | and its deletednodes
688                for (i in z) { memberDeleted('Node',z[i]); }                    //  |
689
690                // Add to list of merged ways (so they can be deleted on next putway)
691                this.mergedways.push(new Array(otherway._name,otherway.version,otherway.deletednodes));
692                this.mergedways.concat(otherway.mergedways);
693                this.clean=false;
694                markClean(false);
695                if (otherway.locked) { this.locked=true; }
696                removeMovieClip(_root.map.areas[otherway._name]);
697                removeMovieClip(otherway);
698                if (this._name==_root.wayselected) { 
699                        _root.panel.properties.reinit();
700                }
701                if (conflict) { setAdvice(false,iText("Tags don't match - please check (Z to undo)",'advice_tagconflict')); }
702        };
703
704        OSMWay.prototype.addPointFrom=function(topos,otherway,srcpt) {
705                if (topos==0) { if (this.path[0                                 ]==otherway.path[srcpt]) { return; } }  // don't add duplicate points
706                                 else { if (this.path[this.path.length-1]==otherway.path[srcpt]) { return; } }  //  |
707                if (topos==0) { this.path.unshift(otherway.path[srcpt]); }
708                             else { this.path.push(otherway.path[srcpt]); }
709                otherway.path[srcpt].addWay(this._name);
710        };
711
712        OSMWay.prototype.mergeAtCommonPoint=function(sel) {
713                var selstart =sel.path[0];
714                var sellen   =sel.path.length-1;
715                var selend   =sel.path[sellen];
716                var thisstart=this.path[0];
717                var thislen  =this.path.length-1;
718                var thisend  =this.path[thislen];
719                if      (selstart==thisstart) { sel.mergeWay(0,this,0);                    return true; }
720                else if (selstart==thisend  ) { sel.mergeWay(0,this,thislen);      return true; }
721                else if (selend  ==thisstart) { sel.mergeWay(sellen,this,0);       return true; }
722                else if (selend  ==thisend  ) { sel.mergeWay(sellen,this,thislen); return true; }
723                else                                              { setAdvice(true,iText("The ways do not share a common point",'advice_nocommonpoint')); return false; }
724        };
725
726        // ---- Reverse order
727       
728        OSMWay.prototype.reverseWay=function() {
729                if (this.path.length<2) { return; }
730                if (_root.drawpoint>-1) { _root.drawpoint=(this.path.length-1)-_root.drawpoint; }
731                this.path.reverse();
732                this.redraw();
733                this.direction();
734                this.select();
735                this.clean=false;
736                markClean(false);
737                _root.undo.append(UndoStack.prototype.undo_reverse,new Array(this),iText("reversing a way",'action_reverseway'));
738        };
739
740        // ---- Move all nodes within a way
741       
742        OSMWay.prototype.moveNodes=function(xdiff,ydiff) {
743                var i,n;
744                var movedalready=new Array();
745                this.clean=false;
746                markClean(false);
747                for (i=0; i<this.path.length; i+=1) {
748                        n=this.path[i].id;
749                        if (movedalready[n]) {
750                        } else {
751                                this.path[i].moveTo(this.path[i].x+xdiff,
752                                                                        this.path[i].y+ydiff,
753                                                                        this._name);
754                                movedalready[n]=true;
755                        }
756                }
757        };
758
759        // ---- Add node to deleted list
760        //              (should have been removed from way first)
761       
762        OSMWay.prototype.markAsDeleted=function(rnode) {
763                //      Check how many times it's used in this way
764                var z=this.path; var d=true;
765                for (var i in z) { if (this.path[i].id==rnode.id) { d=false; } }
766
767                if (d) { rnode.removeWay(this._name); }
768                if (rnode.numberOfWays()==0 && rnode.id>0) { this.deletednodes[rnode.id]=rnode.version; }
769        };
770
771
772        // ---- Check for duplicates (e.g. when C is removed from ABCB)
773       
774        OSMWay.prototype.removeDuplicates=function() {
775                var z=this.path; var ch=false;
776                for (var i in z) {
777                        if (i>0) {
778                                if (this.path[i]==this.path[i-1]) { this.path.splice(i,1); ch=true; }
779                        }
780                }
781                return ch;
782        };
783
784        // ---- Add point into way with SHIFT-clicking
785        //              cf http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/source.vba
786        //              for algorithm to find nearest point on a line
787       
788        OSMWay.prototype.insertAnchorPoint=function(nodeobj) {
789                var nx,ny,u,closest,closei,i,a,b,direct,via,newpoint;
790                nx=_root.map._xmouse;   // where we're inserting it
791                ny=_root.map._ymouse;   //      |
792                closest=0.1; closei=0;
793                for (i=0; i<(this.path.length)-1; i+=1) {
794                        a=this.path[i  ];
795                        b=this.path[i+1];
796                        direct=Math.sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
797                        via   =Math.sqrt((nx -a.x)*(nx -a.x)+(ny -a.y)*(ny -a.y));
798                        via  +=Math.sqrt((nx -b.x)*(nx -b.x)+(ny -b.y)*(ny -b.y));
799                        if (Math.abs(via/direct-1)<closest) {
800                                closei=i+1;
801                                closest=Math.abs(via/direct-1);
802                                u=((nx-a.x)*(b.x-a.x)+
803                                   (ny-a.y)*(b.y-a.y))/
804                                   (Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2));
805                                nodeobj.x=a.x+u*(b.x-a.x);
806                                nodeobj.y=a.y+u*(b.y-a.y);
807                        }
808                }
809                // Insert
810                nodeobj.addWay(this._name);
811                this.path.splice(closei,0,nodeobj);
812                this.clean=false;
813                this.redraw();
814                markClean(false);
815//              _root.adjustedxmouse=tx;        // in case we're adding extra points...
816//              _root.adjustedymouse=ty;        // should probably return an array or an object **
817                return closei;
818        };
819
820        //              Wrapper around the above to:
821        //              - insert at mouse position
822        //              - add to undo stack
823        //              - add intersection at any crossing ways
824
825        OSMWay.prototype.insertAnchorPointAtMouse=function() {
826                _root.newnodeid--;
827                _root.nodes[newnodeid]=new Node(newnodeid,0,0,new Object(),0);
828                _root.pointselected=this.insertAnchorPoint(_root.nodes[newnodeid]);
829                var waylist=new Array(); waylist.push(this);
830                var poslist=new Array(); poslist.push(_root.pointselected);
831                for (qway in _root.map.ways) {
832                        if (_root.map.ways[qway].hitTest(_root._xmouse,_root._ymouse,true) && qway!=this._name) {
833                                poslist.push(_root.map.ways[qway].insertAnchorPoint(_root.nodes[newnodeid]));
834                                waylist.push(_root.map.ways[qway]);
835                        }
836                }
837                _root.undo.append(UndoStack.prototype.undo_addpoint,
838                                                  new Array(waylist,poslist), iText("adding a node into a way",'action_insertnode'));
839                _root.ws.highlightPoints(5000,"anchor");
840                _root.map.anchors[pointselected].beginDrag();
841        };
842
843        // ---- Remove point from this way (only)
844       
845        OSMWay.prototype.removeAnchorPoint=function(point) {
846                // ** if length<2, then mark as way removal
847                _root.undo.append(UndoStack.prototype.undo_deletepoint,
848                                                  new Array(deepCopy(this.path[point]),
849                                                                        new Array(this._name),
850                                                                        new Array(point)),
851                                                  iText("deleting a point",'action_deletepoint'));
852                var rnode=this.path[point];
853                this.path.splice(point,1);
854                this.removeDuplicates();
855                this.markAsDeleted(rnode);
856                if (rnode.numberOfWays()==0) { memberDeleted('Node', rnode.id); }
857                if (this.path.length<2) { this.remove(); }
858                                                   else { this.redraw(); this.clean=false; }
859        };
860
861        // ---- Bounding box utility functions
862
863        OSMWay.prototype.resetBBox=function() {
864                this.xmin=this.ymin= 999;
865                this.xmax=this.ymax=-999;
866        };
867       
868        OSMWay.prototype.updateBBox=function(long,lat) {
869                this.xmin=Math.min(long,this.xmin);
870                this.xmax=Math.max(long,this.xmax);
871                this.ymin=Math.min(lat ,this.ymin);
872                this.ymax=Math.max(lat ,this.ymax);
873        };
874
875        // ---- Node->way associations
876       
877        OSMWay.prototype.createNodeIndex  =function() { var z=this.path; for (var i in z) { this.path[i].addWay(this._name);    } };
878        OSMWay.prototype.removeNodeIndex  =function() { var z=this.path; for (var i in z) { this.path[i].removeWay(this._name); } };
879        OSMWay.prototype.renumberNodeIndex=function(n) {
880                var z=this.path; for (i in z) { 
881                        this.path[i].removeWay(this._name);
882                        this.path[i].addWay(n);
883                }
884        };
885        OSMWay.prototype.hasDependentNodes=function() {
886                var d=false;
887                var z=this.path; for (var i in z) {
888                        if (this.path[i].id<0) {
889                                var ways=this.path[i].ways; for (var w in ways) {
890                                        if (_root.map.ways[w].uploading) { d=true; }
891                                }
892                        }
893                }
894                return d;
895        };
896
897        // =====================================================================================
898        // Offset path
899        // ** much of the dialogue box could be refactored to share with relations dialogue
900
901        function askOffset() {
902                if (!_root.wayselected) { return; }
903                _root.windows.attachMovie("modal","offset",++windowdepth);
904                _root.windows.offset.init(300, 170, [iText("Cancel",'cancel'), iText("Ok",'ok')], completeOffset);
905                var z = 5;
906                var box = _root.windows.offset.box;
907               
908                box.createTextField("title",z++,7,7,300-14,20);
909                box.title.text = iText("Create parallel way",'prompt_createparallel');
910                with (box.title) {
911                        wordWrap=true;
912                        setTextFormat(boldText);
913                        selectable=false; type='dynamic';
914                }
915               
916                box.createTextField("instr",z++,7,30,300-14,40);
917
918                // Create radio buttons and menu
919
920                box.attachMovie("radio","offsetoption",z++);
921                box.offsetoption.addButton(10,35 ,iText("Dual carriageway (D2)",'offset_dual'));
922                box.offsetoption.addButton(10,55 ,iText("Motorway (D3)",'offset_motorway'));
923                box.offsetoption.addButton(10,75 ,iText("Narrow canal towpath",'offset_narrowcanal'));
924                box.offsetoption.addButton(10,95 ,iText("Broad canal towpath",'offset_broadcanal'));
925                box.offsetoption.addButton(10,115,iText("Choose offset (m)",'offset_choose'));
926                box.offsetoption.select(1);
927
928                var w=box.offsetoption[5].prompt._width+25;
929                box.createTextField("useroffset",z++,w,110,290-w,17);
930                box.useroffset.setNewTextFormat(plainSmall);
931                box.useroffset.type='input';
932                box.useroffset.backgroundColor=0xDDDDDD;
933                box.useroffset.background=true;
934                box.useroffset.border=true;
935                box.useroffset.borderColor=0xFFFFFF;
936                box.useroffset.onSetFocus=function() { this._parent.offsetoption.select(5); };
937        }
938
939        // typical widths:
940        // central reservation:
941        //       4.5m on a rural motorway/dual carriageway
942        //       3.5m on an urban motorway
943        //       1.8m on an urban dual carriageway
944        // lane widths are typically always 3.65m
945        // hard shoulders are typically 3.30m
946        // hard strips are typically 1m
947
948        function completeOffset(button) {
949                if (button!=iText("Ok",'ok')) { return false; }
950                var radio=_root.windows.offset.box.offsetoption.selected;
951                var m;
952                if (radio==5) {
953                        m=_root.windows.offset.box.useroffset.text;
954                        if (!button) { return false; }
955                } else {
956                        m=new Array(0,4.5+3.65*2,4.5+3.65*3,5.5,11);
957                        m=m[radio];
958                }
959                var thislat=coord2lat(_root.map._y);                    // near as dammit
960                var latfactor=Math.cos(thislat/(180/Math.PI));  // 111200m in a degree at the equator
961                m=masterscale/(111200*latfactor)*m;                             // 111200m*cos(lat in radians) elsewhere
962                _root.ws.offset( m);
963                _root.ws.offset(-m);
964                _root.undo.append(UndoStack.prototype.undo_makeways,
965                                                  new Array(_root.newwayid,_root.newwayid+1),
966                                                  iText("creating parallel ways",'action_createparallel'));
967        }
968
969        // Create (locked) offset way
970        // offset is + or - depending on which side
971
972        OSMWay.prototype.offset=function(tpoffset) {
973                var a,b,o,df,x,y;
974                var offsetx=new Array();
975                var offsety=new Array();
976                var wm=1;       // was 10 before
977
978                _root.newwayid--;                                                                                       // create new way
979                _root.map.ways.attachMovie("way",newwayid,++waydepth);          //  |
980                var nw=_root.map.ways[newwayid];
981                nw.locked=true;
982                nw.clean=false;
983
984                // Normalise, and calculate offset vectors
985
986                for (var i=0; i<this.path.length; i++) {
987                        a=this.path[i  ].y - this.path[i+1].y;
988                        b=this.path[i+1].x - this.path[i  ].x;
989                        h=Math.sqrt(a*a+b*b);
990                        if (h!=0) { a=a/h; b=b/h; }
991                                 else { a=0; b=0; }
992                        offsetx[i]=wm*a;
993                        offsety[i]=wm*b;
994                }
995
996                _root.newnodeid--;
997                _root.nodes[newnodeid]=new Node(newnodeid,this.path[0].x+tpoffset*offsetx[0],
998                                                                                                  this.path[0].y+tpoffset*offsety[0],
999                                                                                                  new Object(),0);
1000                nw.path.push(_root.nodes[newnodeid]);
1001               
1002                for (i=1; i<(this.path.length-1); i++) {
1003       
1004                        a=det(offsetx[i]-offsetx[i-1],
1005                                  offsety[i]-offsety[i-1],
1006                                  this.path[i+1].x - this.path[i  ].x,
1007                                  this.path[i+1].y - this.path[i  ].y);
1008                        b=det(this.path[i  ].x - this.path[i-1].x,
1009                                  this.path[i  ].y - this.path[i-1].y,
1010                                  this.path[i+1].x - this.path[i  ].x,
1011                                  this.path[i+1].y - this.path[i  ].y);
1012                        if (b!=0) { df=a/b; } else { df=0; }
1013                       
1014                        x=this.path[i].x + tpoffset*(offsetx[i-1]+df*(this.path[i].x - this.path[i-1].x));
1015                        y=this.path[i].y + tpoffset*(offsety[i-1]+df*(this.path[i].y - this.path[i-1].y));
1016       
1017                        _root.newnodeid--;
1018                        _root.nodes[newnodeid]=new Node(newnodeid,x,y,new Object(),0);
1019                        nw.path.push(_root.nodes[newnodeid]);
1020                }
1021       
1022                _root.newnodeid--;
1023                _root.nodes[newnodeid]=new Node(newnodeid,this.path[i].x+tpoffset*offsetx[i-1],
1024                                                                                                  this.path[i].y+tpoffset*offsety[i-1],new Object(),0);
1025                nw.path.push(_root.nodes[newnodeid]);
1026                nw.redraw();
1027        };
1028
1029    function det(a,b,c,d) { return a*d-b*c; }
1030
1031
1032        Object.registerClass("way",OSMWay);
1033
1034
1035        // =====================================================================================
1036        // Drawing support functions
1037
1038        // removeNodeFromWays - now see Node.removeFromAllWays
1039
1040        // startNewWay            - create new way from first node
1041
1042        function startNewWay(node) {
1043                uploadSelected();
1044                _root.newwayid--;
1045                selectWay(newwayid);
1046                _root.poiselected=0;
1047                _root.map.ways.attachMovie("way",newwayid,++waydepth);
1048                _root.map.ways[newwayid].path[0]=_root.nodes[node];
1049                _root.map.ways[newwayid].redraw();
1050                _root.map.ways[newwayid].select();
1051                _root.map.ways[newwayid].clean=false;
1052                _root.nodes[node].addWay(newwayid);
1053                _root.map.anchors[0].startElastic();
1054                _root.drawpoint=0;
1055                markClean(false);
1056                setTooltip(iText("click to add point\ndouble-click/Return\nto end line",'hint_drawmode'),0);
1057        }
1058
1059        // addEndPoint(node object) - add point to start/end of line
1060
1061        function addEndPoint(node) {
1062                var drawnode=_root.ws.path[_root.drawpoint];
1063                if (_root.drawpoint==_root.ws.path.length-1) {
1064                        _root.ws.path.push(node);
1065                        _root.drawpoint=_root.ws.path.length-1;
1066                } else {
1067                        _root.ws.path.unshift(node);    // drawpoint=0, add to start
1068                }
1069                node.addWay(_root.wayselected);
1070       
1071                // Redraw line (if possible, just extend it to save time)
1072                if (_root.ws.getFill()>-1 || 
1073                        _root.ws.path.length<3 ||
1074                        _root.pointselected>-2) {
1075                        _root.ws.redraw();
1076                        _root.ws.select();
1077                } else {
1078                        _root.ws.line.moveTo(drawnode.x,drawnode.y);
1079                        _root.ws.line.lineTo(node.x,node.y);
1080                        if (casing[_root.ws.attr['highway']]) {
1081                                _root.map.areas[wayselected].moveTo(drawnode.x,drawnode.y);
1082                                _root.map.areas[wayselected].lineTo(node.x,node.y);
1083                        }
1084                        _root.map.highlight.moveTo(drawnode.x,drawnode.y);
1085                        _root.map.highlight.lineTo(node.x,node.y);
1086                        _root.ws.direction();
1087                        _root.ws.highlightPoints(5000,"anchor");
1088                        removeMovieClip(_root.map.anchorhints);
1089                        var z=_root.wayrels[_root.wayselected];
1090                        for (var rel in z) { _root.map.relations[rel].redraw(); }
1091                }
1092                // Mark as unclean
1093                _root.ws.clean=false;
1094                markClean(false);
1095                _root.map.elastic.clear();
1096                var poslist=new Array(); poslist.push(_root.drawpoint);
1097                _root.undo.append(UndoStack.prototype.undo_addpoint,
1098                                                  new Array(new Array(_root.ws),poslist),
1099                                                  iText("adding a node to the end of a way",'action_addpoint'));
1100        }
1101
1102        function stopDrawing() {
1103                _root.map.anchors[_root.drawpoint].endElastic();
1104                _root.drawpoint=-1;
1105                if (_root.ws.path.length<=1) { 
1106                        // way not long enough, so abort
1107                        _root.ws.removeNodeIndex();
1108                        removeMovieClip(_root.map.areas[wayselected]);
1109                        removeMovieClip(_root.ws);
1110                        removeMovieClip(_root.map.anchors);
1111                }
1112                _root.map.elastic.clear();
1113                clearTooltip();
1114        };
1115
1116        // cycleStacked - cycle through ways sharing same point
1117
1118        function cycleStacked() {
1119                if (_root.pointselected>-2) {
1120                        stopDrawing();
1121                        var id=_root.ws.path[_root.pointselected].id;
1122                        var firstfound=0; var nextfound=0;
1123                        for (qway in _root.map.ways) {
1124                                if (qway!=_root.wayselected) {
1125                                        for (qs=0; qs<_root.map.ways[qway].path.length; qs+=1) {
1126                                                if (_root.map.ways[qway].path[qs].id==id) {
1127                                                        var qw=Math.floor(qway);
1128                                                        if (firstfound==0 || qw<firstfound) { firstfound=qw; }
1129                                                        if ((nextfound==0 || qw<nextfound) && qw>wayselected) { nextfound=qw; }
1130                                                }
1131                                        }
1132                                }
1133                        }
1134                        if (firstfound) {
1135                                if (nextfound==0) { var nextfound=firstfound; }
1136                                _root.map.ways[nextfound].swapDepths(_root.ws);
1137                                _root.map.ways[nextfound].select();
1138                        }
1139                }
1140        };
1141
1142        // ================================================================
1143        // Way communication
1144       
1145        // whichWays    - get list of ways from remoting server
1146
1147        function whichWays() {
1148                _root.lastwhichways=new Date();
1149                if (_root.waycount>500) { purgeWays(); }
1150                if (_root.poicount>500) { purgePOIs(); }
1151                if (_root.edge_l>=_root.bigedge_l &&
1152                        _root.edge_r<=_root.bigedge_r &&
1153                        _root.edge_b>=_root.bigedge_b &&
1154                        _root.edge_t<=_root.bigedge_t) {
1155                        // we have already loaded this area, so ignore
1156                } else {
1157                        whichresponder=function() {};
1158                        whichresponder.onResult=function(result) {
1159                                var code=result.shift(); if (code) { handleError(code,result); return; }
1160                                _root.whichreceived+=1;
1161                                waylist  =result[0];
1162                                pointlist=result[1];
1163                                relationlist=result[2];
1164
1165                                for (i in waylist) {                                                                            // ways
1166                                        way=waylist[i][0];                                                                              //  |
1167                                        if (!_root.map.ways[way] || _root.map.ways[way].version!=waylist[i][1]) {
1168                                                _root.map.ways.attachMovie("way",way,++waydepth);       //  |
1169                                                _root.map.ways[way].load();                                                     //  |
1170                                                _root.waycount+=1;                                                                      //  |
1171                                                _root.waysrequested+=1;                                                         //  |
1172                                        }
1173                                }
1174                               
1175                                for (i in pointlist) {                                                                          // POIs
1176                                        point=pointlist[i][0];                                                                  //  |
1177                                        if (!_root.map.pois[point] || _root.map.pois[point].version!=pointlist[i][4]) {
1178                                                // **** attach correct icon:
1179                                                // if (pointlist[i][3]["place"]) {
1180                                                // _root.map.pois.attachMovie("poi_22",point,++poidepth);
1181                                                _root.map.pois.attachMovie("poi",point,++poidepth);     //  |
1182                                                _root.map.pois[point]._x=long2coord(pointlist[i][1]);// |
1183                                                _root.map.pois[point]._y=lat2coord (pointlist[i][2]);// |
1184                                                _root.map.pois[point]._xscale=
1185                                                _root.map.pois[point]._yscale=Math.max(100/Math.pow(2,_root.scale-13),6.25);
1186                                                _root.map.pois[point].version=pointlist[i][4];          //  |
1187                                                _root.map.pois[point].attr=pointlist[i][3];                     //  |
1188                                                _root.poicount+=1;                                                                      //  |
1189                                                if (point==prenode) { deselectAll(); prenode=undefined;
1190                                                                                          _root.map.pois[point].select(); }
1191                                        }
1192                                }
1193
1194                                for (i in relationlist) {
1195                                        rel = relationlist[i][0];
1196                    if (!_root.map.relations[rel] || _root.map.relations[rel].version!=relationlist[i][1]) {
1197                                                _root.map.relations.attachMovie("relation",rel,++reldepth);
1198                                                _root.map.relations[rel].load();
1199                                                _root.relcount+=1;
1200                                                _root.relsrequested+=1;
1201                                        }
1202                }
1203                        };
1204                        remote_read.call('whichways',whichresponder,_root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t);
1205                        _root.bigedge_l=_root.edge_l; _root.bigedge_r=_root.edge_r;
1206                        _root.bigedge_b=_root.edge_b; _root.bigedge_t=_root.edge_t;
1207                        _root.whichrequested+=1;
1208                }
1209        }
1210
1211        // purgeWays - remove any clean ways outside current view
1212       
1213        function purgeWays() {
1214                for (qway in _root.map.ways) {
1215                        if (qway==_root.wayselected) {
1216                        } else if (!_root.map.ways[qway].clean) {
1217                                _root.map.ways[qway].upload();
1218                                uploadDirtyRelations();
1219                        } else if (((_root.map.ways[qway].xmin<edge_l && _root.map.ways[qway].xmax<edge_l) ||
1220                                                (_root.map.ways[qway].xmin>edge_r && _root.map.ways[qway].xmax>edge_r) ||
1221                                            (_root.map.ways[qway].ymin<edge_b && _root.map.ways[qway].ymax<edge_b) ||
1222                                                (_root.map.ways[qway].ymin>edge_t && _root.map.ways[qway].ymax>edge_t))) {
1223                                removeMovieClip(_root.map.ways[qway]);
1224                                removeMovieClip(_root.map.areas[qway]);
1225                                _root.waycount-=1;
1226                        }
1227                }
1228                _root.bigedge_l=_root.edge_l; _root.bigedge_r=_root.edge_r;
1229                _root.bigedge_b=_root.edge_b; _root.bigedge_t=_root.edge_t;
1230                // ** remove unused nodes (i.e. this.ways only contains dead ones)
1231        }
1232
1233        function selectWay(id) {
1234                _root.lastwayselected=_root.wayselected;
1235                _root.wayselected=Math.floor(id);
1236                _root.ws=_root.map.ways[id];
1237        }
Note: See TracBrowser for help on using the repository browser.