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

Last change on this file since 8926 was 8894, checked in by richard, 11 years ago

Potlatch 0.10

File size: 32.5 KB
Line 
1
2        // =====================================================================================
3        // OOP classes - OSMWay
4
5        // ---- Initialise
6       
7        function OSMWay() {
8                this.path=new Array();                  // list of nodes
9                this.attr=new Array();                  // hash of tags
10                this.clean=true;                                // altered since last upload?
11                this.uploading=false;                   // currently uploading?
12                this.locked=false;                              // locked against upload?
13                this.oldversion=0;                              // is this an undeleted, not-uploaded way?
14                this.mergedways=new Array();    // list of ways merged into this
15                this.checkconnections=false;    // check shared nodes on reload
16                this.resetBBox();
17        };
18        OSMWay.prototype=new MovieClip();
19
20        // ---- Load from remote server
21
22        OSMWay.prototype.load=function() {
23                responder = function() { };
24                responder.onResult = function(result) {
25                        _root.waysreceived+=1;
26                        var w=result[0];
27                        if (length(result[1])==0) { removeMovieClip(_root.map.ways[w]); 
28                                                                                removeMovieClip(_root.map.areas[w]); return; }
29                        var i,id,x,y,prepoint;
30                        _root.map.ways[w].clean=true;
31                        _root.map.ways[w].locked=false;
32                        _root.map.ways[w].oldversion=0;
33                        _root.map.ways[w].path=[];
34                        _root.map.ways[w].resetBBox();
35                        for (i=0; i<result[1].length; i++) {
36                                x =result[1][i][0];
37                                y =result[1][i][1];
38                                id=result[1][i][2];
39                                _root.map.ways[w].updateBBox(x,y);
40                                x=long2coord(x); y=lat2coord(y);
41                                _root.map.ways[w].path.push(id);
42                                if (nodes[id]) {
43                                        // already exists: move node in other ways if required
44                                        // ** maybe we should take out 'w'? not sure
45                                        if (_root.map.ways[w].checkconnections) { nodes[id].moveTo(x,y,w); }
46                                } else {
47                                        // doesn't exist, so create new node
48                                        _root.nodes[id]=new Node(id,x,y,result[1][i][4]);
49                                        if (id==prenode) { prepoint=i; }
50                                }
51                        }
52                        _root.map.ways[w].attr=result[2];
53                        _root.map.ways[w].redraw();
54                        if (w==preway) { _root.map.ways[w].select(); preway=undefined; }
55                        if (prepoint)  { _root.map.ways[w].select(); 
56                                                         _root.map.anchors[prepoint].select();
57                                                         prenode=prepoint=undefined; }
58                        _root.map.ways[w].clearPOIs();
59                        _root.map.ways[w].checkconnections=false;
60                };
61                remote.call('getway',responder,Math.floor(this._name));
62        };
63
64        OSMWay.prototype.loadFromDeleted=function(version) {
65                delresponder=function() { };
66                delresponder.onResult=function(result) {
67                        var code=result.shift(); if (code) { handleError(code,result); return; }
68                        var i,id;
69                        var w=result[0];
70                        _root.map.ways[w].clean=false;
71                        _root.map.ways[w].oldversion=result[7];
72                        _root.map.ways[w].path=[];
73                        _root.map.ways[w].resetBBox();
74                        for (i=0; i<result[1].length; i++) {
75                                x =result[1][i][0];
76                                y =result[1][i][1];
77                                id=result[1][i][2]; if (id<0) { id=--_root.newnodeid; } // assign negative IDs to anything moved
78                                _root.map.ways[w].updateBBox(x,y);
79                                x=long2coord(x); y=lat2coord(y);
80                                _root.map.ways[w].path.push(id);
81                                if (nodes[id]) {
82                                        nodes[id].moveTo(x,y,w);
83                                } else {
84                                        _root.nodes[id]=new Node(id,x,y,result[1][i][4]);
85                                }
86                        }
87                        _root.map.ways[w].attr=result[2];
88                        if (w==wayselected) { _root.map.ways[w].select(); markClean(false); }
89                                                   else { _root.map.ways[w].locked=true; }
90                        _root.map.ways[w].redraw();
91                        _root.map.ways[w].clearPOIs();
92                };
93                remote.call('getway_old',delresponder,Math.floor(this._name),Math.floor(version));
94        };
95
96        OSMWay.prototype.clearPOIs=function() {
97                // check if any way nodes are POIs, delete the POIs if so
98                var i,z;
99                z=this.path;
100                for (i in z) {
101                        if (_root.map.pois[this.path[i]]) { removeMovieClip(_root.map.pois[this.path[i]]); }
102                }
103        };
104
105        // ---- Draw line
106
107        OSMWay.prototype.redraw=function() {
108                this.createEmptyMovieClip("line",1);                                    // clear line
109                this.createEmptyMovieClip("taggednodes",2);                             // POIs in way
110                var linealpha=100; // -50*(this.locked==true);
111                var taggedscale;
112                if (preferences.data.thinlines) { taggedscale=100/Math.pow(2,_root.scale-13); }
113                                                                   else { taggedscale=Math.max(100/Math.pow(2,_root.scale-13),6.25); }
114
115                // Set stroke
116
117                if              (this.locked)                                    { this.line.lineStyle(linewidth,0xFF0000,linealpha,false,"none"); }
118                else if (colours[this.attr["highway"]])  { this.line.lineStyle(linewidth,colours[this.attr["highway" ]],linealpha,false,"none"); }
119                else if (colours[this.attr["waterway"]]) { this.line.lineStyle(linewidth,colours[this.attr["waterway"]],linealpha,false,"none"); }
120                else if (colours[this.attr["railway"]])  { this.line.lineStyle(linewidth,colours[this.attr["railway" ]],linealpha,false,"none"); }
121                else {
122                        var c=0xAAAAAA; var z=this.attr;
123                        for (var i in z) { if (i!='created_by' && this.attr[i]!='' && this.attr[i].substr(0,6)!='(type ') { c=0x707070; } }
124                        this.line.lineStyle(linewidth,c,linealpha,false,"none");
125                }
126               
127                // Draw fill/casing
128
129                var f=this.getFill();
130                if ((f>-1 || casing[this.attr['highway']]) && !this.locked) {
131                        if (!_root.map.areas[this._name]) { _root.map.areas.createEmptyMovieClip(this._name,++areadepth); }
132                        with (_root.map.areas[this._name]) {
133                                clear();
134                                enabled=false;
135                                moveTo(nodes[this.path[0]].x,nodes[this.path[0]].y); 
136                                if (f>-1) { beginFill(f,20); }
137                                         else { lineStyle(linewidth*1.5,0,100,false,"none"); }
138                                for (var i=1; i<this.path.length; i+=1) {
139                                        lineTo(nodes[this.path[i]].x,nodes[this.path[i]].y);
140                                }
141                                if (f>-1) { endFill(); }
142                        };
143                } else if (_root.map.areas[this._name]) {
144                        removeMovieClip(_root.map.areas[this._name]);
145                }
146
147                // Draw line and tagged nodes
148
149                this.line.moveTo(nodes[this.path[0]].x,nodes[this.path[0]].y);
150                for (var i=1; i<this.path.length; i+=1) {
151                        this.line.lineTo(nodes[this.path[i]].x,nodes[this.path[i]].y);
152                        if (nodes[this.path[i]].tagged) {
153                                this.taggednodes.attachMovie("poiinway",i,i);
154                                this.taggednodes[i]._x=nodes[this.path[i]].x;
155                                this.taggednodes[i]._y=nodes[this.path[i]].y;
156                                this.taggednodes[i]._xscale=this.taggednodes[i]._yscale=taggedscale;
157                        }
158                }
159                redrawRelationsForMember('way', this._name);
160        };
161
162        OSMWay.prototype.getFill=function() {
163                var f=-1; 
164                if (this.path[this.path.length-1]==this.path[0] && this.path.length>2) {
165                        if (this.attr['area']) { f='0x777777'; }
166                        var z=this.attr;
167                        for (var i in z) { if (areas[i] && this.attr[i]!='' && this.attr[i]!='coastline') { f=areas[i]; } }
168                }
169                return f;
170        };
171
172        // ---- Show direction
173
174        OSMWay.prototype.direction=function() {
175                if (this.path.length<2) {
176                        _root.panel.i_clockwise._visible=false;
177                        _root.panel.i_anticlockwise._visible=false;
178                        _root.panel.i_direction._visible=true;
179                        _root.panel.i_direction._alpha=50;
180                } else {
181                        var dx=nodes[this.path[this.path.length-1]].x-nodes[this.path[0]].x;
182                        var dy=nodes[this.path[this.path.length-1]].y-nodes[this.path[0]].y;
183                        if (dx!=0 || dy!=0) {
184                                // Non-circular
185                                _root.panel.i_direction._rotation=180-Math.atan2(dx,dy)*(180/Math.PI)-45;
186                                _root.panel.i_direction._alpha=100;
187                                _root.panel.i_direction._visible=true;
188                                _root.panel.i_clockwise._visible=false;
189                                _root.panel.i_anticlockwise._visible=false;
190                        } else {
191                                // Circular
192                                _root.panel.i_direction._visible=false;
193                                // Find lowest rightmost point
194                                // cf http://geometryalgorithms.com/Archive/algorithm_0101/
195                                var lowest=0;
196                                var xmax=-999999; var ymin=-999999;
197                                for (var i=0; i<this.path.length; i++) {
198                                        if      (nodes[this.path[i]].y> ymin) { lowest=i; xmin=nodes[this.path[i]].x; ymin=nodes[this.path[i]].y; }
199                                        else if (nodes[this.path[i]].y==ymin
200                                                  && nodes[this.path[i]].x> xmax) { lowest=i; xmin=nodes[this.path[i]].x; ymin=nodes[this.path[i]].y; }
201                                }
202                                var clockwise=(this.onLeft(lowest)>0);
203                                _root.panel.i_clockwise._visible=clockwise;
204                                _root.panel.i_anticlockwise._visible=!clockwise;
205                        }
206                }
207        };
208
209        OSMWay.prototype.onLeft=function(j) {
210                var i=j-1; if (i==-1) { i=this.path.length-1; }
211                var k=j+1; if (k==this.path.length) { k=0; }
212                return ((nodes[this.path[j]].x-nodes[this.path[i]].x) * (nodes[this.path[k]].y-nodes[this.path[i]].y) -
213                            (nodes[this.path[k]].x-nodes[this.path[i]].x) * (nodes[this.path[j]].y-nodes[this.path[i]].y));
214        };
215       
216
217        // ---- Remove from server
218       
219        OSMWay.prototype.remove=function() {
220                // ** undo
221                this.deleteMergedWays();
222                memberDeleted('way', this._name);
223                if (this._name>=0 && !_root.sandbox && this.oldversion==0) {
224                        deleteresponder = function() { };
225                        deleteresponder.onResult = function(result) {
226                                var code=result.shift(); if (code) { handleError(code,result); return; }
227                                if (wayselected==result[0]) { deselectAll(); }
228                                removeMovieClip(_root.map.ways[result[0]]);
229                                removeMovieClip(_root.map.areas[result[0]]);
230                        };
231                        remote.call('deleteway',deleteresponder,_root.usertoken,Math.floor(this._name));
232                } else {
233                        if (this._name==wayselected) { stopDrawing(); deselectAll(); }
234                        removeMovieClip(_root.map.areas[this._name]);
235                        removeMovieClip(this);
236                }
237        };
238
239        // ---- Variant with confirmation if any nodes have tags
240       
241        OSMWay.prototype.removeWithConfirm=function() {
242                // ** undo
243                var c=true;
244                var z=this.path;
245                for (var i in z) {
246                        if (nodes[this.path[i]].tagged) { c=false; }
247                }
248                if (c) {
249                        _root.ws.saveUndo(iText("deleting",'deleting'));
250                        this.remove();
251                } else {
252                        _root.windows.attachMovie("modal","confirm",++windowdepth);
253                        _root.windows.confirm.init(275,80,new Array(iText('Cancel','cancel'),iText('Delete','delete')),
254                                function(choice) {
255                                        if (choice==iText('Delete','delete')) { _root.ws.saveUndo(iText("deleting",'deleting')); _root.ws.remove(); }
256                                });
257                        _root.windows.confirm.box.createTextField("prompt",2,7,9,250,100);
258                        writeText(_root.windows.confirm.box.prompt,iText("Some of the points on this way are tagged. Really delete?",'prompt_taggedpoints'));
259                }
260        };
261
262        // ---- Upload to server
263       
264        OSMWay.prototype.upload=function() {
265                putresponder=function() { };
266                putresponder.onResult=function(result) {
267                        var code=result.shift(); if (code) { handleError(code,result); return; }
268                        var i,r,z,nw,qway,qs;
269                        nw=result[1];                   // new way ID
270                        if (result[0]!=nw) {    // renumber way?
271                                _root.map.ways[result[0]]._name=nw;
272                                renumberMemberOfRelation('way', result[0], nw);
273                                if (_root.map.areas[result[0]]) { _root.map.areas[result[0]]._name=nw; }
274                                if (_root.panel.t_details.text==result[0]) { _root.panel.t_details.text=nw; _root.panel.t_details.setTextFormat(plainText); }
275                                if (wayselected==result[0]) { selectWay(nw); }
276                        }
277                        // ** used to have bbox code here, but don't think we need it
278                        _root.map.ways[nw].uploading=false;
279                        _root.map.ways[nw].oldversion=0;
280
281                        z=result[2];
282                        // renumber nodes (and any relations/ways they're in)
283                        for (var oid in z) {
284                                var nid = result[2][oid];
285                                nodes[oid].renumberTo(nid);
286                                renumberMemberOfRelation('node', oid, nid);
287                        }
288                        _root.map.ways[nw].clearPOIs();
289                        _root.map.ways[nw].deleteMergedWays();
290                };
291                if (!this.uploading && !this.locked && !_root.sandbox && this.path.length>1) {
292                        // Assemble 'sendpath' and upload it
293                        this.attr['created_by']=_root.signature;
294                        this.uploading=true;
295                        var sendpath=new Array();
296                        for (i=0; i<this.path.length; i++) {
297                                sendpath.push(new Array(coord2long(nodes[this.path[i]].x),
298                                                                                coord2lat (nodes[this.path[i]].y),
299                                                                                this.path[i],null,
300                                                                                deepCopy  (nodes[this.path[i]].attr)));
301                        }
302                        remote.call('putway',putresponder,_root.usertoken,Number(this._name),sendpath,this.attr);
303                        this.clean=true;
304                }
305        };
306
307        // ---- Delete any ways merged into this one
308
309        OSMWay.prototype.deleteMergedWays=function() {
310                while (this.mergedways.length>0) {
311                        var i=this.mergedways.shift();
312                        _root.map.ways.attachMovie("way",i,++waydepth); // can't remove unless the movieclip exists!
313                        _root.map.ways[i].remove();
314                }
315        };
316
317        // ---- Revert to copy in database
318       
319        OSMWay.prototype.reload=function() {
320                _root.waysrequested+=1;
321                while (this.mergedways.length>0) {
322                        var i=this.mergedways.shift();
323                        _root.waysrequested+=1;
324                        _root.map.ways.attachMovie("way",i,++waydepth);
325                        _root.map.ways[i].load();
326                }
327                this.checkconnections=true;
328                this.load();
329        };
330       
331        // ---- Save for undo
332
333        OSMWay.prototype.saveUndo=function(str) {
334                _root.undo.append(UndoStack.prototype.undo_deleteway,
335                                                  new Array(this._name,this._x,this._y,
336                                                                        deepCopy(this.attr),
337                                                                        deepCopy(this.path)),iText("$1 a way",'a_way',str));
338        };
339
340
341        // ---- Click handling 
342
343        OSMWay.prototype.onRollOver=function() {
344                if (this._name!=_root.wayselected && _root.drawpoint>-1) {
345                        this.highlightPoints(5001,"anchorhint");
346                        setPointer('penplus');
347                } else if (_root.drawpoint>-1) { setPointer('penplus'); }
348                                                                  else { setPointer(''); }
349        };
350       
351        OSMWay.prototype.onRollOut=function() {
352                if (_root.wayselected) { setPointer(''   ); }
353                                                  else { setPointer('pen'); }
354                _root.map.anchorhints.removeMovieClip();
355        };
356       
357        OSMWay.prototype.onPress=function() {
358                removeWelcome(true);
359                if (Key.isDown(Key.SHIFT) && this._name==_root.wayselected && _root.drawpoint==-1) {
360                        // shift-click current way: insert point
361                        this.insertAnchorPointAtMouse();
362                } else if (Key.isDown(Key.SHIFT) && _root.wayselected && this.name!=_root.wayselected && _root.drawpoint==-1) {
363                        if (_root.ws.hitTest(_root._xmouse,_root._ymouse,true)) {
364                                // shift-click other way (at intersection with current): make intersection
365                                this.insertAnchorPointAtMouse();
366                        } else {
367                                // shift-click other way: merge two ways
368                                this.mergeAtCommonPoint(_root.ws);
369                                _root.ws.redraw();
370                                _root.ws.select();
371//                              _root.ws.upload();
372//                              _root.map.ways[this._name ].remove(wayselected);
373                        }
374                } else if (_root.drawpoint>-1) {
375                        // click other way while drawing: insert point as junction
376                        if (this.oldversion==0) {
377                                if (this._name==_root.wayselected && _root.drawpoint>0) {
378                                        _root.drawpoint+=1;     // inserting node earlier into the way currently being drawn
379                                }
380                                _root.newnodeid--;
381                                this.insertAnchorPoint(_root.newnodeid);
382                                this.highlightPoints(5001,"anchorhint");
383                                addEndPoint(newnodeid);
384                        }
385                        _root.junction=true;
386                        restartElastic();
387                } else {
388                        // click way: select
389                        _root.panel.properties.saveAttributes();
390                        this.select();
391                        clearTooltip();
392                        _root.clicktime=new Date();
393                        // was the click on a tagged node? if so, select directly
394                        var n;
395                        for (var i=0; i<this.path.length; i+=1) {
396                                if (this.taggednodes[i].hitTest(_root._xmouse,_root._ymouse,true)) { n=i; }
397                        }
398                        if (n) { _root.map.anchors[n].beginDrag();
399                                         _root.map.anchors[n].select(); }
400                          else { this.beginDrag(); }
401                }
402        };
403
404        OSMWay.prototype.beginDrag=function() {
405                this.onMouseMove=function() { this.trackDrag(); };
406                this.onMouseUp  =function() { this.endDrag();   };
407                this.dragged=false;
408                this.held=true;
409                _root.firstxmouse=_root.map._xmouse;
410                _root.firstymouse=_root.map._ymouse;
411        };
412
413        OSMWay.prototype.trackDrag=function() {
414                var t=new Date();
415                var longclick=(t.getTime()-_root.clicktime)>1000;
416                var xdist=Math.abs(_root.map._xmouse-_root.firstxmouse);
417                var ydist=Math.abs(_root.map._ymouse-_root.firstymouse);
418                // Don't enable drag unless way held for a while after click
419                if ((xdist>=tolerance   || ydist>=tolerance  ) &&
420                        (t.getTime()-_root.clicktime)<300 &&
421                        lastwayselected!=wayselected) { this.held=false; }
422                // Move way if dragged a long way, or dragged a short way after a while
423                if ((xdist>=tolerance*4 || ydist>=tolerance*4) ||
424                   ((xdist>=tolerance/4 || ydist>=tolerance/4) && longclick) &&
425                   this.held) {
426                        this.dragged=true;
427                }
428                if (this.dragged) {
429                        _root.map.anchors._x=_root.map.areas[this._name]._x=_root.map.highlight._x=this._x=_root.map._xmouse-_root.firstxmouse;
430                        _root.map.anchors._y=_root.map.areas[this._name]._y=_root.map.highlight._y=this._y=_root.map._ymouse-_root.firstymouse;
431                }
432        };
433       
434        OSMWay.prototype.endDrag=function() {
435                this.onMouseMove=function() {};
436                this.onMouseUp  =function() {};
437                _root.map.anchors._x=_root.map.areas[this._name]._x=_root.map.highlight._x=this._x=0;
438                _root.map.anchors._y=_root.map.areas[this._name]._y=_root.map.highlight._y=this._y=0;
439                if (this.dragged) {
440                        this.moveNodes(_root.map._xmouse-_root.firstxmouse,_root.map._ymouse-_root.firstymouse);
441                        this.redraw();
442                        this.select();
443                        _root.undo.append(UndoStack.prototype.undo_movenodes,
444                                                          new Array(this,_root.map._xmouse-_root.firstxmouse,
445                                                                                         _root.map._ymouse-_root.firstymouse),
446                                                          iText("moving a way",'action_moveway'));
447                }
448        };
449       
450        // ---- Select/highlight
451       
452        OSMWay.prototype.select=function() {
453                _root.panel.properties.tidy();
454                if (_root.wayselected!=this._name || _root.poiselected!=0) { uploadSelected(); }
455//              _root.panel.properties.saveAttributes();
456                selectWay(this._name);
457                _root.pointselected=-2;
458                _root.poiselected=0;
459                this.highlightPoints(5000,"anchor");
460                removeMovieClip(_root.map.anchorhints);
461                this.highlight();
462                setTypeText(iText("Way",'way'),this._name);
463                _root.panel.properties.init('way',getPanelColumns(),4);
464                _root.panel.presets.init(_root.panel.properties);
465                updateButtons();
466                updateScissors(false);
467        };
468       
469        OSMWay.prototype.highlight=function() {
470                _root.map.createEmptyMovieClip("highlight",5);
471                if (_root.pointselected>-2) {
472                        highlightSquare(_root.map.anchors[pointselected]._x,_root.map.anchors[pointselected]._y,8/Math.pow(2,Math.min(_root.scale,17)-13));
473                } else {
474                        var linecolour=0xFFFF00; if (this.locked) { var linecolour=0x00FFFF; }
475                        _root.map.highlight.lineStyle(linewidth*1.5+8,linecolour,80,false,"none");
476                        _root.map.highlight.moveTo(nodes[this.path[0]].x,nodes[this.path[0]].y);
477                        for (var i=1; i<this.path.length; i+=1) {
478                                _root.map.highlight.lineTo(nodes[this.path[i]].x,nodes[this.path[i]].y);
479                        }
480                }
481                this.direction();
482        };
483
484        OSMWay.prototype.highlightPoints=function(d,atype) {
485                var enlarge=1;
486                var anchorsize=120/Math.pow(2,_root.scale-13);
487                if (preferences.data.thinlines) { enlarge=0.5; }
488                if (_root.scale>15) {
489                        switch (_root.scale) {
490                                case 15: anchorsize+=10*enlarge; break;
491                                case 16: anchorsize+=7 *enlarge; break;
492                                case 17: anchorsize+=5 *enlarge; break;
493                                case 18: anchorsize+=6 *enlarge; break;
494                                case 19: anchorsize+=6 *enlarge; break;
495                        }
496                }
497                var group=atype+"s";
498                _root.map.createEmptyMovieClip(group,d);
499                for (var i=0; i<this.path.length; i+=1) {
500                        _root.map[group].attachMovie(atype,i,i);
501                        _root.map[group][i]._x=nodes[this.path[i]].x;
502                        _root.map[group][i]._y=nodes[this.path[i]].y;
503                        _root.map[group][i]._xscale=anchorsize;
504                        _root.map[group][i]._yscale=anchorsize;
505                        _root.map[group][i].node=this.path[i];
506                        _root.map[group][i].way=this;
507                        if (nodes[this.path[i]].tagged) {
508                                // anchor point should be black if it has tags
509                                _root.map[group][i].blacken=new Color(_root.map[group][i]);
510                                _root.map[group][i].blacken.setTransform(to_black);
511                        }
512                }
513        };
514
515        // ---- Split, merge, reverse
516
517        OSMWay.prototype.splitWay=function(point,newattr) {
518                var i,z;
519                if (point>0 && point<(this.path.length-1) && this.oldversion==0) {
520                        _root.newwayid--;                                                                                       // create new way
521                        _root.map.ways.attachMovie("way",newwayid,++waydepth);          //  |
522
523                        _root.map.ways[newwayid].path=deepCopy(this.path);                      // deep copy path array
524
525                        if (newattr) { _root.map.ways[newwayid].attr=newattr; }
526                                        else { _root.map.ways[newwayid].attr=deepCopy(this.attr); }
527
528                        z=getRelationsForWay(this._name);                                                       // copy relations
529                        for (i in z) {                                                                                          //  |
530                                _root.map.relations[z[i]].setWayRole(newwayid,_root.map.relations[z[i]].getWayRole(this._name));
531                        }                                                                                                                       //  |
532
533                        this.path.splice(Math.floor(point)+1);                                          // current way
534                        this.redraw();                                                                                          //  |
535
536                        _root.map.ways[newwayid].path.splice(0,point);                          // new way
537                        _root.map.ways[newwayid].locked=this.locked;                            //  |
538                        _root.map.ways[newwayid].redraw();                                                      //  |
539                        _root.map.ways[newwayid].upload();                                                      //  |
540
541                        this.upload();                                                                                          // upload current way
542                        this.select();                                                                                          //  |
543                        uploadDirtyRelations();
544                        _root.undo.append(UndoStack.prototype.undo_splitway,
545                                                          new Array(this,_root.map.ways[newwayid]),
546                                                          iText("splitting a way",'action_splitway'));
547                };
548        };
549
550        //              Merge (start/end of this way,other way object,start/end of other way)
551
552        OSMWay.prototype.mergeWay=function(topos,otherway,frompos) {
553                var i,z;
554                if (this.oldversion>0 || otherway.oldversion>0) { return; }
555
556                var mergepoint=this.path.length;
557                _root.undo.append(UndoStack.prototype.undo_mergeways,
558                                                  new Array(this,deepCopy(this.attr),deepCopy(otherway.attr),topos),
559                                                  iText("merging two ways",'action_mergeways'));
560                if (frompos==0) { for (i=0; i<otherway.path.length;    i+=1) { this.addPointFrom(topos,otherway,i); } }
561                                   else { for (i=otherway.path.length-1; i>=0; i-=1) { this.addPointFrom(topos,otherway,i); } }
562
563                z=otherway.attr;
564                for (i in z) {
565                        if (otherway.attr[i].substr(0,6)=='(type ') { otherway.attr[i]=null; }
566                        if (this.attr[i].substr(0,6)=='(type ') { this.attr[i]=null; }
567                        if (this.attr[i]) {
568                                if (this.attr[i]!=otherway.attr[i] && otherway.attr[i]) { this.attr[i]+='; '+otherway.attr[i]; }
569                        } else {
570                                this.attr[i]=otherway.attr[i];
571                        }
572                        if (!this.attr[i]) { delete this.attr[i]; }
573                }
574
575                z=getRelationsForWay(otherway._name);                                           // copy relations
576                for (i in z) {                                                                                          //  |
577                        if (!_root.map.relations[z[i]].hasWay(this._name)) {    //  |
578                                _root.map.relations[z[i]].setWayRole(this._name,_root.map.relations[z[i]].getWayRole(otherway._name));
579                        }                                                                                                               //  |
580                }                                                                                                                       //  |
581
582                this.mergedways.push(otherway._name);
583                this.mergedways.concat(otherway.mergedways);
584                this.clean=false;
585                markClean(false);
586                if (otherway.locked) { this.locked=true; }
587                removeMovieClip(_root.map.areas[otherway._name]);
588                removeMovieClip(otherway);
589                if (this._name==_root.wayselected) { 
590                        _root.panel.properties.reinit();
591                }
592        };
593
594        OSMWay.prototype.addPointFrom=function(topos,otherway,srcpt) {
595                if (topos==0) { if (nodes[this.path[0                             ]]==nodes[otherway.path[srcpt]]) { return; } }        // don't add duplicate points
596                                 else { if (nodes[this.path[this.path.length-1]]==nodes[otherway.path[srcpt]]) { return; } }    //  |
597                if (topos==0) { this.path.unshift(otherway.path[srcpt]); }
598                             else { this.path.push(otherway.path[srcpt]); }
599        };
600
601        OSMWay.prototype.mergeAtCommonPoint=function(sel) {
602                var selstart =sel.path[0];
603                var sellen   =sel.path.length-1;
604                var selend   =sel.path[sellen];
605                var thisstart=this.path[0];
606                var thislen  =this.path.length-1;
607                var thisend  =this.path[thislen];
608                if      (selstart==thisstart) { sel.mergeWay(0,this,0);                    return true; }
609                else if (selstart==thisend  ) { sel.mergeWay(0,this,thislen);      return true; }
610                else if (selend  ==thisstart) { sel.mergeWay(sellen,this,0);       return true; }
611                else if (selend  ==thisend  ) { sel.mergeWay(sellen,this,thislen); return true; }
612                else                                              { return false; }
613        };
614
615        // ---- Reverse order
616       
617        OSMWay.prototype.reverseWay=function() {
618                if (this.path.length<2) { return; }
619                if (_root.drawpoint>-1) { _root.drawpoint=(this.path.length-1)-_root.drawpoint; }
620                this.path.reverse();
621                this.redraw();
622                this.direction();
623                this.select();
624                this.clean=false;
625                markClean(false);
626                _root.undo.append(UndoStack.prototype.undo_reverse,new Array(this),iText("reversing a way",'action_reverseway'));
627        };
628
629        // ---- Move all nodes within a way
630       
631        OSMWay.prototype.moveNodes=function(xdiff,ydiff) {
632                var i,n;
633                var movedalready=new Array();
634                this.clean=false;
635                markClean(false);
636                for (i=0; i<this.path.length; i+=1) {
637                        n=this.path[i];
638                        if (movedalready[n]) {
639                        } else {
640                                nodes[n].moveTo(nodes[n].x+xdiff,
641                                                                nodes[n].y+ydiff,
642                                                                this._name);
643                                movedalready[n]=true;
644                        }
645                }
646        };
647
648        // ---- Check for duplicates (e.g. when C is removed from ABCB)
649       
650        OSMWay.prototype.removeDuplicates=function() {
651                var z=this.path; var ch=false;
652                for (var i in z) {
653                        if (i>0) {
654                                if (this.path[i]==this.path[i-1]) { this.path.splice(i,1); ch=true; }
655                        }
656                }
657                return ch;
658        };
659
660        // ---- Add point into way with SHIFT-clicking
661        //              cf http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/source.vba
662        //              for algorithm to find nearest point on a line
663       
664        OSMWay.prototype.insertAnchorPoint=function(nodeid) {
665                var nx,ny,tx,ty,u,closest,closei,i,a,b,direct,via,newpoint;
666                nx=_root.map._xmouse;   // where we're inserting it
667                ny=_root.map._ymouse;   //      |
668                closest=0.05; closei=0;
669                for (i=0; i<(this.path.length)-1; i+=1) {
670                        a=nodes[this.path[i  ]];
671                        b=nodes[this.path[i+1]];
672                        direct=Math.sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
673                        via   =Math.sqrt((nx -a.x)*(nx -a.x)+(ny -a.y)*(ny -a.y));
674                        via  +=Math.sqrt((nx -b.x)*(nx -b.x)+(ny -b.y)*(ny -b.y));
675                        if (Math.abs(via/direct-1)<closest) {
676                                closei=i+1;
677                                closest=Math.abs(via/direct-1);
678                                u=((nx-a.x)*(b.x-a.x)+
679                                   (ny-a.y)*(b.y-a.y))/
680                                   (Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2));
681                                tx=a.x+u*(b.x-a.x);
682                                ty=a.y+u*(b.y-a.y);
683                        }
684                }
685                // Insert
686                this.path.splice(closei,0,nodeid);
687                _root.nodes[nodeid]=new Node(nodeid,tx,ty,new Array());
688                this.clean=false;
689                this.redraw();
690                markClean(false);
691//              _root.adjustedxmouse=tx;        // in case we're adding extra points...
692//              _root.adjustedymouse=ty;        // should probably return an array or an object **
693                return closei;
694        };
695
696        //              Wrapper around the above to:
697        //              - insert at mouse position
698        //              - add to undo stack
699        //              - add intersection at any crossing ways
700
701        OSMWay.prototype.insertAnchorPointAtMouse=function() {
702                _root.newnodeid--;
703                _root.pointselected=this.insertAnchorPoint(_root.newnodeid);
704                var waylist=new Array(); waylist.push(this);
705                var poslist=new Array(); poslist.push(_root.pointselected);
706                for (qway in _root.map.ways) {
707                        if (_root.map.ways[qway].hitTest(_root._xmouse,_root._ymouse,true) && qway!=this._name) {
708                                poslist.push(_root.map.ways[qway].insertAnchorPoint(_root.newnodeid));
709                                waylist.push(_root.map.ways[qway]);
710                        }
711                }
712                _root.undo.append(UndoStack.prototype.undo_addpoint,
713                                                  new Array(waylist,poslist), iText("adding a node into a way",'action_insertnode'));
714                _root.ws.highlightPoints(5000,"anchor");
715                _root.map.anchors[pointselected].beginDrag();
716        };
717
718        // ---- Remove point from this way (only)
719       
720        OSMWay.prototype.removeAnchorPoint=function(point) {
721                // ** if length<2, then mark as way removal
722                _root.undo.append(UndoStack.prototype.undo_deletepoint,
723                                                  new Array(deepCopy(nodes[this.path[point]]),
724                                                                        new Array(this._name),
725                                                                        new Array(point)),
726                                                  iText("deleting a point",'action_deletepoint'));
727                this.path.splice(point,1);
728                this.removeDuplicates();
729                if (this.path.length<2) { this.remove(); }
730                                                   else { this.redraw(); this.clean=false; }
731        };
732
733        // ---- Bounding box utility functions
734
735        OSMWay.prototype.resetBBox=function() {
736                this.xmin=this.ymin= 999;
737                this.xmax=this.ymax=-999;
738        };
739       
740        OSMWay.prototype.updateBBox=function(long,lat) {
741                this.xmin=Math.min(long,this.xmin);
742                this.xmax=Math.max(long,this.xmax);
743                this.ymin=Math.min(lat ,this.ymin);
744                this.ymax=Math.max(lat ,this.ymax);
745        };
746
747        Object.registerClass("way",OSMWay);
748
749
750        // =====================================================================================
751        // Drawing support functions
752
753        // removeNodeFromWays - now see Node.removeFromAllWays
754
755        // startNewWay            - create new way from first node
756
757        function startNewWay(node) {
758                uploadSelected();
759                _root.newwayid--;
760                selectWay(newwayid);
761                _root.poiselected=0;
762                _root.map.ways.attachMovie("way",newwayid,++waydepth);
763                _root.map.ways[newwayid].path[0]=node;
764                _root.map.ways[newwayid].redraw();
765                _root.map.ways[newwayid].select();
766                _root.map.ways[newwayid].clean=false;
767                _root.map.anchors[0].startElastic();
768                _root.drawpoint=0;
769                markClean(false);
770                setTooltip(iText("click to add point\ndouble-click/Return\nto end line",'hint_drawmode'),0);
771        }
772
773        // addEndPoint - add point to start/end of line
774
775        function addEndPoint(node) {
776                var drawnode=nodes[_root.ws.path[_root.drawpoint]];
777                if (_root.drawpoint==_root.ws.path.length-1) {
778                        _root.ws.path.push(node);
779                        _root.drawpoint=_root.ws.path.length-1;
780                } else {
781                        _root.ws.path.unshift(node);    // drawpoint=0, add to start
782                }
783       
784                // Redraw line (if possible, just extend it to save time)
785                if (_root.ws.getFill()>-1 || 
786                        _root.ws.path.length<3 ||
787                        _root.pointselected>-2) {
788                        _root.ws.redraw();
789                        _root.ws.select();
790                } else {
791                        _root.ws.line.moveTo(drawnode.x,drawnode.y);
792                        _root.ws.line.lineTo(nodes[node].x,nodes[node].y);
793                        if (casing[_root.ws.attr['highway']]) {
794                                _root.map.areas[wayselected].moveTo(drawnode.x,drawnode.y);
795                                _root.map.areas[wayselected].lineTo(nodes[node].x,nodes[node].y);
796                        }
797                        _root.map.highlight.moveTo(drawnode.x,drawnode.y);
798                        _root.map.highlight.lineTo(nodes[node].x,nodes[node].y);
799                        _root.ws.direction();
800                        _root.ws.highlightPoints(5000,"anchor");
801                        removeMovieClip(_root.map.anchorhints);
802                }
803                redrawRelationsForMember('way',_root.wayselected);
804                // Mark as unclean
805                _root.ws.clean=false;
806                markClean(false);
807                _root.map.elastic.clear();
808                var poslist=new Array(); poslist.push(_root.drawpoint);
809                _root.undo.append(UndoStack.prototype.undo_addpoint,
810                                                  new Array(new Array(_root.ws),poslist),
811                                                  iText("adding a node to the end of a way",'action_addpoint'));
812        }
813
814        function stopDrawing() {
815                _root.map.anchors[_root.drawpoint].endElastic();
816                _root.drawpoint=-1;
817                if (_root.ws.path.length<=1) { 
818                        // way not long enough, so abort
819                        removeMovieClip(_root.map.areas[wayselected]);
820                        removeMovieClip(_root.ws);
821                        removeMovieClip(_root.map.anchors);
822                }
823                _root.map.elastic.clear();
824                clearTooltip();
825        };
826
827        // cycleStacked - cycle through ways sharing same point
828
829        function cycleStacked() {
830                if (_root.pointselected>-2) {
831                        var id=_root.ws.path[_root.pointselected];
832                        var firstfound=0; var nextfound=0;
833                        for (qway in _root.map.ways) {
834                                if (qway!=_root.wayselected) {
835                                        for (qs=0; qs<_root.map.ways[qway].path.length; qs+=1) {
836                                                if (_root.map.ways[qway].path[qs]==id) {
837                                                        var qw=Math.floor(qway);
838                                                        if (firstfound==0 || qw<firstfound) { firstfound=qw; }
839                                                        if ((nextfound==0 || qw<nextfound) && qw>wayselected) { nextfound=qw; }
840                                                }
841                                        }
842                                }
843                        }
844                        if (firstfound) {
845                                if (nextfound==0) { var nextfound=firstfound; }
846                                _root.map.ways[nextfound].swapDepths(_root.ws);
847                                _root.map.ways[nextfound].select();
848                        }
849                }
850        };
851
852        // ================================================================
853        // Way communication
854       
855        // whichWays    - get list of ways from remoting server
856
857        function whichWays() {
858                _root.lastwhichways=new Date();
859                if (_root.waycount>500) { purgeWays(); }
860                if (_root.poicount>500) { purgePOIs(); }
861                if (_root.edge_l>_root.bigedge_l &&
862                        _root.edge_r<_root.bigedge_r &&
863                        _root.edge_b>_root.bigedge_b &&
864                        _root.edge_t<_root.bigedge_t) {
865                        // we have already loaded this area, so ignore
866                } else {
867                        whichresponder=function() {};
868                        whichresponder.onResult=function(result) {
869                                _root.whichreceived+=1;
870                                waylist  =result[0];
871                                pointlist=result[1];
872                                relationlist=result[2];
873
874                                for (i in waylist) {                                                                            // ways
875                                        way=waylist[i];                                                                                 //  |
876                                        if (!_root.map.ways[way]) {                                                             //  |
877                                                _root.map.ways.attachMovie("way",way,++waydepth);       //  |
878                                                _root.map.ways[way].load();                                                     //  |
879                                                _root.waycount+=1;                                                                      //  |
880                                                _root.waysrequested+=1;                                                         //  |
881                                        }
882                                }
883                               
884                                for (i in pointlist) {                                                                          // POIs
885                                        point=pointlist[i][0];                                                                  //  |
886                                        if (!_root["map"]["pois"][point]) {                                             //  |
887                                                _root.map.pois.attachMovie("poi",point,++poidepth);     //  |
888                                                _root.map.pois[point]._x=long2coord(pointlist[i][1]);// |
889                                                _root.map.pois[point]._y=lat2coord (pointlist[i][2]);// |
890                                                _root.map.pois[point]._xscale=
891                                                _root.map.pois[point]._yscale=Math.max(100/Math.pow(2,_root.scale-13),6.25);
892                                                _root.map.pois[point].attr=pointlist[i][3];                     //  |
893                                                _root.poicount+=1;                                                                      //  |
894                                                if (point==prenode) { deselectAll(); prenode=undefined;
895                                                                                          _root.map.pois[point].select(); }
896                                        }
897                                }
898
899                                for (i in relationlist) {
900                                        rel = relationlist[i];
901                    if (!_root.map.relations[rel]) {
902                                                _root.map.relations.attachMovie("relation",rel,++reldepth);
903                                                _root.map.relations[rel].load();
904                                                _root.relcount+=1;
905                                                _root.relsrequested+=1;
906                                        }
907                }
908                        };
909                        remote.call('whichways',whichresponder,_root.edge_l,_root.edge_b,_root.edge_r,_root.edge_t);
910                        _root.bigedge_l=_root.edge_l; _root.bigedge_r=_root.edge_r;
911                        _root.bigedge_b=_root.edge_b; _root.bigedge_t=_root.edge_t;
912                        _root.whichrequested+=1;
913                }
914        }
915
916        // purgeWays - remove any clean ways outside current view
917       
918        function purgeWays() {
919                for (qway in _root.map.ways) {
920                        if (qway==_root.wayselected) {
921                        } else if (!_root.map.ways[qway].clean) {
922                                _root.map.ways[qway].upload();
923                                uploadDirtyRelations();
924                        } else if (((_root.map.ways[qway].xmin<edge_l && _root.map.ways[qway].xmax<edge_l) ||
925                                                (_root.map.ways[qway].xmin>edge_r && _root.map.ways[qway].xmax>edge_r) ||
926                                            (_root.map.ways[qway].ymin<edge_b && _root.map.ways[qway].ymax<edge_b) ||
927                                                (_root.map.ways[qway].ymin>edge_t && _root.map.ways[qway].ymax>edge_t))) {
928                                removeMovieClip(_root.map.ways[qway]);
929                                removeMovieClip(_root.map.areas[qway]);
930                                _root.waycount-=1;
931                        }
932                }
933                _root.bigedge_l=_root.edge_l; _root.bigedge_r=_root.edge_r;
934                _root.bigedge_b=_root.edge_b; _root.bigedge_t=_root.edge_t;
935        }
936
937        function selectWay(id) {
938                _root.lastwayselected=_root.wayselected;
939                _root.wayselected=Math.floor(id);
940                _root.ws=_root.map.ways[id];
941        }
Note: See TracBrowser for help on using the repository browser.