OpenLayers OpenLayers

Changeset 5435

Show
Ignore:
Timestamp:
12/15/07 16:45:51 (1 year ago)
Author:
crschmidt
Message:

GeoJSON should parse and serialize GeometryCollections as a Geometry.Collection
object. (Closes #1067)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/openlayers/lib/OpenLayers/Format/GeoJSON.js

    r5401 r5435  
    4141     * json - {String} A GeoJSON string 
    4242     * type - {String} Optional string that determines the structure of 
    43      *     the output.  Supported values are "Geometry", "Feature", 
    44      *     "GeometryCollection", and "FeatureCollection".  If absent or null, 
    45      *     a default of "FeatureCollection" is assumed. 
     43     *     the output.  Supported values are "Geometry", "Feature", and 
     44     *     "FeatureCollection".  If absent or null, a default of 
     45     *     "FeatureCollection" is assumed. 
    4646     * filter - {Function} A function which will be called for every key and 
    4747     *     value at every level of the final result. Each value will be 
     
    5757     *     <OpenLayers.Geometry>.  If type is "Feature", the input json must 
    5858     *     represent a single feature, and the return will be an 
    59      *     <OpenLayers.Feature.Vector>.  If type is "GeometryCollection", the 
    60      *     input json must represent a geometry collection, and the return will 
    61      *     be an array of <OpenLayers.Geometry>. 
     59     *     <OpenLayers.Feature.Vector>. 
    6260     */ 
    6361    read: function(json, type, filter) { 
     
    9290                    } 
    9391                    break; 
    94                 case "GeometryCollection": 
    95                     results = []; 
    96                     for(var i=0; i<obj.geometries.length; ++i) { 
    97                         try { 
    98                             results.push(this.parseGeometry(obj.geometries[i])); 
    99                         } catch(err) { 
    100                             results = null; 
    101                             OpenLayers.Console.error(err); 
    102                         } 
    103                     } 
    104                     break; 
    10592                case "FeatureCollection": 
    10693                    // for type FeatureCollection, we allow input to be any type 
     
    125112                            } 
    126113                            break; 
    127                         case "GeometryCollection": 
    128                             for(var i=0; i<obj.geometries.length; ++i) { 
    129                                 try { 
    130                                     var geom = this.parseGeometry(obj.geometries[i]); 
    131                                     results.push(new OpenLayers.Feature.Vector(geom)); 
    132                                 } catch(err) { 
    133                                     results = null; 
    134                                     OpenLayers.Console.error(err); 
    135                                 } 
    136                             } 
    137                             break; 
    138114                        default: 
    139115                            try { 
     
    162138        switch(type) { 
    163139            case "Geometry": 
    164                 if(OpenLayers.Util.indexOf(["Point", "MultiPoint", "LineString", 
    165                                             "MultiLineString", "Polygon", 
    166                                             "MultiPolygon", "Box"], obj.type) == -1) { 
     140                if(OpenLayers.Util.indexOf( 
     141                    ["Point", "MultiPoint", "LineString", "MultiLineString", 
     142                     "Polygon", "MultiPolygon", "Box", "GeometryCollection"], 
     143                    obj.type) == -1) { 
    167144                    // unsupported geometry type 
    168145                    OpenLayers.Console.error("Unsupported geometry type: " + 
     
    177154                break; 
    178155            default: 
    179                 // for GeometryCollection and Feature, types must match 
     156                // for Feature types must match 
    180157                if(obj.type == type) { 
    181158                    valid = true; 
     
    227204    parseGeometry: function(obj) { 
    228205        var geometry; 
    229         if(!(obj.coordinates instanceof Array)) { 
    230             throw "Geometry must have coordinates array: " + obj; 
    231         } 
    232         if(!this.parseCoords[obj.type.toLowerCase()]) { 
    233             throw "Unsupported geometry type: " + obj.type; 
    234         } 
    235         try { 
    236             geometry = this.parseCoords[obj.type.toLowerCase()].apply(this, [obj.coordinates]); 
    237         } catch(err) { 
    238             // deal with bad coordinates 
    239             throw err; 
     206        if(obj.type == "GeometryCollection") { 
     207            if(!(obj.geometries instanceof Array)) { 
     208                throw "GeometryCollection must have geometries array: " + obj; 
     209            } 
     210            var numGeom = obj.geometries.length; 
     211            var components = new Array(numGeom); 
     212            for(var i=0; i<numGeom; ++i) { 
     213                components[i] = this.parseGeometry.apply( 
     214                    this, [obj.geometries[i]] 
     215                ); 
     216            } 
     217            geometry = new OpenLayers.Geometry.Collection(components); 
     218        } else { 
     219            if(!(obj.coordinates instanceof Array)) { 
     220                throw "Geometry must have coordinates array: " + obj; 
     221            } 
     222            if(!this.parseCoords[obj.type.toLowerCase()]) { 
     223                throw "Unsupported geometry type: " + obj.type; 
     224            } 
     225            try { 
     226                geometry = this.parseCoords[obj.type.toLowerCase()].apply( 
     227                    this, [obj.coordinates] 
     228                ); 
     229            } catch(err) { 
     230                // deal with bad coordinates 
     231                throw err; 
     232            } 
    240233        } 
    241234        return geometry; 
     
    419412    /** 
    420413     * APIMethod: write 
    421      * Serialize a feature, geometry, array of features, or array of geometries 
    422      *     into a GeoJSON string. 
     414     * Serialize a feature, geometry, array of features into a GeoJSON string. 
    423415     * 
    424416     * Parameters: 
    425417     * obj - {Object} An <OpenLayers.Feature.Vector>, <OpenLayers.Geometry>, 
    426      *     or an array of either features or geometries. 
     418     *     or an array of features. 
    427419     * pretty - {Boolean} Structure the output with newlines and indentation. 
    428420     *     Default is false. 
     
    430422     * Returns: 
    431423     * {String} The GeoJSON string representation of the input geometry, 
    432      *     features, array of geometries, or array of features. 
     424     *     features, or array of features. 
    433425     */ 
    434426    write: function(obj, pretty) { 
     
    437429        }; 
    438430        if(obj instanceof Array) { 
    439             if(obj[0] instanceof OpenLayers.Feature.Vector) { 
    440                 geojson.features = []; 
    441             } else if (obj[0].CLASS_NAME.search("OpenLayers.Geometry") == 0) { 
    442                 geojson.geometries = []; 
    443             }     
    444             for(var i=0; i<obj.length; ++i) { 
     431            geojson.type = "FeatureCollection"; 
     432            var numFeatures = obj.length; 
     433            geojson.features = new Array(numFeatures); 
     434            for(var i=0; i<numFeatures; ++i) { 
    445435                var element = obj[i]; 
    446                 if(element instanceof OpenLayers.Feature.Vector) { 
    447                     if(geojson.type == null) { 
    448                         geojson.type = "FeatureCollection"; 
    449                         if(element.layer && element.layer.projection) { 
    450                             geojson.crs = this.createCRSObject(element); 
    451                         } 
    452                     } else if(geojson.type != "FeatureCollection") { 
    453                         OpenLayers.Console.error("FeatureCollection only supports collections of features: " + element); 
    454                         break; 
    455                     } 
    456                     geojson.features.push(this.extract.feature.apply(this, [element])); 
    457                 } else if (element.CLASS_NAME.search("OpenLayers.Geometry") == 0) { 
    458                     if(geojson.type == null) { 
    459                         geojson.type = "GeometryCollection"; 
    460                     } else if(geojson.type != "GeometryCollection") { 
    461                         OpenLayers.Console.error("GeometryCollection only supports collections of geometries: " + element); 
    462                         break; 
    463                     } 
    464                     geojson.geometries.push(this.extract.geometry.apply(this, [element])); 
    465                 } 
    466             } 
    467         } else if (obj.CLASS_NAME.search("OpenLayers.Geometry") == 0) { 
     436                if(!element instanceof OpenLayers.Feature.Vector) { 
     437                    var msg = "FeatureCollection only supports collections " + 
     438                              "of features: " + element; 
     439                    throw msg; 
     440                } 
     441                geojson.features[i] = this.extract.feature.apply( 
     442                    this, [element] 
     443                ); 
     444            } 
     445        } else if (obj.CLASS_NAME.indexOf("OpenLayers.Geometry") == 0) { 
    468446            geojson = this.extract.geometry.apply(this, [obj]); 
    469447        } else if (obj instanceof OpenLayers.Feature.Vector) { 
     
    551529            var geometryType = geometry.CLASS_NAME.split('.')[2]; 
    552530            var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]); 
    553             return { 
    554                 "type": geometryType, 
    555                 "coordinates": data 
    556             }; 
    557         }, 
    558  
    559         /** 
    560          * Method: extract.poin 
     531            var json; 
     532            if(geometryType == "Collection") { 
     533                json = { 
     534                    "type": "GeometryCollection", 
     535                    "geometries": data 
     536                }; 
     537            } else { 
     538                json = { 
     539                    "type": geometryType, 
     540                    "coordinates": data 
     541                }; 
     542            } 
     543             
     544            return json; 
     545        }, 
     546 
     547        /** 
     548         * Method: extract.point 
    561549         * Return an array of coordinates from a point. 
    562550         * 
     
    663651            } 
    664652            return array; 
    665         } 
     653        }, 
     654         
     655        /** 
     656         * Method: extract.collection 
     657         * Return an array of geometries from a geometry collection. 
     658         *  
     659         * Parameters: 
     660         * collection - {<OpenLayers.Geometry.Collection>} 
     661         *  
     662         * Returns: 
     663         * {Array} An array of geometry objects representing the geometry 
     664         *     collection. 
     665         */ 
     666        'collection': function(collection) { 
     667            var len = collection.components.length; 
     668            var array = new Array(len); 
     669            for(var i=0; i<len; ++i) { 
     670                array[i] = this.extract.geometry.apply( 
     671                    this, [collection.components[i]] 
     672                ); 
     673            } 
     674            return array; 
     675        }, 
     676         
    666677 
    667678    }, 
  • trunk/openlayers/tests/Format/test_GeoJSON.html

    r4819 r5435  
    2323 
    2424    function test_Format_GeoJSON_valid_type(t) {  
    25         t.plan(13); 
     25        t.plan(14); 
    2626 
    2727        OpenLayers.Console.error = function(error) { window.global_error = error; } 
    28         var types = ["Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", "Box"]; 
     28        var types = ["Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", "Box", "GeometryCollection"]; 
    2929        for (var i = 0; i < types.length; i++) { 
    3030            t.ok(parser.isValidType({'type':types[i]}, "Geometry"), "Geometry with type " + types[i] + " is valid"); 
     
    141141 
    142142    // This test is from the geom_collection example on geojson spec. 
    143     function test_Format_GeoJSON_geom_collection(t) { 
    144        t.plan(7); 
     143    function test_Format_GeoJSON_collection(t) { 
     144       t.plan(10); 
    145145 
    146146       var geomcol = { 
     
    159159           ] 
    160160        }; 
    161         data = parser.read(geomcol, "GeometryCollection"); 
    162         t.eq(data[0].CLASS_NAME,  
    163               "OpenLayers.Geometry.Point", "First geom in geom collection is point type");   
    164         t.eq(data[0].x, 100, "First geom in geom collection has correct x");   
    165         t.eq(data[0].y, 0, "First geom in geom collection has correct x");   
     161        data = parser.read(geomcol, "Geometry"); 
     162        t.eq(data.CLASS_NAME, "OpenLayers.Geometry.Collection", 
     163             "GeometryCollection deserialized into geometry.collection");   
     164        t.eq(data.components[0].CLASS_NAME, "OpenLayers.Geometry.Point", 
     165             "First geom is correct type");   
     166        t.eq(data.components[0].x, 100, 
     167             "First geom in geom collection has correct x");   
     168        t.eq(data.components[0].y, 0, 
     169             "First geom in geom collection has correct x");   
    166170         
    167         t.eq(data[1].CLASS_NAME,  
    168               "OpenLayers.Geometry.LineString", "Second geom in geom collection is point linestring");   
    169         t.eq(data[1].components.length, 2, "linestring is correct length"); 
    170         t.eq(data[1].components[1].x, 102, "linestring is correct x end"); 
    171         t.eq(data[1].components[1].y, 1, "linestring is correct y end"); 
     171        t.eq(data.components[1].CLASS_NAME, "OpenLayers.Geometry.LineString", 
     172             "Second geom in geom collection is point linestring");   
     173        t.eq(data.components[1].components.length, 2, 
     174             "linestring is correct length"); 
     175        t.eq(data.components[1].components[1].x, 102, 
     176             "linestring is correct x end"); 
     177        t.eq(data.components[1].components[1].y, 1, 
     178             "linestring is correct y end"); 
     179 
     180        data = parser.read(geomcol, "FeatureCollection"); 
     181        t.eq(data[0].CLASS_NAME, "OpenLayers.Feature.Vector", 
     182             "GeometryCollection can be read in as a feature collection"); 
     183        t.eq(data[0].geometry.CLASS_NAME, "OpenLayers.Geometry.Collection", 
     184             "feature contains the correct geometry type"); 
     185        var feature = { 
     186           "type": "Feature", 
     187           "geometry": { 
     188              "type": "GeometryCollection", 
     189              "geometries": [ 
     190                  { 
     191                    "type": "Point", 
     192                    "coordinates": [100.0, 0.0] 
     193                  }, 
     194                  { 
     195                    "type": "LineString", 
     196                    "coordinates": [ 
     197                        [101.0, 0.0], [102.0, 1.0] 
     198                    ] 
     199                  } 
     200              ] 
     201           }, 
     202           "properties": { 
     203               "prop0": "value0", 
     204               "prop1": "value1" 
     205           } 
     206        }; 
     207        data = parser.read(feature); 
     208        t.eq(data.geometry.CLASS_NAME, "OpenLayers.Geometry.Collection", "Geometry of feature is a collection"); 
     209        var l = new OpenLayers.Layer.Vector(); 
     210        l.addFeatures(data); 
     211        t.ok(true, "adding a feature with geomcollection to layer doesn't cause error.");  
    172212    } 
    173213 
     
    264304                ]),  
    265305                '{"type":"Polygon","coordinates":[[[1,2],[3,4],[5,6],[1,2]]]}' 
     306            ], 
     307            [ 
     308                new OpenLayers.Geometry.Collection([ 
     309                    new OpenLayers.Geometry.Polygon([ 
     310                        new OpenLayers.Geometry.LinearRing([ 
     311                            new OpenLayers.Geometry.Point(1,2),  
     312                            new OpenLayers.Geometry.Point(3,4),  
     313                            new OpenLayers.Geometry.Point(5,6) 
     314                        ]) 
     315                    ]),  
     316                    new OpenLayers.Geometry.LineString([ 
     317                        new OpenLayers.Geometry.Point(1,2),  
     318                        new OpenLayers.Geometry.Point(3,4) 
     319                    ]), 
     320                    new OpenLayers.Geometry.Point(1,2) 
     321                ]), 
     322                '{"type":"GeometryCollection","geometries":[{"type":"Polygon","coordinates":[[[1,2],[3,4],[5,6],[1,2]]]},{"type":"LineString","coordinates":[[1,2],[3,4]]},{"type":"Point","coordinates":[1,2]}]}' 
    266323            ] 
    267324        ]; 
     
    272329        serialize_tests.push([multipolygon, '{"type":"MultiPolygon","coordinates":[[[[1,2],[3,4],[5,6],[1,2]]],[[[1,2],[3,4],[5,6],[1,2]]]]}']); 
    273330        serialize_tests.push([ [ serialize_tests[0][0] ], '{"type":"FeatureCollection","features":[{"type":"Feature","id":0,"properties":{},"geometry":{"type":"Point","coordinates":[1,2]}}]}' ]); 
    274         serialize_tests.push([ [ serialize_tests[1][0], serialize_tests[2][0] ], '{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[1,2]},{"type":"MultiPoint","coordinates":[[1,2]]}]}' ]); 
    275331        for (var i = 0; i < serialize_tests.length; i++) { 
    276332            var input = serialize_tests[i][0];