| 276 | | }, |
|---|
| | 276 | }, |
|---|
| | 277 | |
|---|
| | 278 | /** |
|---|
| | 279 | * APIMethod: write |
|---|
| | 280 | * Takes a list of features, returns a serialized OSM format file for use |
|---|
| | 281 | * in tools like JOSM. |
|---|
| | 282 | * |
|---|
| | 283 | * Parameters: |
|---|
| | 284 | * features - Array({<OpenLayers.Feature.Vector>}) |
|---|
| | 285 | */ |
|---|
| | 286 | write: function(features) { |
|---|
| | 287 | if (!(features instanceof Array)) { |
|---|
| | 288 | features = [features]; |
|---|
| | 289 | } |
|---|
| | 290 | |
|---|
| | 291 | this.osm_id = 1; |
|---|
| | 292 | this.created_nodes = {}; |
|---|
| | 293 | var root_node = document.createElementNS(null, "osm"); |
|---|
| | 294 | root_node.setAttribute("version", "0.5"); |
|---|
| | 295 | root_node.setAttribute("generator", "OpenLayers "+ OpenLayers.VERSION_NUMBER); |
|---|
| | 296 | |
|---|
| | 297 | // Loop backwards, because the deserializer puts nodes last, and |
|---|
| | 298 | // we want them first if possible |
|---|
| | 299 | for(var i = features.length - 1; i >= 0; i--) { |
|---|
| | 300 | var nodes = this.createFeatureNodes(features[i]); |
|---|
| | 301 | for (var j = 0; j < nodes.length; j++) { |
|---|
| | 302 | root_node.appendChild(nodes[j]); |
|---|
| | 303 | } |
|---|
| | 304 | } |
|---|
| | 305 | return OpenLayers.Format.XML.prototype.write.apply(this, [root_node]); |
|---|
| | 306 | }, |
|---|
| | 307 | |
|---|
| | 308 | /** |
|---|
| | 309 | * Method: createFeatureNodes |
|---|
| | 310 | * Takes a feature, returns a list of nodes from size 0->n. |
|---|
| | 311 | * Will include all pieces of the serialization that are required which |
|---|
| | 312 | * have not already been created. Calls out to createXML based on geometry |
|---|
| | 313 | * type. |
|---|
| | 314 | * |
|---|
| | 315 | * Parameters: |
|---|
| | 316 | * feature - {<OpenLayers.Feature.Vector>} |
|---|
| | 317 | */ |
|---|
| | 318 | createFeatureNodes: function(feature) { |
|---|
| | 319 | var nodes = []; |
|---|
| | 320 | var className = feature.geometry.CLASS_NAME; |
|---|
| | 321 | var type = className.substring(className.lastIndexOf(".") + 1) |
|---|
| | 322 | type = type.toLowerCase(); |
|---|
| | 323 | var builder = this.createXML[type]; |
|---|
| | 324 | if (builder) { |
|---|
| | 325 | nodes = builder.apply(this, [feature]); |
|---|
| | 326 | } |
|---|
| | 327 | return nodes; |
|---|
| | 328 | }, |
|---|
| | 329 | |
|---|
| | 330 | /** |
|---|
| | 331 | * Method: createXML |
|---|
| | 332 | * Takes a feature, returns a list of nodes from size 0->n. |
|---|
| | 333 | * Will include all pieces of the serialization that are required which |
|---|
| | 334 | * have not already been created. |
|---|
| | 335 | * |
|---|
| | 336 | * Parameters: |
|---|
| | 337 | * feature - {<OpenLayers.Feature.Vector>} |
|---|
| | 338 | */ |
|---|
| | 339 | createXML: { |
|---|
| | 340 | 'point': function(point) { |
|---|
| | 341 | var id = null; |
|---|
| | 342 | var geometry = point.geometry ? point.geometry : point; |
|---|
| | 343 | var already_exists = false; // We don't return anything if the node |
|---|
| | 344 | // has already been created |
|---|
| | 345 | if (point.osm_id) { |
|---|
| | 346 | id = point.osm_id; |
|---|
| | 347 | if (this.created_nodes[id]) { |
|---|
| | 348 | already_exists = true; |
|---|
| | 349 | } |
|---|
| | 350 | } else { |
|---|
| | 351 | id = -this.osm_id; |
|---|
| | 352 | this.osm_id++; |
|---|
| | 353 | } |
|---|
| | 354 | if (already_exists) { |
|---|
| | 355 | node = this.created_nodes[id]; |
|---|
| | 356 | } else { |
|---|
| | 357 | var node = this.createElementNS(null, "node"); |
|---|
| | 358 | } |
|---|
| | 359 | this.created_nodes[id] = node; |
|---|
| | 360 | node.setAttribute("id", id); |
|---|
| | 361 | node.setAttribute("lon", geometry.x); |
|---|
| | 362 | node.setAttribute("lat", geometry.y); |
|---|
| | 363 | if (point.attributes) { |
|---|
| | 364 | this.serializeTags(point, node); |
|---|
| | 365 | } |
|---|
| | 366 | this.setState(point, node); |
|---|
| | 367 | return already_exists ? [] : [node]; |
|---|
| | 368 | }, |
|---|
| | 369 | linestring: function(feature) { |
|---|
| | 370 | var nodes = []; |
|---|
| | 371 | var geometry = feature.geometry; |
|---|
| | 372 | if (feature.osm_id) { |
|---|
| | 373 | id = feature.osm_id; |
|---|
| | 374 | } else { |
|---|
| | 375 | id = -this.osm_id; |
|---|
| | 376 | this.osm_id++; |
|---|
| | 377 | } |
|---|
| | 378 | var way = this.createElementNS(null, "way"); |
|---|
| | 379 | way.setAttribute("id", id); |
|---|
| | 380 | for (var i = 0; i < geometry.components.length; i++) { |
|---|
| | 381 | var node = this.createXML['point'].apply(this, [geometry.components[i]]); |
|---|
| | 382 | if (node.length) { |
|---|
| | 383 | node = node[0]; |
|---|
| | 384 | var node_ref = node.getAttribute("id"); |
|---|
| | 385 | nodes.push(node); |
|---|
| | 386 | } else { |
|---|
| | 387 | node_ref = geometry.components[i].osm_id; |
|---|
| | 388 | node = this.created_nodes[node_ref]; |
|---|
| | 389 | } |
|---|
| | 390 | this.setState(feature, node); |
|---|
| | 391 | var nd_dom = this.createElementNS(null, "nd"); |
|---|
| | 392 | nd_dom.setAttribute("ref", node_ref); |
|---|
| | 393 | way.appendChild(nd_dom); |
|---|
| | 394 | } |
|---|
| | 395 | this.serializeTags(feature, way); |
|---|
| | 396 | nodes.push(way); |
|---|
| | 397 | |
|---|
| | 398 | return nodes; |
|---|
| | 399 | }, |
|---|
| | 400 | polygon: function(feature) { |
|---|
| | 401 | var attrs = OpenLayers.Util.extend({'area':'yes'}, feature.attributes); |
|---|
| | 402 | var feat = new OpenLayers.Feature.Vector(feature.geometry.components[0], attrs); |
|---|
| | 403 | feat.osm_id = feature.osm_id; |
|---|
| | 404 | return this.createXML['linestring'].apply(this, [feat]); |
|---|
| | 405 | } |
|---|
| | 406 | }, |
|---|
| | 407 | |
|---|
| | 408 | /** |
|---|
| | 409 | * Method: serializeTags |
|---|
| | 410 | * Given a feature, serialize the attributes onto the given node. |
|---|
| | 411 | * |
|---|
| | 412 | * Parameters: |
|---|
| | 413 | * feature - {<OpenLayers.Feature.Vector>} |
|---|
| | 414 | * node - {DOMNode} |
|---|
| | 415 | */ |
|---|
| | 416 | serializeTags: function(feature, node) { |
|---|
| | 417 | for (var key in feature.attributes) { |
|---|
| | 418 | var tag = this.createElementNS(null, "tag"); |
|---|
| | 419 | tag.setAttribute("k", key); |
|---|
| | 420 | tag.setAttribute("v", feature.attributes[key]); |
|---|
| | 421 | node.appendChild(tag); |
|---|
| | 422 | } |
|---|
| | 423 | }, |
|---|
| | 424 | |
|---|
| | 425 | /** |
|---|
| | 426 | * Method: setState |
|---|
| | 427 | * OpenStreetMap has a convention that 'state' is stored for modification or deletion. |
|---|
| | 428 | * This allows the file to be uploaded via JOSM or the bulk uploader tool. |
|---|
| | 429 | * |
|---|
| | 430 | * Parameters: |
|---|
| | 431 | * feature - {<OpenLayers.Feature.Vector>} |
|---|
| | 432 | * node - {DOMNode} |
|---|
| | 433 | */ |
|---|
| | 434 | setState: function(feature, node) { |
|---|
| | 435 | if (feature.state) { |
|---|
| | 436 | var state = null; |
|---|
| | 437 | switch(feature.state) { |
|---|
| | 438 | case OpenLayers.State.UPDATE: |
|---|
| | 439 | state = "modify"; |
|---|
| | 440 | case OpenLayers.State.DELETE: |
|---|
| | 441 | state = "delete"; |
|---|
| | 442 | } |
|---|
| | 443 | if (state) { |
|---|
| | 444 | node.setAttribute("state", state); |
|---|
| | 445 | } |
|---|
| | 446 | } |
|---|
| | 447 | }, |
|---|
| | 448 | |
|---|