diff --git a/src/ol/array.js b/src/ol/array.js index 9bd4df5a7a..6c0e28ab62 100644 --- a/src/ol/array.js +++ b/src/ol/array.js @@ -1,16 +1,50 @@ goog.provide('ol.array'); -goog.require('goog.array'); goog.require('goog.asserts'); +/** + * Performs a binary search on the provided sorted list and returns the index of the item if found. If it can't be found it'll return -1. + * https://github.com/darkskyapp/binary-search + * + * @param {Array.<*>} haystack Items to search through. + * @param {*} needle The item to look for. + * @param {Function=} opt_comparator Comparator function. + * @return {number} The index of the item if found, -1 if not. + */ +ol.array.binarySearch = function(haystack, needle, opt_comparator) { + var mid, cmp; + var comparator = opt_comparator || ol.array.numberSafeCompareFunction; + var low = 0; + var high = haystack.length; + var found = false; + + while (low < high) { + /* Note that "(low + high) >>> 1" may overflow, and results in a typecast + * to double (which gives the wrong results). */ + mid = low + (high - low >> 1); + cmp = +comparator(haystack[mid], needle); + + if (cmp < 0.0) { /* Too low. */ + low = mid + 1; + + } else { /* Key found or too high */ + high = mid; + found = !cmp; + } + } + + /* Key not found. */ + return found ? low : ~low; +} + /** * @param {Array.} arr Array. * @param {number} target Target. * @return {number} Index. */ ol.array.binaryFindNearest = function(arr, target) { - var index = goog.array.binarySearch(arr, target, + var index = ol.array.binarySearch(arr, target, /** * @param {number} a A. * @param {number} b B. @@ -127,3 +161,143 @@ ol.array.reverseSubArray = function(arr, begin, end) { --end; } }; + + +/** + * @param {Array.<*>} arr Array. + * @return {!Array.} Flattened Array. + */ +ol.array.flatten = function(arr) { + var data = arr.reduce(function(flattened, value) { + if (goog.isArray(value)) { + return flattened.concat(ol.array.flatten(value)); + } else { + return flattened.concat(value); + } + }, []); + return data; +}; + + +/** + * @param {Array.} arr The array to modify. + * @param {Array.|VALUE} data The elements or arrays of elements + * to add to arr. + * @template VALUE + */ +ol.array.extend = function(arr, data) { + var i; + var extension = goog.isArrayLike(data) ? data : [data]; + var length = extension.length + for (i = 0; i < length; i++) { + arr[arr.length] = extension[i]; + } +} + + +/** + * @param {Array.} arr The array to modify. + * @param {VALUE} obj The element to remove. + * @template VALUE + * @return {boolean} If the element was removed. + */ +ol.array.remove = function(arr, obj) { + var i = arr.indexOf(obj); + var found = i > -1; + if (found) { + arr.splice(i, 1); + } + return found; +} + + +/** + * @param {Array.} arr The array to search in. + * @param {function(VALUE, number, ?) : boolean} func The function to compare. + * @template VALUE + * @return {VALUE} The element found. + */ +ol.array.find = function(arr, func) { + var length = arr.length >>> 0; + var value; + + for (var i = 0; i < length; i++) { + value = arr[i]; + if (func(value, i, arr)) { + return value; + } + } + return null; +} + + +/** +* @param {Array|Uint8ClampedArray} arr1 The first array to compare. +* @param {Array|Uint8ClampedArray} arr2 The second array to compare. +* @return {boolean} Whether the two arrays are equal. + */ +ol.array.equals = function(arr1, arr2) { + var len1 = arr1.length; + if (len1 !== arr2.length) { + return false; + } + for (var i = 0; i < len1; i++) { + if (arr1[i] !== arr2[i]) { + return false; + } + } + return true; +} + + +/** +* @param {Array.<*>} arr The array to sort (modifies original). +* @param {Function} compareFnc Comparison function. + */ +ol.array.stableSort = function(arr, compareFnc) { + var length = arr.length; + var tmp = Array(arr.length); + var i; + for (i = 0; i < length; i++) { + tmp[i] = {index: i, value: arr[i]}; + } + tmp.sort(function(a, b) { + return compareFnc(a.value, b.value) || a.index - b.index; + }); + for (i = 0; i < arr.length; i++) { + arr[i] = tmp[i].value; + } +} + + +/** +* @param {Array.<*>} arr The array to search in. +* @param {Function} func Comparison function. +* @return {number} Return index. + */ +ol.array.findIndex = function(arr, func) { + var index; + var found = !arr.every(function(el, idx) { + index = idx; + return !func(el, idx, arr); + }); + return found ? index : -1; +} + + +/** +* @param {Array.<*>} arr The array to test. +* @param {Function=} opt_func Comparison function. +* @param {boolean=} opt_strict Strictly sorted (default false). +* @return {boolean} Return index. + */ +ol.array.isSorted = function(arr, opt_func, opt_strict) { + var compare = opt_func || ol.array.numberSafeCompareFunction; + return arr.every(function(currentVal, index) { + if (index === 0) { + return true; + } + var res = compare(arr[index - 1], currentVal); + return !(res > 0 || opt_strict && res === 0); + }); +} diff --git a/src/ol/collection.js b/src/ol/collection.js index 005947634c..fff2bcd803 100644 --- a/src/ol/collection.js +++ b/src/ol/collection.js @@ -7,7 +7,6 @@ goog.provide('ol.Collection'); goog.provide('ol.CollectionEvent'); goog.provide('ol.CollectionEventType'); -goog.require('goog.array'); goog.require('goog.events.Event'); goog.require('ol.Object'); @@ -180,7 +179,7 @@ ol.Collection.prototype.getLength = function() { * @api stable */ ol.Collection.prototype.insertAt = function(index, elem) { - goog.array.insertAt(this.array_, elem, index); + this.array_.splice(index, 0, elem); this.updateLength_(); this.dispatchEvent( new ol.CollectionEvent(ol.CollectionEventType.ADD, elem, this)); @@ -238,7 +237,7 @@ ol.Collection.prototype.remove = function(elem) { */ ol.Collection.prototype.removeAt = function(index) { var prev = this.array_[index]; - goog.array.removeAt(this.array_, index); + this.array_.splice(index, 1); this.updateLength_(); this.dispatchEvent( new ol.CollectionEvent(ol.CollectionEventType.REMOVE, prev, this)); diff --git a/src/ol/format/esrijsonformat.js b/src/ol/format/esrijsonformat.js index 5831756aa5..7d62c8d00d 100644 --- a/src/ol/format/esrijsonformat.js +++ b/src/ol/format/esrijsonformat.js @@ -1,8 +1,8 @@ goog.provide('ol.format.EsriJSON'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.object'); +goog.require('ol.array'); goog.require('ol.Feature'); goog.require('ol.extent'); goog.require('ol.format.Feature'); @@ -104,7 +104,7 @@ ol.format.EsriJSON.convertRings_ = function(rings, layout) { var holes = []; var i, ii; for (i = 0, ii = rings.length; i < ii; ++i) { - var flatRing = goog.array.flatten(rings[i]); + var flatRing = ol.array.flatten(rings[i]); // is this ring an outer ring? is it clockwise? var clockwise = ol.geom.flat.orient.linearRingIsClockwise(flatRing, 0, flatRing.length, layout.length); diff --git a/src/ol/format/gml/gml3format.js b/src/ol/format/gml/gml3format.js index 30242c0a60..7fa417d5fe 100644 --- a/src/ol/format/gml/gml3format.js +++ b/src/ol/format/gml/gml3format.js @@ -1,11 +1,11 @@ goog.provide('ol.format.GML'); goog.provide('ol.format.GML3'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.object'); goog.require('ol'); +goog.require('ol.array'); goog.require('ol.Feature'); goog.require('ol.extent'); goog.require('ol.format.Feature'); @@ -305,7 +305,7 @@ ol.format.GML3.prototype.readSurface_ = function(node, objectStack) { var ends = [flatCoordinates.length]; var i, ii; for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); + ol.array.extend(flatCoordinates, flatLinearRings[i]); ends.push(flatCoordinates.length); } polygon.setFlatCoordinates( diff --git a/src/ol/format/gml/gmlbaseformat.js b/src/ol/format/gml/gmlbaseformat.js index 6a50ba5ac2..54d3626aa8 100644 --- a/src/ol/format/gml/gmlbaseformat.js +++ b/src/ol/format/gml/gmlbaseformat.js @@ -3,11 +3,11 @@ // envelopes/extents, only geometries! goog.provide('ol.format.GMLBase'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.object'); goog.require('goog.string'); +goog.require('ol.array'); goog.require('ol.Feature'); goog.require('ol.format.Feature'); goog.require('ol.format.XMLFeature'); @@ -451,7 +451,7 @@ ol.format.GMLBase.prototype.readPolygon = function(node, objectStack) { var ends = [flatCoordinates.length]; var i, ii; for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); + ol.array.extend(flatCoordinates, flatLinearRings[i]); ends.push(flatCoordinates.length); } polygon.setFlatCoordinates( diff --git a/src/ol/format/kmlformat.js b/src/ol/format/kmlformat.js index d853520b85..3cec0193f0 100644 --- a/src/ol/format/kmlformat.js +++ b/src/ol/format/kmlformat.js @@ -7,7 +7,6 @@ goog.provide('ol.format.KML'); goog.require('goog.Uri'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.object'); @@ -1021,7 +1020,7 @@ ol.format.KML.readMultiGeometry_ = function(node, objectStack) { 'geometry should be an ol.geom.Point'); goog.asserts.assert(geometry.getLayout() == layout, 'geometry layout should be consistent'); - goog.array.extend(flatCoordinates, geometry.getFlatCoordinates()); + ol.array.extend(flatCoordinates, geometry.getFlatCoordinates()); } var multiPoint = new ol.geom.MultiPoint(null); multiPoint.setFlatCoordinates(layout, flatCoordinates); @@ -1100,7 +1099,7 @@ ol.format.KML.readPolygon_ = function(node, objectStack) { var ends = [flatCoordinates.length]; var i, ii; for (i = 1, ii = flatLinearRings.length; i < ii; ++i) { - goog.array.extend(flatCoordinates, flatLinearRings[i]); + ol.array.extend(flatCoordinates, flatLinearRings[i]); ends.push(flatCoordinates.length); } polygon.setFlatCoordinates( @@ -1955,7 +1954,7 @@ ol.format.KML.prototype.readFeaturesFromNode = function(node, opt_options) { for (n = node.firstElementChild; n; n = n.nextElementSibling) { var fs = this.readFeaturesFromNode(n, opt_options); if (fs) { - goog.array.extend(features, fs); + ol.array.extend(features, fs); } } return features; @@ -2044,14 +2043,14 @@ ol.format.KML.prototype.readNameFromNode = function(node) { ol.format.KML.prototype.readNetworkLinks = function(source) { var networkLinks = []; if (ol.xml.isDocument(source)) { - goog.array.extend(networkLinks, this.readNetworkLinksFromDocument( + ol.array.extend(networkLinks, this.readNetworkLinksFromDocument( /** @type {Document} */ (source))); } else if (ol.xml.isNode(source)) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode( + ol.array.extend(networkLinks, this.readNetworkLinksFromNode( /** @type {Node} */ (source))); } else if (goog.isString(source)) { var doc = ol.xml.parse(source); - goog.array.extend(networkLinks, this.readNetworkLinksFromDocument(doc)); + ol.array.extend(networkLinks, this.readNetworkLinksFromDocument(doc)); } else { goog.asserts.fail('unknown type for source'); } @@ -2067,7 +2066,7 @@ ol.format.KML.prototype.readNetworkLinksFromDocument = function(doc) { var n, networkLinks = []; for (n = doc.firstChild; n; n = n.nextSibling) { if (n.nodeType == goog.dom.NodeType.ELEMENT) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); + ol.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); } } return networkLinks; @@ -2094,7 +2093,7 @@ ol.format.KML.prototype.readNetworkLinksFromNode = function(node) { (localName == 'Document' || localName == 'Folder' || localName == 'kml')) { - goog.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); + ol.array.extend(networkLinks, this.readNetworkLinksFromNode(n)); } } return networkLinks; diff --git a/src/ol/format/osmxmlformat.js b/src/ol/format/osmxmlformat.js index 398ece9a71..54630e5526 100644 --- a/src/ol/format/osmxmlformat.js +++ b/src/ol/format/osmxmlformat.js @@ -1,10 +1,10 @@ // FIXME add typedef for stack state objects goog.provide('ol.format.OSMXML'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.object'); +goog.require('ol.array'); goog.require('ol.Feature'); goog.require('ol.format.Feature'); goog.require('ol.format.XMLFeature'); @@ -103,7 +103,7 @@ ol.format.OSMXML.readWay_ = function(node, objectStack) { var flatCoordinates = /** @type {Array.} */ ([]); for (var i = 0, ii = values.ndrefs.length; i < ii; i++) { var point = state.nodes[values.ndrefs[i]]; - goog.array.extend(flatCoordinates, point); + ol.array.extend(flatCoordinates, point); } var geometry; if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) { diff --git a/src/ol/format/wmsgetfeatureinfoformat.js b/src/ol/format/wmsgetfeatureinfoformat.js index 0157b197fe..a9af65ae14 100644 --- a/src/ol/format/wmsgetfeatureinfoformat.js +++ b/src/ol/format/wmsgetfeatureinfoformat.js @@ -1,6 +1,5 @@ goog.provide('ol.format.WMSGetFeatureInfo'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.object'); @@ -118,7 +117,7 @@ ol.format.WMSGetFeatureInfo.prototype.readFeatures_ = function(node, objectStack var layerFeatures = ol.xml.pushParseAndPop( [], parsersNS, layer, objectStack, this.gmlFormat_); if (layerFeatures) { - goog.array.extend(features, layerFeatures); + ol.array.extend(features, layerFeatures); } } } diff --git a/src/ol/format/xmlfeatureformat.js b/src/ol/format/xmlfeatureformat.js index 76b86baf6b..49e3288258 100644 --- a/src/ol/format/xmlfeatureformat.js +++ b/src/ol/format/xmlfeatureformat.js @@ -1,9 +1,9 @@ goog.provide('ol.format.XMLFeature'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.dom.xml'); +goog.require('ol.array'); goog.require('ol.format.Feature'); goog.require('ol.format.FormatType'); goog.require('ol.proj'); @@ -108,7 +108,7 @@ ol.format.XMLFeature.prototype.readFeaturesFromDocument = function( var n; for (n = doc.firstChild; n; n = n.nextSibling) { if (n.nodeType == goog.dom.NodeType.ELEMENT) { - goog.array.extend(features, this.readFeaturesFromNode(n, opt_options)); + ol.array.extend(features, this.readFeaturesFromNode(n, opt_options)); } } return features; diff --git a/src/ol/geom/flat/interpolateflatgeom.js b/src/ol/geom/flat/interpolateflatgeom.js index 896b1028bd..ef76bbcef0 100644 --- a/src/ol/geom/flat/interpolateflatgeom.js +++ b/src/ol/geom/flat/interpolateflatgeom.js @@ -1,8 +1,8 @@ goog.provide('ol.geom.flat.interpolate'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.math'); +goog.require('ol.array'); /** @@ -15,6 +15,7 @@ goog.require('goog.math'); * @return {Array.} Destination. */ ol.geom.flat.interpolate.lineString = function(flatCoordinates, offset, end, stride, fraction, opt_dest) { + // FIXME does not work when vertices are repeated // FIXME interpolate extra dimensions goog.asserts.assert(0 <= fraction && fraction <= 1, 'fraction should be in between 0 and 1'); @@ -46,7 +47,7 @@ ol.geom.flat.interpolate.lineString = function(flatCoordinates, offset, end, str y1 = y2; } var target = fraction * length; - var index = goog.array.binarySearch(cumulativeLengths, target); + var index = ol.array.binarySearch(cumulativeLengths, target); if (index < 0) { var t = (target - cumulativeLengths[-index - 2]) / (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]); diff --git a/src/ol/geom/linestring.js b/src/ol/geom/linestring.js index 2be2b21b10..4d8722584c 100644 --- a/src/ol/geom/linestring.js +++ b/src/ol/geom/linestring.js @@ -1,8 +1,8 @@ goog.provide('ol.geom.LineString'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('ol'); +goog.require('ol.array'); goog.require('ol.extent'); goog.require('ol.geom.GeometryLayout'); goog.require('ol.geom.GeometryType'); @@ -72,7 +72,7 @@ ol.geom.LineString.prototype.appendCoordinate = function(coordinate) { if (!this.flatCoordinates) { this.flatCoordinates = coordinate.slice(); } else { - goog.array.extend(this.flatCoordinates, coordinate); + ol.array.extend(this.flatCoordinates, coordinate); } this.changed(); }; diff --git a/src/ol/geom/multilinestring.js b/src/ol/geom/multilinestring.js index fce9293baf..81b91f22b6 100644 --- a/src/ol/geom/multilinestring.js +++ b/src/ol/geom/multilinestring.js @@ -1,8 +1,8 @@ goog.provide('ol.geom.MultiLineString'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('ol'); +goog.require('ol.array'); goog.require('ol.extent'); goog.require('ol.geom.GeometryLayout'); goog.require('ol.geom.GeometryType'); @@ -65,7 +65,7 @@ ol.geom.MultiLineString.prototype.appendLineString = function(lineString) { if (!this.flatCoordinates) { this.flatCoordinates = lineString.getFlatCoordinates().slice(); } else { - goog.array.extend( + ol.array.extend( this.flatCoordinates, lineString.getFlatCoordinates().slice()); } this.ends_.push(this.flatCoordinates.length); @@ -216,7 +216,7 @@ ol.geom.MultiLineString.prototype.getFlatMidpoints = function() { var end = ends[i]; var midpoint = ol.geom.flat.interpolate.lineString( flatCoordinates, offset, end, stride, 0.5); - goog.array.extend(midpoints, midpoint); + ol.array.extend(midpoints, midpoint); offset = end; } return midpoints; @@ -319,7 +319,7 @@ ol.geom.MultiLineString.prototype.setLineStrings = function(lineStrings) { goog.asserts.assert(lineString.getLayout() == layout, 'layout of lineString should match layout'); } - goog.array.extend(flatCoordinates, lineString.getFlatCoordinates()); + ol.array.extend(flatCoordinates, lineString.getFlatCoordinates()); ends.push(flatCoordinates.length); } this.setFlatCoordinates(layout, flatCoordinates, ends); diff --git a/src/ol/geom/multipoint.js b/src/ol/geom/multipoint.js index 5a8d9d1201..b9eaae92a5 100644 --- a/src/ol/geom/multipoint.js +++ b/src/ol/geom/multipoint.js @@ -1,7 +1,7 @@ goog.provide('ol.geom.MultiPoint'); -goog.require('goog.array'); goog.require('goog.asserts'); +goog.require('ol.array'); goog.require('ol.extent'); goog.require('ol.geom.GeometryLayout'); goog.require('ol.geom.GeometryType'); @@ -40,7 +40,7 @@ ol.geom.MultiPoint.prototype.appendPoint = function(point) { if (!this.flatCoordinates) { this.flatCoordinates = point.getFlatCoordinates().slice(); } else { - goog.array.extend(this.flatCoordinates, point.getFlatCoordinates()); + ol.array.extend(this.flatCoordinates, point.getFlatCoordinates()); } this.changed(); }; diff --git a/src/ol/geom/multipolygon.js b/src/ol/geom/multipolygon.js index 0570ebca48..5e943c03f9 100644 --- a/src/ol/geom/multipolygon.js +++ b/src/ol/geom/multipolygon.js @@ -1,9 +1,9 @@ goog.provide('ol.geom.MultiPolygon'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.object'); goog.require('ol'); +goog.require('ol.array'); goog.require('ol.extent'); goog.require('ol.geom.GeometryLayout'); goog.require('ol.geom.GeometryType'); @@ -100,7 +100,7 @@ ol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) { this.endss_.push(); } else { var offset = this.flatCoordinates.length; - goog.array.extend(this.flatCoordinates, polygon.getFlatCoordinates()); + ol.array.extend(this.flatCoordinates, polygon.getFlatCoordinates()); ends = polygon.getEnds().slice(); var i, ii; for (i = 0, ii = ends.length; i < ii; ++i) { @@ -424,7 +424,7 @@ ol.geom.MultiPolygon.prototype.setPolygons = function(polygons) { for (j = 0, jj = ends.length; j < jj; ++j) { ends[j] += offset; } - goog.array.extend(flatCoordinates, polygon.getFlatCoordinates()); + ol.array.extend(flatCoordinates, polygon.getFlatCoordinates()); endss.push(ends); } this.setFlatCoordinates(layout, flatCoordinates, endss); diff --git a/src/ol/geom/polygon.js b/src/ol/geom/polygon.js index 24fa72c6e9..741589ac58 100644 --- a/src/ol/geom/polygon.js +++ b/src/ol/geom/polygon.js @@ -1,9 +1,9 @@ goog.provide('ol.geom.Polygon'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.math'); goog.require('ol'); +goog.require('ol.array'); goog.require('ol.extent'); goog.require('ol.geom.GeometryLayout'); goog.require('ol.geom.GeometryType'); @@ -94,7 +94,7 @@ ol.geom.Polygon.prototype.appendLinearRing = function(linearRing) { if (!this.flatCoordinates) { this.flatCoordinates = linearRing.getFlatCoordinates().slice(); } else { - goog.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates()); + ol.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates()); } this.ends_.push(this.flatCoordinates.length); this.changed(); @@ -390,7 +390,7 @@ ol.geom.Polygon.circular = function(sphere, center, radius, opt_n) { var flatCoordinates = []; var i; for (i = 0; i < n; ++i) { - goog.array.extend( + ol.array.extend( flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n)); } flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]); @@ -435,7 +435,11 @@ ol.geom.Polygon.fromCircle = function(circle, opt_sides, opt_angle) { var stride = circle.getStride(); var layout = circle.getLayout(); var polygon = new ol.geom.Polygon(null, layout); - var flatCoordinates = goog.array.repeat(0, stride * (sides + 1)); + var arrayLength = stride * (sides + 1); + var flatCoordinates = new Array(arrayLength); + for (var i = 0; i < arrayLength; i++) { + flatCoordinates[i] = 0; + } var ends = [flatCoordinates.length]; polygon.setFlatCoordinates(layout, flatCoordinates, ends); ol.geom.Polygon.makeRegular( diff --git a/src/ol/interaction/modifyinteraction.js b/src/ol/interaction/modifyinteraction.js index e840dedcea..5b33daf68d 100644 --- a/src/ol/interaction/modifyinteraction.js +++ b/src/ol/interaction/modifyinteraction.js @@ -1,7 +1,6 @@ goog.provide('ol.interaction.Modify'); goog.provide('ol.interaction.ModifyEvent'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.events'); goog.require('goog.events.Event'); @@ -14,6 +13,7 @@ goog.require('ol.Feature'); goog.require('ol.MapBrowserEvent.EventType'); goog.require('ol.MapBrowserPointerEvent'); goog.require('ol.ViewHint'); +goog.require('ol.array'); goog.require('ol.coordinate'); goog.require('ol.events.condition'); goog.require('ol.extent'); @@ -999,9 +999,7 @@ ol.interaction.Modify.prototype.updateSegmentIndices_ = function( this.rBush_.forEachInExtent(geometry.getExtent(), function(segmentDataMatch) { if (segmentDataMatch.geometry === geometry && (depth === undefined || segmentDataMatch.depth === undefined || - goog.array.equals( - /** @type {null|{length: number}} */ (segmentDataMatch.depth), - depth)) && + ol.array.equals(segmentDataMatch.depth, depth)) && segmentDataMatch.index > index) { segmentDataMatch.index += delta; } diff --git a/src/ol/interaction/selectinteraction.js b/src/ol/interaction/selectinteraction.js index 81fa25838f..a11231a5bc 100644 --- a/src/ol/interaction/selectinteraction.js +++ b/src/ol/interaction/selectinteraction.js @@ -3,7 +3,6 @@ goog.provide('ol.interaction.SelectEvent'); goog.provide('ol.interaction.SelectEventType'); goog.provide('ol.interaction.SelectFilterFunction'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.events'); goog.require('goog.events.Event'); @@ -384,9 +383,9 @@ ol.interaction.Select.prototype.setMap = function(map) { */ ol.interaction.Select.getDefaultStyleFunction = function() { var styles = ol.style.createDefaultEditingStyles(); - goog.array.extend(styles[ol.geom.GeometryType.POLYGON], + ol.array.extend(styles[ol.geom.GeometryType.POLYGON], styles[ol.geom.GeometryType.LINE_STRING]); - goog.array.extend(styles[ol.geom.GeometryType.GEOMETRY_COLLECTION], + ol.array.extend(styles[ol.geom.GeometryType.GEOMETRY_COLLECTION], styles[ol.geom.GeometryType.LINE_STRING]); return function(feature, resolution) { diff --git a/src/ol/map.js b/src/ol/map.js index 2e9faa1794..700ec6754e 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -5,7 +5,6 @@ goog.provide('ol.Map'); goog.provide('ol.MapProperty'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.async.AnimationDelay'); goog.require('goog.async.nextTick'); @@ -45,6 +44,7 @@ goog.require('ol.Size'); goog.require('ol.TileQueue'); goog.require('ol.View'); goog.require('ol.ViewHint'); +goog.require('ol.array'); goog.require('ol.control'); goog.require('ol.extent'); goog.require('ol.has'); @@ -574,7 +574,7 @@ ol.Map.prototype.beforeRender = function(var_args) { * @return {boolean} Whether the preRenderFunction has been found and removed. */ ol.Map.prototype.removePreRenderFunction = function(preRenderFunction) { - return goog.array.remove(this.preRenderFunctions_, preRenderFunction); + return ol.array.remove(this.preRenderFunctions_, preRenderFunction); }; diff --git a/src/ol/pointer/touchsource.js b/src/ol/pointer/touchsource.js index 820cb15eb4..eb760009e7 100644 --- a/src/ol/pointer/touchsource.js +++ b/src/ol/pointer/touchsource.js @@ -30,11 +30,11 @@ goog.provide('ol.pointer.TouchSource'); -goog.require('goog.array'); goog.require('goog.object'); goog.require('ol'); goog.require('ol.pointer.EventSource'); goog.require('ol.pointer.MouseSource'); +goog.require('ol.array'); /** @@ -443,7 +443,7 @@ ol.pointer.TouchSource.prototype.dedupSynthMouse_ = function(inEvent) { goog.global.setTimeout(function() { // remove touch after timeout - goog.array.remove(lts, lt); + ol.array.remove(lts, lt); }, ol.pointer.TouchSource.DEDUP_TIMEOUT); } }; diff --git a/src/ol/render/canvas/canvasimmediate.js b/src/ol/render/canvas/canvasimmediate.js index 9003160ae6..cabb1c0129 100644 --- a/src/ol/render/canvas/canvasimmediate.js +++ b/src/ol/render/canvas/canvasimmediate.js @@ -4,7 +4,6 @@ goog.provide('ol.render.canvas.Immediate'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.vec.Mat4'); goog.require('ol.array'); @@ -768,7 +767,7 @@ ol.render.canvas.Immediate.prototype.setContextStrokeState_ = function(strokeSta contextStrokeState.lineCap = context.lineCap = strokeState.lineCap; } if (ol.has.CANVAS_LINE_DASH) { - if (!goog.array.equals( + if (!ol.array.equals( contextStrokeState.lineDash, strokeState.lineDash)) { context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash); } diff --git a/src/ol/render/canvas/canvasreplay.js b/src/ol/render/canvas/canvasreplay.js index ddfcd46144..9cc8dca3d7 100644 --- a/src/ol/render/canvas/canvasreplay.js +++ b/src/ol/render/canvas/canvasreplay.js @@ -8,7 +8,6 @@ goog.provide('ol.render.canvas.Replay'); goog.provide('ol.render.canvas.ReplayGroup'); goog.provide('ol.render.canvas.TextReplay'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.object'); goog.require('goog.vec.Mat4'); @@ -1037,7 +1036,7 @@ ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() { goog.asserts.assert(miterLimit !== undefined, 'miterLimit should be defined'); if (state.currentStrokeStyle != strokeStyle || state.currentLineCap != lineCap || - !goog.array.equals(state.currentLineDash, lineDash) || + !ol.array.equals(state.currentLineDash, lineDash) || state.currentLineJoin != lineJoin || state.currentLineWidth != lineWidth || state.currentMiterLimit != miterLimit) { diff --git a/src/ol/renderer/canvas/canvaslayerrenderer.js b/src/ol/renderer/canvas/canvaslayerrenderer.js index b556e91fff..a3502a1d10 100644 --- a/src/ol/renderer/canvas/canvaslayerrenderer.js +++ b/src/ol/renderer/canvas/canvaslayerrenderer.js @@ -1,8 +1,8 @@ goog.provide('ol.renderer.canvas.Layer'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.vec.Mat4'); +goog.require('ol.array'); goog.require('ol.dom'); goog.require('ol.extent'); goog.require('ol.layer.Layer'); @@ -262,7 +262,7 @@ ol.renderer.canvas.Layer.testCanvasSize = (function() { var y = size[1] - 1; context.putImageData(imageData, x, y); var result = context.getImageData(x, y, 1, 1); - good = goog.array.equals(imageData.data, result.data); + good = ol.array.equals(imageData.data, result.data); } return good; }; diff --git a/src/ol/renderer/canvas/canvasmaprenderer.js b/src/ol/renderer/canvas/canvasmaprenderer.js index 88f2ed55b7..f446e6a7e7 100644 --- a/src/ol/renderer/canvas/canvasmaprenderer.js +++ b/src/ol/renderer/canvas/canvasmaprenderer.js @@ -2,13 +2,13 @@ goog.provide('ol.renderer.canvas.Map'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom'); goog.require('goog.style'); goog.require('goog.vec.Mat4'); goog.require('ol'); goog.require('ol.RendererType'); +goog.require('ol.array'); goog.require('ol.css'); goog.require('ol.dom'); goog.require('ol.layer.Image'); @@ -171,7 +171,7 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); + ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); var viewResolution = frameState.viewState.resolution; var i, ii, layer, layerRenderer, layerState; diff --git a/src/ol/renderer/dom/dommaprenderer.js b/src/ol/renderer/dom/dommaprenderer.js index 1f701ee79c..8d8297d67a 100644 --- a/src/ol/renderer/dom/dommaprenderer.js +++ b/src/ol/renderer/dom/dommaprenderer.js @@ -1,6 +1,5 @@ goog.provide('ol.renderer.dom.Map'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom'); goog.require('goog.events'); @@ -10,6 +9,7 @@ goog.require('goog.style'); goog.require('goog.vec.Mat4'); goog.require('ol'); goog.require('ol.RendererType'); +goog.require('ol.array'); goog.require('ol.css'); goog.require('ol.dom'); goog.require('ol.layer.Image'); @@ -176,7 +176,7 @@ ol.renderer.dom.Map.prototype.renderFrame = function(frameState) { this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState); var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); + ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); var viewResolution = frameState.viewState.resolution; var i, ii, layer, layerRenderer, layerState; diff --git a/src/ol/renderer/webgl/webglmaprenderer.js b/src/ol/renderer/webgl/webglmaprenderer.js index 68df7370da..9ece2811f6 100644 --- a/src/ol/renderer/webgl/webglmaprenderer.js +++ b/src/ol/renderer/webgl/webglmaprenderer.js @@ -2,7 +2,6 @@ goog.provide('ol.renderer.webgl.Map'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom'); goog.require('goog.events'); @@ -14,6 +13,7 @@ goog.require('goog.style'); goog.require('goog.webgl'); goog.require('ol'); goog.require('ol.RendererType'); +goog.require('ol.array'); goog.require('ol.css'); goog.require('ol.dom'); goog.require('ol.layer.Image'); @@ -470,7 +470,7 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { /** @type {Array.} */ var layerStatesToDraw = []; var layerStatesArray = frameState.layerStatesArray; - goog.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); + ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex); var viewResolution = frameState.viewState.resolution; var i, ii, layerRenderer, layerState; diff --git a/src/ol/source/imagesource.js b/src/ol/source/imagesource.js index 12e4e6b15f..02cd6bc2fd 100644 --- a/src/ol/source/imagesource.js +++ b/src/ol/source/imagesource.js @@ -1,7 +1,6 @@ goog.provide('ol.source.Image'); goog.provide('ol.source.ImageEvent'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.events.Event'); goog.require('ol.Attribution'); @@ -52,7 +51,7 @@ ol.source.Image = function(options) { this.resolutions_ = options.resolutions !== undefined ? options.resolutions : null; goog.asserts.assert(!this.resolutions_ || - goog.array.isSorted(this.resolutions_, + ol.array.isSorted(this.resolutions_, function(a, b) { return b - a; }, true), 'resolutions must be null or sorted in descending order'); diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index 8a40546170..38867af174 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -5,7 +5,6 @@ goog.provide('ol.source.Vector'); goog.provide('ol.source.VectorEvent'); goog.provide('ol.source.VectorEventType'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.events'); goog.require('goog.events.Event'); @@ -19,6 +18,7 @@ goog.require('ol.Feature'); goog.require('ol.FeatureLoader'); goog.require('ol.LoadingStrategy'); goog.require('ol.ObjectEventType'); +goog.require('ol.array'); goog.require('ol.extent'); goog.require('ol.featureloader'); goog.require('ol.loadingstrategy'); @@ -552,7 +552,7 @@ ol.source.Vector.prototype.getFeatures = function() { } else if (this.featuresRtree_) { features = this.featuresRtree_.getAll(); if (!goog.object.isEmpty(this.nullGeometryFeatures_)) { - goog.array.extend( + ol.array.extend( features, goog.object.getValues(this.nullGeometryFeatures_)); } } diff --git a/src/ol/source/wmtssource.js b/src/ol/source/wmtssource.js index 77c322a4d7..8284404296 100644 --- a/src/ol/source/wmtssource.js +++ b/src/ol/source/wmtssource.js @@ -1,7 +1,6 @@ goog.provide('ol.source.WMTS'); goog.provide('ol.source.WMTSRequestEncoding'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.object'); goog.require('goog.uri.utils'); @@ -327,7 +326,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { 'config "layer" must not be null'); var layers = wmtsCap['Contents']['Layer']; - var l = goog.array.find(layers, function(elt, index, array) { + var l = ol.array.find(layers, function(elt, index, array) { return elt['Identifier'] == config['layer']; }); goog.asserts.assert(l, 'found a matching layer in Contents/Layer'); @@ -338,9 +337,9 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { var idx, matrixSet; if (l['TileMatrixSetLink'].length > 1) { if ('projection' in config) { - idx = goog.array.findIndex(l['TileMatrixSetLink'], + idx = ol.array.findIndex(l['TileMatrixSetLink'], function(elt, index, array) { - var tileMatrixSet = goog.array.find(tileMatrixSets, function(el) { + var tileMatrixSet = ol.array.find(tileMatrixSets, function(el) { return el['Identifier'] == elt['TileMatrixSet']; }); return tileMatrixSet['SupportedCRS'].replace( @@ -348,7 +347,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { ) == config['projection']; }); } else { - idx = goog.array.findIndex(l['TileMatrixSetLink'], + idx = ol.array.findIndex(l['TileMatrixSetLink'], function(elt, index, array) { return elt['TileMatrixSet'] == config['matrixSet']; }); @@ -368,7 +367,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { if ('format' in config) { format = config['format']; } - idx = goog.array.findIndex(l['Style'], function(elt, index, array) { + idx = ol.array.findIndex(l['Style'], function(elt, index, array) { if ('style' in config) { return elt['Title'] == config['style']; } else { @@ -397,7 +396,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { } var matrixSets = wmtsCap['Contents']['TileMatrixSet']; - var matrixSetObj = goog.array.find(matrixSets, function(elt, index, array) { + var matrixSetObj = ol.array.find(matrixSets, function(elt, index, array) { return elt['Identifier'] == matrixSet; }); goog.asserts.assert(matrixSetObj, @@ -457,7 +456,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) { var gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get']; for (var i = 0, ii = gets.length; i < ii; ++i) { - var constraint = goog.array.find(gets[i]['Constraint'], + var constraint = ol.array.find(gets[i]['Constraint'], function(elt, index, array) { return elt['name'] == 'GetEncoding'; }); diff --git a/src/ol/tilegrid/tilegrid.js b/src/ol/tilegrid/tilegrid.js index 87df9da396..41ebf2d3c2 100644 --- a/src/ol/tilegrid/tilegrid.js +++ b/src/ol/tilegrid/tilegrid.js @@ -1,6 +1,5 @@ goog.provide('ol.tilegrid.TileGrid'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.object'); goog.require('ol'); @@ -42,7 +41,7 @@ ol.tilegrid.TileGrid = function(options) { * @type {!Array.} */ this.resolutions_ = options.resolutions; - goog.asserts.assert(goog.array.isSorted(this.resolutions_, function(a, b) { + goog.asserts.assert(ol.array.isSorted(this.resolutions_, function(a, b) { return b - a; }, true), 'resolutions must be sorted in descending order'); diff --git a/src/ol/xml.js b/src/ol/xml.js index 3a681947e3..780a9be248 100644 --- a/src/ol/xml.js +++ b/src/ol/xml.js @@ -1,11 +1,11 @@ goog.provide('ol.xml'); -goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom.NodeType'); goog.require('goog.dom.xml'); goog.require('goog.object'); goog.require('goog.userAgent'); +goog.require('ol.array'); /** @@ -370,7 +370,7 @@ ol.xml.makeArrayExtender = function(valueReader, opt_this) { (objectStack[objectStack.length - 1]); goog.asserts.assert(goog.isArray(array), 'objectStack is supposed to be an array of arrays'); - goog.array.extend(array, value); + ol.array.extend(array, value); } }); }; diff --git a/test/spec/ol/array.test.js b/test/spec/ol/array.test.js index 035824e045..4926ddbe10 100644 --- a/test/spec/ol/array.test.js +++ b/test/spec/ol/array.test.js @@ -2,12 +2,305 @@ goog.provide('ol.test.array'); describe('ol.array', function() { - describe('numberSafeCompareFunction', function() { - it('sorts as expected', function() { - var arr = [40, 200, 3000]; - // default sort would yield [200, 3000, 40] - arr.sort(ol.array.numberSafeCompareFunction); - expect(arr).to.eql(arr); + describe('binarySearch', function() { + + var insertionPoint = function(position) { + return -(position + 1); + }; + var revNumCompare = function(a, b) { + return b - a; + }; + + describe('default comparison on array of String(s)', function() { + var a = [ + '1000', '9', 'AB', 'ABC', 'ABCABC', 'ABD', 'ABDA', 'B', 'B', 'B', + 'C', 'CA', 'CC', 'ZZZ', 'ab', 'abc', 'abcabc', 'abd', 'abda', 'b', + 'c', 'ca', 'cc', 'zzz' + ]; + + it('should find \'1000\' at index 0', function() { + expect(ol.array.binarySearch(a, '1000')).to.be(0); + }); + it('should find \'zzz\' at index ' + (a.length - 1), function() { + expect(ol.array.binarySearch(a, 'zzz')).to.be(a.length - 1); + }); + it('should find \'C\' at index 10', function() { + expect(ol.array.binarySearch(a, 'C')).to.be(10); + }); + it('should find \'B\' at index 7 || 8 || 9', function() { + var pos = ol.array.binarySearch(a, 'B'); + expect(pos == 7 || pos == 8 || pos == 9).to.be.ok(); + }); + it('should not find \'100\'', function() { + var pos = ol.array.binarySearch(a, '100'); + expect(pos < 0).to.be.ok(); + }); + it('should have an insertion point of 0 for \'100\'', function() { + var pos = ol.array.binarySearch(a, '100'); + expect(insertionPoint(pos)).to.be(0); + }); + it('should not find \'zzz0\'', function() { + var pos = ol.array.binarySearch(a, 'zzz0'); + expect(pos < 0).to.be.ok(); + }); + it('should have an insertion point of ' + (a.length) + ' for \'zzz0\'', + function() { + var pos = ol.array.binarySearch(a, 'zzz0'); + expect(insertionPoint(pos)).to.be(a.length); + } + ); + it('should not find \'BA\'', function() { + var pos = ol.array.binarySearch(a, 'zzz0'); + expect(pos < 0).to.be.ok(); + }); + it('should have an insertion point of 10 for \'BA\'', + function() { + var pos = ol.array.binarySearch(a, 'BA'); + expect(insertionPoint(pos)).to.be(10); + } + ); + }); + + describe('0 length array with default comparison', function() { + var b = []; + it('should not find \'a\'', function() { + expect(ol.array.binarySearch(b, 'a') < 0).to.be.ok(); + }); + it('should have an insertion point of 0 for \'a\'', + function() { + var pos = ol.array.binarySearch(b, 'a'); + expect(insertionPoint(pos)).to.be(0); + } + ); + }); + + describe('single element array with default lexiographical comparison', + function() { + var c = ['only item']; + it('should find \'only item\' at index 0', function() { + expect(ol.array.binarySearch(c, 'only item')).to.be(0); + }); + it('should not find \'a\'', function() { + expect(ol.array.binarySearch(c, 'a') < 0).to.be.ok(); + }); + it('should have an insertion point of 0 for \'a\'', + function() { + var pos = ol.array.binarySearch(c, 'a'); + expect(insertionPoint(pos)).to.be(0); + } + ); + it('should not find \'z\'', function() { + expect(ol.array.binarySearch(c, 'z') < 0).to.be.ok(); + }); + it('should have an insertion point of 1 for \'z\'', + function() { + var pos = ol.array.binarySearch(c, 'z'); + expect(insertionPoint(pos)).to.be(1); + } + ); + } + ); + + describe('default comparison on array of Number(s)', function() { + var d = [-897123.9, -321434.58758, -1321.3124, -324, -9, -3, 0, 0, 0, + 0.31255, 5, 142.88888708, 334, 342, 453, 54254]; + it('should find -897123.9 at index 0', function() { + expect(ol.array.binarySearch(d, -897123.9)).to.be(0); + }); + it('should find 54254 at index ' + (d.length - 1), function() { + expect(ol.array.binarySearch(d, 54254)).to.be(d.length - 1); + }); + it('should find -3 at index 5', function() { + expect(ol.array.binarySearch(d, -3)).to.be(5); + }); + it('should find 0 at index 6 || 7 || 8', function() { + var pos = ol.array.binarySearch(d, 0); + expect(pos == 6 || pos == 7 || pos == 8).to.be(true); + }); + it('should not find -900000', function() { + var pos = ol.array.binarySearch(d, -900000); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of 0 for -900000', function() { + var pos = ol.array.binarySearch(d, -900000); + expect(insertionPoint(pos)).to.be(0); + }); + it('should not find 54255', function() { + var pos = ol.array.binarySearch(d, 54255); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of ' + (d.length) + ' for 54255', + function() { + var pos = ol.array.binarySearch(d, 54255); + expect(insertionPoint(pos)).to.be(d.length); + } + ); + it('should not find 1.1', function() { + var pos = ol.array.binarySearch(d, 1.1); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of 10 for 1.1', function() { + var pos = ol.array.binarySearch(d, 1.1); + expect(insertionPoint(pos)).to.be(10); + }); + }); + + describe('custom comparison function, which reverse orders numbers', + function() { + var e = [54254, 453, 342, 334, 142.88888708, 5, 0.31255, 0, 0, 0, -3, + -9, -324, -1321.3124, -321434.58758, -897123.9]; + it('should find 54254 at index 0', function() { + var pos = ol.array.binarySearch(e, 54254, revNumCompare); + expect(pos).to.be(0); + }); + it('should find -897123.9 at index ' + (e.length - 1), function() { + var pos = ol.array.binarySearch(e, -897123.9, revNumCompare); + expect(pos).to.be(e.length - 1); + }); + it('should find -3 at index 10', function() { + var pos = ol.array.binarySearch(e, -3, revNumCompare); + expect(pos).to.be(10); + }); + it('should find 0 at index 7 || 8 || 9', function() { + var pos = ol.array.binarySearch(e, 0, revNumCompare); + expect(pos == 7 || pos == 8 || pos == 9).to.be(true); + }); + it('should not find 54254.1', function() { + var pos = ol.array.binarySearch(e, 54254.1, revNumCompare); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of 0 for 54254.1', function() { + var pos = ol.array.binarySearch(e, 54254.1, revNumCompare); + expect(insertionPoint(pos)).to.be(0); + }); + it('should not find -897124', function() { + var pos = ol.array.binarySearch(e, -897124, revNumCompare); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of ' + e.length + ' for -897124', + function() { + var pos = ol.array.binarySearch(e, -897124, revNumCompare); + expect(insertionPoint(pos)).to.be(e.length); + } + ); + it('should not find 1.1', function() { + var pos = ol.array.binarySearch(e, 1.1, revNumCompare); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of 0 for 1.1', function() { + var pos = ol.array.binarySearch(e, 1.1, revNumCompare); + expect(insertionPoint(pos)).to.be(6); + }); + } + ); + + describe('0 length array with custom comparison function', function() { + var f = []; + it('should not find 0', function() { + var pos = ol.array.binarySearch(f, 0, revNumCompare); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of 0 for 0', function() { + var pos = ol.array.binarySearch(f, 0, revNumCompare); + expect(insertionPoint(pos)).to.be(0); + }); + }); + + describe('single element array with custom comparison function', + function() { + var g = [1]; + it('should not find 1 at index 0', function() { + var pos = ol.array.binarySearch(g, 1, revNumCompare); + expect(pos).to.be(0); + }); + it('should not find 2', function() { + var pos = ol.array.binarySearch(g, 2, revNumCompare); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of 0 for 2', function() { + var pos = ol.array.binarySearch(g, 2, revNumCompare); + expect(insertionPoint(pos)).to.be(0); + }); + it('should not find 0', function() { + var pos = ol.array.binarySearch(g, 0, revNumCompare); + expect(pos < 0).to.be(true); + }); + it('should have an insertion point of 1 for 0', function() { + var pos = ol.array.binarySearch(g, 0, revNumCompare); + expect(insertionPoint(pos)).to.be(1); + }); + } + ); + + describe('finding first index when multiple candidates', function() { + it('should find the index of the first 0', function() { + expect(ol.array.binarySearch([0, 0, 1], 0)).to.be(0); + }); + it('should find the index of the first 1', function() { + expect(ol.array.binarySearch([0, 1, 1], 1)).to.be(1); + }); + }); + + describe('Don\'t use Array#slice, Function#apply and Function#call', + function() { + var a = [1, 5, 7, 11, 13, 16, 19, 24, 28, 31, 33, 36, 40, 50, 52, 55]; + var calls = { + 'Array#slice': false, + 'Function#apply': false, + 'Function#call': false + }; + var origArraySlice; + var origFunctionApply; + var origFunctionCall; + + it('does not use potentially slow methods (default & custom compare)', + function() { + // Mockup (I failed to use sinon.spy and beforeEach-hooks) + origArraySlice = Array.prototype.slice; + origFunctionApply = Function.prototype.apply; + origFunctionCall = Function.prototype.call; + Array.prototype.slice = function() { + calls['Array#slice'] = true; + }; + Function.prototype.apply = function() { + calls['Function#apply'] = true; + }; + Function.prototype.call = function() { + calls['Function#call'] = true; + }; + + // Now actually call and test the method twice + ol.array.binarySearch(a, 48); + ol.array.binarySearch(a, 13, function(a, b) { + return a > b ? 1 : a < b ? -1 : 0; + }); + + // Restore mocked up methods + Array.prototype.slice = origArraySlice; + Function.prototype.apply = origFunctionApply; + Function.prototype.call = origFunctionCall; + + // Expectations + expect(calls['Array#slice']).to.be(false); + expect(calls['Function#apply']).to.be(false); + expect(calls['Function#call']).to.be(false); + } + ); + } + ); + + describe('when items are not found', function() { + var arr = [1, 2, 2, 2, 3, 5, 9]; + + it('should return the index of where the item would go plus one, negated, if the item is not found', function() { + expect(ol.array.binarySearch(arr, 4)).to.equal(-6); + }); + it('should work even on empty arrays', function() { + expect(ol.array.binarySearch([], 42)).to.equal(-1); + }); + it('should work even on arrays of doubles', function() { + expect(ol.array.binarySearch([0.0, 0.1, 0.2, 0.3, 0.4], 0.25)).to.equal(-4); + }); }); }); @@ -33,6 +326,180 @@ describe('ol.array', function() { }); }); + describe('equals', function() { + it('returns true for [] == []', function() { + expect(ol.array.equals([], [])).to.be(true); + }); + it('returns true for [1] == [1]', function() { + expect(ol.array.equals([1], [1])).to.be(true); + }); + it('returns true for [\'1\'] == [\'1\']', function() { + expect(ol.array.equals(['1'], ['1'])).to.be(true); + }); + it('returns false for [1] == [\'1\']', function() { + expect(ol.array.equals([1], ['1'])).to.be(false); + }); + it('returns true for [null] == [null]', function() { + expect(ol.array.equals([null], [null])).to.be(true); + }); + it('returns false for [null] == [undefined]', function() { + expect(ol.array.equals([null], [undefined])).to.be(false); + }); + it('returns true for [1, 2] == [1, 2]', function() { + expect(ol.array.equals([1, 2], [1, 2])).to.be(true); + }); + it('returns false for [1, 2] == [2, 1]', function() { + expect(ol.array.equals([1, 2], [2, 1])).to.be(false); + }); + it('returns false for [1, 2] == [1]', function() { + expect(ol.array.equals([1, 2], [1])).to.be(false); + }); + it('returns false for [1] == [1, 2]', function() { + expect(ol.array.equals([1], [1, 2])).to.be(false); + }); + it('returns false for [{}] == [{}]', function() { + expect(ol.array.equals([{}], [{}])).to.be(false); + }); + }); + describe('extend', function() { + it('extends an array in place with an array', function() { + var a = [0, 1]; + ol.array.extend(a, [2, 3]); + expect(a).to.eql([0, 1, 2, 3]); + }); + it('extends an array in place with a number', function() { + var a = [0, 1]; + ol.array.extend(a, 2); + expect(a).to.eql([0, 1, 2]); + }); + it('extends an array in place with an arraylike object', function() { + var a = [0, 1]; + var arrayLikeObject = {0: 2, 1: 3, length: 2}; + ol.array.extend(a, arrayLikeObject); + expect(a).to.eql([0, 1, 2, 3]); + }); + it('extends an array in place with an empty arraylike object', function() { + var a = [0, 1]; + var arrayLikeObject = {length: 0}; + ol.array.extend(a, arrayLikeObject); + expect(a).to.eql([0, 1]); + }); + it('extends an array in place with a big array', function() { + var a = []; + var i = 500000; // original test has 1.000.000, but that was too slow + var bigArray = Array(i); + while (i--) { + bigArray[i] = i; + } + ol.array.extend(a, bigArray); + expect(a).to.eql(bigArray); + }); + it('extends an array in place with arguments', function() { + var f = function() { + return arguments; + }; + var a = [0]; + ol.array.extend(a, f(1, 2, 3)); + expect(a).to.eql([0, 1, 2, 3]); + }); + it('extends an array with a NodeList (from querySelectorAll)', function() { + var a = []; + ol.array.extend(a, document.querySelectorAll('head')); + expect(a.length).to.be(1); + expect(a[0]).to.be(document.head); + }); + }); + + describe('find', function() { + it('finds numbers in an array', function() { + var a = [0, 1, 2, 3]; + var b = ol.array.find(a, function(val, index, a2) { + expect(a).to.equal(a2); + expect(typeof index).to.be('number'); + return val > 1; + }); + expect(b).to.be(2); + }); + + it('returns null when an item in an array is not found', function() { + var a = [0, 1, 2, 3]; + var b = ol.array.find(a, function(val, index, a2) { + return val > 100; + }); + expect(b).to.be(null); + }); + + it('finds items in an array-like', function() { + var a = 'abCD'; + var b = ol.array.find(a, function(val, index, a2) { + expect(a).to.equal(a2); + expect(typeof index).to.be('number'); + return val >= 'A' && val <= 'Z'; + }); + expect(b).to.be('C'); + }); + + it('returns null when nothing in an array-like is found', function() { + var a = 'abcd'; + var b = ol.array.find(a, function(val, index, a2) { + return val >= 'A' && val <= 'Z'; + }); + expect(b).to.be(null); + }); + }); + + describe('findIndex', function() { + it('finds index of numbers in an array', function() { + var a = [0, 1, 2, 3]; + var b = ol.array.findIndex(a, function(val, index, a2) { + expect(a).to.equal(a2); + expect(typeof index).to.be('number'); + return val > 1; + }); + expect(b).to.be(2); + }); + + it('returns -1 when an item in an array is not found', function() { + var a = [0, 1, 2, 3]; + var b = ol.array.findIndex(a, function(val, index, a2) { + return val > 100; + }); + expect(b).to.be(-1); + }); + }); + + describe('flatten', function() { + it('flattens different kinds of nested arrays', function() { + expect(ol.array.flatten([1, 2])).to.eql([1, 2]); + expect(ol.array.flatten([1, [2, [3, [4, 5]]]])).to.eql([1, 2, 3, 4, 5]); + expect(ol.array.flatten([[[[1], 2], 3], 4])).to.eql([1, 2, 3, 4]); + expect(ol.array.flatten([[1]])).to.eql([1]); + expect(ol.array.flatten([])).to.eql([]); + }); + }); + + describe('isSorted', function() { + it('works with just an array as argument', function() { + expect(ol.array.isSorted([1, 2, 3])).to.be(true); + expect(ol.array.isSorted([1, 2, 2])).to.be(true); + expect(ol.array.isSorted([1, 2, 1])).to.be(false); + }); + + it('works with strict comparison without compare function', function() { + expect(ol.array.isSorted([1, 2, 3], null, true)).to.be(true); + expect(ol.array.isSorted([1, 2, 2], null, true)).to.be(false); + expect(ol.array.isSorted([1, 2, 1], null, true)).to.be(false); + }); + + it('works with a compare function', function() { + function compare(a, b) { + return b - a; + } + expect(ol.array.isSorted([1, 2, 3], compare)).to.be(false); + expect(ol.array.isSorted([3, 2, 2], compare)).to.be(true); + }); + }); + describe('linearFindNearest', function() { it('returns expected value', function() { var arr = [1000, 500, 100]; @@ -83,6 +550,25 @@ describe('ol.array', function() { }); }); + describe('numberSafeCompareFunction', function() { + it('sorts as expected', function() { + var arr = [40, 200, 3000]; + // default sort would yield [200, 3000, 40] + arr.sort(ol.array.numberSafeCompareFunction); + expect(arr).to.eql(arr); + }); + }); + + describe('remove', function() { + it('removes elements from an array', function() { + var a = ['a', 'b', 'c', 'd']; + ol.array.remove(a, 'c'); + expect(a).to.eql(['a', 'b', 'd']); + ol.array.remove(a, 'x'); + expect(a).to.eql(['a', 'b', 'd']); + }); + }); + describe('reverseSubArray', function() { it('returns expected value', function() { var arr; @@ -105,6 +591,29 @@ describe('ol.array', function() { expect(arr).to.eql(expected); }); }); + + describe('stableSort', function() { + var arr, wantedSortedValues; + + beforeEach(function() { + arr = [{key: 3, val: 'a'}, {key: 2, val: 'b'}, {key: 3, val: 'c'}, + {key: 4, val: 'd'}, {key: 3, val: 'e'}]; + wantedSortedValues = ['b', 'a', 'c', 'e', 'd']; + }); + + it('works on an array with custom comparison function', function() { + function comparisonFn(obj1, obj2) { + return obj1.key - obj2.key; + } + ol.array.stableSort(arr, comparisonFn); + var sortedValues = []; + for (var i = 0; i < arr.length; i++) { + sortedValues.push(arr[i].val); + } + expect(wantedSortedValues).to.eql(sortedValues); + }); + }); + }); goog.require('ol.array'); diff --git a/test/spec/ol/geom/flat/interpolateflatgeom.test.js b/test/spec/ol/geom/flat/interpolateflatgeom.test.js index bbd5d91cbe..6639b7d99d 100644 --- a/test/spec/ol/geom/flat/interpolateflatgeom.test.js +++ b/test/spec/ol/geom/flat/interpolateflatgeom.test.js @@ -27,6 +27,13 @@ describe('ol.geom.flat.interpolate', function() { expect(point).to.eql([2, 3]); }); + xit('also when vertices are repeated', function() { + var flatCoordinates = [0, 1, 2, 3, 2, 3, 4, 5]; + var point = ol.geom.flat.interpolate.lineString( + flatCoordinates, 0, 6, 2, 0.5); + expect(point).to.eql([2, 3]); + }); + it('returns the expected value when the midpoint falls halfway between ' + 'two existing coordinates', function() { @@ -36,6 +43,13 @@ describe('ol.geom.flat.interpolate', function() { expect(point).to.eql([3, 4]); }); + xit('also when vertices are repeated', function() { + var flatCoordinates = [0, 1, 2, 3, 2, 3, 4, 5, 6, 7]; + var point = ol.geom.flat.interpolate.lineString( + flatCoordinates, 0, 8, 2, 0.5); + expect(point).to.eql([3, 4]); + }); + it('returns the expected value when the coordinates are not evenly spaced', function() { var flatCoordinates = [0, 1, 2, 3, 6, 7]; @@ -44,6 +58,14 @@ describe('ol.geom.flat.interpolate', function() { expect(point).to.eql([3, 4]); }); + xit('also when vertices are repeated', + function() { + var flatCoordinates = [0, 1, 2, 3, 2, 3, 6, 7]; + var point = ol.geom.flat.interpolate.lineString( + flatCoordinates, 0, 6, 2, 0.5); + expect(point).to.eql([3, 4]); + }); + it('returns the expected value when using opt_dest', function() { var flatCoordinates = [0, 1, 2, 3, 6, 7];