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

Last change on this file since 19967 was 19965, checked in by richard, 10 years ago

bunch of join/unjoin fixes

File size: 55.8 KB
RevLine 
[7126]1
[6739]2        // =====================================================================================
3        // OOP classes - OSMWay
4
5        // ---- Initialise
6       
7        function OSMWay() {
[10776]8                this.resetBBox();
[8894]9                this.path=new Array();                  // list of nodes
10                this.attr=new Array();                  // hash of tags
[6739]11                this.mergedways=new Array();    // list of ways merged into this
[14830]12                this.deletednodes=new Object(); // hash of nodes deleted from this
[6739]13        };
[10776]14
[6739]15        OSMWay.prototype=new MovieClip();
[10776]16        OSMWay.prototype.clean=true;                            // altered since last upload?
17        OSMWay.prototype.uploading=false;                       // currently uploading?
18        OSMWay.prototype.locked=false;                          // locked against upload?
[11859]19        OSMWay.prototype.version=0;                                     // version number?
[16388]20        OSMWay.prototype.uid=0;                                         // user ID (used for TIGER detection)
[11859]21        OSMWay.prototype.historic=false;                        // is this an undeleted, not-uploaded way?
[10776]22        OSMWay.prototype.checkconnections=false;        // check shared nodes on reload
[6739]23
24        // ---- Load from remote server
25
26        OSMWay.prototype.load=function() {
27                responder = function() { };
28                responder.onResult = function(result) {
29                        _root.waysreceived+=1;
[15136]30                        var code=result.shift(); var msg=result.shift(); if (code) { handleError(code,msg,result); return; }
[6739]31                        var w=result[0];
32                        if (length(result[1])==0) { removeMovieClip(_root.map.ways[w]); 
33                                                                                removeMovieClip(_root.map.areas[w]); return; }
[19965]34                        var i,id,x,y,prepoint,redrawws,l,n,b;
[6739]35                        _root.map.ways[w].clean=true;
36                        _root.map.ways[w].locked=false;
[11859]37                        _root.map.ways[w].historic=false;
38                        _root.map.ways[w].version=result[3];
[16388]39                        _root.map.ways[w].uid=result[4];
[10776]40                        _root.map.ways[w].removeNodeIndex();
[8894]41                        _root.map.ways[w].path=[];
42                        _root.map.ways[w].resetBBox();
43                        for (i=0; i<result[1].length; i++) {
44                                x =result[1][i][0];
45                                y =result[1][i][1];
46                                id=result[1][i][2];
47                                _root.map.ways[w].updateBBox(x,y);
48                                x=long2coord(x); y=lat2coord(y);
49                                if (nodes[id]) {
50                                        // already exists: move node in other ways if required
51                                        // ** maybe we should take out 'w'? not sure
52                                        if (_root.map.ways[w].checkconnections) { nodes[id].moveTo(x,y,w); }
53                                } else {
54                                        // doesn't exist, so create new node
[12386]55                                        _root.nodes[id]=new Node(id,x,y,result[1][i][3],result[1][i][4]);
[12402]56                                        _root.nodes[id].clean=true;
[8894]57                                        if (id==prenode) { prepoint=i; }
58                                }
[10776]59                                _root.map.ways[w].path.push(_root.nodes[id]);
60                                _root.nodes[id].addWay(w);
[16388]61                                if (_root.nodes[id].ways[_root.wayselected] && w!=_root.wayselected) { redrawws=true; }
[19965]62                                else if (_root.nodes[id].isDupe()) {
63                                        l=_root.pos[x+","+y]; for (b in l) {
64                                                n=_root.pos[x+","+y][b];
65                                                if (n.id!=id && n.ways[wayselected]) { redrawws=true; }
66                                        }
67                                }
[8894]68                        }
[7118]69                        _root.map.ways[w].attr=result[2];
[6739]70                        _root.map.ways[w].redraw();
[16388]71                        if (redrawws)  { _root.ws.highlightPoints(5000,"anchor"); }     // need to redraw [_]s if new connections loaded
[8894]72                        if (w==preway) { _root.map.ways[w].select(); preway=undefined; }
73                        if (prepoint)  { _root.map.ways[w].select(); 
74                                                         _root.map.anchors[prepoint].select();
75                                                         prenode=prepoint=undefined; }
[6739]76                        _root.map.ways[w].clearPOIs();
[8894]77                        _root.map.ways[w].checkconnections=false;
[6739]78                };
[11151]79                remote_read.call('getway',responder,Math.floor(this._name));
[6739]80        };
81
[13889]82        OSMWay.prototype.loadFromDeleted=function(timestamp) {
[6739]83                delresponder=function() { };
84                delresponder.onResult=function(result) {
[15136]85                        var code=result.shift(); var msg=result.shift(); if (code) { handleError(code,msg,result); return; }
[13903]86                        var i,id,n;
87                        var w=_root.map.ways[result[0]];
[16388]88                        var oldpath=new Object();               // make sure to delete any nodes not in reverted way
89                        for (i=0; i<w.path.length; i++) { oldpath[w.path[i].id]=w.path[i].version; }
[13903]90                        if (result[4]) { w.historic=false; w.clean=true;  }
91                                  else { w.historic=true;  w.clean=false; }
92                        w.version=result[3];
93                        w.removeNodeIndex();
94                        w.path=[];
95                        w.resetBBox();
[8894]96                        for (i=0; i<result[1].length; i++) {
[13903]97                                n=result[1][i];
98                                x=n[0]; y=n[1]; id=n[2];                                        // 3:current version, 4:tags, 5:reuse?
99                                if (id<0) { id=--_root.newnodeid; }                     // assign negative IDs to anything moved
[16388]100                                delete oldpath[id];
[13903]101                                w.updateBBox(x,y);
[8894]102                                x=long2coord(x); y=lat2coord(y);
103                                if (nodes[id]) {
[13903]104                                        if (x!=nodes[id].x || y!=nodes[id].y) {
105                                                // ** also needs to check that tags haven't changed
106                                                nodes[id].moveTo(x,y,w);
107                                                nodes[id].attr=n[4];
108                                                nodes[id].version=n[3];
[14735]109                                                w.clean=false;
[13903]110                                        }
111                                        if (n[5]) { nodes[id].clean=true; }             // is visible and current version
[8894]112                                } else {
[13903]113                                        _root.nodes[id]=new Node(id,x,y,n[4],n[3]);
[8894]114                                }
[13903]115                                w.path.push(_root.nodes[id]);
116                                _root.nodes[id].addWay(result[0]);
[6739]117                        }
[16388]118                        for (i in oldpath) { if (i>0) { w.deletednodes[i]=oldpath[i]; } }
[13903]119                        w.attr=result[2];
120                        if (w==ws) { w.select(); }
121                                  else { w.locked=true; }
122                        w.redraw();
123                        w.clearPOIs();
[6739]124                };
[13889]125                remote_read.call('getway_old',delresponder,Number(this._name),timestamp);
[6739]126        };
127
128        OSMWay.prototype.clearPOIs=function() {
129                // check if any way nodes are POIs, delete the POIs if so
130                var i,z;
131                z=this.path;
132                for (i in z) {
[10776]133                        if (_root.map.pois[this.path[i].id]) { removeMovieClip(_root.map.pois[this.path[i].id]); }
[6739]134                }
135        };
136
137        // ---- Draw line
138
[16869]139        OSMWay.prototype.redraw=function(skip,skiponeway) {
[16700]140                this.createEmptyMovieClip("taggednodes",3);
[8894]141
[16869]142                if (skip && !this.attr["oneway"]) {
[11040]143                        // We're at the same scale as previously, so don't redraw
144                        // ** will refactor this when we do proper POI icons
[16426]145                        for (var i=0; i<this.path.length; i+=1) {
[11040]146                                if (this.path[i].tagged) {
147                                        this.taggednodes.attachMovie("poiinway",i,i);
148                                        this.taggednodes[i]._x=this.path[i].x;
149                                        this.taggednodes[i]._y=this.path[i].y;
150                                        this.taggednodes[i]._xscale=this.taggednodes[i]._yscale=taggedscale;
[6739]151                                }
[11040]152                        }
153                } else {
[6739]154
[11040]155                        // Either the line has changed, or we've changed scale
156                        this.createEmptyMovieClip("line",1);                                    // clear line
[16700]157                        this.createEmptyMovieClip("arrows",2);                                  //  |
[11040]158                        var linealpha=100; // -50*(this.locked==true);
[16869]159                        var casingx=(scale<17 || preferences.data.thinlines) ? 1.5 : 1.3; var casingcol=0x222222;
[11040]160       
161                        // Set stroke
162       
[16388]163                        var f=this.getFill();
[11040]164                        if              (this.locked)                                    { this.line.lineStyle(linewidth,0xFF0000,linealpha,false,"none"); }
165                        else if (colours[this.attr["highway"]])  { this.line.lineStyle(linewidth,colours[this.attr["highway" ]],linealpha,false,"none"); }
166                        else if (colours[this.attr["waterway"]]) { this.line.lineStyle(linewidth,colours[this.attr["waterway"]],linealpha,false,"none"); }
167                        else if (colours[this.attr["railway"]])  { this.line.lineStyle(linewidth,colours[this.attr["railway" ]],linealpha,false,"none"); }
168                        else {
169                                var c=0xAAAAAA; var z=this.attr;
170                                for (var i in z) { if (i!='created_by' && this.attr[i]!='' && this.attr[i].substr(0,6)!='(type ') { c=0x707070; } }
[17889]171                                this.line.lineStyle((f>-1 || this.attr['boundary']) ? areawidth : linewidth,c,linealpha,false,"none");
[8894]172                        }
[11040]173                       
174                        // Draw fill/casing
175       
[15136]176                        var br=false;
[16388]177                        if (preferences.data.tiger && this.uid==7168 && this.version==1 && this.clean && this.attr["tiger:tlid"]) {
178                casingx=2; casingcol=0xFF00FF;
179                        } else if (preferences.data.noname && this.attr["highway"] && (!this.attr["name"] || this.attr["name"].substr(0,6)=='(type ')) {
[15136]180                casingx=2; casingcol=0xFF0000;
181                        } else if (this.attr["bridge"] && this.attr["bridge"]!="no") {
[16700]182                                casingx=(scale<17) ? 2 : 1.8; br=true;
[15136]183                        }
184
185                        if ((f>-1 || br || casing[this.attr['highway']]) && !this.locked) {
[11040]186                                if (!_root.map.areas[this._name]) { _root.map.areas.createEmptyMovieClip(this._name,++areadepth); }
187                                with (_root.map.areas[this._name]) {
188                                        clear();
189                                        enabled=false;
190                                        moveTo(this.path[0].x,this.path[0].y); 
191                                        if (f>-1) { beginFill(f,20); }
[11420]192                                                 else { lineStyle(linewidth*casingx,casingcol,100,false,"none"); }
[11040]193                                        for (var i=1; i<this.path.length; i+=1) {
194                                                lineTo(this.path[i].x,this.path[i].y);
195                                        }
196                                        if (f>-1) { endFill(); }
197                                };
198                        } else if (_root.map.areas[this._name]) {
199                                removeMovieClip(_root.map.areas[this._name]);
200                        }
201       
202                        // Draw line and tagged nodes
203       
204                        this.line.moveTo(this.path[0].x,this.path[0].y);
[14979]205                        for (var i=0; i<this.path.length; i+=1) {
206                                if (i>0) { this.line.lineTo(this.path[i].x,this.path[i].y); }
[11040]207                                if (this.path[i].tagged) {
[11420]208                                        // **** attach correct icon:
209                                        // if (this.path[i].attr['frog']) {
210                                        // this.taggednodes.attachMovie("poi_22",i,i);
211                                        // ...probably don't have to do _root.map.pois[point].__proto__=undefined;
212                                        //    because clicks are handled by the way movieclip
[11040]213                                        this.taggednodes.attachMovie("poiinway",i,i);
214                                        this.taggednodes[i]._x=this.path[i].x;
215                                        this.taggednodes[i]._y=this.path[i].y;
216                                        this.taggednodes[i]._xscale=this.taggednodes[i]._yscale=taggedscale;
217                                }
218                        }
[14727]219
220                        // Draw relations
221
[14765]222                        var z=_root.wayrels[this._name];
[14727]223                        for (var rel in z) { _root.map.relations[rel].redraw(); }
[16700]224                       
225                        // Draw direction arrows
226                       
[16869]227                        if (this.attr["oneway"] && !skiponeway) {
[16700]228                                this.drawArrows(this.attr["oneway"]);
229                        }
[6739]230                }
231        };
232
233        OSMWay.prototype.getFill=function() {
234                var f=-1; 
[8894]235                if (this.path[this.path.length-1]==this.path[0] && this.path.length>2) {
[6739]236                        if (this.attr['area']) { f='0x777777'; }
237                        var z=this.attr;
238                        for (var i in z) { if (areas[i] && this.attr[i]!='' && this.attr[i]!='coastline') { f=areas[i]; } }
239                }
240                return f;
241        };
242
[16700]243        OSMWay.prototype.drawArrows=function(dir) {
244                if (dir=='no' || dir=='false') { return; }
245                var dashes=[4,1,1,1,1,10];
246                var widths=[2,7,5,3,1,0];
247                if (dir=="-1") { dashes.reverse(); widths.reverse(); }
248                var arrowcol=0x6C70D5; if (this.attr['highway']=='primary' || this.attr['highway']=='primary_link' || 
249                                                                   this.attr['highway']=='trunk' || this.attr['highway']=='trunk_link' || 
250                                                                   this.attr['highway']=='motorway' || this.attr['highway']=='motorway_link') { arrowcol=0; }
251               
252                var draw=false;
253                var dashleft=0;
254                var segleft=0;
255                var dc=[]; var wc=[];
256                var a,xc,yc,curx,cury,dx,dy;
257                var i=0;
258
259                var g=this.arrows;
260                g.moveTo(this.path[0].x,this.path[0].y);
261                while (i<this.path.length-1 || segleft>0) {
262                        if (dashleft<=0) {
263                                if (dc.length==0) { dc=dashes.slice(0); wc=widths.slice(0); }
264                                dashleft=dc.shift()/bscale*2;
265                                dashwidth=wc.shift();
266                        }
267                        if (segleft<=0) {
268                                curx=this.path[i].x; dx=this.path[i+1].x-curx;
269                                cury=this.path[i].y; dy=this.path[i+1].y-cury;
270                                a=Math.atan2(dy,dx); xc=Math.cos(a); yc=Math.sin(a);
271                                segleft=Math.sqrt(dx*dx+dy*dy);
272                                i++;
273                        }
274
275                        if (segleft<=dashleft) {
276                                // the path segment is shorter than the dash
277                                curx+=dx; cury+=dy;
278                                moveLine(g,curx,cury,dashwidth,arrowcol);
279                                dashleft-=segleft; segleft=0;
280                        } else {
281                                // the path segment is longer than the dash
282                                curx+=dashleft*xc; dx-=dashleft*xc;
283                                cury+=dashleft*yc; dy-=dashleft*yc;
284                                moveLine(g,curx,cury,dashwidth,arrowcol);
285                                segleft-=dashleft; dashleft=0;
286                        }
287                }
288        };
289
290        function moveLine(g,x,y,dashwidth,colour) {
291                if (dashwidth==0) {
292                        g.moveTo(x,y);
293                } else {
294                        g.lineStyle(dashwidth,colour,100,false,"none","none");
295                        g.lineTo(x,y);
296                }
297        };
298
[16388]299        // ---- Tidy in line/circle
300       
301        OSMWay.prototype.tidy=function() {
302                var a=this.path[0]; var b=this.path[this.path.length-1];
303                var w=new Object(); w[this._name]=true;
304                if (a.id==b.id) {
305                        // Tidy in circle
306                        if (this.path.length<4) { return; }
[16865]307                        this.saveChangeUndo();
[16388]308                       
309                        // Find centre-point
310                        var patharea=0;
311                        var cx=0; var lx=b.x; //coord2long(b.x);
312                        var cy=0; var ly=b.y; //coord2y(b.y);
313                        for (var i=0; i<this.path.length; i++) {
314                var latp=this.path[i].y; //coord2y(this.path[i].y);
315                var lon =this.path[i].x; // coord2long(this.path[i].x);
316                                var sc = (lx*latp-lon*ly); //*masterscale;
317                                cx += (lx+lon)*sc;
318                                cy += (ly+latp)*sc;
319                                patharea += sc;
320                                lx=lon; ly=latp;
321                        }
322                        patharea/=2;
323                        cx=cx/patharea/6; //long2coord(cx/patharea/6);
324                        cy=cy/patharea/6; //y2coord(cy/patharea/6);
325
326                        // Average distance to centre
327                        var d=0; var angles=[];
328                        for (var i=0; i<this.path.length; i++) {
329                                d+=Math.sqrt(Math.pow(this.path[i].x-cx,2)+Math.pow(this.path[i].y-cy,2));
330                        }
331                        d=d/this.path.length;
332                       
333                        // Move each node
334                        for (var i=0; i<this.path.length-1; i++) {
335                                var c=Math.sqrt(Math.pow(this.path[i].x-cx,2)+Math.pow(this.path[i].y-cy,2));
[19957]336                                this.path[i].unsetPosition();
[16388]337                                this.path[i].x=cx+(this.path[i].x-cx)/c*d;
338                                this.path[i].y=cy+(this.path[i].y-cy)/c*d;
[19957]339                                this.path[i].setPosition();
[16424]340                                this.path[i].clean=false;
[16388]341                                var l=this.path[i].ways; for (var o in l) { w[o]=true; }
342                        }
343
344                        // Insert extra nodes to make circle
345                        // clockwise: angles decrease, wrapping round from -170 to 170
346                        var newpath=[]; var diff,b;
347                        var clockwise=_root.panel.i_clockwise._visible;
348                        for (var i=0; i<this.path.length-1; i++) {
349                                var j=(i+1) % this.path.length;
350                                newpath.push(this.path[i]);
351                                a1=Math.atan2(this.path[i].x-cx,this.path[i].y-cy)*(180/Math.PI);
352                                a2=Math.atan2(this.path[j].x-cx,this.path[j].y-cy)*(180/Math.PI);
353
354                                if (clockwise) {
355                                        if (a2>a1) { a2=a2-360; }
356                                        diff=a1-a2;
357                                        if (diff>20) {
[16412]358                                                for (var ang=a1-20; ang>a2+10; ang-=20) {
[16388]359                                                        _root.newnodeid--;
360                                                        _root.nodes[newnodeid]=new Node(newnodeid,cx+Math.sin(ang*Math.PI/180)*d,cy+Math.cos(ang*Math.PI/180)*d,new Object(),0);
[16901]361                                                        _root.nodes[newnodeid].addWay(this._name);
[16388]362                                                        newpath.push(_root.nodes[newnodeid]);
363                                                }
364                                        }
365                                } else {
366                                        if (a1>a2) { a1=a1-360; }
367                                        diff=a2-a1;
368                                        if (diff>20) {
[16412]369                                                for (var ang=a1+20; ang<a2-10; ang+=20) {
[16388]370                                                        _root.newnodeid--;
371                                                        _root.nodes[newnodeid]=new Node(newnodeid,cx+Math.sin(ang*Math.PI/180)*d,cy+Math.cos(ang*Math.PI/180)*d,new Object(),0);
[16901]372                                                        _root.nodes[newnodeid].addWay(this._name);
[16388]373                                                        newpath.push(_root.nodes[newnodeid]);
374                                                }
375                                        }
376                                }
377                        }
378                        newpath.push(this.path[this.path.length-1]);
379                        this.path=newpath;
380
381                } else {
382                        // Tidy in line
383                        if (this.path.length<3) { return; }
[17393]384
385                        // First, calculate divergence to make sure we're not straightening a really bendy way
386                        var d=0; var t,x1,y1;
387                        var thislat=coord2lat(_root.map._y); var latfactor=Math.cos(thislat/(180/Math.PI));
388                        for (var i=1; i<this.path.length-1; i++) {
389                                u=((this.path[i].x-a.x)*(b.x-a.x)+
390                                   (this.path[i].y-a.y)*(b.y-a.y))/
391                                   (Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2));
392                                x1=a.x+u*(b.x-a.x);
393                                y1=a.y+u*(b.y-a.y);
394                                t=Math.sqrt(Math.pow(x1-this.path[i].x,2)+Math.pow(y1-this.path[i].y,2));
395                                t=Math.floor((111200*latfactor)*t/masterscale);
396                                if (t>d) { d=t; }
397                        }
[17776]398                        if (d>50 && !Key.isDown(Key.SHIFT)) { setAdvice(false,iText('advice_bendy')); return; }
[16865]399                        this.saveChangeUndo();
[16388]400
[16393]401                        var el=long2coord(_root.bigedge_l);             // We don't want to delete any off-screen nodes
402                        var er=long2coord(_root.bigedge_r);             // (because they might be used in other ways)
403                        var et= lat2coord(_root.bigedge_t);
404                        var eb= lat2coord(_root.bigedge_b);
[16388]405                        var retain=new Array(a);
406                        for (var i=1; i<this.path.length-1; i++) {
[16393]407                                if (this.path[i].numberOfWays()>1 || hasTags(this.path[i].attr) ||
408                                        this.path[i].x<el || this.path[i].x>er || 
409                                        this.path[i].y<et || this.path[i].y>eb) {
[16388]410                                        u=((this.path[i].x-a.x)*(b.x-a.x)+
411                                           (this.path[i].y-a.y)*(b.y-a.y))/
412                                           (Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2));
[19957]413                                        this.path[i].unsetPosition();
[16388]414                                        this.path[i].x=a.x+u*(b.x-a.x);
415                                        this.path[i].y=a.y+u*(b.y-a.y);
[19957]416                                        this.path[i].setPosition();
[16388]417                                        this.path[i].clean=false;
418                                        var l=this.path[i].ways; for (var o in l) { w[o]=true; }
419                                        retain.push(this.path[i]);
420                                } else {
[16525]421                                        this.markAsDeleted(this.path[i],false);
[19965]422                                        this.path[i].unsetPosition();
[16388]423                                        memberDeleted('Node', this.path[i].id);
424                                }
425                        }
426                        retain.push(b);
427                        this.path=retain;
428                        this.removeDuplicates();
429                }
430                this.clean=false; markClean(false);
431                for (var i in w) { _root.map.ways[i].redraw(); }
432                this.select();
433        };
434
435
436
[6739]437        // ---- Show direction
438
439        OSMWay.prototype.direction=function() {
440                if (this.path.length<2) {
[7984]441                        _root.panel.i_clockwise._visible=false;
442                        _root.panel.i_anticlockwise._visible=false;
[6739]443                        _root.panel.i_direction._visible=true;
444                        _root.panel.i_direction._alpha=50;
445                } else {
[10776]446                        var dx=this.path[this.path.length-1].x-this.path[0].x;
447                        var dy=this.path[this.path.length-1].y-this.path[0].y;
[7984]448                        if (dx!=0 || dy!=0) {
449                                // Non-circular
[6739]450                                _root.panel.i_direction._rotation=180-Math.atan2(dx,dy)*(180/Math.PI)-45;
451                                _root.panel.i_direction._alpha=100;
452                                _root.panel.i_direction._visible=true;
[7984]453                                _root.panel.i_clockwise._visible=false;
454                                _root.panel.i_anticlockwise._visible=false;
455                        } else {
456                                // Circular
457                                _root.panel.i_direction._visible=false;
458                                // Find lowest rightmost point
459                                // cf http://geometryalgorithms.com/Archive/algorithm_0101/
460                                var lowest=0;
461                                var xmax=-999999; var ymin=-999999;
462                                for (var i=0; i<this.path.length; i++) {
[10776]463                                        if      (this.path[i].y> ymin) { lowest=i; xmin=this.path[i].x; ymin=this.path[i].y; }
464                                        else if (this.path[i].y==ymin
465                                                  && this.path[i].x> xmax) { lowest=i; xmin=this.path[i].x; ymin=this.path[i].y; }
[7984]466                                }
467                                var clockwise=(this.onLeft(lowest)>0);
468                                _root.panel.i_clockwise._visible=clockwise;
469                                _root.panel.i_anticlockwise._visible=!clockwise;
[6739]470                        }
471                }
472        };
473
[7984]474        OSMWay.prototype.onLeft=function(j) {
[11040]475                var left=0;
476                if (this.path.length>=3) {
477                        var i=j-1; if (i==-1) { i=this.path.length-2; }
478                        var k=j+1; if (k==this.path.length) { k=1; }
479                        left=((this.path[j].x-this.path[i].x) * (this.path[k].y-this.path[i].y) -
480                                  (this.path[k].x-this.path[i].x) * (this.path[j].y-this.path[i].y));
481                }
482                return left;
[7984]483        };
484       
485
[14727]486
[6739]487        // ---- Remove from server
488       
489        OSMWay.prototype.remove=function() {
[14904]490                clearFloater();
[14727]491                memberDeleted('Way', this._name);
492                var z=this.path; for (var i in z) {
[19965]493                        if (z[i].numberOfWays()==1) { z[i].unsetPosition(); memberDeleted('Node', z[i].id); }
[14727]494                }
495                uploadDirtyRelations();
496
[6739]497                this.deleteMergedWays();
[10776]498                this.removeNodeIndex();
[14727]499
[17662]500                if (!this.historic && !this.locked) {
[14830]501                        var z=shallowCopy(this.path); this.path=new Array();
[19965]502                        for (var i in z) { this.markAsDeleted(z[i],false); }
[15136]503                        if (_root.sandbox) {
[17662]504                                if (this._name>=0) { 
505                                        _root.waystodelete[this._name]=[this.version,deepCopy(this.deletednodes)];
506                                } else {
507                                        var z=this.deletednodes; for (var j in z) { deleteNodeAsPOI(j); }
508                                        var z=this.path;         for (var j in z) { deleteNodeAsPOI(j.id); }
509                                        markClean(false);
510                                }
511                        } else if (this._name>=0) {
[18431]512                                if (renewChangeset()) { return; }
[15136]513                                deleteresponder = function() { };
514                                deleteresponder.onResult = function(result) { deletewayRespond(result); };
515                                _root.writesrequested++;
516                                remote_write.call('deleteway',deleteresponder,_root.usertoken,_root.changeset,Number(this._name),Number(this.version),this.deletednodes);
517                        }
518                }
519
[14066]520                if (this._name==wayselected) { stopDrawing(); deselectAll(); }
521                removeMovieClip(_root.map.areas[this._name]);
522                removeMovieClip(this);
[6739]523        };
524
[15136]525        function deletewayRespond(result) {
526                _root.writesrequested--;
527                var code=result.shift(); var msg=result.shift(); if (code) { handleError(code,msg,result); return; }
528                var z=result[2]; for (var i in z) { delete _root.nodes[i]; }
529                operationDone(result[0]);
[18431]530                freshenChangeset();
[15136]531        };
532
[17662]533        function deleteNodeAsPOI(nid) {
534                if (nid<0) { return; }
535                if (_root.nodes[nid].numberOfWays()>0) { return; }
536                // if we're not going to send a deleteway for this (because it's negative - probably due to a split),
537                // then delete it as a POI instead
538                var n=_root.nodes[nid];
539                _root.poistodelete[nid]=[n.version,coord2long(n.x),coord2lat(n.y),deepCopy(n.attr)];
540        }
541
[7506]542        // ---- Variant with confirmation if any nodes have tags
543       
544        OSMWay.prototype.removeWithConfirm=function() {
545                var c=true;
546                var z=this.path;
547                for (var i in z) {
[10804]548                        if (this.path[i].tagged && hashLength(this.path[i].ways)==1) { c=false; }
[7506]549                }
550                if (c) {
[17776]551                        _root.ws.saveDeleteUndo(iText('deleting'));
[7506]552                        this.remove();
[16388]553                        markClean(true);
[7506]554                } else {
[7922]555                        _root.windows.attachMovie("modal","confirm",++windowdepth);
[17776]556                        _root.windows.confirm.init(275,80,new Array(iText('cancel'),iText('delete')),
[7718]557                                function(choice) {
[17776]558                                        if (choice==iText('delete')) { _root.ws.saveDeleteUndo(iText('deleting')); _root.ws.remove(); markClean(true); }
[7718]559                                });
[7922]560                        _root.windows.confirm.box.createTextField("prompt",2,7,9,250,100);
[17776]561                        writeText(_root.windows.confirm.box.prompt,iText('prompt_taggedpoints'));
[7506]562                }
563        };
564
[6739]565        // ---- Upload to server
566       
567        OSMWay.prototype.upload=function() {
568                putresponder=function() { };
569                putresponder.onResult=function(result) {
[15136]570                        _root.writesrequested--;
571                        var code=result.shift(); var msg=result.shift(); if (code) { _root.map.ways[result[0]].notUploading(); handleError(code,msg,result); return; }
[12386]572
573                        var i,r,z,nw,ow;
[10776]574                        ow=result[0];                   // old way ID
[8894]575                        nw=result[1];                   // new way ID
[16865]576                        if (ow!=nw) { renumberWay(ow,nw); }
[16525]577                        _root.map.ways[nw].clean=true;
[6739]578                        _root.map.ways[nw].uploading=false;
[11859]579                        _root.map.ways[nw].historic=false;
580                        _root.map.ways[nw].version=result[3];
[10776]581                       
582                        // renumber nodes (and any relations/ways they're in)
[8894]583                        z=result[2];
584                        for (var oid in z) {
[7115]585                                var nid = result[2][oid];
[8894]586                                nodes[oid].renumberTo(nid);
[10776]587                                nodes[nid].addWay(nw);
[14695]588                                renumberMemberOfRelation('Node', oid, nid);
[7115]589                        }
[10776]590                        for (var oid in z) { delete _root.nodes[oid]; } // delete -ve nodes
[12402]591                       
[14904]592                        // set versions, clean, not uploading
593                        z=result[4]; for (var nid in z) { nodes[nid].version=result[4][nid]; nodes[nid].uploading=false; nodes[nid].clean=true; }
594
595                        // remove deleted nodes
[15136]596                        z=result[5]; for (var nid in z) { c=_root.map.ways[nw]; delete c.deletednodes[nid]; delete _root.nodes[nid]; }
[12402]597                       
[6739]598                        _root.map.ways[nw].clearPOIs();
[14727]599                        uploadDirtyRelations();
[6739]600                        _root.map.ways[nw].deleteMergedWays();
[10776]601                        uploadDirtyWays();                      // make sure dependencies are uploaded
[15136]602                        operationDone(ow);
[18431]603                        freshenChangeset();
[16865]604                        updateInspector();
[6739]605                };
[12065]606
[15136]607                if (!this.uploading && !this.hasDependentNodes() && !this.locked && (!_root.sandbox || _root.uploading) && this.path.length>1) {
[14830]608                        this.deleteMergedWays();
609
[12386]610                        // Assemble list of changed nodes, and send
[18431]611                        if (renewChangeset()) { return; }
[6739]612                        this.uploading=true;
[12386]613                        var sendpath =new Array();
614                        var sendnodes=new Array();
[8894]615                        for (i=0; i<this.path.length; i++) {
[12386]616                                sendpath.push(this.path[i].id);
[14904]617                                if (!this.path[i].clean && !this.path[i].uploading) {
[12386]618                                        sendnodes.push(new Array(coord2long(this.path[i].x),
619                                                                                         coord2lat (this.path[i].y),
[12402]620                                                                                         this.path[i].id,this.path[i].version,
[12386]621                                                                                         deepCopy  (this.path[i].attr)));
[14904]622                                        this.path[i].uploading=true;
[12386]623                                }
[8894]624                        }
[17393]625                        delete this.attr['created_by'];
[11420]626                        _root.writesrequested++;
[14830]627                        remote_write.call('putway',putresponder,_root.usertoken,_root.changeset,this.version,Number(this._name),sendpath,this.attr,sendnodes,this.deletednodes);
[16865]628                        updateInspector();
[17422]629                } else { 
630                        operationDone(this._name);      // next please!
[6739]631                }
632        };
633
634        // ---- Delete any ways merged into this one
635
636        OSMWay.prototype.deleteMergedWays=function() {
637                while (this.mergedways.length>0) {
638                        var i=this.mergedways.shift();
[14066]639                        _root.map.ways.attachMovie("way",i[0],++waydepth);      // can't remove unless the movieclip exists!
640                        _root.map.ways[i[0]].version=i[1];                                      //  |
[16388]641                        _root.map.ways[i[0]].deletednodes=i[2];                         //  |
[14066]642                        _root.map.ways[i[0]].remove();
[6739]643                }
644        };
645
646        // ---- Revert to copy in database
647       
648        OSMWay.prototype.reload=function() {
649                _root.waysrequested+=1;
650                while (this.mergedways.length>0) {
651                        var i=this.mergedways.shift();
652                        _root.waysrequested+=1;
[14066]653                        _root.map.ways.attachMovie("way",i[0],++waydepth);
654                        _root.map.ways[i[0]].load();
[6739]655                }
[7761]656                this.checkconnections=true;
[6739]657                this.load();
658        };
[7718]659       
660        // ---- Save for undo
[6739]661
[16865]662        OSMWay.prototype.saveDeleteUndo=function(str) {
[7718]663                _root.undo.append(UndoStack.prototype.undo_deleteway,
664                                                  new Array(this._name,this._x,this._y,
[16388]665                                                                        deepCopy(this.attr),deepCopy(this.path),this.version),
[17776]666                                                                        iText('a_way',str));
[7718]667        };
[16865]668       
669        OSMWay.prototype.saveChangeUndo=function(str) {
670                _root.undo.append(UndoStack.prototype.undo_changeway,
671                                                  new Array(this._name,deepCopy(this.path),deepCopy(this.deletednodes),deepCopy(this.attr)),
[17776]672                                                  iText('action_changeway'));
[16865]673        };
[7718]674
675
[6739]676        // ---- Click handling 
677
678        OSMWay.prototype.onRollOver=function() {
[16388]679                if (this._name!=_root.wayselected && _root.drawpoint>-1 && !_root.map.anchorhints) {
[6739]680                        this.highlightPoints(5001,"anchorhint");
681                        setPointer('penplus');
682                } else if (_root.drawpoint>-1) { setPointer('penplus'); }
683                                                                  else { setPointer(''); }
[15136]684                if (this._name!=_root.wayselected) { var a=getName(this.attr,waynames); if (a) { setFloater(a); } }
[6739]685        };
686       
687        OSMWay.prototype.onRollOut=function() {
[16388]688                if (this.hitTest(_root._xmouse,_root._ymouse,true)) { return; } // false rollout
[6739]689                if (_root.wayselected) { setPointer(''   ); }
690                                                  else { setPointer('pen'); }
691                _root.map.anchorhints.removeMovieClip();
[14904]692                clearFloater();
[6739]693        };
694       
695        OSMWay.prototype.onPress=function() {
[8894]696                removeWelcome(true);
[6739]697                if (Key.isDown(Key.SHIFT) && this._name==_root.wayselected && _root.drawpoint==-1) {
698                        // shift-click current way: insert point
[8894]699                        this.insertAnchorPointAtMouse();
[18686]700                } else if (Key.isDown(Key.SHIFT) && _root.wayselected && this.name!=_root.wayselected && _root.drawpoint==-1 && _root.ws.hitTest(_root._xmouse,_root._ymouse,true)) {
701                        // shift-click other way (at intersection with current): make intersection
702                        this.insertAnchorPointAtMouse();
703                } else if (Key.isDown(Key.CONTROL) && _root.wayselected && this.name!=_root.wayselected && _root.drawpoint==-1) {
704                        // control/command-click other way: merge two ways
705                        mergeWayKeepingID(this,_root.ws);
[6739]706                } else if (_root.drawpoint>-1) {
707                        // click other way while drawing: insert point as junction
[11859]708                        if (!this.historic) {
[6739]709                                if (this._name==_root.wayselected && _root.drawpoint>0) {
710                                        _root.drawpoint+=1;     // inserting node earlier into the way currently being drawn
711                                }
[7604]712                                _root.newnodeid--;
[12386]713                                _root.nodes[newnodeid]=new Node(newnodeid,0,0,new Object(),0);
[11040]714                                this.insertAnchorPoint(_root.nodes[newnodeid]);
[6739]715                                this.highlightPoints(5001,"anchorhint");
[10776]716                                addEndPoint(_root.nodes[newnodeid]);
[6739]717                        }
718                        _root.junction=true;
719                        restartElastic();
720                } else {
721                        // click way: select
[7984]722                        _root.panel.properties.saveAttributes();
[6739]723                        this.select();
724                        clearTooltip();
[7718]725                        _root.clicktime=new Date();
[8894]726                        // was the click on a tagged node? if so, select directly
727                        var n;
728                        for (var i=0; i<this.path.length; i+=1) {
729                                if (this.taggednodes[i].hitTest(_root._xmouse,_root._ymouse,true)) { n=i; }
730                        }
731                        if (n) { _root.map.anchors[n].beginDrag();
732                                         _root.map.anchors[n].select(); }
733                          else { this.beginDrag(); }
[6739]734                }
735        };
[7718]736
737        OSMWay.prototype.beginDrag=function() {
738                this.onMouseMove=function() { this.trackDrag(); };
739                this.onMouseUp  =function() { this.endDrag();   };
740                this.dragged=false;
[7761]741                this.held=true;
[7718]742                _root.firstxmouse=_root.map._xmouse;
743                _root.firstymouse=_root.map._ymouse;
744        };
745
746        OSMWay.prototype.trackDrag=function() {
747                var t=new Date();
748                var longclick=(t.getTime()-_root.clicktime)>1000;
749                var xdist=Math.abs(_root.map._xmouse-_root.firstxmouse);
750                var ydist=Math.abs(_root.map._ymouse-_root.firstymouse);
[7761]751                // Don't enable drag unless way held for a while after click
752                if ((xdist>=tolerance   || ydist>=tolerance  ) &&
753                        (t.getTime()-_root.clicktime)<300 &&
754                        lastwayselected!=wayselected) { this.held=false; }
755                // Move way if dragged a long way, or dragged a short way after a while
[7718]756                if ((xdist>=tolerance*4 || ydist>=tolerance*4) ||
[7761]757                   ((xdist>=tolerance/4 || ydist>=tolerance/4) && longclick) &&
758                   this.held) {
[7718]759                        this.dragged=true;
760                }
761                if (this.dragged) {
762                        _root.map.anchors._x=_root.map.areas[this._name]._x=_root.map.highlight._x=this._x=_root.map._xmouse-_root.firstxmouse;
763                        _root.map.anchors._y=_root.map.areas[this._name]._y=_root.map.highlight._y=this._y=_root.map._ymouse-_root.firstymouse;
764                }
765        };
[6739]766       
[7718]767        OSMWay.prototype.endDrag=function() {
[10776]768                delete this.onMouseMove;
769                delete this.onMouseUp;
[7718]770                _root.map.anchors._x=_root.map.areas[this._name]._x=_root.map.highlight._x=this._x=0;
771                _root.map.anchors._y=_root.map.areas[this._name]._y=_root.map.highlight._y=this._y=0;
772                if (this.dragged) {
773                        this.moveNodes(_root.map._xmouse-_root.firstxmouse,_root.map._ymouse-_root.firstymouse);
[17776]774                        setAdvice(false,iText('advice_waydragged'));
[7718]775                        this.redraw();
776                        this.select();
777                        _root.undo.append(UndoStack.prototype.undo_movenodes,
778                                                          new Array(this,_root.map._xmouse-_root.firstxmouse,
779                                                                                         _root.map._ymouse-_root.firstymouse),
[17776]780                                                          iText('action_moveway'));
[7718]781                }
782        };
783       
[6739]784        // ---- Select/highlight
785       
786        OSMWay.prototype.select=function() {
[8894]787                _root.panel.properties.tidy();
[6739]788                if (_root.wayselected!=this._name || _root.poiselected!=0) { uploadSelected(); }
[7984]789//              _root.panel.properties.saveAttributes();
[16888]790                _root.pointselected=-2;
[6739]791                selectWay(this._name);
792                _root.poiselected=0;
793                this.highlightPoints(5000,"anchor");
794                removeMovieClip(_root.map.anchorhints);
795                this.highlight();
[17776]796                setTypeText(iText('way'),this._name);
[16416]797                removeIconPanel();
[7115]798                _root.panel.properties.init('way',getPanelColumns(),4);
799                _root.panel.presets.init(_root.panel.properties);
800                updateButtons();
801                updateScissors(false);
[6739]802        };
803       
804        OSMWay.prototype.highlight=function() {
805                _root.map.createEmptyMovieClip("highlight",5);
806                if (_root.pointselected>-2) {
[18749]807                        highlightSquare(_root.map.anchors[pointselected]._x,_root.map.anchors[pointselected]._y, _root.anchorsize*0.05);
[6739]808                } else {
809                        var linecolour=0xFFFF00; if (this.locked) { var linecolour=0x00FFFF; }
[7604]810                        _root.map.highlight.lineStyle(linewidth*1.5+8,linecolour,80,false,"none");
[10776]811                        _root.map.highlight.moveTo(this.path[0].x,this.path[0].y);
[6739]812                        for (var i=1; i<this.path.length; i+=1) {
[10776]813                                _root.map.highlight.lineTo(this.path[i].x,this.path[i].y);
[6739]814                        }
815                }
816                this.direction();
817        };
818
819        OSMWay.prototype.highlightPoints=function(d,atype) {
[7604]820                var group=atype+"s";
[6739]821                _root.map.createEmptyMovieClip(group,d);
822                for (var i=0; i<this.path.length; i+=1) {
[19957]823                        var asprite=atype; 
824                        if (this.path[i].isDupe()) { asprite+="_dupe"; }
825                        else if (this.path[i].numberOfWays()>1) { asprite+="_junction"; }
[15136]826                        _root.map[group].attachMovie(asprite,i,i);
[10776]827                        _root.map[group][i]._x=this.path[i].x;
828                        _root.map[group][i]._y=this.path[i].y;
[18749]829                        _root.map[group][i]._xscale=_root.anchorsize;
830                        _root.map[group][i]._yscale=_root.anchorsize;
[10776]831                        _root.map[group][i].node=this.path[i].id;
[8894]832                        _root.map[group][i].way=this;
[10776]833                        if (this.path[i].tagged) {
[8894]834                                // anchor point should be black if it has tags
835                                _root.map[group][i].blacken=new Color(_root.map[group][i]);
836                                _root.map[group][i].blacken.setTransform(to_black);
837                        }
[6739]838                }
839        };
840
841        // ---- Split, merge, reverse
842
[7658]843        OSMWay.prototype.splitWay=function(point,newattr) {
[7126]844                var i,z;
[11859]845                if (point>0 && point<(this.path.length-1) && !this.historic) {
[6739]846                        _root.newwayid--;                                                                                       // create new way
847                        _root.map.ways.attachMovie("way",newwayid,++waydepth);          //  |
[10804]848                        _root.map.ways[newwayid].path=shallowCopy(this.path);           // deep copy path array
[10776]849                        this.removeNodeIndex();
[6739]850
[7658]851                        if (newattr) { _root.map.ways[newwayid].attr=newattr; }
852                                        else { _root.map.ways[newwayid].attr=deepCopy(this.attr); }
853
[14765]854                        z=_root.wayrels[this._name];                                                            // copy relations
[7126]855                        for (i in z) {                                                                                          //  |
[14727]856                                _root.map.relations[i].setWayRole(newwayid,z[i]);               //  |
[7126]857                        }                                                                                                                       //  |
[15136]858 
[7658]859                        this.path.splice(Math.floor(point)+1);                                          // current way
[6739]860                        this.redraw();                                                                                          //  |
[10776]861                        this.createNodeIndex();
[6739]862
[7658]863                        _root.map.ways[newwayid].path.splice(0,point);                          // new way
[6739]864                        _root.map.ways[newwayid].locked=this.locked;                            //  |
865                        _root.map.ways[newwayid].redraw();                                                      //  |
[12065]866                        _root.map.ways[newwayid].clean=false;                                           //  | - in case it doesn't upload
[6739]867                        _root.map.ways[newwayid].upload();                                                      //  |
[10776]868                        _root.map.ways[newwayid].createNodeIndex();                                     //  |
[6739]869
[12065]870                        this.clean=false;                                                                                       // upload current way
871                        this.upload();                                                                                          //  |
[6739]872                        this.select();                                                                                          //  |
[7126]873                        uploadDirtyRelations();
[7658]874                        _root.undo.append(UndoStack.prototype.undo_splitway,
875                                                          new Array(this,_root.map.ways[newwayid]),
[17776]876                                                          iText('action_splitway'));
[6739]877                };
878        };
879
880        //              Merge (start/end of this way,other way object,start/end of other way)
881
882        OSMWay.prototype.mergeWay=function(topos,otherway,frompos) {
883                var i,z;
[10804]884                var conflict=false;
[11859]885                if (this.historic || otherway.historic) { return; }
[18823]886                if (otherway==this) { return; }
[6739]887
[7658]888                var mergepoint=this.path.length;
[10804]889                if (topos==0) {
890                        _root.undo.append(UndoStack.prototype.undo_mergeways,
891                                                          new Array(this,deepCopy(otherway.attr),deepCopy(this.attr),frompos),
[17776]892                                                          iText('action_mergeways'));
[10804]893                } else {
894                        _root.undo.append(UndoStack.prototype.undo_mergeways,
895                                                          new Array(this,deepCopy(this.attr),deepCopy(otherway.attr),topos),
[17776]896                                                          iText('action_mergeways'));
[10804]897                }
[6739]898                if (frompos==0) { for (i=0; i<otherway.path.length;    i+=1) { this.addPointFrom(topos,otherway,i); } }
899                                   else { for (i=otherway.path.length-1; i>=0; i-=1) { this.addPointFrom(topos,otherway,i); } }
900
[14066]901                // Merge attributes
[6739]902                z=otherway.attr;
903                for (i in z) {
904                        if (otherway.attr[i].substr(0,6)=='(type ') { otherway.attr[i]=null; }
905                        if (this.attr[i].substr(0,6)=='(type ') { this.attr[i]=null; }
[7984]906                        if (this.attr[i]) {
[16882]907                                if (this.attr[i]!=otherway.attr[i] && otherway.attr[i]) { var s=this.attr[i]+'; '+otherway.attr[i]; this.attr[i]=s.substr(0,255); conflict=true; }
[6739]908                        } else {
909                                this.attr[i]=otherway.attr[i];
910                        }
911                        if (!this.attr[i]) { delete this.attr[i]; }
912                }
913
[14066]914                // Merge relations
[14765]915                z=_root.wayrels[otherway._name];                                                // copy relations
[14727]916                for (i in z) {                                                                                  //  |
[14765]917                        if (!_root.wayrels[this._name][i]) {                            //  |
[14727]918                                _root.map.relations[i].setWayRole(this._name,z[i]);     
919                        }                                                                                                       //  |
920                }                                                                                                               //  |
921                memberDeleted('Way', otherway._name);                                   // then remove old way from them
[14830]922                z=otherway.deletednodes;                                                                //  | and its deletednodes
923                for (i in z) { memberDeleted('Node',z[i]); }                    //  |
[7126]924
[14066]925                // Add to list of merged ways (so they can be deleted on next putway)
[15136]926        if (_root.sandbox) {
927            otherway.remove();
928        } else {
929                this.mergedways.push(new Array(otherway._name,otherway.version,otherway.deletednodes));
930                this.mergedways.concat(otherway.mergedways);
931        }
[6739]932                this.clean=false;
933                markClean(false);
934                if (otherway.locked) { this.locked=true; }
[15136]935                otherway.removeNodeIndex();
[6739]936                removeMovieClip(_root.map.areas[otherway._name]);
937                removeMovieClip(otherway);
[6955]938                if (this._name==_root.wayselected) { 
[7115]939                        _root.panel.properties.reinit();
[6955]940                }
[17776]941                if (conflict) { setAdvice(false,iText('advice_tagconflict')); }
[6739]942        };
[7658]943
[6739]944        OSMWay.prototype.addPointFrom=function(topos,otherway,srcpt) {
[10776]945                if (topos==0) { if (this.path[0                                 ]==otherway.path[srcpt]) { return; } }  // don't add duplicate points
946                                 else { if (this.path[this.path.length-1]==otherway.path[srcpt]) { return; } }  //  |
[8894]947                if (topos==0) { this.path.unshift(otherway.path[srcpt]); }
948                             else { this.path.push(otherway.path[srcpt]); }
[10776]949                otherway.path[srcpt].addWay(this._name);
[6739]950        };
951
[7658]952        OSMWay.prototype.mergeAtCommonPoint=function(sel) {
[8894]953                var selstart =sel.path[0];
[7658]954                var sellen   =sel.path.length-1;
[8894]955                var selend   =sel.path[sellen];
956                var thisstart=this.path[0];
[7658]957                var thislen  =this.path.length-1;
[8894]958                var thisend  =this.path[thislen];
[7658]959                if      (selstart==thisstart) { sel.mergeWay(0,this,0);                    return true; }
960                else if (selstart==thisend  ) { sel.mergeWay(0,this,thislen);      return true; }
961                else if (selend  ==thisstart) { sel.mergeWay(sellen,this,0);       return true; }
962                else if (selend  ==thisend  ) { sel.mergeWay(sellen,this,thislen); return true; }
[17776]963                else                                              { setAdvice(true,iText('advice_nocommonpoint')); return false; }
[7658]964        };
965
[6739]966        // ---- Reverse order
967       
968        OSMWay.prototype.reverseWay=function() {
969                if (this.path.length<2) { return; }
970                if (_root.drawpoint>-1) { _root.drawpoint=(this.path.length-1)-_root.drawpoint; }
971                this.path.reverse();
972                this.redraw();
973                this.direction();
974                this.select();
975                this.clean=false;
976                markClean(false);
[17776]977                _root.undo.append(UndoStack.prototype.undo_reverse,new Array(this),iText('action_reverseway'));
[6739]978        };
979
[19957]980        // ---- Remove dupe nodes
981       
982        OSMWay.prototype.joinNodes=function() {
983                for (var i=0; i<this.path.length; i++) {
984                        if (this.path[i].isDupe()) {
985                                this.path[i].removeDupes([]);
986                        }
987                }
988                this.redraw();
989                this.select();
990                this.clean=false;
991                markClean(false);
992        };
993       
[7718]994        // ---- Move all nodes within a way
995       
996        OSMWay.prototype.moveNodes=function(xdiff,ydiff) {
[8894]997                var i,n;
[7718]998                var movedalready=new Array();
999                this.clean=false;
1000                markClean(false);
[8894]1001                for (i=0; i<this.path.length; i+=1) {
[10776]1002                        n=this.path[i].id;
[8894]1003                        if (movedalready[n]) {
[7718]1004                        } else {
[10776]1005                                this.path[i].moveTo(this.path[i].x+xdiff,
1006                                                                        this.path[i].y+ydiff,
1007                                                                        this._name);
[8894]1008                                movedalready[n]=true;
[7718]1009                        }
1010                }
1011        };
1012
[14830]1013        // ---- Add node to deleted list
1014        //              (should have been removed from way first)
1015       
[15136]1016        OSMWay.prototype.markAsDeleted=function(rnode,check2) {
1017                var d=true;
1018                // If we're just removing one point, check it's not used elsewhere in the way before removing from .ways
1019                if (check2) {
1020                        var z=this.path; 
1021                        for (var i in z) { if (this.path[i].id==rnode.id) { d=false; } }
1022                }
[14830]1023                if (d) { rnode.removeWay(this._name); }
1024                if (rnode.numberOfWays()==0 && rnode.id>0) { this.deletednodes[rnode.id]=rnode.version; }
1025        };
1026
1027
[7217]1028        // ---- Check for duplicates (e.g. when C is removed from ABCB)
1029       
1030        OSMWay.prototype.removeDuplicates=function() {
1031                var z=this.path; var ch=false;
1032                for (var i in z) {
1033                        if (i>0) {
[8894]1034                                if (this.path[i]==this.path[i-1]) { this.path.splice(i,1); ch=true; }
[7217]1035                        }
1036                }
1037                return ch;
1038        };
1039
[7604]1040        // ---- Add point into way with SHIFT-clicking
[7984]1041        //              cf http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/source.vba
1042        //              for algorithm to find nearest point on a line
[6739]1043       
[11040]1044        OSMWay.prototype.insertAnchorPoint=function(nodeobj) {
1045                var nx,ny,u,closest,closei,i,a,b,direct,via,newpoint;
[6739]1046                nx=_root.map._xmouse;   // where we're inserting it
1047                ny=_root.map._ymouse;   //      |
[11040]1048                closest=0.1; closei=0;
[7604]1049                for (i=0; i<(this.path.length)-1; i+=1) {
[10776]1050                        a=this.path[i  ];
1051                        b=this.path[i+1];
[8894]1052                        direct=Math.sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
1053                        via   =Math.sqrt((nx -a.x)*(nx -a.x)+(ny -a.y)*(ny -a.y));
1054                        via  +=Math.sqrt((nx -b.x)*(nx -b.x)+(ny -b.y)*(ny -b.y));
[6739]1055                        if (Math.abs(via/direct-1)<closest) {
1056                                closei=i+1;
1057                                closest=Math.abs(via/direct-1);
[8894]1058                                u=((nx-a.x)*(b.x-a.x)+
1059                                   (ny-a.y)*(b.y-a.y))/
1060                                   (Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2));
[19957]1061                                nodeobj.unsetPosition();
[11040]1062                                nodeobj.x=a.x+u*(b.x-a.x);
1063                                nodeobj.y=a.y+u*(b.y-a.y);
[19957]1064                                nodeobj.setPosition();
[6739]1065                        }
1066                }
[7984]1067                // Insert
[11040]1068                nodeobj.addWay(this._name);
1069                this.path.splice(closei,0,nodeobj);
[7604]1070                this.clean=false;
1071                this.redraw();
[6739]1072                markClean(false);
[8894]1073//              _root.adjustedxmouse=tx;        // in case we're adding extra points...
1074//              _root.adjustedymouse=ty;        // should probably return an array or an object **
[6739]1075                return closei;
[7604]1076        };
[6739]1077
[8894]1078        //              Wrapper around the above to:
1079        //              - insert at mouse position
1080        //              - add to undo stack
1081        //              - add intersection at any crossing ways
1082
1083        OSMWay.prototype.insertAnchorPointAtMouse=function() {
1084                _root.newnodeid--;
[12386]1085                _root.nodes[newnodeid]=new Node(newnodeid,0,0,new Object(),0);
[11040]1086                _root.pointselected=this.insertAnchorPoint(_root.nodes[newnodeid]);
[8894]1087                var waylist=new Array(); waylist.push(this);
1088                var poslist=new Array(); poslist.push(_root.pointselected);
1089                for (qway in _root.map.ways) {
1090                        if (_root.map.ways[qway].hitTest(_root._xmouse,_root._ymouse,true) && qway!=this._name) {
[11040]1091                                poslist.push(_root.map.ways[qway].insertAnchorPoint(_root.nodes[newnodeid]));
[8894]1092                                waylist.push(_root.map.ways[qway]);
1093                        }
1094                }
1095                _root.undo.append(UndoStack.prototype.undo_addpoint,
[17776]1096                                                  new Array(waylist,poslist), iText('action_insertnode'));
[8894]1097                _root.ws.highlightPoints(5000,"anchor");
1098                _root.map.anchors[pointselected].beginDrag();
[16865]1099                updateInspector();
[8894]1100        };
1101
[7658]1102        // ---- Remove point from this way (only)
1103       
1104        OSMWay.prototype.removeAnchorPoint=function(point) {
1105                // ** if length<2, then mark as way removal
1106                _root.undo.append(UndoStack.prototype.undo_deletepoint,
[10776]1107                                                  new Array(deepCopy(this.path[point]),
[7658]1108                                                                        new Array(this._name),
1109                                                                        new Array(point)),
[17776]1110                                                  iText('action_deletepoint'));
[14830]1111                var rnode=this.path[point];
[7658]1112                this.path.splice(point,1);
1113                this.removeDuplicates();
[15136]1114                this.markAsDeleted(rnode,true);
[19965]1115                if (rnode.numberOfWays()==0) { memberDeleted('Node', rnode.id); rnode.unsetPosition(); }
[7658]1116                if (this.path.length<2) { this.remove(); }
1117                                                   else { this.redraw(); this.clean=false; }
1118        };
[7604]1119
[8894]1120        // ---- Bounding box utility functions
1121
1122        OSMWay.prototype.resetBBox=function() {
1123                this.xmin=this.ymin= 999;
1124                this.xmax=this.ymax=-999;
1125        };
1126       
1127        OSMWay.prototype.updateBBox=function(long,lat) {
1128                this.xmin=Math.min(long,this.xmin);
1129                this.xmax=Math.max(long,this.xmax);
1130                this.ymin=Math.min(lat ,this.ymin);
1131                this.ymax=Math.max(lat ,this.ymax);
1132        };
1133
[15136]1134        // ---- Reset 'uploading' flag
1135
1136        OSMWay.prototype.notUploading=function() {
1137                this.uploading=false;
1138                var z=this.path; for (i in z) { this.path[i].uploading=false; }
[16865]1139                updateInspector();
[15136]1140        };
1141
[10776]1142        // ---- Node->way associations
1143       
1144        OSMWay.prototype.createNodeIndex  =function() { var z=this.path; for (var i in z) { this.path[i].addWay(this._name);    } };
1145        OSMWay.prototype.removeNodeIndex  =function() { var z=this.path; for (var i in z) { this.path[i].removeWay(this._name); } };
1146        OSMWay.prototype.renumberNodeIndex=function(n) {
1147                var z=this.path; for (i in z) { 
1148                        this.path[i].removeWay(this._name);
1149                        this.path[i].addWay(n);
1150                }
1151        };
1152        OSMWay.prototype.hasDependentNodes=function() {
[15136]1153        if (_root.sandbox && _root.uploading) { return false; }    // not an issue in consecutive uploads
[10776]1154                var d=false;
1155                var z=this.path; for (var i in z) {
1156                        if (this.path[i].id<0) {
1157                                var ways=this.path[i].ways; for (var w in ways) {
1158                                        if (_root.map.ways[w].uploading) { d=true; }
1159                                }
1160                        }
1161                }
1162                return d;
1163        };
1164
[11040]1165        // =====================================================================================
1166        // Offset path
[11420]1167        // ** much of the dialogue box could be refactored to share with relations dialogue
[11040]1168
[11420]1169        function askOffset() {
1170                if (!_root.wayselected) { return; }
1171                _root.windows.attachMovie("modal","offset",++windowdepth);
[17776]1172                _root.windows.offset.init(300, 170, [iText('cancel'), iText('ok')], completeOffset);
[11420]1173                var z = 5;
1174                var box = _root.windows.offset.box;
1175               
1176                box.createTextField("title",z++,7,7,300-14,20);
[17776]1177                box.title.text = iText('prompt_createparallel');
[11420]1178                with (box.title) {
1179                        wordWrap=true;
1180                        setTextFormat(boldText);
1181                        selectable=false; type='dynamic';
1182                }
[17393]1183                adjustTextField(box.title);
[11420]1184               
1185                box.createTextField("instr",z++,7,30,300-14,40);
1186
1187                // Create radio buttons and menu
1188
1189                box.attachMovie("radio","offsetoption",z++);
[17776]1190                box.offsetoption.addButton(10,35 ,iText('offset_dual'));
1191                box.offsetoption.addButton(10,55 ,iText('offset_motorway'));
1192                box.offsetoption.addButton(10,75 ,iText('offset_narrowcanal'));
1193                box.offsetoption.addButton(10,95 ,iText('offset_broadcanal'));
1194                box.offsetoption.addButton(10,115,iText('offset_choose'));
[11420]1195                box.offsetoption.select(1);
1196
1197                var w=box.offsetoption[5].prompt._width+25;
1198                box.createTextField("useroffset",z++,w,110,290-w,17);
1199                box.useroffset.setNewTextFormat(plainSmall);
1200                box.useroffset.type='input';
1201                box.useroffset.backgroundColor=0xDDDDDD;
1202                box.useroffset.background=true;
1203                box.useroffset.border=true;
1204                box.useroffset.borderColor=0xFFFFFF;
1205                box.useroffset.onSetFocus=function() { this._parent.offsetoption.select(5); };
1206        }
1207
1208        // typical widths:
1209        // central reservation:
1210        //       4.5m on a rural motorway/dual carriageway
1211        //       3.5m on an urban motorway
1212        //       1.8m on an urban dual carriageway
1213        // lane widths are typically always 3.65m
1214        // hard shoulders are typically 3.30m
1215        // hard strips are typically 1m
1216
1217        function completeOffset(button) {
[17776]1218                if (button!=iText('ok')) { return false; }
[11420]1219                var radio=_root.windows.offset.box.offsetoption.selected;
1220                var m;
1221                if (radio==5) {
1222                        m=_root.windows.offset.box.useroffset.text;
1223                        if (!button) { return false; }
1224                } else {
1225                        m=new Array(0,4.5+3.65*2,4.5+3.65*3,5.5,11);
1226                        m=m[radio];
1227                }
1228                var thislat=coord2lat(_root.map._y);                    // near as dammit
1229                var latfactor=Math.cos(thislat/(180/Math.PI));  // 111200m in a degree at the equator
1230                m=masterscale/(111200*latfactor)*m;                             // 111200m*cos(lat in radians) elsewhere
1231                _root.ws.offset( m);
1232                _root.ws.offset(-m);
1233                _root.undo.append(UndoStack.prototype.undo_makeways,
1234                                                  new Array(_root.newwayid,_root.newwayid+1),
[17776]1235                                                  iText('action_createparallel'));
[11420]1236        }
1237
1238        // Create (locked) offset way
1239        // offset is + or - depending on which side
1240
1241        OSMWay.prototype.offset=function(tpoffset) {
[11040]1242                var a,b,o,df,x,y;
1243                var offsetx=new Array();
1244                var offsety=new Array();
[11420]1245                var wm=1;       // was 10 before
[11040]1246
[11420]1247                _root.newwayid--;                                                                                       // create new way
1248                _root.map.ways.attachMovie("way",newwayid,++waydepth);          //  |
1249                var nw=_root.map.ways[newwayid];
1250                nw.locked=true;
1251                nw.clean=false;
1252
[11040]1253                // Normalise, and calculate offset vectors
1254
1255                for (var i=0; i<this.path.length; i++) {
[11420]1256                        a=this.path[i  ].y - this.path[i+1].y;
1257                        b=this.path[i+1].x - this.path[i  ].x;
[11040]1258                        h=Math.sqrt(a*a+b*b);
1259                        if (h!=0) { a=a/h; b=b/h; }
1260                                 else { a=0; b=0; }
1261                        offsetx[i]=wm*a;
1262                        offsety[i]=wm*b;
1263                }
[11420]1264
1265                _root.newnodeid--;
1266                _root.nodes[newnodeid]=new Node(newnodeid,this.path[0].x+tpoffset*offsetx[0],
1267                                                                                                  this.path[0].y+tpoffset*offsety[0],
[12386]1268                                                                                                  new Object(),0);
[16901]1269                _root.nodes[newnodeid].addWay(newwayid);
[11420]1270                nw.path.push(_root.nodes[newnodeid]);
[11040]1271               
1272                for (i=1; i<(this.path.length-1); i++) {
1273       
1274                        a=det(offsetx[i]-offsetx[i-1],
1275                                  offsety[i]-offsety[i-1],
[11420]1276                                  this.path[i+1].x - this.path[i  ].x,
1277                                  this.path[i+1].y - this.path[i  ].y);
1278                        b=det(this.path[i  ].x - this.path[i-1].x,
1279                                  this.path[i  ].y - this.path[i-1].y,
1280                                  this.path[i+1].x - this.path[i  ].x,
1281                                  this.path[i+1].y - this.path[i  ].y);
[11040]1282                        if (b!=0) { df=a/b; } else { df=0; }
1283                       
[11420]1284                        x=this.path[i].x + tpoffset*(offsetx[i-1]+df*(this.path[i].x - this.path[i-1].x));
1285                        y=this.path[i].y + tpoffset*(offsety[i-1]+df*(this.path[i].y - this.path[i-1].y));
[11040]1286       
[11420]1287                        _root.newnodeid--;
[12386]1288                        _root.nodes[newnodeid]=new Node(newnodeid,x,y,new Object(),0);
[16878]1289                        _root.nodes[newnodeid].addWay(newwayid);
[11420]1290                        nw.path.push(_root.nodes[newnodeid]);
[11040]1291                }
1292       
[11420]1293                _root.newnodeid--;
1294                _root.nodes[newnodeid]=new Node(newnodeid,this.path[i].x+tpoffset*offsetx[i-1],
[12386]1295                                                                                                  this.path[i].y+tpoffset*offsety[i-1],new Object(),0);
[16878]1296                _root.nodes[newnodeid].addWay(newwayid);
[11420]1297                nw.path.push(_root.nodes[newnodeid]);
1298                nw.redraw();
[11040]1299        };
1300
1301    function det(a,b,c,d) { return a*d-b*c; }
1302
[16700]1303        // =====================================================================================
1304        // Inspector
1305       
1306        OSMWay.prototype.inspect=function() {
1307                var str='';
[11040]1308
[16865]1309                // Status
[18174]1310                if (this.locked) { str+=iText('inspector_way_locked') + "\n"; }
1311                if (!this.clean) { str+=iText('inspector_unsaved'); }
1312                if (this.uploading) { str+=' ' + iText('inspector_uploading'); }
[16882]1313                if (!this.clean || this.uploading) { str+="\n"; }
[16865]1314
1315                // Number of nodes
[18174]1316                if (this.path[this.path.length-1]==this.path[0]) {
1317            str += iText('inspector_way_nodes_closed', this.path.length);
1318        } else {
1319            str += iText('inspector_way_nodes', this.path.length);
1320        }
[16865]1321                str+="\n";
1322
[16700]1323                // Connections to other ways of same type
1324                var principal='';
1325                if      (this.attr['highway' ]) { principal='highway';  }
1326                else if (this.attr['waterway']) { principal='waterway'; }
1327                else if (this.attr['railway' ]) { principal='railway';  }
1328                var same=0; var different=0;
1329                var z=this.path; for (i in z) {
1330                        var w=z[i].ways; for (id in w) {
1331                                if (id!=this._name) {
1332                                        if (_root.map.ways[id].attr[principal]==this.attr[principal]) { same++; }
1333                                        else if (_root.map.ways[id].attr[principal]) { different++; }
1334                                }
1335                        }
1336                }
[18174]1337
[16865]1338                if (this.attr[principal]==undefined) { 
[18174]1339            str += iText('inspector_way_connects_to', same);
[16865]1340                } else {
[18174]1341            str += iText('inspector_way_connects_to_principal', same, this.attr[principal], different, principal);
[16865]1342                }
1343
[16700]1344                return "<p>"+str+"</p>";
1345        };
1346
1347
1348
[7604]1349        Object.registerClass("way",OSMWay);
1350
1351
1352        // =====================================================================================
1353        // Drawing support functions
1354
[8894]1355        // removeNodeFromWays - now see Node.removeFromAllWays
[6739]1356
[8894]1357        // startNewWay            - create new way from first node
[7658]1358
[8894]1359        function startNewWay(node) {
[6739]1360                uploadSelected();
1361                _root.newwayid--;
1362                selectWay(newwayid);
1363                _root.poiselected=0;
1364                _root.map.ways.attachMovie("way",newwayid,++waydepth);
[10776]1365                _root.map.ways[newwayid].path[0]=_root.nodes[node];
[6739]1366                _root.map.ways[newwayid].redraw();
1367                _root.map.ways[newwayid].select();
1368                _root.map.ways[newwayid].clean=false;
[10776]1369                _root.nodes[node].addWay(newwayid);
[6739]1370                _root.map.anchors[0].startElastic();
1371                _root.drawpoint=0;
1372                markClean(false);
[17776]1373                setTooltip(iText('hint_drawmode'),0);
[6739]1374        }
1375
[10776]1376        // addEndPoint(node object) - add point to start/end of line
[6739]1377
[8894]1378        function addEndPoint(node) {
[10776]1379                var drawnode=_root.ws.path[_root.drawpoint];
[6739]1380                if (_root.drawpoint==_root.ws.path.length-1) {
[8894]1381                        _root.ws.path.push(node);
[6739]1382                        _root.drawpoint=_root.ws.path.length-1;
1383                } else {
[8894]1384                        _root.ws.path.unshift(node);    // drawpoint=0, add to start
[6739]1385                }
[10776]1386                node.addWay(_root.wayselected);
[6739]1387       
1388                // Redraw line (if possible, just extend it to save time)
1389                if (_root.ws.getFill()>-1 || 
1390                        _root.ws.path.length<3 ||
[16882]1391                        _root.pointselected>-2 ||
1392                        _root.ws.attr['oneway']) {
[6739]1393                        _root.ws.redraw();
1394                        _root.ws.select();
1395                } else {
[8894]1396                        _root.ws.line.moveTo(drawnode.x,drawnode.y);
[10776]1397                        _root.ws.line.lineTo(node.x,node.y);
[6739]1398                        if (casing[_root.ws.attr['highway']]) {
[8894]1399                                _root.map.areas[wayselected].moveTo(drawnode.x,drawnode.y);
[10776]1400                                _root.map.areas[wayselected].lineTo(node.x,node.y);
[6739]1401                        }
[8894]1402                        _root.map.highlight.moveTo(drawnode.x,drawnode.y);
[10776]1403                        _root.map.highlight.lineTo(node.x,node.y);
[6739]1404                        _root.ws.direction();
1405                        _root.ws.highlightPoints(5000,"anchor");
1406                        removeMovieClip(_root.map.anchorhints);
[14765]1407                        var z=_root.wayrels[_root.wayselected];
[14727]1408                        for (var rel in z) { _root.map.relations[rel].redraw(); }
[6739]1409                }
1410                // Mark as unclean
1411                _root.ws.clean=false;
1412                markClean(false);
1413                _root.map.elastic.clear();
[7658]1414                var poslist=new Array(); poslist.push(_root.drawpoint);
1415                _root.undo.append(UndoStack.prototype.undo_addpoint,
1416                                                  new Array(new Array(_root.ws),poslist),
[17776]1417                                                  iText('action_addpoint'));
[16865]1418                updateInspector();
[6739]1419        }
1420
1421        function stopDrawing() {
1422                _root.map.anchors[_root.drawpoint].endElastic();
1423                _root.drawpoint=-1;
1424                if (_root.ws.path.length<=1) { 
1425                        // way not long enough, so abort
[10776]1426                        _root.ws.removeNodeIndex();
[6739]1427                        removeMovieClip(_root.map.areas[wayselected]);
1428                        removeMovieClip(_root.ws);
1429                        removeMovieClip(_root.map.anchors);
[16865]1430                        updateInspector();
[6739]1431                }
1432                _root.map.elastic.clear();
1433                clearTooltip();
1434        };
1435
1436        // cycleStacked - cycle through ways sharing same point
1437
1438        function cycleStacked() {
1439                if (_root.pointselected>-2) {
[10804]1440                        stopDrawing();
1441                        var id=_root.ws.path[_root.pointselected].id;
[6739]1442                        var firstfound=0; var nextfound=0;
1443                        for (qway in _root.map.ways) {
1444                                if (qway!=_root.wayselected) {
[8894]1445                                        for (qs=0; qs<_root.map.ways[qway].path.length; qs+=1) {
[10776]1446                                                if (_root.map.ways[qway].path[qs].id==id) {
[6739]1447                                                        var qw=Math.floor(qway);
1448                                                        if (firstfound==0 || qw<firstfound) { firstfound=qw; }
1449                                                        if ((nextfound==0 || qw<nextfound) && qw>wayselected) { nextfound=qw; }
1450                                                }
1451                                        }
1452                                }
1453                        }
1454                        if (firstfound) {
1455                                if (nextfound==0) { var nextfound=firstfound; }
1456                                _root.map.ways[nextfound].swapDepths(_root.ws);
1457                                _root.map.ways[nextfound].select();
1458                        }
1459                }
1460        };
1461
1462        // ================================================================
1463        // Way communication
1464       
1465        // whichWays    - get list of ways from remoting server
1466
[15136]1467        function whichWays(force) {
[6739]1468                _root.lastwhichways=new Date();
[18823]1469                var within=(_root.edge_l>=_root.bigedge_l &&
1470                                        _root.edge_r<=_root.bigedge_r &&
1471                                        _root.edge_b>=_root.bigedge_b &&
1472                                        _root.edge_t<=_root.bigedge_t);
[6739]1473                if (_root.waycount>500) { purgeWays(); }
1474                if (_root.poicount>500) { purgePOIs(); }
[18823]1475                if (within && !force) {
[6739]1476                        // we have already loaded this area, so ignore
1477                } else {
1478                        whichresponder=function() {};
1479                        whichresponder.onResult=function(result) {
1480                                _root.whichreceived+=1;
[15136]1481                                var code=result.shift(); var msg=result.shift(); if (code) { handleError(code,msg,result); return; }
[17889]1482                                var waylist  =result[0];
1483                                var pointlist=result[1];
1484                                var relationlist=result[2];
1485                                var s;
[6739]1486
1487                                for (i in pointlist) {                                                                          // POIs
1488                                        point=pointlist[i][0];                                                                  //  |
[15136]1489                                        if ((!_root.map.pois[point] || _root.map.pois[point].version!=pointlist[i][4]) && !_root.poistodelete[point]) {
[17889]1490                                                var a=getPOIIcon(pointlist[i][3]);                                      //  |
1491                                                if (a=='poi') { s=poiscale; } else { s=iconscale; }     //  |
[16416]1492                                                _root.map.pois.attachMovie(a,point,++poidepth); //  |
[8894]1493                                                _root.map.pois[point]._x=long2coord(pointlist[i][1]);// |
1494                                                _root.map.pois[point]._y=lat2coord (pointlist[i][2]);// |
[17889]1495                                                _root.map.pois[point]._xscale=_root.map.pois[point]._yscale=s;
[11859]1496                                                _root.map.pois[point].version=pointlist[i][4];          //  |
[7118]1497                                                _root.map.pois[point].attr=pointlist[i][3];                     //  |
[16416]1498                                                _root.map.pois[point].icon=a;                                           //  |
[6739]1499                                                _root.poicount+=1;                                                                      //  |
[8894]1500                                                if (point==prenode) { deselectAll(); prenode=undefined;
1501                                                                                          _root.map.pois[point].select(); }
[6739]1502                                        }
1503                                }
[7115]1504
[18823]1505                                for (i in waylist) {                                                                            // ways
1506                                        way=waylist[i][0];                                                                              //  |
1507                                        if ((!_root.map.ways[way] || _root.map.ways[way].version!=waylist[i][1]) && !_root.waystodelete[way]) {
1508                                                _root.waystoload.push(way);
1509                                        }
1510                                }
1511                               
[7115]1512                                for (i in relationlist) {
[11859]1513                                        rel = relationlist[i][0];
1514                    if (!_root.map.relations[rel] || _root.map.relations[rel].version!=relationlist[i][1]) {
[18823]1515                                                _root.relstoload.push(rel);
[7115]1516                                        }
1517                }
[18823]1518
1519                                if (preferences.data.limitways && _root.relstoload.length+_root.waystoload.length>1200) {
1520                                        _root.windows.attachMovie("modal","confirm",++windowdepth);
1521                                        _root.windows.confirm.init(275,100,new Array(iText('no'),iText('yes')),
1522                                                function(choice) {
1523                                                        if (choice==iText('yes')) { 
1524                                                                _root.waystoload=[];
1525                                                                _root.relstoload=[];
1526                                                                zoomTo(Math.min(_root.scale+2,_root.maxscale),_root.map._x*2-xradius,_root.map._y*2-yradius,true,true);
1527                                                        } else {
1528                                                                loadItems();
1529                                                        }
1530                                                });
1531                                        _root.windows.confirm.box.createTextField("prompt",2,7,9,250,120);
1532                                        writeText(_root.windows.confirm.box.prompt,iText('prompt_manyways'));
1533                                } else {
1534                                        loadItems();
1535                                }
1536
[6739]1537                        };
[11151]1538                        remote_read.call('whichways',whichresponder,_root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t);
[6739]1539                        _root.whichrequested+=1;
1540                }
1541        }
1542
[18823]1543        // loadWay/loadRelation
1544
1545        function loadItems() {
1546                while (_root.waystoload.length) { loadWay(_root.waystoload.pop()); }
1547                while (_root.relstoload.length) { loadRelation(_root.relstoload.pop()); }
1548                if (_root.edge_l<_root.bigedge_l ||
1549                        _root.edge_r>_root.bigedge_r ||
1550                        _root.edge_t>_root.bigedge_t ||
1551                        _root.edge_b<_root.bigedge_b) { setBigEdges(); }
1552        }
1553
1554        function loadWay(way) {
1555                _root.map.ways.attachMovie("way",way,++waydepth);
1556                _root.map.ways[way].load();
1557                _root.waycount+=1;
1558                _root.waysrequested+=1;
1559        }
1560       
1561        function loadRelation(rel) {
1562                _root.map.relations.attachMovie("relation",rel,++reldepth);
1563                _root.map.relations[rel].load();
1564                _root.relcount+=1;
1565                _root.relsrequested+=1;
1566        }
1567       
1568        function setBigEdges() {
1569                _root.bigedge_l=_root.edge_l; _root.bigedge_r=_root.edge_r;
1570                _root.bigedge_b=_root.edge_b; _root.bigedge_t=_root.edge_t;
1571        }
1572
[6739]1573        // purgeWays - remove any clean ways outside current view
1574       
1575        function purgeWays() {
1576                for (qway in _root.map.ways) {
1577                        if (qway==_root.wayselected) {
1578                        } else if (!_root.map.ways[qway].clean) {
1579                                _root.map.ways[qway].upload();
[7126]1580                                uploadDirtyRelations();
[6739]1581                        } else if (((_root.map.ways[qway].xmin<edge_l && _root.map.ways[qway].xmax<edge_l) ||
1582                                                (_root.map.ways[qway].xmin>edge_r && _root.map.ways[qway].xmax>edge_r) ||
1583                                            (_root.map.ways[qway].ymin<edge_b && _root.map.ways[qway].ymax<edge_b) ||
1584                                                (_root.map.ways[qway].ymin>edge_t && _root.map.ways[qway].ymax>edge_t))) {
1585                                removeMovieClip(_root.map.ways[qway]);
1586                                removeMovieClip(_root.map.areas[qway]);
1587                                _root.waycount-=1;
1588                        }
1589                }
[18823]1590                setBigEdges();
[6739]1591        }
1592
1593        function selectWay(id) {
[7761]1594                _root.lastwayselected=_root.wayselected;
[6739]1595                _root.wayselected=Math.floor(id);
1596                _root.ws=_root.map.ways[id];
[16865]1597               
1598                if (id==0) {
1599                        _root.panel.advanced.disableOption(0);
1600                        _root.panel.advanced.disableOption(1);
1601                } else {
1602                        _root.panel.advanced.enableOption(0);
1603                        _root.panel.advanced.enableOption(1);
1604                }
1605                updateInspector();
[6739]1606        }
[16865]1607       
1608        function renumberWay(ow,nw) {
1609                _root.map.ways[ow].renumberNodeIndex(nw);
1610                wayrels[nw]=wayrels[ow]; delete wayrels[ow];
1611                _root.map.ways[ow]._name=nw;
[16876]1612                renumberMemberOfRelation('Way', ow, nw);
[16865]1613                if (_root.map.areas[ow]) { _root.map.areas[ow]._name=nw; }
1614                if (_root.panel.t_details.text==ow) { _root.panel.t_details.text=nw; _root.panel.t_details.setTextFormat(plainText); }
1615                if (wayselected==ow) { selectWay(nw); }
1616        }
1617       
1618        function mergeWayKeepingID(w1,w2) {
1619                var t=(w1==_root.ws || w2==_root.ws);
1620                var w,s;
1621                if (Number(w1._name)<0 && Number(w2._name)>0) {
1622                        s=w1.mergeAtCommonPoint(w2); w=w2;
1623                } else {
1624                        s=w2.mergeAtCommonPoint(w1); w=w1;
1625                }
1626                if (s) { w.redraw(); if (t) { w.select(); } }
1627        }
[15136]1628
1629        function uploadDirtyWays(allow_ws) {
[15192]1630                if (_root.sandbox) { return; }
[15136]1631                var z=_root.map.ways;
1632                for (i in z) {
1633                        if (!_root.map.ways[i].clean && (i!=wayselected || allow_ws) && !_root.map.ways[i].hasDependentNodes()) { 
1634                                _root.map.ways[i].upload();
1635                        }
1636                }
1637        };
1638
Note: See TracBrowser for help on using the repository browser.