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

Last change on this file since 14716 was 14695, checked in by richard, 10 years ago

change relation_member 'type' case, to match change in database

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