diff --git a/spec/suites/geo/LatLngSpec.js b/spec/suites/geo/LatLngSpec.js index aefea668..933fe324 100644 --- a/spec/suites/geo/LatLngSpec.js +++ b/spec/suites/geo/LatLngSpec.js @@ -15,6 +15,20 @@ describe('LatLng', function() { var a = new L.LatLng(NaN, NaN); }).to.throwError(); }); + + it ('does not set altitude if undefined', function () { + var a = new L.LatLng(25, 74); + expect(typeof a.altitude).to.eql('undefined'); + }); + + it ('sets altitude', function () { + var a = new L.LatLng(25, 74, 50); + expect(a.altitude).to.eql(50); + + var b = new L.LatLng(-25, -74, -50); + expect(b.altitude).to.eql(-50); + }); + }); describe('#equals', function() { diff --git a/spec/suites/layer/GeoJSONSpec.js b/spec/suites/layer/GeoJSONSpec.js index 3ffc990b..c7f71ba4 100644 --- a/spec/suites/layer/GeoJSONSpec.js +++ b/spec/suites/layer/GeoJSONSpec.js @@ -5,7 +5,7 @@ describe("L.GeoJSON", function () { properties: {}, geometry: { type: 'Point', - coordinates: [20, 10] + coordinates: [20, 10, 5] } }; @@ -24,47 +24,79 @@ describe("L.GeoJSON", function () { }); describe("L.Marker#toGeoJSON", function () { - it("returns a Point object", function () { + it("returns a 2D Point object", function () { var marker = new L.Marker([10, 20]); expect(marker.toGeoJSON().geometry).to.eql({ type: 'Point', coordinates: [20, 10] }); }); + + it("returns a 3D Point object", function () { + var marker = new L.Marker([10, 20, 30]); + expect(marker.toGeoJSON().geometry).to.eql({ + type: 'Point', + coordinates: [20, 10, 30] + }); + }); }); describe("L.Circle#toGeoJSON", function () { - it("returns a Point object", function () { + it("returns a 2D Point object", function () { var circle = new L.Circle([10, 20], 100); expect(circle.toGeoJSON().geometry).to.eql({ type: 'Point', coordinates: [20, 10] }); }); + + it("returns a 3D Point object", function () { + var circle = new L.Circle([10, 20, 30], 100); + expect(circle.toGeoJSON().geometry).to.eql({ + type: 'Point', + coordinates: [20, 10, 30] + }); + }); }); describe("L.CircleMarker#toGeoJSON", function () { - it("returns a Point object", function () { + it("returns a 2D Point object", function () { var marker = new L.CircleMarker([10, 20]); expect(marker.toGeoJSON().geometry).to.eql({ type: 'Point', coordinates: [20, 10] }); }); + + it("returns a 3D Point object", function () { + var marker = new L.CircleMarker([10, 20, 30]); + expect(marker.toGeoJSON().geometry).to.eql({ + type: 'Point', + coordinates: [20, 10, 30] + }); + }); }); describe("L.Polyline#toGeoJSON", function () { - it("returns a LineString object", function () { + it("returns a 2D LineString object", function () { var polyline = new L.Polyline([[10, 20], [2, 5]]); expect(polyline.toGeoJSON().geometry).to.eql({ type: 'LineString', coordinates: [[20, 10], [5, 2]] }); }); + + it("returns a 3D LineString object", function () { + var polyline = new L.Polyline([[10, 20, 30], [2, 5, 10]]); + expect(polyline.toGeoJSON().geometry).to.eql({ + type: 'LineString', + coordinates: [[20, 10, 30], [5, 2, 10]] + }); + }); }); describe("L.MultiPolyline#toGeoJSON", function () { - it("returns a MultiLineString object", function () { + it("returns a 2D MultiLineString object", function () { var multiPolyline = new L.MultiPolyline([[[10, 20], [2, 5]], [[1, 2], [3, 4]]]); expect(multiPolyline.toGeoJSON().geometry).to.eql({ type: 'MultiLineString', @@ -74,10 +106,21 @@ describe("L.MultiPolyline#toGeoJSON", function () { ] }); }); + + it("returns a 3D MultiLineString object", function () { + var multiPolyline = new L.MultiPolyline([[[10, 20, 30], [2, 5, 10]], [[1, 2, 3], [4, 5, 6]]]); + expect(multiPolyline.toGeoJSON().geometry).to.eql({ + type: 'MultiLineString', + coordinates: [ + [[20, 10, 30], [5, 2, 10]], + [[2, 1, 3], [5, 4, 6]] + ] + }); + }); }); describe("L.Polygon#toGeoJSON", function () { - it("returns a Polygon object (no holes)", function () { + it("returns a 2D Polygon object (no holes)", function () { var polygon = new L.Polygon([[1, 2], [3, 4], [5, 6]]); expect(polygon.toGeoJSON().geometry).to.eql({ type: 'Polygon', @@ -85,7 +128,15 @@ describe("L.Polygon#toGeoJSON", function () { }); }); - it("returns a Polygon object (with holes)", function () { + it("returns a 3D Polygon object (no holes)", function () { + var polygon = new L.Polygon([[1, 2, 3], [4, 5, 6], [7, 8, 9]]); + expect(polygon.toGeoJSON().geometry).to.eql({ + type: 'Polygon', + coordinates: [[[2, 1, 3], [5, 4, 6], [8, 7, 9], [2, 1, 3]]] + }); + }); + + it("returns a 2D Polygon object (with holes)", function () { var polygon = new L.Polygon([[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]]); expect(polygon.toGeoJSON().geometry).to.eql({ type: 'Polygon', @@ -95,10 +146,21 @@ describe("L.Polygon#toGeoJSON", function () { ] }); }); + + it("returns a 3D Polygon object (with holes)", function () { + var polygon = new L.Polygon([[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16, 17, 18]]]); + expect(polygon.toGeoJSON().geometry).to.eql({ + type: 'Polygon', + coordinates: [ + [[2, 1, 3], [5, 4, 6], [8, 7, 9], [2, 1, 3]], + [[11, 10, 12], [14, 13, 15], [17, 16, 18], [11, 10, 12]] + ] + }); + }); }); describe("L.MultiPolygon#toGeoJSON", function () { - it("returns a MultiPolygon object", function () { + it("returns a 2D MultiPolygon object", function () { var multiPolygon = new L.MultiPolygon([[[1, 2], [3, 4], [5, 6]]]); expect(multiPolygon.toGeoJSON().geometry).to.eql({ type: 'MultiPolygon', @@ -107,10 +169,20 @@ describe("L.MultiPolygon#toGeoJSON", function () { ] }); }); + + it("returns a 3D MultiPolygon object", function () { + var multiPolygon = new L.MultiPolygon([[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]); + expect(multiPolygon.toGeoJSON().geometry).to.eql({ + type: 'MultiPolygon', + coordinates: [ + [[[2, 1, 3], [5, 4, 6], [8, 7, 9], [2, 1, 3]]] + ] + }); + }); }); describe("L.LayerGroup#toGeoJSON", function () { - it("returns a FeatureCollection object", function () { + it("returns a 2D FeatureCollection object", function () { var marker = new L.Marker([10, 20]), polyline = new L.Polyline([[10, 20], [2, 5]]), layerGroup = new L.LayerGroup([marker, polyline]); @@ -120,6 +192,16 @@ describe("L.LayerGroup#toGeoJSON", function () { }); }); + it("returns a 3D FeatureCollection object", function () { + var marker = new L.Marker([10, 20, 30]), + polyline = new L.Polyline([[10, 20, 30], [2, 5, 10]]), + layerGroup = new L.LayerGroup([marker, polyline]); + expect(layerGroup.toGeoJSON()).to.eql({ + type: 'FeatureCollection', + features: [marker.toGeoJSON(), polyline.toGeoJSON()] + }); + }); + it("ensures that every member is a Feature", function () { var tileLayer = new L.TileLayer(), layerGroup = new L.LayerGroup([tileLayer]); diff --git a/src/geo/LatLng.js b/src/geo/LatLng.js index 9e2a453c..26eb709d 100644 --- a/src/geo/LatLng.js +++ b/src/geo/LatLng.js @@ -2,7 +2,7 @@ * L.LatLng represents a geographical point with latitude and longitude coordinates. */ -L.LatLng = function (rawLat, rawLng) { // (Number, Number) +L.LatLng = function (rawLat, rawLng, rawAltitude) { // (Number, Number, Number) var lat = parseFloat(rawLat), lng = parseFloat(rawLng); @@ -12,6 +12,10 @@ L.LatLng = function (rawLat, rawLng) { // (Number, Number) this.lat = lat; this.lng = lng; + + if (typeof rawAltitude !== 'undefined') { + this.altitude = parseFloat(rawAltitude); + } }; L.extend(L.LatLng, { @@ -75,7 +79,7 @@ L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Numbe return a; } if (L.Util.isArray(a)) { - return new L.LatLng(a[0], a[1]); + return new L.LatLng(a[0], a[1], a[2]); } if (a === undefined || a === null) { return a; diff --git a/src/layer/GeoJSON.js b/src/layer/GeoJSON.js index 38cc02d6..04d2ba1c 100644 --- a/src/layer/GeoJSON.js +++ b/src/layer/GeoJSON.js @@ -128,7 +128,7 @@ L.extend(L.GeoJSON, { }, coordsToLatLng: function (coords) { // (Array[, Boolean]) -> LatLng - return new L.LatLng(coords[1], coords[0]); + return new L.LatLng(coords[1], coords[0], coords[2]); }, coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) { // (Array[, Number, Function]) -> Array @@ -147,7 +147,11 @@ L.extend(L.GeoJSON, { }, latLngToCoords: function (latLng) { - return [latLng.lng, latLng.lat]; + if (typeof latLng.altitude === 'undefined') { + return [latLng.lng, latLng.lat]; + } else { + return [latLng.lng, latLng.lat, latLng.altitude]; + } }, latLngsToCoords: function (latLngs) {