1 (function ($, window, undefined) {
2 var pos_oo = Number.POSITIVE_INFINITY,
3 neg_oo = Number.NEGATIVE_INFINITY;
10 _allCoordinates: function (geom) {
11 // return array of all positions in all geometries of geom
13 var geometries = this._flatten(geom),
17 for (; curGeom < geometries.length; curGeom++) {
18 var coordinates = geometries[curGeom].coordinates,
19 isArray = coordinates && $.isArray(coordinates[0]),
20 isDblArray = isArray && $.isArray(coordinates[0][0]),
21 isTriArray = isDblArray && $.isArray(coordinates[0][0][0]),
27 coordinates = [coordinates];
29 coordinates = [coordinates];
31 coordinates = [coordinates];
34 for (i = 0; i < coordinates.length; i++) {
35 for (j = 0; j < coordinates[i].length; j++) {
36 for (k = 0; k < coordinates[i][j].length; k++) {
37 result.push(coordinates[i][j][k]);
45 _isGeodetic: function( coords ) {
46 // returns true if the first coordinate it can find is geodetic
48 while ( $.isArray( coords ) ) {
49 if ( coords.length > 1 && ! $.isArray( coords[ 0 ] ) ) {
50 return ( coords[ 0 ] >= -180 && coords[ 0 ] <= 180 && coords[ 1 ] >= -85 && coords[ 1 ] <= 85 );
63 center: function (bbox, _ignoreGeo /* Internal Use Only */) {
64 // Envelope.centre in JTS
65 // bbox only, use centroid for geom
66 var wasGeodetic = false;
67 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) {
69 bbox = $.geo.proj.fromGeodetic(bbox);
72 var center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
73 return wasGeodetic ? $.geo.proj.toGeodetic(center) : center;
76 expandBy: function (bbox, dx, dy, _ignoreGeo /* Internal Use Only */) {
77 var wasGeodetic = false;
78 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) {
80 bbox = $.geo.proj.fromGeodetic(bbox);
83 bbox = [bbox[0] - dx, bbox[1] - dy, bbox[2] + dx, bbox[3] + dy];
84 return wasGeodetic ? $.geo.proj.toGeodetic(bbox) : bbox;
87 height: function (bbox, _ignoreGeo /* Internal Use Only */ ) {
88 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) {
89 bbox = $.geo.proj.fromGeodetic(bbox);
92 return bbox[3] - bbox[1];
95 _in: function(bbox1, bbox2) {
96 return bbox1[0] <= bbox2[0] &&
97 bbox1[1] <= bbox2[1] &&
98 bbox1[2] >= bbox2[2] &&
102 _bboxDisjoint: function( bbox1, bbox2 ) {
103 return bbox2[ 0 ] > bbox1[ 2 ] ||
104 bbox2[ 2 ] < bbox1[ 0 ] ||
105 bbox2[ 1 ] > bbox1[ 3 ] ||
106 bbox2[ 3 ] < bbox1[ 1 ];
109 reaspect: function (bbox, ratio, _ignoreGeo /* Internal Use Only */ ) {
111 var wasGeodetic = false;
112 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) {
114 bbox = $.geo.proj.fromGeodetic(bbox);
117 var width = this.width(bbox, true),
118 height = this.height(bbox, true),
119 center = this.center(bbox, true),
122 if (width != 0 && height != 0 && ratio > 0) {
123 if (width / height > ratio) {
131 bbox = [center[0] - dx, center[1] - dy, center[0] + dx, center[1] + dy];
134 return wasGeodetic ? $.geo.proj.toGeodetic(bbox) : bbox;
137 recenter: function( bbox, center, _ignoreGeo /* Internal Use Only */ ) {
139 var wasGeodetic = false;
140 if ( !_ignoreGeo && $.geo.proj ) {
141 if ( this._isGeodetic( bbox ) ) {
143 bbox = $.geo.proj.fromGeodetic(bbox);
146 if ( this._isGeodetic( center ) ) {
147 center = $.geo.proj.fromGeodetic(center);
151 var halfWidth = ( bbox[ 2 ] - bbox[ 0 ] ) / 2,
152 halfHeight = ( bbox[ 3 ] - bbox[ 1 ] ) / 2;
155 center[ 0 ] - halfWidth,
156 center[ 1 ] - halfHeight,
157 center[ 0 ] + halfWidth,
158 center[ 1 ] + halfHeight
161 return wasGeodetic ? $.geo.proj.toGeodetic(bbox) : bbox;
164 scaleBy: function ( bbox, scale, _ignoreGeo /* Internal Use Only */ ) {
166 var wasGeodetic = false;
167 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) {
169 bbox = $.geo.proj.fromGeodetic(bbox);
172 var c = this.center(bbox, true),
173 dx = (bbox[2] - bbox[0]) * scale / 2,
174 dy = (bbox[3] - bbox[1]) * scale / 2;
176 bbox = [c[0] - dx, c[1] - dy, c[0] + dx, c[1] + dy];
178 return wasGeodetic ? $.geo.proj.toGeodetic(bbox) : bbox;
181 width: function (bbox, _ignoreGeo /* Internal Use Only */ ) {
182 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( bbox ) ) {
183 bbox = $.geo.proj.fromGeodetic(bbox);
186 return bbox[2] - bbox[0];
190 // geometry functions
193 // bbox (Geometry.getEnvelope in JTS)
195 bbox: function ( geom, _ignoreGeo /* Internal Use Only */ ) {
198 } else if ( geom.bbox ) {
199 result = ( !_ignoreGeo && $.geo.proj && this._isGeodetic( geom.bbox ) ) ? $.geo.proj.fromGeodetic( geom.bbox ) : geom.bbox;
201 result = [ pos_oo, pos_oo, neg_oo, neg_oo ];
203 var coordinates = this._allCoordinates( geom ),
206 if ( coordinates.length == 0 ) {
210 var wasGeodetic = false;
211 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( coordinates ) ) {
213 coordinates = $.geo.proj.fromGeodetic( coordinates );
216 for ( ; curCoord < coordinates.length; curCoord++ ) {
217 result[0] = Math.min(coordinates[curCoord][0], result[0]);
218 result[1] = Math.min(coordinates[curCoord][1], result[1]);
219 result[2] = Math.max(coordinates[curCoord][0], result[2]);
220 result[3] = Math.max(coordinates[curCoord][1], result[3]);
224 return wasGeodetic ? $.geo.proj.toGeodetic(result) : result;
229 centroid: function( geom, _ignoreGeo /* Internal Use Only */ ) {
232 return $.extend({}, geom);
238 coords = $.merge( [ ], geom.type == "Polygon" ? geom.coordinates[0] : geom.coordinates ),
241 var wasGeodetic = false;
242 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( coords ) ) {
244 coords = $.geo.proj.fromGeodetic(coords);
247 //if (coords[0][0] != coords[coords.length - 1][0] || coords[0][1] != coords[coords.length - 1][1]) {
248 // coords.push(coords[0]);
251 for (; i <= coords.length; i++) {
252 j = i % coords.length;
253 n = (coords[i - 1][0] * coords[j][1]) - (coords[j][0] * coords[i - 1][1]);
255 c[0] += (coords[i - 1][0] + coords[j][0]) * n;
256 c[1] += (coords[i - 1][1] + coords[j][1]) * n;
260 if (coords.length > 0) {
263 return { type: "Point", coordinates: wasGeodetic ? $.geo.proj.toGeodetic(c) : c };
273 return { type: "Point", coordinates: wasGeodetic ? $.geo.proj.toGeodetic(c) : c };
280 contains: function (geom1, geom2) {
281 if (geom1.type != "Polygon") {
285 switch (geom2.type) {
287 return this._containsPolygonPoint(geom1.coordinates, geom2.coordinates);
290 return this._containsPolygonLineString(geom1.coordinates, geom2.coordinates);
293 return this._containsPolygonLineString(geom1.coordinates, geom2.coordinates[0]);
300 _containsPolygonPoint: function (polygonCoordinates, pointCoordinate) {
301 if (polygonCoordinates.length == 0 || polygonCoordinates[0].length < 4) {
306 a = polygonCoordinates[0][0],
311 for (; i < polygonCoordinates[0].length; i++) {
312 b = polygonCoordinates[0][i];
314 if ((a[1] <= pointCoordinate[1] && pointCoordinate[1] < b[1]) || (b[1] <= pointCoordinate[1] && pointCoordinate[1] < a[1]) && (pointCoordinate[0] < a[0] || pointCoordinate[0] < b[0])) {
315 x = a[0] + (b[0] - a[0]) * (pointCoordinate[1] - a[1]) / (b[1] - a[1]);
317 if (x > pointCoordinate[0]) {
325 return rayCross % 2 == 1;
328 _containsPolygonLineString: function (polygonCoordinates, lineStringCoordinates) {
329 for (var i = 0; i < lineStringCoordinates.length; i++) {
330 if (!this._containsPolygonPoint(polygonCoordinates, lineStringCoordinates[i])) {
339 distance: function ( geom1, geom2, _ignoreGeo /* Internal Use Only */ ) {
340 var geom1CoordinatesProjected = ( !_ignoreGeo && $.geo.proj && this._isGeodetic( geom1.coordinates ) ) ? $.geo.proj.fromGeodetic(geom1.coordinates) : geom1.coordinates,
341 geom2CoordinatesProjected = ( !_ignoreGeo && $.geo.proj && this._isGeodetic( geom2.coordinates ) ) ? $.geo.proj.fromGeodetic(geom2.coordinates) : geom2.coordinates;
343 switch (geom1.type) {
345 switch (geom2.type) {
347 return this._distancePointPoint(geom2CoordinatesProjected, geom1CoordinatesProjected);
349 return this._distanceLineStringPoint(geom2CoordinatesProjected, geom1CoordinatesProjected);
351 return this._containsPolygonPoint(geom2CoordinatesProjected, geom1CoordinatesProjected) ? 0 : this._distanceLineStringPoint(geom2CoordinatesProjected[0], geom1CoordinatesProjected);
358 switch (geom2.type) {
360 return this._distanceLineStringPoint(geom1CoordinatesProjected, geom2CoordinatesProjected);
362 return this._distanceLineStringLineString(geom1CoordinatesProjected, geom2CoordinatesProjected);
364 return this._containsPolygonLineString(geom2CoordinatesProjected, geom1CoordinatesProjected) ? 0 : this._distanceLineStringLineString(geom2CoordinatesProjected[0], geom1CoordinatesProjected);
371 switch (geom2.type) {
373 return this._containsPolygonPoint(geom1CoordinatesProjected, geom2CoordinatesProjected) ? 0 : this._distanceLineStringPoint(geom1CoordinatesProjected[0], geom2CoordinatesProjected);
375 return this._containsPolygonLineString(geom1CoordinatesProjected, geom2CoordinatesProjected) ? 0 : this._distanceLineStringLineString(geom1CoordinatesProjected[0], geom2CoordinatesProjected);
377 return this._containsPolygonLineString(geom1CoordinatesProjected, geom2CoordinatesProjected[0]) ? 0 : this._distanceLineStringLineString(geom1CoordinatesProjected[0], geom2CoordinatesProjected[0]);
385 _distancePointPoint: function (coordinate1, coordinate2) {
386 var dx = coordinate2[0] - coordinate1[0],
387 dy = coordinate2[1] - coordinate1[1];
388 return Math.sqrt((dx * dx) + (dy * dy));
391 _distanceLineStringPoint: function (lineStringCoordinates, pointCoordinate) {
392 var minDist = pos_oo;
394 if (lineStringCoordinates.length > 0) {
395 var a = lineStringCoordinates[0],
397 apx = pointCoordinate[0] - a[0],
398 apy = pointCoordinate[1] - a[1];
400 if (lineStringCoordinates.length == 1) {
401 return Math.sqrt(apx * apx + apy * apy);
403 for (var i = 1; i < lineStringCoordinates.length; i++) {
404 var b = lineStringCoordinates[i],
408 bpx = pointCoordinate[0] - b[0],
409 bpy = pointCoordinate[1] - b[1],
411 d = this._distanceSegmentPoint(abx, aby, apx, apy, bpx, bpy);
428 return Math.sqrt(minDist);
431 _distanceSegmentPoint: function (abx, aby, apx, apy, bpx, bpy) {
432 var dot1 = abx * apx + aby * apy;
435 return apx * apx + apy * apy;
438 var dot2 = abx * abx + aby * aby;
441 return bpx * bpx + bpy * bpy;
444 return apx * apx + apy * apy - dot1 * dot1 / dot2;
447 _distanceLineStringLineString: function (lineStringCoordinates1, lineStringCoordinates2) {
448 var minDist = pos_oo;
449 for (var i = 0; i < lineStringCoordinates2.length; i++) {
450 minDist = Math.min(minDist, this._distanceLineStringPoint(lineStringCoordinates1, lineStringCoordinates2[i]));
457 _buffer: function( geom, distance, _ignoreGeo /* Internal Use Only */ ) {
458 var wasGeodetic = false,
459 coords = geom.coordinates;
461 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( geom.coordinates ) ) {
463 coords = $.geo.proj.fromGeodetic( geom.coordinates );
466 switch ( geom.type ) {
468 var resultCoords = [],
473 for ( ; i <= slices; i++ ) {
474 a = ( i * 360 / slices ) * ( Math.PI / 180 );
476 coords[ 0 ] + Math.cos( a ) * distance,
477 coords[ 1 ] + Math.sin( a ) * distance
483 coordinates: [ ( wasGeodetic ? $.geo.proj.toGeodetic( resultCoords ) : resultCoords ) ]
498 _flatten: function (geom) {
499 // return an array of all basic geometries
505 $.merge(geometries, this._flatten(geom.geometry));
508 case "FeatureCollection":
509 for (; curGeom < geom.features.length; curGeom++) {
510 $.merge(geometries, this._flatten(geom.features[curGeom].geometry));
514 case "GeometryCollection":
515 for (; curGeom < geom.geometries.length; curGeom++) {
516 $.merge(geometries, this._flatten(geom.geometries[curGeom]));
521 geometries[0] = geom;
527 length: function( geom, _ignoreGeo /* Internal Use Only */ ) {
529 lineStringCoordinates,
532 switch ( geom.type ) {
537 lineStringCoordinates = geom.coordinates;
541 lineStringCoordinates = geom.coordinates[ 0 ];
545 if ( lineStringCoordinates ) {
546 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( lineStringCoordinates ) ) {
547 lineStringCoordinates = $.geo.proj.fromGeodetic( lineStringCoordinates );
550 for ( ; i < lineStringCoordinates.length; i++ ) {
551 dx = lineStringCoordinates[ i ][0] - lineStringCoordinates[ i - 1 ][0];
552 dy = lineStringCoordinates[ i ][1] - lineStringCoordinates[ i - 1 ][1];
553 sum += Math.sqrt((dx * dx) + (dy * dy));
562 area: function( geom, _ignoreGeo /* Internal Use Only */ ) {
567 switch ( geom.type ) {
573 polygonCoordinates = geom.coordinates[ 0 ];
577 if ( polygonCoordinates ) {
578 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( polygonCoordinates ) ) {
579 polygonCoordinates = $.geo.proj.fromGeodetic( polygonCoordinates );
582 for ( ; i <= polygonCoordinates.length; i++) {
583 j = i % polygonCoordinates.length;
584 sum += ( polygonCoordinates[ i - 1 ][ 0 ] - polygonCoordinates[ j ][ 0 ] ) * ( polygonCoordinates[ i - 1 ][ 1 ] + polygonCoordinates[ j ][ 1 ] ) / 2;
587 return Math.abs( sum );
591 pointAlong: function( geom, percentage, _ignoreGeo /* Internal Use Only */ ) {
593 previousPercentageSum = 0,
595 remainderPercentageSum,
597 lineStringCoordinates,
603 switch ( geom.type ) {
605 return $.extend( { }, geom );
608 lineStringCoordinates = geom.coordinates;
612 lineStringCoordinates = geom.coordinates[ 0 ];
616 if ( lineStringCoordinates ) {
617 if ( percentage === 0 ) {
620 coordinates: [ lineStringCoordinates[ 0 ][ 0 ], lineStringCoordinates[ 0 ][ 1 ] ]
622 } else if ( percentage === 1 ) {
623 i = lineStringCoordinates.length - 1;
626 coordinates: [ lineStringCoordinates[ i ][ 0 ], lineStringCoordinates[ i ][ 1 ] ]
629 if ( !_ignoreGeo && $.geo.proj && this._isGeodetic( lineStringCoordinates ) ) {
631 lineStringCoordinates = $.geo.proj.fromGeodetic( lineStringCoordinates );
634 for ( ; i < lineStringCoordinates.length; i++ ) {
635 dx = lineStringCoordinates[ i ][ 0 ] - lineStringCoordinates[ i - 1 ][ 0 ];
636 dy = lineStringCoordinates[ i ][ 1 ] - lineStringCoordinates[ i - 1 ][ 1 ];
637 len = Math.sqrt((dx * dx) + (dy * dy));
638 segmentLengths.push( len );
642 for ( i = 0; i < segmentLengths.length && percentageSum < percentage; i++ ) {
643 previousPercentageSum = percentageSum;
644 percentageSum += ( segmentLengths[ i ] / totalLength );
647 remainderPercentageSum = percentage - previousPercentageSum;
649 c0 = lineStringCoordinates[ i - 1 ];
650 c1 = lineStringCoordinates[ i ];
653 c0[ 0 ] + ( remainderPercentageSum * ( c1[ 0 ] - c0[ 0 ] ) ),
654 c0[ 1 ] + ( remainderPercentageSum * ( c1[ 1 ] - c0[ 1 ] ) )
659 coordinates: wasGeodetic ? $.geo.proj.toGeodetic(c) : c
670 function pointToString(value) {
671 return "POINT " + pointToUntaggedString(value.coordinates);
674 function pointToUntaggedString(coordinates) {
675 if (!(coordinates && coordinates.length)) {
678 return "(" + coordinates.join(" ") + ")";
682 function lineStringToString(value) {
683 return "LINESTRING " + lineStringToUntaggedString(value.coordinates);
686 function lineStringToUntaggedString(coordinates) {
687 if (!(coordinates && coordinates.length)) {
692 for (var i = 0; i < coordinates.length; i++) {
693 points.push(coordinates[i].join(" "));
696 return "(" + points + ")";
700 function polygonToString(value) {
701 return "POLYGON " + polygonToUntaggedString(value.coordinates);
704 function polygonToUntaggedString(coordinates) {
705 if (!(coordinates && coordinates.length)) {
708 var lineStrings = [];
710 for (var i = 0; i < coordinates.length; i++) {
711 lineStrings.push(lineStringToUntaggedString(coordinates[i]));
714 return "(" + lineStrings + ")";
718 function multiPointToString(value) {
719 return "MULTIPOINT " + lineStringToUntaggedString(value.coordinates);
722 function multiLineStringToString(value) {
723 return "MULTILINSTRING " + polygonToUntaggedString(value.coordinates);
726 function multiPolygonToString(value) {
727 return "MULTIPOLYGON " + multiPolygonToUntaggedString(value.coordinates);
730 function multiPolygonToUntaggedString(coordinates) {
731 if (!(coordinates && coordinates.length)) {
735 for (var i = 0; i < coordinates.length; i++) {
736 polygons.push(polygonToUntaggedString(coordinates[i]));
738 return "(" + polygons + ")";
742 function geometryCollectionToString(value) {
743 return "GEOMETRYCOLLECTION " + geometryCollectionToUntaggedString(value.geometries);
746 function geometryCollectionToUntaggedString(geometries) {
747 if (!(geometries && geometries.length)) {
750 var geometryText = [];
751 for (var i = 0; i < geometries.length; i++) {
752 geometryText.push(stringify(geometries[i]));
754 return "(" + geometries + ")";
758 function stringify(value) {
759 if (!(value && value.type)) {
762 switch (value.type) {
764 return pointToString(value);
767 return lineStringToString(value);
770 return polygonToString(value);
773 return multiPointToString(value);
775 case "MultiLineString":
776 return multiLineStringToString(value);
779 return multiPolygonToString(value);
781 case "GeometryCollection":
782 return geometryCollectionToString(value);
790 function pointParseUntagged(wkt) {
791 var pointString = wkt.match( /\(\s*([\d\.-]+)\s+([\d\.-]+)\s*\)/ );
792 return pointString && pointString.length > 2 ? {
795 parseFloat(pointString[1]),
796 parseFloat(pointString[2])
801 function lineStringParseUntagged(wkt) {
802 var lineString = wkt.match( /\s*\((.*)\)/ ),
808 if ( lineString.length > 1 ) {
809 pointStrings = lineString[ 1 ].match( /[\d\.-]+\s+[\d\.-]+/g );
811 for ( ; i < pointStrings.length; i++ ) {
812 pointParts = pointStrings[ i ].match( /\s*([\d\.-]+)\s+([\d\.-]+)\s*/ );
813 coords[ i ] = [ parseFloat( pointParts[ 1 ] ), parseFloat( pointParts[ 2 ] ) ];
825 function polygonParseUntagged(wkt) {
826 var polygon = wkt.match( /\s*\(\s*\((.*)\)\s*\)/ ),
832 if ( polygon.length > 1 ) {
833 pointStrings = polygon[ 1 ].match( /[\d\.-]+\s+[\d\.-]+/g );
835 for ( ; i < pointStrings.length; i++ ) {
836 pointParts = pointStrings[ i ].match( /\s*([\d\.-]+)\s+([\d\.-]+)\s*/ );
837 coords[ i ] = [ parseFloat( pointParts[ 1 ] ), parseFloat( pointParts[ 2 ] ) ];
842 coordinates: [ coords ]
849 function parse(wkt) {
852 var typeIndex = wkt.indexOf( " " ),
853 untagged = wkt.substr( typeIndex + 1 );
855 switch (wkt.substr(0, typeIndex).toUpperCase()) {
857 return pointParseUntagged( untagged );
860 return lineStringParseUntagged( untagged );
863 return polygonParseUntagged( untagged );
871 stringify: stringify,
878 // projection functions
882 var halfPi = 1.5707963267948966192,
883 quarterPi = 0.7853981633974483096,
884 radiansPerDegree = 0.0174532925199432958,
885 degreesPerRadian = 57.295779513082320877,
886 semiMajorAxis = 6378137;
889 fromGeodeticPos: function (coordinate) {
894 semiMajorAxis * coordinate[ 0 ] * radiansPerDegree,
895 semiMajorAxis * Math.log(Math.tan(quarterPi + coordinate[ 1 ] * radiansPerDegree / 2))
899 fromGeodetic: function ( coordinates ) {
900 if ( ! $.geo._isGeodetic( coordinates ) ) {
904 var isMultiPointOrLineString = $.isArray(coordinates[ 0 ]),
905 fromGeodeticPos = this.fromGeodeticPos;
907 if (!isMultiPointOrLineString && coordinates.length == 4) {
909 var min = fromGeodeticPos([ coordinates[ 0 ], coordinates[ 1 ] ]),
910 max = fromGeodeticPos([ coordinates[ 2 ], coordinates[ 3 ] ]);
911 return [ min[ 0 ], min[ 1 ], max[ 0 ], max[ 1 ] ];
914 var isMultiLineStringOrPolygon = isMultiPointOrLineString && $.isArray(coordinates[ 0 ][ 0 ]),
915 isMultiPolygon = isMultiLineStringOrPolygon && $.isArray(coordinates[ 0 ][ 0 ][ 0 ]),
919 if (!isMultiPolygon) {
920 if (!isMultiLineStringOrPolygon) {
921 if (!isMultiPointOrLineString) {
922 coordinates = [ coordinates ];
924 coordinates = [ coordinates ];
926 coordinates = [ coordinates ];
929 for ( i = 0; i < coordinates.length; i++ ) {
931 for ( j = 0; j < coordinates[ i ].length; j++ ) {
932 result[ i ][ j ] = [ ];
933 for ( k = 0; k < coordinates[ i ][ j ].length; k++ ) {
934 result[ i ][ j ][ k ] = fromGeodeticPos(coordinates[ i ][ j ][ k ]);
939 return isMultiPolygon ? result : isMultiLineStringOrPolygon ? result[ 0 ] : isMultiPointOrLineString ? result[ 0 ][ 0 ] : result[ 0 ][ 0 ][ 0 ];
943 toGeodeticPos: function (coordinate) {
945 (coordinate[ 0 ] / semiMajorAxis) * degreesPerRadian,
946 (halfPi - 2 * Math.atan(1 / Math.exp(coordinate[ 1 ] / semiMajorAxis))) * degreesPerRadian
950 toGeodetic: function (coordinates) {
951 if ( $.geo._isGeodetic( coordinates ) ) {
955 var isMultiPointOrLineString = $.isArray(coordinates[ 0 ]),
956 toGeodeticPos = this.toGeodeticPos;
958 if (!isMultiPointOrLineString && coordinates.length == 4) {
960 var min = toGeodeticPos([ coordinates[ 0 ], coordinates[ 1 ] ]),
961 max = toGeodeticPos([ coordinates[ 2 ], coordinates[ 3 ] ]);
962 return [ min[ 0 ], min[ 1 ], max[ 0 ], max[ 1 ] ];
965 var isMultiLineStringOrPolygon = isMultiPointOrLineString && $.isArray(coordinates[ 0 ][ 0 ]),
966 isMultiPolygon = isMultiLineStringOrPolygon && $.isArray(coordinates[ 0 ][ 0 ][ 0 ]),
969 if (!isMultiPolygon) {
970 if (!isMultiLineStringOrPolygon) {
971 if (!isMultiPointOrLineString) {
972 coordinates = [ coordinates ];
974 coordinates = [ coordinates ];
976 coordinates = [ coordinates ];
979 for ( i = 0; i < coordinates.length; i++ ) {
981 for ( j = 0; j < coordinates[ i ].length; j++ ) {
982 result[ i ][ j ] = [ ];
983 for ( k = 0; k < coordinates[ i ][ j ].length; k++ ) {
984 result[ i ][ j ][ k ] = toGeodeticPos(coordinates[ i ][ j ][ k ]);
989 return isMultiPolygon ? result : isMultiLineStringOrPolygon ? result[ 0 ] : isMultiPointOrLineString ? result[ 0 ][ 0 ] : result[ 0 ][ 0 ][ 0 ];
996 // service types (defined in other files)