{"version":3,"file":"index-e44a857a.js","sources":["../../node_modules/ol/events/Event.js","../../node_modules/ol/ObjectEventType.js","../../node_modules/ol/Disposable.js","../../node_modules/ol/array.js","../../node_modules/ol/functions.js","../../node_modules/ol/obj.js","../../node_modules/ol/events/Target.js","../../node_modules/ol/events/EventType.js","../../node_modules/ol/events.js","../../node_modules/ol/Observable.js","../../node_modules/ol/util.js","../../node_modules/ol/Object.js","../../node_modules/ol/CollectionEventType.js","../../node_modules/ol/Collection.js","../../node_modules/ol/asserts.js","../../node_modules/ol/Feature.js","../../node_modules/ol/has.js","../../node_modules/ol/transform.js","../../node_modules/ol/extent/Relationship.js","../../node_modules/ol/extent.js","../../node_modules/ol/proj/Units.js","../../node_modules/ol/proj/Projection.js","../../node_modules/ol/proj/epsg3857.js","../../node_modules/ol/proj/epsg4326.js","../../node_modules/ol/proj/projections.js","../../node_modules/ol/proj/transforms.js","../../node_modules/ol/math.js","../../node_modules/ol/coordinate.js","../../node_modules/ol/sphere.js","../../node_modules/ol/console.js","../../node_modules/ol/proj.js","../../node_modules/ol/geom/flat/transform.js","../../node_modules/ol/geom/Geometry.js","../../node_modules/ol/geom/SimpleGeometry.js","../../node_modules/ol/geom/flat/closest.js","../../node_modules/ol/geom/flat/deflate.js","../../node_modules/ol/geom/flat/simplify.js","../../node_modules/ol/geom/flat/inflate.js","../../node_modules/ol/geom/flat/area.js","../../node_modules/ol/geom/LinearRing.js","../../node_modules/ol/geom/Point.js","../../node_modules/ol/geom/flat/contains.js","../../node_modules/ol/geom/flat/interiorpoint.js","../../node_modules/ol/geom/flat/segments.js","../../node_modules/ol/geom/flat/intersectsextent.js","../../node_modules/ol/geom/flat/reverse.js","../../node_modules/ol/geom/flat/orient.js","../../node_modules/ol/geom/Polygon.js","../../node_modules/ol/render/EventType.js","../../node_modules/ol/style/Fill.js","../../node_modules/ol/geom/flat/interpolate.js","../../node_modules/ol/geom/flat/length.js","../../node_modules/ol/style/Stroke.js","../../node_modules/ol/ImageState.js","../../node_modules/ol/size.js","../../node_modules/ol/style/Image.js","../../node_modules/color-space/rgb.js","../../node_modules/color-space/xyz.js","../../node_modules/color-space/luv.js","../../node_modules/color-space/lchuv.js","../../node_modules/color-name/index.js","../../node_modules/color-parse/index.js","../../node_modules/color-space/hsl.js","../../node_modules/color-rgba/index.js","../../node_modules/ol/color.js","../../node_modules/ol/colorlike.js","../../node_modules/ol/dom.js","../../node_modules/ol/css.js","../../node_modules/ol/render/canvas.js","../../node_modules/ol/style/RegularShape.js","../../node_modules/ol/style/Circle.js","../../node_modules/ol/style/Style.js","../../node_modules/ol/style/Text.js","../../node_modules/ol/layer/Property.js","../../node_modules/ol/layer/Base.js","../../node_modules/ol/ViewHint.js","../../node_modules/ol/ViewProperty.js","../../node_modules/ol/tilegrid/common.js","../../node_modules/ol/centerconstraint.js","../../node_modules/ol/resolutionconstraint.js","../../node_modules/ol/rotationconstraint.js","../../node_modules/ol/easing.js","../../node_modules/ol/View.js","../../node_modules/ol/layer/Layer.js","../../node_modules/quickselect/index.js","../../node_modules/rbush/index.js","../../node_modules/ol/Image.js","../../node_modules/ol/style/IconImageCache.js","../../node_modules/ol/style/IconImage.js","../../node_modules/ol/style/Icon.js","../../node_modules/ol/expr/expression.js","../../node_modules/ol/expr/cpu.js","../../node_modules/ol/render/canvas/style.js","../../node_modules/ol/layer/BaseVector.js","../../node_modules/ol/render/canvas/Instruction.js","../../node_modules/ol/render/VectorContext.js","../../node_modules/ol/render/canvas/Builder.js","../../node_modules/ol/render/canvas/ImageBuilder.js","../../node_modules/ol/render/canvas/LineStringBuilder.js","../../node_modules/ol/render/canvas/PolygonBuilder.js","../../node_modules/ol/geom/flat/linechunk.js","../../node_modules/ol/geom/flat/straightchunk.js","../../node_modules/ol/render/canvas/TextBuilder.js","../../node_modules/ol/render/canvas/BuilderGroup.js","../../node_modules/ol/renderer/Layer.js","../../node_modules/ol/render/Event.js","../../node_modules/ol/renderer/canvas/Layer.js","../../node_modules/ol/geom/flat/textpath.js","../../node_modules/ol/render/canvas/Executor.js","../../node_modules/ol/render/canvas/ExecutorGroup.js","../../node_modules/ol/render/canvas/Immediate.js","../../node_modules/ol/render/canvas/hitdetect.js","../../node_modules/ol/renderer/vector.js","../../node_modules/ol/renderer/canvas/VectorLayer.js","../../node_modules/ol/layer/Vector.js","../../node_modules/ol/structs/RBush.js","../../node_modules/ol/geom/flat/center.js","../../node_modules/ol/render/Feature.js","../../node_modules/ol/source/Source.js","../../node_modules/ol/source/VectorEventType.js","../../node_modules/ol/loadingstrategy.js","../../node_modules/ol/featureloader.js","../../node_modules/ol/source/Vector.js","../../node_modules/ol/TileState.js","../../node_modules/ol/Tile.js","../../node_modules/ol/ImageTile.js","../../node_modules/ol/Kinetic.js","../../node_modules/ol/renderer/Map.js","../../node_modules/ol/renderer/Composite.js","../../node_modules/ol/layer/Group.js","../../node_modules/ol/MapEvent.js","../../node_modules/ol/MapBrowserEvent.js","../../node_modules/ol/MapBrowserEventType.js","../../node_modules/ol/pointer/EventType.js","../../node_modules/ol/MapBrowserEventHandler.js","../../node_modules/ol/MapEventType.js","../../node_modules/ol/MapProperty.js","../../node_modules/ol/structs/PriorityQueue.js","../../node_modules/ol/TileQueue.js","../../node_modules/ol/control/Control.js","../../node_modules/ol/control/Attribution.js","../../node_modules/ol/control/Rotate.js","../../node_modules/ol/control/Zoom.js","../../node_modules/ol/control/defaults.js","../../node_modules/ol/interaction/Property.js","../../node_modules/ol/interaction/Interaction.js","../../node_modules/ol/interaction/DoubleClickZoom.js","../../node_modules/ol/interaction/Pointer.js","../../node_modules/ol/events/condition.js","../../node_modules/ol/interaction/DragPan.js","../../node_modules/ol/interaction/DragRotate.js","../../node_modules/ol/render/Box.js","../../node_modules/ol/interaction/DragBox.js","../../node_modules/ol/interaction/DragZoom.js","../../node_modules/ol/events/Key.js","../../node_modules/ol/interaction/KeyboardPan.js","../../node_modules/ol/interaction/KeyboardZoom.js","../../node_modules/ol/interaction/MouseWheelZoom.js","../../node_modules/ol/interaction/PinchRotate.js","../../node_modules/ol/interaction/PinchZoom.js","../../node_modules/ol/interaction/defaults.js","../../node_modules/ol/Map.js","../../node_modules/ol/structs/LRUCache.js","../../node_modules/ol/tilecoord.js","../../node_modules/ol/TileCache.js","../../node_modules/ol/TileRange.js","../../node_modules/ol/layer/TileProperty.js","../../node_modules/ol/layer/BaseTile.js","../../node_modules/ol/reproj/common.js","../../node_modules/ol/reproj/Triangulation.js","../../node_modules/ol/reproj.js","../../node_modules/ol/reproj/Tile.js","../../node_modules/ol/renderer/canvas/TileLayer.js","../../node_modules/ol/layer/Tile.js","../../node_modules/ol/source/TileEventType.js","../../node_modules/ol/tilegrid/TileGrid.js","../../node_modules/ol/tilegrid.js","../../node_modules/ol/source/Tile.js","../../node_modules/ol/tileurlfunction.js","../../node_modules/ol/source/UrlTile.js","../../node_modules/ol/source/TileImage.js","../../node_modules/ol/source/XYZ.js","../../node_modules/ol/source/OSM.js","../../clubhuis.js"],"sourcesContent":["/**\n * @module ol/events/Event\n */\n\n/**\n * @classdesc\n * Stripped down implementation of the W3C DOM Level 2 Event interface.\n * See https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface.\n *\n * This implementation only provides `type` and `target` properties, and\n * `stopPropagation` and `preventDefault` methods. It is meant as base class\n * for higher level events defined in the library, and works with\n * {@link module:ol/events/Target~Target}.\n */\nclass BaseEvent {\n /**\n * @param {string} type Type.\n */\n constructor(type) {\n /**\n * @type {boolean}\n */\n this.propagationStopped;\n\n /**\n * @type {boolean}\n */\n this.defaultPrevented;\n\n /**\n * The event type.\n * @type {string}\n * @api\n */\n this.type = type;\n\n /**\n * The event target.\n * @type {Object}\n * @api\n */\n this.target = null;\n }\n\n /**\n * Prevent default. This means that no emulated `click`, `singleclick` or `doubleclick` events\n * will be fired.\n * @api\n */\n preventDefault() {\n this.defaultPrevented = true;\n }\n\n /**\n * Stop event propagation.\n * @api\n */\n stopPropagation() {\n this.propagationStopped = true;\n }\n}\n\n/**\n * @param {Event|import(\"./Event.js\").default} evt Event\n */\nexport function stopPropagation(evt) {\n evt.stopPropagation();\n}\n\n/**\n * @param {Event|import(\"./Event.js\").default} evt Event\n */\nexport function preventDefault(evt) {\n evt.preventDefault();\n}\n\nexport default BaseEvent;\n","/**\n * @module ol/ObjectEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * Triggered when a property is changed.\n * @event module:ol/Object.ObjectEvent#propertychange\n * @api\n */\n PROPERTYCHANGE: 'propertychange',\n};\n\n/**\n * @typedef {'propertychange'} Types\n */\n","/**\n * @module ol/Disposable\n */\n\n/**\n * @classdesc\n * Objects that need to clean up after themselves.\n */\nclass Disposable {\n constructor() {\n /**\n * The object has already been disposed.\n * @type {boolean}\n * @protected\n */\n this.disposed = false;\n }\n\n /**\n * Clean up.\n */\n dispose() {\n if (!this.disposed) {\n this.disposed = true;\n this.disposeInternal();\n }\n }\n\n /**\n * Extension point for disposable objects.\n * @protected\n */\n disposeInternal() {}\n}\n\nexport default Disposable;\n","/**\n * @module ol/array\n */\n\n/**\n * 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.\n * https://github.com/darkskyapp/binary-search\n *\n * @param {Array<*>} haystack Items to search through.\n * @param {*} needle The item to look for.\n * @param {Function} [comparator] Comparator function.\n * @return {number} The index of the item if found, -1 if not.\n */\nexport function binarySearch(haystack, needle, comparator) {\n let mid, cmp;\n comparator = comparator || ascending;\n let low = 0;\n let high = haystack.length;\n let found = false;\n\n while (low < high) {\n /* Note that \"(low + high) >>> 1\" may overflow, and results in a typecast\n * to double (which gives the wrong results). */\n mid = low + ((high - low) >> 1);\n cmp = +comparator(haystack[mid], needle);\n\n if (cmp < 0.0) {\n /* Too low. */\n low = mid + 1;\n } else {\n /* Key found or too high */\n high = mid;\n found = !cmp;\n }\n }\n\n /* Key not found. */\n return found ? low : ~low;\n}\n\n/**\n * Compare function sorting arrays in ascending order. Safe to use for numeric values.\n * @param {*} a The first object to be compared.\n * @param {*} b The second object to be compared.\n * @return {number} A negative number, zero, or a positive number as the first\n * argument is less than, equal to, or greater than the second.\n */\nexport function ascending(a, b) {\n return a > b ? 1 : a < b ? -1 : 0;\n}\n\n/**\n * Compare function sorting arrays in descending order. Safe to use for numeric values.\n * @param {*} a The first object to be compared.\n * @param {*} b The second object to be compared.\n * @return {number} A negative number, zero, or a positive number as the first\n * argument is greater than, equal to, or less than the second.\n */\nexport function descending(a, b) {\n return a < b ? 1 : a > b ? -1 : 0;\n}\n\n/**\n * {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution} can use a function\n * of this type to determine which nearest resolution to use.\n *\n * This function takes a `{number}` representing a value between two array entries,\n * a `{number}` representing the value of the nearest higher entry and\n * a `{number}` representing the value of the nearest lower entry\n * as arguments and returns a `{number}`. If a negative number or zero is returned\n * the lower value will be used, if a positive number is returned the higher value\n * will be used.\n * @typedef {function(number, number, number): number} NearestDirectionFunction\n * @api\n */\n\n/**\n * @param {Array} arr Array in descending order.\n * @param {number} target Target.\n * @param {number|NearestDirectionFunction} direction\n * 0 means return the nearest,\n * > 0 means return the largest nearest,\n * < 0 means return the smallest nearest.\n * @return {number} Index.\n */\nexport function linearFindNearest(arr, target, direction) {\n if (arr[0] <= target) {\n return 0;\n }\n\n const n = arr.length;\n if (target <= arr[n - 1]) {\n return n - 1;\n }\n\n if (typeof direction === 'function') {\n for (let i = 1; i < n; ++i) {\n const candidate = arr[i];\n if (candidate === target) {\n return i;\n }\n if (candidate < target) {\n if (direction(target, arr[i - 1], candidate) > 0) {\n return i - 1;\n }\n return i;\n }\n }\n return n - 1;\n }\n\n if (direction > 0) {\n for (let i = 1; i < n; ++i) {\n if (arr[i] < target) {\n return i - 1;\n }\n }\n return n - 1;\n }\n\n if (direction < 0) {\n for (let i = 1; i < n; ++i) {\n if (arr[i] <= target) {\n return i;\n }\n }\n return n - 1;\n }\n\n for (let i = 1; i < n; ++i) {\n if (arr[i] == target) {\n return i;\n }\n if (arr[i] < target) {\n if (arr[i - 1] - target < target - arr[i]) {\n return i - 1;\n }\n return i;\n }\n }\n return n - 1;\n}\n\n/**\n * @param {Array<*>} arr Array.\n * @param {number} begin Begin index.\n * @param {number} end End index.\n */\nexport function reverseSubArray(arr, begin, end) {\n while (begin < end) {\n const tmp = arr[begin];\n arr[begin] = arr[end];\n arr[end] = tmp;\n ++begin;\n --end;\n }\n}\n\n/**\n * @param {Array} arr The array to modify.\n * @param {!Array|VALUE} data The elements or arrays of elements to add to arr.\n * @template VALUE\n */\nexport function extend(arr, data) {\n const extension = Array.isArray(data) ? data : [data];\n const length = extension.length;\n for (let i = 0; i < length; i++) {\n arr[arr.length] = extension[i];\n }\n}\n\n/**\n * @param {Array} arr The array to modify.\n * @param {VALUE} obj The element to remove.\n * @template VALUE\n * @return {boolean} If the element was removed.\n */\nexport function remove(arr, obj) {\n const i = arr.indexOf(obj);\n const found = i > -1;\n if (found) {\n arr.splice(i, 1);\n }\n return found;\n}\n\n/**\n * @param {Array|Uint8ClampedArray} arr1 The first array to compare.\n * @param {Array|Uint8ClampedArray} arr2 The second array to compare.\n * @return {boolean} Whether the two arrays are equal.\n */\nexport function equals(arr1, arr2) {\n const len1 = arr1.length;\n if (len1 !== arr2.length) {\n return false;\n }\n for (let i = 0; i < len1; i++) {\n if (arr1[i] !== arr2[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Sort the passed array such that the relative order of equal elements is preserved.\n * See https://en.wikipedia.org/wiki/Sorting_algorithm#Stability for details.\n * @param {Array<*>} arr The array to sort (modifies original).\n * @param {!function(*, *): number} compareFnc Comparison function.\n * @api\n */\nexport function stableSort(arr, compareFnc) {\n const length = arr.length;\n const tmp = Array(arr.length);\n let i;\n for (i = 0; i < length; i++) {\n tmp[i] = {index: i, value: arr[i]};\n }\n tmp.sort(function (a, b) {\n return compareFnc(a.value, b.value) || a.index - b.index;\n });\n for (i = 0; i < arr.length; i++) {\n arr[i] = tmp[i].value;\n }\n}\n\n/**\n * @param {Array<*>} arr The array to test.\n * @param {Function} [func] Comparison function.\n * @param {boolean} [strict] Strictly sorted (default false).\n * @return {boolean} Return index.\n */\nexport function isSorted(arr, func, strict) {\n const compare = func || ascending;\n return arr.every(function (currentVal, index) {\n if (index === 0) {\n return true;\n }\n const res = compare(arr[index - 1], currentVal);\n return !(res > 0 || (strict && res === 0));\n });\n}\n","/**\n * @module ol/functions\n */\n\nimport {equals as arrayEquals} from './array.js';\n\n/**\n * Always returns true.\n * @return {boolean} true.\n */\nexport function TRUE() {\n return true;\n}\n\n/**\n * Always returns false.\n * @return {boolean} false.\n */\nexport function FALSE() {\n return false;\n}\n\n/**\n * A reusable function, used e.g. as a default for callbacks.\n *\n * @return {void} Nothing.\n */\nexport function VOID() {}\n\n/**\n * Wrap a function in another function that remembers the last return. If the\n * returned function is called twice in a row with the same arguments and the same\n * this object, it will return the value from the first call in the second call.\n *\n * @param {function(...any): ReturnType} fn The function to memoize.\n * @return {function(...any): ReturnType} The memoized function.\n * @template ReturnType\n */\nexport function memoizeOne(fn) {\n let called = false;\n\n /** @type {ReturnType} */\n let lastResult;\n\n /** @type {Array} */\n let lastArgs;\n\n let lastThis;\n\n return function () {\n const nextArgs = Array.prototype.slice.call(arguments);\n if (!called || this !== lastThis || !arrayEquals(nextArgs, lastArgs)) {\n called = true;\n lastThis = this;\n lastArgs = nextArgs;\n lastResult = fn.apply(this, arguments);\n }\n return lastResult;\n };\n}\n\n/**\n * @template T\n * @param {function(): (T | Promise)} getter A function that returns a value or a promise for a value.\n * @return {Promise} A promise for the value.\n */\nexport function toPromise(getter) {\n function promiseGetter() {\n let value;\n try {\n value = getter();\n } catch (err) {\n return Promise.reject(err);\n }\n if (value instanceof Promise) {\n return value;\n }\n return Promise.resolve(value);\n }\n return promiseGetter();\n}\n","/**\n * @module ol/obj\n */\n\n/**\n * Removes all properties from an object.\n * @param {Object} object The object to clear.\n */\nexport function clear(object) {\n for (const property in object) {\n delete object[property];\n }\n}\n\n/**\n * Determine if an object has any properties.\n * @param {Object} object The object to check.\n * @return {boolean} The object is empty.\n */\nexport function isEmpty(object) {\n let property;\n for (property in object) {\n return false;\n }\n return !property;\n}\n","/**\n * @module ol/events/Target\n */\nimport Disposable from '../Disposable.js';\nimport Event from './Event.js';\nimport {VOID} from '../functions.js';\nimport {clear} from '../obj.js';\n\n/**\n * @typedef {EventTarget|Target} EventTargetLike\n */\n\n/**\n * @classdesc\n * A simplified implementation of the W3C DOM Level 2 EventTarget interface.\n * See https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget.\n *\n * There are two important simplifications compared to the specification:\n *\n * 1. The handling of `useCapture` in `addEventListener` and\n * `removeEventListener`. There is no real capture model.\n * 2. The handling of `stopPropagation` and `preventDefault` on `dispatchEvent`.\n * There is no event target hierarchy. When a listener calls\n * `stopPropagation` or `preventDefault` on an event object, it means that no\n * more listeners after this one will be called. Same as when the listener\n * returns false.\n */\nclass Target extends Disposable {\n /**\n * @param {*} [target] Default event target for dispatched events.\n */\n constructor(target) {\n super();\n\n /**\n * @private\n * @type {*}\n */\n this.eventTarget_ = target;\n\n /**\n * @private\n * @type {Object|null}\n */\n this.pendingRemovals_ = null;\n\n /**\n * @private\n * @type {Object|null}\n */\n this.dispatching_ = null;\n\n /**\n * @private\n * @type {Object>|null}\n */\n this.listeners_ = null;\n }\n\n /**\n * @param {string} type Type.\n * @param {import(\"../events.js\").Listener} listener Listener.\n */\n addEventListener(type, listener) {\n if (!type || !listener) {\n return;\n }\n const listeners = this.listeners_ || (this.listeners_ = {});\n const listenersForType = listeners[type] || (listeners[type] = []);\n if (!listenersForType.includes(listener)) {\n listenersForType.push(listener);\n }\n }\n\n /**\n * Dispatches an event and calls all listeners listening for events\n * of this type. The event parameter can either be a string or an\n * Object with a `type` property.\n *\n * @param {import(\"./Event.js\").default|string} event Event object.\n * @return {boolean|undefined} `false` if anyone called preventDefault on the\n * event object or if any of the listeners returned false.\n * @api\n */\n dispatchEvent(event) {\n const isString = typeof event === 'string';\n const type = isString ? event : event.type;\n const listeners = this.listeners_ && this.listeners_[type];\n if (!listeners) {\n return;\n }\n\n const evt = isString ? new Event(event) : /** @type {Event} */ (event);\n if (!evt.target) {\n evt.target = this.eventTarget_ || this;\n }\n const dispatching = this.dispatching_ || (this.dispatching_ = {});\n const pendingRemovals =\n this.pendingRemovals_ || (this.pendingRemovals_ = {});\n if (!(type in dispatching)) {\n dispatching[type] = 0;\n pendingRemovals[type] = 0;\n }\n ++dispatching[type];\n let propagate;\n for (let i = 0, ii = listeners.length; i < ii; ++i) {\n if ('handleEvent' in listeners[i]) {\n propagate = /** @type {import(\"../events.js\").ListenerObject} */ (\n listeners[i]\n ).handleEvent(evt);\n } else {\n propagate = /** @type {import(\"../events.js\").ListenerFunction} */ (\n listeners[i]\n ).call(this, evt);\n }\n if (propagate === false || evt.propagationStopped) {\n propagate = false;\n break;\n }\n }\n if (--dispatching[type] === 0) {\n let pr = pendingRemovals[type];\n delete pendingRemovals[type];\n while (pr--) {\n this.removeEventListener(type, VOID);\n }\n delete dispatching[type];\n }\n return propagate;\n }\n\n /**\n * Clean up.\n */\n disposeInternal() {\n this.listeners_ && clear(this.listeners_);\n }\n\n /**\n * Get the listeners for a specified event type. Listeners are returned in the\n * order that they will be called in.\n *\n * @param {string} type Type.\n * @return {Array|undefined} Listeners.\n */\n getListeners(type) {\n return (this.listeners_ && this.listeners_[type]) || undefined;\n }\n\n /**\n * @param {string} [type] Type. If not provided,\n * `true` will be returned if this event target has any listeners.\n * @return {boolean} Has listeners.\n */\n hasListener(type) {\n if (!this.listeners_) {\n return false;\n }\n return type\n ? type in this.listeners_\n : Object.keys(this.listeners_).length > 0;\n }\n\n /**\n * @param {string} type Type.\n * @param {import(\"../events.js\").Listener} listener Listener.\n */\n removeEventListener(type, listener) {\n if (!this.listeners_) {\n return;\n }\n const listeners = this.listeners_[type];\n if (!listeners) {\n return;\n }\n const index = listeners.indexOf(listener);\n if (index !== -1) {\n if (this.pendingRemovals_ && type in this.pendingRemovals_) {\n // make listener a no-op, and remove later in #dispatchEvent()\n listeners[index] = VOID;\n ++this.pendingRemovals_[type];\n } else {\n listeners.splice(index, 1);\n if (listeners.length === 0) {\n delete this.listeners_[type];\n }\n }\n }\n }\n}\n\nexport default Target;\n","/**\n * @module ol/events/EventType\n */\n\n/**\n * @enum {string}\n * @const\n */\nexport default {\n /**\n * Generic change event. Triggered when the revision counter is increased.\n * @event module:ol/events/Event~BaseEvent#change\n * @api\n */\n CHANGE: 'change',\n\n /**\n * Generic error event. Triggered when an error occurs.\n * @event module:ol/events/Event~BaseEvent#error\n * @api\n */\n ERROR: 'error',\n\n BLUR: 'blur',\n CLEAR: 'clear',\n CONTEXTMENU: 'contextmenu',\n CLICK: 'click',\n DBLCLICK: 'dblclick',\n DRAGENTER: 'dragenter',\n DRAGOVER: 'dragover',\n DROP: 'drop',\n FOCUS: 'focus',\n KEYDOWN: 'keydown',\n KEYPRESS: 'keypress',\n LOAD: 'load',\n RESIZE: 'resize',\n TOUCHMOVE: 'touchmove',\n WHEEL: 'wheel',\n};\n","/**\n * @module ol/events\n */\nimport {clear} from './obj.js';\n\n/**\n * Key to use with {@link module:ol/Observable.unByKey}.\n * @typedef {Object} EventsKey\n * @property {ListenerFunction} listener Listener.\n * @property {import(\"./events/Target.js\").EventTargetLike} target Target.\n * @property {string} type Type.\n * @api\n */\n\n/**\n * Listener function. This function is called with an event object as argument.\n * When the function returns `false`, event propagation will stop.\n *\n * @typedef {function((Event|import(\"./events/Event.js\").default)): (void|boolean)} ListenerFunction\n * @api\n */\n\n/**\n * @typedef {Object} ListenerObject\n * @property {ListenerFunction} handleEvent HandleEvent listener function.\n */\n\n/**\n * @typedef {ListenerFunction|ListenerObject} Listener\n */\n\n/**\n * Registers an event listener on an event target. Inspired by\n * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html\n *\n * This function efficiently binds a `listener` to a `this` object, and returns\n * a key for use with {@link module:ol/events.unlistenByKey}.\n *\n * @param {import(\"./events/Target.js\").EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {ListenerFunction} listener Listener.\n * @param {Object} [thisArg] Object referenced by the `this` keyword in the\n * listener. Default is the `target`.\n * @param {boolean} [once] If true, add the listener as one-off listener.\n * @return {EventsKey} Unique key for the listener.\n */\nexport function listen(target, type, listener, thisArg, once) {\n if (thisArg && thisArg !== target) {\n listener = listener.bind(thisArg);\n }\n if (once) {\n const originalListener = listener;\n listener = function () {\n target.removeEventListener(type, listener);\n originalListener.apply(this, arguments);\n };\n }\n const eventsKey = {\n target: target,\n type: type,\n listener: listener,\n };\n target.addEventListener(type, listener);\n return eventsKey;\n}\n\n/**\n * Registers a one-off event listener on an event target. Inspired by\n * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html\n *\n * This function efficiently binds a `listener` as self-unregistering listener\n * to a `this` object, and returns a key for use with\n * {@link module:ol/events.unlistenByKey} in case the listener needs to be\n * unregistered before it is called.\n *\n * When {@link module:ol/events.listen} is called with the same arguments after this\n * function, the self-unregistering listener will be turned into a permanent\n * listener.\n *\n * @param {import(\"./events/Target.js\").EventTargetLike} target Event target.\n * @param {string} type Event type.\n * @param {ListenerFunction} listener Listener.\n * @param {Object} [thisArg] Object referenced by the `this` keyword in the\n * listener. Default is the `target`.\n * @return {EventsKey} Key for unlistenByKey.\n */\nexport function listenOnce(target, type, listener, thisArg) {\n return listen(target, type, listener, thisArg, true);\n}\n\n/**\n * Unregisters event listeners on an event target. Inspired by\n * https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html\n *\n * The argument passed to this function is the key returned from\n * {@link module:ol/events.listen} or {@link module:ol/events.listenOnce}.\n *\n * @param {EventsKey} key The key.\n */\nexport function unlistenByKey(key) {\n if (key && key.target) {\n key.target.removeEventListener(key.type, key.listener);\n clear(key);\n }\n}\n","/**\n * @module ol/Observable\n */\nimport EventTarget from './events/Target.js';\nimport EventType from './events/EventType.js';\nimport {listen, listenOnce, unlistenByKey} from './events.js';\n\n/***\n * @template {string} Type\n * @template {Event|import(\"./events/Event.js\").default} EventClass\n * @template Return\n * @typedef {(type: Type, listener: (event: EventClass) => ?) => Return} OnSignature\n */\n\n/***\n * @template {string} Type\n * @template Return\n * @typedef {(type: Type[], listener: (event: Event|import(\"./events/Event\").default) => ?) => Return extends void ? void : Return[]} CombinedOnSignature\n */\n\n/**\n * @typedef {'change'|'error'} EventTypes\n */\n\n/***\n * @template Return\n * @typedef {OnSignature & CombinedOnSignature} ObservableOnSignature\n */\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * An event target providing convenient methods for listener registration\n * and unregistration. A generic `change` event is always available through\n * {@link module:ol/Observable~Observable#changed}.\n *\n * @fires import(\"./events/Event.js\").default\n * @api\n */\nclass Observable extends EventTarget {\n constructor() {\n super();\n\n this.on =\n /** @type {ObservableOnSignature} */ (\n this.onInternal\n );\n\n this.once =\n /** @type {ObservableOnSignature} */ (\n this.onceInternal\n );\n\n this.un = /** @type {ObservableOnSignature} */ (this.unInternal);\n\n /**\n * @private\n * @type {number}\n */\n this.revision_ = 0;\n }\n\n /**\n * Increases the revision counter and dispatches a 'change' event.\n * @api\n */\n changed() {\n ++this.revision_;\n this.dispatchEvent(EventType.CHANGE);\n }\n\n /**\n * Get the version number for this object. Each time the object is modified,\n * its version number will be incremented.\n * @return {number} Revision.\n * @api\n */\n getRevision() {\n return this.revision_;\n }\n\n /**\n * @param {string|Array} type Type.\n * @param {function((Event|import(\"./events/Event\").default)): ?} listener Listener.\n * @return {import(\"./events.js\").EventsKey|Array} Event key.\n * @protected\n */\n onInternal(type, listener) {\n if (Array.isArray(type)) {\n const len = type.length;\n const keys = new Array(len);\n for (let i = 0; i < len; ++i) {\n keys[i] = listen(this, type[i], listener);\n }\n return keys;\n }\n return listen(this, /** @type {string} */ (type), listener);\n }\n\n /**\n * @param {string|Array} type Type.\n * @param {function((Event|import(\"./events/Event\").default)): ?} listener Listener.\n * @return {import(\"./events.js\").EventsKey|Array} Event key.\n * @protected\n */\n onceInternal(type, listener) {\n let key;\n if (Array.isArray(type)) {\n const len = type.length;\n key = new Array(len);\n for (let i = 0; i < len; ++i) {\n key[i] = listenOnce(this, type[i], listener);\n }\n } else {\n key = listenOnce(this, /** @type {string} */ (type), listener);\n }\n /** @type {Object} */ (listener).ol_key = key;\n return key;\n }\n\n /**\n * Unlisten for a certain type of event.\n * @param {string|Array} type Type.\n * @param {function((Event|import(\"./events/Event\").default)): ?} listener Listener.\n * @protected\n */\n unInternal(type, listener) {\n const key = /** @type {Object} */ (listener).ol_key;\n if (key) {\n unByKey(key);\n } else if (Array.isArray(type)) {\n for (let i = 0, ii = type.length; i < ii; ++i) {\n this.removeEventListener(type[i], listener);\n }\n } else {\n this.removeEventListener(type, listener);\n }\n }\n}\n\n/**\n * Listen for a certain type of event.\n * @function\n * @param {string|Array} type The event type or array of event types.\n * @param {function((Event|import(\"./events/Event\").default)): ?} listener The listener function.\n * @return {import(\"./events.js\").EventsKey|Array} Unique key for the listener. If\n * called with an array of event types as the first argument, the return\n * will be an array of keys.\n * @api\n */\nObservable.prototype.on;\n\n/**\n * Listen once for a certain type of event.\n * @function\n * @param {string|Array} type The event type or array of event types.\n * @param {function((Event|import(\"./events/Event\").default)): ?} listener The listener function.\n * @return {import(\"./events.js\").EventsKey|Array} Unique key for the listener. If\n * called with an array of event types as the first argument, the return\n * will be an array of keys.\n * @api\n */\nObservable.prototype.once;\n\n/**\n * Unlisten for a certain type of event.\n * @function\n * @param {string|Array} type The event type or array of event types.\n * @param {function((Event|import(\"./events/Event\").default)): ?} listener The listener function.\n * @api\n */\nObservable.prototype.un;\n\n/**\n * Removes an event listener using the key returned by `on()` or `once()`.\n * @param {import(\"./events.js\").EventsKey|Array} key The key returned by `on()`\n * or `once()` (or an array of keys).\n * @api\n */\nexport function unByKey(key) {\n if (Array.isArray(key)) {\n for (let i = 0, ii = key.length; i < ii; ++i) {\n unlistenByKey(key[i]);\n }\n } else {\n unlistenByKey(/** @type {import(\"./events.js\").EventsKey} */ (key));\n }\n}\n\nexport default Observable;\n","/**\n * @module ol/util\n */\n\n/**\n * @return {never} Any return.\n */\nexport function abstract() {\n throw new Error('Unimplemented abstract method.');\n}\n\n/**\n * Counter for getUid.\n * @type {number}\n * @private\n */\nlet uidCounter_ = 0;\n\n/**\n * Gets a unique ID for an object. This mutates the object so that further calls\n * with the same object as a parameter returns the same value. Unique IDs are generated\n * as a strictly increasing sequence. Adapted from goog.getUid.\n *\n * @param {Object} obj The object to get the unique ID for.\n * @return {string} The unique ID for the object.\n * @api\n */\nexport function getUid(obj) {\n return obj.ol_uid || (obj.ol_uid = String(++uidCounter_));\n}\n\n/**\n * OpenLayers version.\n * @type {string}\n */\nexport const VERSION = '8.2.0';\n","/**\n * @module ol/Object\n */\nimport Event from './events/Event.js';\nimport ObjectEventType from './ObjectEventType.js';\nimport Observable from './Observable.js';\nimport {getUid} from './util.js';\nimport {isEmpty} from './obj.js';\n\n/**\n * @classdesc\n * Events emitted by {@link module:ol/Object~BaseObject} instances are instances of this type.\n */\nexport class ObjectEvent extends Event {\n /**\n * @param {string} type The event type.\n * @param {string} key The property name.\n * @param {*} oldValue The old value for `key`.\n */\n constructor(type, key, oldValue) {\n super(type);\n\n /**\n * The name of the property whose value is changing.\n * @type {string}\n * @api\n */\n this.key = key;\n\n /**\n * The old value. To get the new value use `e.target.get(e.key)` where\n * `e` is the event object.\n * @type {*}\n * @api\n */\n this.oldValue = oldValue;\n }\n}\n\n/***\n * @template Return\n * @typedef {import(\"./Observable\").OnSignature &\n * import(\"./Observable\").OnSignature &\n * import(\"./Observable\").CombinedOnSignature} ObjectOnSignature\n */\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Most non-trivial classes inherit from this.\n *\n * This extends {@link module:ol/Observable~Observable} with observable\n * properties, where each property is observable as well as the object as a\n * whole.\n *\n * Classes that inherit from this have pre-defined properties, to which you can\n * add your owns. The pre-defined properties are listed in this documentation as\n * 'Observable Properties', and have their own accessors; for example,\n * {@link module:ol/Map~Map} has a `target` property, accessed with\n * `getTarget()` and changed with `setTarget()`. Not all properties are however\n * settable. There are also general-purpose accessors `get()` and `set()`. For\n * example, `get('target')` is equivalent to `getTarget()`.\n *\n * The `set` accessors trigger a change event, and you can monitor this by\n * registering a listener. For example, {@link module:ol/View~View} has a\n * `center` property, so `view.on('change:center', function(evt) {...});` would\n * call the function whenever the value of the center property changes. Within\n * the function, `evt.target` would be the view, so `evt.target.getCenter()`\n * would return the new center.\n *\n * You can add your own observable properties with\n * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`.\n * You can listen for changes on that property value with\n * `object.on('change:prop', listener)`. You can get a list of all\n * properties with {@link module:ol/Object~BaseObject#getProperties}.\n *\n * Note that the observable properties are separate from standard JS properties.\n * You can, for example, give your map object a title with\n * `map.title='New title'` and with `map.set('title', 'Another title')`. The\n * first will be a `hasOwnProperty`; the second will appear in\n * `getProperties()`. Only the second is observable.\n *\n * Properties can be deleted by using the unset method. E.g.\n * object.unset('foo').\n *\n * @fires ObjectEvent\n * @api\n */\nclass BaseObject extends Observable {\n /**\n * @param {Object} [values] An object with key-value pairs.\n */\n constructor(values) {\n super();\n\n /***\n * @type {ObjectOnSignature}\n */\n this.on;\n\n /***\n * @type {ObjectOnSignature}\n */\n this.once;\n\n /***\n * @type {ObjectOnSignature}\n */\n this.un;\n\n // Call {@link module:ol/util.getUid} to ensure that the order of objects' ids is\n // the same as the order in which they were created. This also helps to\n // ensure that object properties are always added in the same order, which\n // helps many JavaScript engines generate faster code.\n getUid(this);\n\n /**\n * @private\n * @type {Object|null}\n */\n this.values_ = null;\n\n if (values !== undefined) {\n this.setProperties(values);\n }\n }\n\n /**\n * Gets a value.\n * @param {string} key Key name.\n * @return {*} Value.\n * @api\n */\n get(key) {\n let value;\n if (this.values_ && this.values_.hasOwnProperty(key)) {\n value = this.values_[key];\n }\n return value;\n }\n\n /**\n * Get a list of object property names.\n * @return {Array} List of property names.\n * @api\n */\n getKeys() {\n return (this.values_ && Object.keys(this.values_)) || [];\n }\n\n /**\n * Get an object of all property names and values.\n * @return {Object} Object.\n * @api\n */\n getProperties() {\n return (this.values_ && Object.assign({}, this.values_)) || {};\n }\n\n /**\n * Get an object of all property names and values.\n * @return {Object?} Object.\n */\n getPropertiesInternal() {\n return this.values_;\n }\n\n /**\n * @return {boolean} The object has properties.\n */\n hasProperties() {\n return !!this.values_;\n }\n\n /**\n * @param {string} key Key name.\n * @param {*} oldValue Old value.\n */\n notify(key, oldValue) {\n let eventType;\n eventType = `change:${key}`;\n if (this.hasListener(eventType)) {\n this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));\n }\n eventType = ObjectEventType.PROPERTYCHANGE;\n if (this.hasListener(eventType)) {\n this.dispatchEvent(new ObjectEvent(eventType, key, oldValue));\n }\n }\n\n /**\n * @param {string} key Key name.\n * @param {import(\"./events.js\").Listener} listener Listener.\n */\n addChangeListener(key, listener) {\n this.addEventListener(`change:${key}`, listener);\n }\n\n /**\n * @param {string} key Key name.\n * @param {import(\"./events.js\").Listener} listener Listener.\n */\n removeChangeListener(key, listener) {\n this.removeEventListener(`change:${key}`, listener);\n }\n\n /**\n * Sets a value.\n * @param {string} key Key name.\n * @param {*} value Value.\n * @param {boolean} [silent] Update without triggering an event.\n * @api\n */\n set(key, value, silent) {\n const values = this.values_ || (this.values_ = {});\n if (silent) {\n values[key] = value;\n } else {\n const oldValue = values[key];\n values[key] = value;\n if (oldValue !== value) {\n this.notify(key, oldValue);\n }\n }\n }\n\n /**\n * Sets a collection of key-value pairs. Note that this changes any existing\n * properties and adds new ones (it does not remove any existing properties).\n * @param {Object} values Values.\n * @param {boolean} [silent] Update without triggering an event.\n * @api\n */\n setProperties(values, silent) {\n for (const key in values) {\n this.set(key, values[key], silent);\n }\n }\n\n /**\n * Apply any properties from another object without triggering events.\n * @param {BaseObject} source The source object.\n * @protected\n */\n applyProperties(source) {\n if (!source.values_) {\n return;\n }\n Object.assign(this.values_ || (this.values_ = {}), source.values_);\n }\n\n /**\n * Unsets a property.\n * @param {string} key Key name.\n * @param {boolean} [silent] Unset without triggering an event.\n * @api\n */\n unset(key, silent) {\n if (this.values_ && key in this.values_) {\n const oldValue = this.values_[key];\n delete this.values_[key];\n if (isEmpty(this.values_)) {\n this.values_ = null;\n }\n if (!silent) {\n this.notify(key, oldValue);\n }\n }\n }\n}\n\nexport default BaseObject;\n","/**\n * @module ol/CollectionEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * Triggered when an item is added to the collection.\n * @event module:ol/Collection.CollectionEvent#add\n * @api\n */\n ADD: 'add',\n /**\n * Triggered when an item is removed from the collection.\n * @event module:ol/Collection.CollectionEvent#remove\n * @api\n */\n REMOVE: 'remove',\n};\n","/**\n * @module ol/Collection\n */\nimport BaseObject from './Object.js';\nimport CollectionEventType from './CollectionEventType.js';\nimport Event from './events/Event.js';\n\n/**\n * @enum {string}\n * @private\n */\nconst Property = {\n LENGTH: 'length',\n};\n\n/**\n * @classdesc\n * Events emitted by {@link module:ol/Collection~Collection} instances are instances of this\n * type.\n * @template T\n */\nexport class CollectionEvent extends Event {\n /**\n * @param {import(\"./CollectionEventType.js\").default} type Type.\n * @param {T} element Element.\n * @param {number} index The index of the added or removed element.\n */\n constructor(type, element, index) {\n super(type);\n\n /**\n * The element that is added to or removed from the collection.\n * @type {T}\n * @api\n */\n this.element = element;\n\n /**\n * The index of the added or removed element.\n * @type {number}\n * @api\n */\n this.index = index;\n }\n}\n\n/***\n * @template T\n * @template Return\n * @typedef {import(\"./Observable\").OnSignature &\n * import(\"./Observable\").OnSignature &\n * import(\"./Observable\").OnSignature<'add'|'remove', CollectionEvent, Return> &\n * import(\"./Observable\").CombinedOnSignature} CollectionOnSignature\n */\n\n/**\n * @typedef {Object} Options\n * @property {boolean} [unique=false] Disallow the same item from being added to\n * the collection twice.\n */\n\n/**\n * @classdesc\n * An expanded version of standard JS Array, adding convenience methods for\n * manipulation. Add and remove changes to the Collection trigger a Collection\n * event. Note that this does not cover changes to the objects _within_ the\n * Collection; they trigger events on the appropriate object, not on the\n * Collection as a whole.\n *\n * @fires CollectionEvent\n *\n * @template T\n * @api\n */\nclass Collection extends BaseObject {\n /**\n * @param {Array} [array] Array.\n * @param {Options} [options] Collection options.\n */\n constructor(array, options) {\n super();\n\n /***\n * @type {CollectionOnSignature}\n */\n this.on;\n\n /***\n * @type {CollectionOnSignature}\n */\n this.once;\n\n /***\n * @type {CollectionOnSignature}\n */\n this.un;\n\n options = options || {};\n\n /**\n * @private\n * @type {boolean}\n */\n this.unique_ = !!options.unique;\n\n /**\n * @private\n * @type {!Array}\n */\n this.array_ = array ? array : [];\n\n if (this.unique_) {\n for (let i = 0, ii = this.array_.length; i < ii; ++i) {\n this.assertUnique_(this.array_[i], i);\n }\n }\n\n this.updateLength_();\n }\n\n /**\n * Remove all elements from the collection.\n * @api\n */\n clear() {\n while (this.getLength() > 0) {\n this.pop();\n }\n }\n\n /**\n * Add elements to the collection. This pushes each item in the provided array\n * to the end of the collection.\n * @param {!Array} arr Array.\n * @return {Collection} This collection.\n * @api\n */\n extend(arr) {\n for (let i = 0, ii = arr.length; i < ii; ++i) {\n this.push(arr[i]);\n }\n return this;\n }\n\n /**\n * Iterate over each element, calling the provided callback.\n * @param {function(T, number, Array): *} f The function to call\n * for every element. This function takes 3 arguments (the element, the\n * index and the array). The return value is ignored.\n * @api\n */\n forEach(f) {\n const array = this.array_;\n for (let i = 0, ii = array.length; i < ii; ++i) {\n f(array[i], i, array);\n }\n }\n\n /**\n * Get a reference to the underlying Array object. Warning: if the array\n * is mutated, no events will be dispatched by the collection, and the\n * collection's \"length\" property won't be in sync with the actual length\n * of the array.\n * @return {!Array} Array.\n * @api\n */\n getArray() {\n return this.array_;\n }\n\n /**\n * Get the element at the provided index.\n * @param {number} index Index.\n * @return {T} Element.\n * @api\n */\n item(index) {\n return this.array_[index];\n }\n\n /**\n * Get the length of this collection.\n * @return {number} The length of the array.\n * @observable\n * @api\n */\n getLength() {\n return this.get(Property.LENGTH);\n }\n\n /**\n * Insert an element at the provided index.\n * @param {number} index Index.\n * @param {T} elem Element.\n * @api\n */\n insertAt(index, elem) {\n if (index < 0 || index > this.getLength()) {\n throw new Error('Index out of bounds: ' + index);\n }\n if (this.unique_) {\n this.assertUnique_(elem);\n }\n this.array_.splice(index, 0, elem);\n this.updateLength_();\n this.dispatchEvent(\n new CollectionEvent(CollectionEventType.ADD, elem, index)\n );\n }\n\n /**\n * Remove the last element of the collection and return it.\n * Return `undefined` if the collection is empty.\n * @return {T|undefined} Element.\n * @api\n */\n pop() {\n return this.removeAt(this.getLength() - 1);\n }\n\n /**\n * Insert the provided element at the end of the collection.\n * @param {T} elem Element.\n * @return {number} New length of the collection.\n * @api\n */\n push(elem) {\n if (this.unique_) {\n this.assertUnique_(elem);\n }\n const n = this.getLength();\n this.insertAt(n, elem);\n return this.getLength();\n }\n\n /**\n * Remove the first occurrence of an element from the collection.\n * @param {T} elem Element.\n * @return {T|undefined} The removed element or undefined if none found.\n * @api\n */\n remove(elem) {\n const arr = this.array_;\n for (let i = 0, ii = arr.length; i < ii; ++i) {\n if (arr[i] === elem) {\n return this.removeAt(i);\n }\n }\n return undefined;\n }\n\n /**\n * Remove the element at the provided index and return it.\n * Return `undefined` if the collection does not contain this index.\n * @param {number} index Index.\n * @return {T|undefined} Value.\n * @api\n */\n removeAt(index) {\n if (index < 0 || index >= this.getLength()) {\n return undefined;\n }\n const prev = this.array_[index];\n this.array_.splice(index, 1);\n this.updateLength_();\n this.dispatchEvent(\n /** @type {CollectionEvent} */ (\n new CollectionEvent(CollectionEventType.REMOVE, prev, index)\n )\n );\n return prev;\n }\n\n /**\n * Set the element at the provided index.\n * @param {number} index Index.\n * @param {T} elem Element.\n * @api\n */\n setAt(index, elem) {\n const n = this.getLength();\n if (index >= n) {\n this.insertAt(index, elem);\n return;\n }\n if (index < 0) {\n throw new Error('Index out of bounds: ' + index);\n }\n if (this.unique_) {\n this.assertUnique_(elem, index);\n }\n const prev = this.array_[index];\n this.array_[index] = elem;\n this.dispatchEvent(\n /** @type {CollectionEvent} */ (\n new CollectionEvent(CollectionEventType.REMOVE, prev, index)\n )\n );\n this.dispatchEvent(\n /** @type {CollectionEvent} */ (\n new CollectionEvent(CollectionEventType.ADD, elem, index)\n )\n );\n }\n\n /**\n * @private\n */\n updateLength_() {\n this.set(Property.LENGTH, this.array_.length);\n }\n\n /**\n * @private\n * @param {T} elem Element.\n * @param {number} [except] Optional index to ignore.\n */\n assertUnique_(elem, except) {\n for (let i = 0, ii = this.array_.length; i < ii; ++i) {\n if (this.array_[i] === elem && i !== except) {\n throw new Error('Duplicate item added to a unique collection');\n }\n }\n }\n}\n\nexport default Collection;\n","/**\n * @module ol/asserts\n */\n\n/**\n * @param {*} assertion Assertion we expected to be truthy.\n * @param {string} errorMessage Error message.\n */\nexport function assert(assertion, errorMessage) {\n if (!assertion) {\n throw new Error(errorMessage);\n }\n}\n","/**\n * @module ol/Feature\n */\nimport BaseObject from './Object.js';\nimport EventType from './events/EventType.js';\nimport {assert} from './asserts.js';\nimport {listen, unlistenByKey} from './events.js';\n\n/**\n * @typedef {typeof Feature|typeof import(\"./render/Feature.js\").default} FeatureClass\n */\n\n/**\n * @typedef {Feature|import(\"./render/Feature.js\").default} FeatureLike\n */\n\n/***\n * @template Return\n * @typedef {import(\"./Observable\").OnSignature &\n * import(\"./Observable\").OnSignature &\n * import(\"./Observable\").CombinedOnSignature} FeatureOnSignature\n */\n\n/***\n * @template {import(\"./geom/Geometry.js\").default} [Geometry=import(\"./geom/Geometry.js\").default]\n * @typedef {Object & { geometry?: Geometry }} ObjectWithGeometry\n */\n\n/**\n * @classdesc\n * A vector object for geographic features with a geometry and other\n * attribute properties, similar to the features in vector file formats like\n * GeoJSON.\n *\n * Features can be styled individually with `setStyle`; otherwise they use the\n * style of their vector layer.\n *\n * Note that attribute properties are set as {@link module:ol/Object~BaseObject} properties on\n * the feature object, so they are observable, and have get/set accessors.\n *\n * Typically, a feature has a single geometry property. You can set the\n * geometry using the `setGeometry` method and get it with `getGeometry`.\n * It is possible to store more than one geometry on a feature using attribute\n * properties. By default, the geometry used for rendering is identified by\n * the property name `geometry`. If you want to use another geometry property\n * for rendering, use the `setGeometryName` method to change the attribute\n * property associated with the geometry for the feature. For example:\n *\n * ```js\n *\n * import Feature from 'ol/Feature.js';\n * import Polygon from 'ol/geom/Polygon.js';\n * import Point from 'ol/geom/Point.js';\n *\n * const feature = new Feature({\n * geometry: new Polygon(polyCoords),\n * labelPoint: new Point(labelCoords),\n * name: 'My Polygon',\n * });\n *\n * // get the polygon geometry\n * const poly = feature.getGeometry();\n *\n * // Render the feature as a point using the coordinates from labelPoint\n * feature.setGeometryName('labelPoint');\n *\n * // get the point geometry\n * const point = feature.getGeometry();\n * ```\n *\n * @api\n * @template {import(\"./geom/Geometry.js\").default} [Geometry=import(\"./geom/Geometry.js\").default]\n */\nclass Feature extends BaseObject {\n /**\n * @param {Geometry|ObjectWithGeometry} [geometryOrProperties]\n * You may pass a Geometry object directly, or an object literal containing\n * properties. If you pass an object literal, you may include a Geometry\n * associated with a `geometry` key.\n */\n constructor(geometryOrProperties) {\n super();\n\n /***\n * @type {FeatureOnSignature}\n */\n this.on;\n\n /***\n * @type {FeatureOnSignature}\n */\n this.once;\n\n /***\n * @type {FeatureOnSignature}\n */\n this.un;\n\n /**\n * @private\n * @type {number|string|undefined}\n */\n this.id_ = undefined;\n\n /**\n * @type {string}\n * @private\n */\n this.geometryName_ = 'geometry';\n\n /**\n * User provided style.\n * @private\n * @type {import(\"./style/Style.js\").StyleLike}\n */\n this.style_ = null;\n\n /**\n * @private\n * @type {import(\"./style/Style.js\").StyleFunction|undefined}\n */\n this.styleFunction_ = undefined;\n\n /**\n * @private\n * @type {?import(\"./events.js\").EventsKey}\n */\n this.geometryChangeKey_ = null;\n\n this.addChangeListener(this.geometryName_, this.handleGeometryChanged_);\n\n if (geometryOrProperties) {\n if (\n typeof (\n /** @type {?} */ (geometryOrProperties).getSimplifiedGeometry\n ) === 'function'\n ) {\n const geometry = /** @type {Geometry} */ (geometryOrProperties);\n this.setGeometry(geometry);\n } else {\n /** @type {Object} */\n const properties = geometryOrProperties;\n this.setProperties(properties);\n }\n }\n }\n\n /**\n * Clone this feature. If the original feature has a geometry it\n * is also cloned. The feature id is not set in the clone.\n * @return {Feature} The clone.\n * @api\n */\n clone() {\n const clone = /** @type {Feature} */ (\n new Feature(this.hasProperties() ? this.getProperties() : null)\n );\n clone.setGeometryName(this.getGeometryName());\n const geometry = this.getGeometry();\n if (geometry) {\n clone.setGeometry(/** @type {Geometry} */ (geometry.clone()));\n }\n const style = this.getStyle();\n if (style) {\n clone.setStyle(style);\n }\n return clone;\n }\n\n /**\n * Get the feature's default geometry. A feature may have any number of named\n * geometries. The \"default\" geometry (the one that is rendered by default) is\n * set when calling {@link module:ol/Feature~Feature#setGeometry}.\n * @return {Geometry|undefined} The default geometry for the feature.\n * @api\n * @observable\n */\n getGeometry() {\n return /** @type {Geometry|undefined} */ (this.get(this.geometryName_));\n }\n\n /**\n * Get the feature identifier. This is a stable identifier for the feature and\n * is either set when reading data from a remote source or set explicitly by\n * calling {@link module:ol/Feature~Feature#setId}.\n * @return {number|string|undefined} Id.\n * @api\n */\n getId() {\n return this.id_;\n }\n\n /**\n * Get the name of the feature's default geometry. By default, the default\n * geometry is named `geometry`.\n * @return {string} Get the property name associated with the default geometry\n * for this feature.\n * @api\n */\n getGeometryName() {\n return this.geometryName_;\n }\n\n /**\n * Get the feature's style. Will return what was provided to the\n * {@link module:ol/Feature~Feature#setStyle} method.\n * @return {import(\"./style/Style.js\").StyleLike|undefined} The feature style.\n * @api\n */\n getStyle() {\n return this.style_;\n }\n\n /**\n * Get the feature's style function.\n * @return {import(\"./style/Style.js\").StyleFunction|undefined} Return a function\n * representing the current style of this feature.\n * @api\n */\n getStyleFunction() {\n return this.styleFunction_;\n }\n\n /**\n * @private\n */\n handleGeometryChange_() {\n this.changed();\n }\n\n /**\n * @private\n */\n handleGeometryChanged_() {\n if (this.geometryChangeKey_) {\n unlistenByKey(this.geometryChangeKey_);\n this.geometryChangeKey_ = null;\n }\n const geometry = this.getGeometry();\n if (geometry) {\n this.geometryChangeKey_ = listen(\n geometry,\n EventType.CHANGE,\n this.handleGeometryChange_,\n this\n );\n }\n this.changed();\n }\n\n /**\n * Set the default geometry for the feature. This will update the property\n * with the name returned by {@link module:ol/Feature~Feature#getGeometryName}.\n * @param {Geometry|undefined} geometry The new geometry.\n * @api\n * @observable\n */\n setGeometry(geometry) {\n this.set(this.geometryName_, geometry);\n }\n\n /**\n * Set the style for the feature to override the layer style. This can be a\n * single style object, an array of styles, or a function that takes a\n * resolution and returns an array of styles. To unset the feature style, call\n * `setStyle()` without arguments or a falsey value.\n * @param {import(\"./style/Style.js\").StyleLike} [style] Style for this feature.\n * @api\n * @fires module:ol/events/Event~BaseEvent#event:change\n */\n setStyle(style) {\n this.style_ = style;\n this.styleFunction_ = !style ? undefined : createStyleFunction(style);\n this.changed();\n }\n\n /**\n * Set the feature id. The feature id is considered stable and may be used when\n * requesting features or comparing identifiers returned from a remote source.\n * The feature id can be used with the\n * {@link module:ol/source/Vector~VectorSource#getFeatureById} method.\n * @param {number|string|undefined} id The feature id.\n * @api\n * @fires module:ol/events/Event~BaseEvent#event:change\n */\n setId(id) {\n this.id_ = id;\n this.changed();\n }\n\n /**\n * Set the property name to be used when getting the feature's default geometry.\n * When calling {@link module:ol/Feature~Feature#getGeometry}, the value of the property with\n * this name will be returned.\n * @param {string} name The property name of the default geometry.\n * @api\n */\n setGeometryName(name) {\n this.removeChangeListener(this.geometryName_, this.handleGeometryChanged_);\n this.geometryName_ = name;\n this.addChangeListener(this.geometryName_, this.handleGeometryChanged_);\n this.handleGeometryChanged_();\n }\n}\n\n/**\n * Convert the provided object into a feature style function. Functions passed\n * through unchanged. Arrays of Style or single style objects wrapped\n * in a new feature style function.\n * @param {!import(\"./style/Style.js\").StyleFunction|!Array|!import(\"./style/Style.js\").default} obj\n * A feature style function, a single style, or an array of styles.\n * @return {import(\"./style/Style.js\").StyleFunction} A style function.\n */\nexport function createStyleFunction(obj) {\n if (typeof obj === 'function') {\n return obj;\n }\n /**\n * @type {Array}\n */\n let styles;\n if (Array.isArray(obj)) {\n styles = obj;\n } else {\n assert(\n typeof (/** @type {?} */ (obj).getZIndex) === 'function',\n 'Expected an `ol/style/Style` or an array of `ol/style/Style.js`'\n );\n const style = /** @type {import(\"./style/Style.js\").default} */ (obj);\n styles = [style];\n }\n return function () {\n return styles;\n };\n}\nexport default Feature;\n","/**\n * @module ol/has\n */\n\nconst ua =\n typeof navigator !== 'undefined' && typeof navigator.userAgent !== 'undefined'\n ? navigator.userAgent.toLowerCase()\n : '';\n\n/**\n * User agent string says we are dealing with Firefox as browser.\n * @type {boolean}\n */\nexport const FIREFOX = ua.includes('firefox');\n\n/**\n * User agent string says we are dealing with Safari as browser.\n * @type {boolean}\n */\nexport const SAFARI = ua.includes('safari') && !ua.includes('chrom');\n\n/**\n * https://bugs.webkit.org/show_bug.cgi?id=237906\n * @type {boolean}\n */\nexport const SAFARI_BUG_237906 =\n SAFARI &&\n (ua.includes('version/15.4') ||\n /cpu (os|iphone os) 15_4 like mac os x/.test(ua));\n\n/**\n * User agent string says we are dealing with a WebKit engine.\n * @type {boolean}\n */\nexport const WEBKIT = ua.includes('webkit') && !ua.includes('edge');\n\n/**\n * User agent string says we are dealing with a Mac as platform.\n * @type {boolean}\n */\nexport const MAC = ua.includes('macintosh');\n\n/**\n * The ratio between physical pixels and device-independent pixels\n * (dips) on the device (`window.devicePixelRatio`).\n * @const\n * @type {number}\n * @api\n */\nexport const DEVICE_PIXEL_RATIO =\n typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n\n/**\n * The execution context is a worker with OffscreenCanvas available.\n * @const\n * @type {boolean}\n */\nexport const WORKER_OFFSCREEN_CANVAS =\n typeof WorkerGlobalScope !== 'undefined' &&\n typeof OffscreenCanvas !== 'undefined' &&\n self instanceof WorkerGlobalScope; //eslint-disable-line\n\n/**\n * Image.prototype.decode() is supported.\n * @type {boolean}\n */\nexport const IMAGE_DECODE =\n typeof Image !== 'undefined' && Image.prototype.decode;\n\n/**\n * createImageBitmap() is supported.\n * @type {boolean}\n */\nexport const CREATE_IMAGE_BITMAP = typeof createImageBitmap === 'function';\n\n/**\n * @type {boolean}\n */\nexport const PASSIVE_EVENT_LISTENERS = (function () {\n let passive = false;\n try {\n const options = Object.defineProperty({}, 'passive', {\n get: function () {\n passive = true;\n },\n });\n\n // @ts-ignore Ignore invalid event type '_'\n window.addEventListener('_', null, options);\n // @ts-ignore Ignore invalid event type '_'\n window.removeEventListener('_', null, options);\n } catch (error) {\n // passive not supported\n }\n return passive;\n})();\n","/**\n * @module ol/transform\n */\nimport {WORKER_OFFSCREEN_CANVAS} from './has.js';\nimport {assert} from './asserts.js';\n\n/**\n * An array representing an affine 2d transformation for use with\n * {@link module:ol/transform} functions. The array has 6 elements.\n * @typedef {!Array} Transform\n * @api\n */\n\n/**\n * Collection of affine 2d transformation functions. The functions work on an\n * array of 6 elements. The element order is compatible with the [SVGMatrix\n * interface](https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix) and is\n * a subset (elements a to f) of a 3×3 matrix:\n * ```\n * [ a c e ]\n * [ b d f ]\n * [ 0 0 1 ]\n * ```\n */\n\n/**\n * @private\n * @type {Transform}\n */\nconst tmp_ = new Array(6);\n\n/**\n * Create an identity transform.\n * @return {!Transform} Identity transform.\n */\nexport function create() {\n return [1, 0, 0, 1, 0, 0];\n}\n\n/**\n * Resets the given transform to an identity transform.\n * @param {!Transform} transform Transform.\n * @return {!Transform} Transform.\n */\nexport function reset(transform) {\n return set(transform, 1, 0, 0, 1, 0, 0);\n}\n\n/**\n * Multiply the underlying matrices of two transforms and return the result in\n * the first transform.\n * @param {!Transform} transform1 Transform parameters of matrix 1.\n * @param {!Transform} transform2 Transform parameters of matrix 2.\n * @return {!Transform} transform1 multiplied with transform2.\n */\nexport function multiply(transform1, transform2) {\n const a1 = transform1[0];\n const b1 = transform1[1];\n const c1 = transform1[2];\n const d1 = transform1[3];\n const e1 = transform1[4];\n const f1 = transform1[5];\n const a2 = transform2[0];\n const b2 = transform2[1];\n const c2 = transform2[2];\n const d2 = transform2[3];\n const e2 = transform2[4];\n const f2 = transform2[5];\n\n transform1[0] = a1 * a2 + c1 * b2;\n transform1[1] = b1 * a2 + d1 * b2;\n transform1[2] = a1 * c2 + c1 * d2;\n transform1[3] = b1 * c2 + d1 * d2;\n transform1[4] = a1 * e2 + c1 * f2 + e1;\n transform1[5] = b1 * e2 + d1 * f2 + f1;\n\n return transform1;\n}\n\n/**\n * Set the transform components a-f on a given transform.\n * @param {!Transform} transform Transform.\n * @param {number} a The a component of the transform.\n * @param {number} b The b component of the transform.\n * @param {number} c The c component of the transform.\n * @param {number} d The d component of the transform.\n * @param {number} e The e component of the transform.\n * @param {number} f The f component of the transform.\n * @return {!Transform} Matrix with transform applied.\n */\nexport function set(transform, a, b, c, d, e, f) {\n transform[0] = a;\n transform[1] = b;\n transform[2] = c;\n transform[3] = d;\n transform[4] = e;\n transform[5] = f;\n return transform;\n}\n\n/**\n * Set transform on one matrix from another matrix.\n * @param {!Transform} transform1 Matrix to set transform to.\n * @param {!Transform} transform2 Matrix to set transform from.\n * @return {!Transform} transform1 with transform from transform2 applied.\n */\nexport function setFromArray(transform1, transform2) {\n transform1[0] = transform2[0];\n transform1[1] = transform2[1];\n transform1[2] = transform2[2];\n transform1[3] = transform2[3];\n transform1[4] = transform2[4];\n transform1[5] = transform2[5];\n return transform1;\n}\n\n/**\n * Transforms the given coordinate with the given transform returning the\n * resulting, transformed coordinate. The coordinate will be modified in-place.\n *\n * @param {Transform} transform The transformation.\n * @param {import(\"./coordinate.js\").Coordinate|import(\"./pixel.js\").Pixel} coordinate The coordinate to transform.\n * @return {import(\"./coordinate.js\").Coordinate|import(\"./pixel.js\").Pixel} return coordinate so that operations can be\n * chained together.\n */\nexport function apply(transform, coordinate) {\n const x = coordinate[0];\n const y = coordinate[1];\n coordinate[0] = transform[0] * x + transform[2] * y + transform[4];\n coordinate[1] = transform[1] * x + transform[3] * y + transform[5];\n return coordinate;\n}\n\n/**\n * Applies rotation to the given transform.\n * @param {!Transform} transform Transform.\n * @param {number} angle Angle in radians.\n * @return {!Transform} The rotated transform.\n */\nexport function rotate(transform, angle) {\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n return multiply(transform, set(tmp_, cos, sin, -sin, cos, 0, 0));\n}\n\n/**\n * Applies scale to a given transform.\n * @param {!Transform} transform Transform.\n * @param {number} x Scale factor x.\n * @param {number} y Scale factor y.\n * @return {!Transform} The scaled transform.\n */\nexport function scale(transform, x, y) {\n return multiply(transform, set(tmp_, x, 0, 0, y, 0, 0));\n}\n\n/**\n * Creates a scale transform.\n * @param {!Transform} target Transform to overwrite.\n * @param {number} x Scale factor x.\n * @param {number} y Scale factor y.\n * @return {!Transform} The scale transform.\n */\nexport function makeScale(target, x, y) {\n return set(target, x, 0, 0, y, 0, 0);\n}\n\n/**\n * Applies translation to the given transform.\n * @param {!Transform} transform Transform.\n * @param {number} dx Translation x.\n * @param {number} dy Translation y.\n * @return {!Transform} The translated transform.\n */\nexport function translate(transform, dx, dy) {\n return multiply(transform, set(tmp_, 1, 0, 0, 1, dx, dy));\n}\n\n/**\n * Creates a composite transform given an initial translation, scale, rotation, and\n * final translation (in that order only, not commutative).\n * @param {!Transform} transform The transform (will be modified in place).\n * @param {number} dx1 Initial translation x.\n * @param {number} dy1 Initial translation y.\n * @param {number} sx Scale factor x.\n * @param {number} sy Scale factor y.\n * @param {number} angle Rotation (in counter-clockwise radians).\n * @param {number} dx2 Final translation x.\n * @param {number} dy2 Final translation y.\n * @return {!Transform} The composite transform.\n */\nexport function compose(transform, dx1, dy1, sx, sy, angle, dx2, dy2) {\n const sin = Math.sin(angle);\n const cos = Math.cos(angle);\n transform[0] = sx * cos;\n transform[1] = sy * sin;\n transform[2] = -sx * sin;\n transform[3] = sy * cos;\n transform[4] = dx2 * sx * cos - dy2 * sx * sin + dx1;\n transform[5] = dx2 * sy * sin + dy2 * sy * cos + dy1;\n return transform;\n}\n\n/**\n * Creates a composite transform given an initial translation, scale, rotation, and\n * final translation (in that order only, not commutative). The resulting transform\n * string can be applied as `transform` property of an HTMLElement's style.\n * @param {number} dx1 Initial translation x.\n * @param {number} dy1 Initial translation y.\n * @param {number} sx Scale factor x.\n * @param {number} sy Scale factor y.\n * @param {number} angle Rotation (in counter-clockwise radians).\n * @param {number} dx2 Final translation x.\n * @param {number} dy2 Final translation y.\n * @return {string} The composite css transform.\n * @api\n */\nexport function composeCssTransform(dx1, dy1, sx, sy, angle, dx2, dy2) {\n return toString(compose(create(), dx1, dy1, sx, sy, angle, dx2, dy2));\n}\n\n/**\n * Invert the given transform.\n * @param {!Transform} source The source transform to invert.\n * @return {!Transform} The inverted (source) transform.\n */\nexport function invert(source) {\n return makeInverse(source, source);\n}\n\n/**\n * Invert the given transform.\n * @param {!Transform} target Transform to be set as the inverse of\n * the source transform.\n * @param {!Transform} source The source transform to invert.\n * @return {!Transform} The inverted (target) transform.\n */\nexport function makeInverse(target, source) {\n const det = determinant(source);\n assert(det !== 0, 'Transformation matrix cannot be inverted');\n\n const a = source[0];\n const b = source[1];\n const c = source[2];\n const d = source[3];\n const e = source[4];\n const f = source[5];\n\n target[0] = d / det;\n target[1] = -b / det;\n target[2] = -c / det;\n target[3] = a / det;\n target[4] = (c * f - d * e) / det;\n target[5] = -(a * f - b * e) / det;\n\n return target;\n}\n\n/**\n * Returns the determinant of the given matrix.\n * @param {!Transform} mat Matrix.\n * @return {number} Determinant.\n */\nexport function determinant(mat) {\n return mat[0] * mat[3] - mat[1] * mat[2];\n}\n\n/**\n * @type {HTMLElement}\n * @private\n */\nlet transformStringDiv;\n\n/**\n * A rounded string version of the transform. This can be used\n * for CSS transforms.\n * @param {!Transform} mat Matrix.\n * @return {string} The transform as a string.\n */\nexport function toString(mat) {\n const transformString = 'matrix(' + mat.join(', ') + ')';\n if (WORKER_OFFSCREEN_CANVAS) {\n return transformString;\n }\n const node =\n transformStringDiv || (transformStringDiv = document.createElement('div'));\n node.style.transform = transformString;\n return node.style.transform;\n}\n","/**\n * @module ol/extent/Relationship\n */\n\n/**\n * Relationship to an extent.\n * @enum {number}\n */\nexport default {\n UNKNOWN: 0,\n INTERSECTING: 1,\n ABOVE: 2,\n RIGHT: 4,\n BELOW: 8,\n LEFT: 16,\n};\n","/**\n * @module ol/extent\n */\nimport Relationship from './extent/Relationship.js';\n\n/**\n * An array of numbers representing an extent: `[minx, miny, maxx, maxy]`.\n * @typedef {Array} Extent\n * @api\n */\n\n/**\n * Extent corner.\n * @typedef {'bottom-left' | 'bottom-right' | 'top-left' | 'top-right'} Corner\n */\n\n/**\n * Build an extent that includes all given coordinates.\n *\n * @param {Array} coordinates Coordinates.\n * @return {Extent} Bounding extent.\n * @api\n */\nexport function boundingExtent(coordinates) {\n const extent = createEmpty();\n for (let i = 0, ii = coordinates.length; i < ii; ++i) {\n extendCoordinate(extent, coordinates[i]);\n }\n return extent;\n}\n\n/**\n * @param {Array} xs Xs.\n * @param {Array} ys Ys.\n * @param {Extent} [dest] Destination extent.\n * @private\n * @return {Extent} Extent.\n */\nfunction _boundingExtentXYs(xs, ys, dest) {\n const minX = Math.min.apply(null, xs);\n const minY = Math.min.apply(null, ys);\n const maxX = Math.max.apply(null, xs);\n const maxY = Math.max.apply(null, ys);\n return createOrUpdate(minX, minY, maxX, maxY, dest);\n}\n\n/**\n * Return extent increased by the provided value.\n * @param {Extent} extent Extent.\n * @param {number} value The amount by which the extent should be buffered.\n * @param {Extent} [dest] Extent.\n * @return {Extent} Extent.\n * @api\n */\nexport function buffer(extent, value, dest) {\n if (dest) {\n dest[0] = extent[0] - value;\n dest[1] = extent[1] - value;\n dest[2] = extent[2] + value;\n dest[3] = extent[3] + value;\n return dest;\n }\n return [\n extent[0] - value,\n extent[1] - value,\n extent[2] + value,\n extent[3] + value,\n ];\n}\n\n/**\n * Creates a clone of an extent.\n *\n * @param {Extent} extent Extent to clone.\n * @param {Extent} [dest] Extent.\n * @return {Extent} The clone.\n */\nexport function clone(extent, dest) {\n if (dest) {\n dest[0] = extent[0];\n dest[1] = extent[1];\n dest[2] = extent[2];\n dest[3] = extent[3];\n return dest;\n }\n return extent.slice();\n}\n\n/**\n * @param {Extent} extent Extent.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {number} Closest squared distance.\n */\nexport function closestSquaredDistanceXY(extent, x, y) {\n let dx, dy;\n if (x < extent[0]) {\n dx = extent[0] - x;\n } else if (extent[2] < x) {\n dx = x - extent[2];\n } else {\n dx = 0;\n }\n if (y < extent[1]) {\n dy = extent[1] - y;\n } else if (extent[3] < y) {\n dy = y - extent[3];\n } else {\n dy = 0;\n }\n return dx * dx + dy * dy;\n}\n\n/**\n * Check if the passed coordinate is contained or on the edge of the extent.\n *\n * @param {Extent} extent Extent.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate.\n * @return {boolean} The coordinate is contained in the extent.\n * @api\n */\nexport function containsCoordinate(extent, coordinate) {\n return containsXY(extent, coordinate[0], coordinate[1]);\n}\n\n/**\n * Check if one extent contains another.\n *\n * An extent is deemed contained if it lies completely within the other extent,\n * including if they share one or more edges.\n *\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @return {boolean} The second extent is contained by or on the edge of the\n * first.\n * @api\n */\nexport function containsExtent(extent1, extent2) {\n return (\n extent1[0] <= extent2[0] &&\n extent2[2] <= extent1[2] &&\n extent1[1] <= extent2[1] &&\n extent2[3] <= extent1[3]\n );\n}\n\n/**\n * Check if the passed coordinate is contained or on the edge of the extent.\n *\n * @param {Extent} extent Extent.\n * @param {number} x X coordinate.\n * @param {number} y Y coordinate.\n * @return {boolean} The x, y values are contained in the extent.\n * @api\n */\nexport function containsXY(extent, x, y) {\n return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];\n}\n\n/**\n * Get the relationship between a coordinate and extent.\n * @param {Extent} extent The extent.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate The coordinate.\n * @return {import(\"./extent/Relationship.js\").default} The relationship (bitwise compare with\n * import(\"./extent/Relationship.js\").Relationship).\n */\nexport function coordinateRelationship(extent, coordinate) {\n const minX = extent[0];\n const minY = extent[1];\n const maxX = extent[2];\n const maxY = extent[3];\n const x = coordinate[0];\n const y = coordinate[1];\n let relationship = Relationship.UNKNOWN;\n if (x < minX) {\n relationship = relationship | Relationship.LEFT;\n } else if (x > maxX) {\n relationship = relationship | Relationship.RIGHT;\n }\n if (y < minY) {\n relationship = relationship | Relationship.BELOW;\n } else if (y > maxY) {\n relationship = relationship | Relationship.ABOVE;\n }\n if (relationship === Relationship.UNKNOWN) {\n relationship = Relationship.INTERSECTING;\n }\n return relationship;\n}\n\n/**\n * Create an empty extent.\n * @return {Extent} Empty extent.\n * @api\n */\nexport function createEmpty() {\n return [Infinity, Infinity, -Infinity, -Infinity];\n}\n\n/**\n * Create a new extent or update the provided extent.\n * @param {number} minX Minimum X.\n * @param {number} minY Minimum Y.\n * @param {number} maxX Maximum X.\n * @param {number} maxY Maximum Y.\n * @param {Extent} [dest] Destination extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdate(minX, minY, maxX, maxY, dest) {\n if (dest) {\n dest[0] = minX;\n dest[1] = minY;\n dest[2] = maxX;\n dest[3] = maxY;\n return dest;\n }\n return [minX, minY, maxX, maxY];\n}\n\n/**\n * Create a new empty extent or make the provided one empty.\n * @param {Extent} [dest] Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateEmpty(dest) {\n return createOrUpdate(Infinity, Infinity, -Infinity, -Infinity, dest);\n}\n\n/**\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate.\n * @param {Extent} [dest] Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateFromCoordinate(coordinate, dest) {\n const x = coordinate[0];\n const y = coordinate[1];\n return createOrUpdate(x, y, x, y, dest);\n}\n\n/**\n * @param {Array} coordinates Coordinates.\n * @param {Extent} [dest] Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateFromCoordinates(coordinates, dest) {\n const extent = createOrUpdateEmpty(dest);\n return extendCoordinates(extent, coordinates);\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {Extent} [dest] Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateFromFlatCoordinates(\n flatCoordinates,\n offset,\n end,\n stride,\n dest\n) {\n const extent = createOrUpdateEmpty(dest);\n return extendFlatCoordinates(extent, flatCoordinates, offset, end, stride);\n}\n\n/**\n * @param {Array>} rings Rings.\n * @param {Extent} [dest] Extent.\n * @return {Extent} Extent.\n */\nexport function createOrUpdateFromRings(rings, dest) {\n const extent = createOrUpdateEmpty(dest);\n return extendRings(extent, rings);\n}\n\n/**\n * Determine if two extents are equivalent.\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @return {boolean} The two extents are equivalent.\n * @api\n */\nexport function equals(extent1, extent2) {\n return (\n extent1[0] == extent2[0] &&\n extent1[2] == extent2[2] &&\n extent1[1] == extent2[1] &&\n extent1[3] == extent2[3]\n );\n}\n\n/**\n * Determine if two extents are approximately equivalent.\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @param {number} tolerance Tolerance in extent coordinate units.\n * @return {boolean} The two extents differ by less than the tolerance.\n */\nexport function approximatelyEquals(extent1, extent2, tolerance) {\n return (\n Math.abs(extent1[0] - extent2[0]) < tolerance &&\n Math.abs(extent1[2] - extent2[2]) < tolerance &&\n Math.abs(extent1[1] - extent2[1]) < tolerance &&\n Math.abs(extent1[3] - extent2[3]) < tolerance\n );\n}\n\n/**\n * Modify an extent to include another extent.\n * @param {Extent} extent1 The extent to be modified.\n * @param {Extent} extent2 The extent that will be included in the first.\n * @return {Extent} A reference to the first (extended) extent.\n * @api\n */\nexport function extend(extent1, extent2) {\n if (extent2[0] < extent1[0]) {\n extent1[0] = extent2[0];\n }\n if (extent2[2] > extent1[2]) {\n extent1[2] = extent2[2];\n }\n if (extent2[1] < extent1[1]) {\n extent1[1] = extent2[1];\n }\n if (extent2[3] > extent1[3]) {\n extent1[3] = extent2[3];\n }\n return extent1;\n}\n\n/**\n * @param {Extent} extent Extent.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate.\n */\nexport function extendCoordinate(extent, coordinate) {\n if (coordinate[0] < extent[0]) {\n extent[0] = coordinate[0];\n }\n if (coordinate[0] > extent[2]) {\n extent[2] = coordinate[0];\n }\n if (coordinate[1] < extent[1]) {\n extent[1] = coordinate[1];\n }\n if (coordinate[1] > extent[3]) {\n extent[3] = coordinate[1];\n }\n}\n\n/**\n * @param {Extent} extent Extent.\n * @param {Array} coordinates Coordinates.\n * @return {Extent} Extent.\n */\nexport function extendCoordinates(extent, coordinates) {\n for (let i = 0, ii = coordinates.length; i < ii; ++i) {\n extendCoordinate(extent, coordinates[i]);\n }\n return extent;\n}\n\n/**\n * @param {Extent} extent Extent.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {Extent} Extent.\n */\nexport function extendFlatCoordinates(\n extent,\n flatCoordinates,\n offset,\n end,\n stride\n) {\n for (; offset < end; offset += stride) {\n extendXY(extent, flatCoordinates[offset], flatCoordinates[offset + 1]);\n }\n return extent;\n}\n\n/**\n * @param {Extent} extent Extent.\n * @param {Array>} rings Rings.\n * @return {Extent} Extent.\n */\nexport function extendRings(extent, rings) {\n for (let i = 0, ii = rings.length; i < ii; ++i) {\n extendCoordinates(extent, rings[i]);\n }\n return extent;\n}\n\n/**\n * @param {Extent} extent Extent.\n * @param {number} x X.\n * @param {number} y Y.\n */\nexport function extendXY(extent, x, y) {\n extent[0] = Math.min(extent[0], x);\n extent[1] = Math.min(extent[1], y);\n extent[2] = Math.max(extent[2], x);\n extent[3] = Math.max(extent[3], y);\n}\n\n/**\n * This function calls `callback` for each corner of the extent. If the\n * callback returns a truthy value the function returns that value\n * immediately. Otherwise the function returns `false`.\n * @param {Extent} extent Extent.\n * @param {function(import(\"./coordinate.js\").Coordinate): S} callback Callback.\n * @return {S|boolean} Value.\n * @template S\n */\nexport function forEachCorner(extent, callback) {\n let val;\n val = callback(getBottomLeft(extent));\n if (val) {\n return val;\n }\n val = callback(getBottomRight(extent));\n if (val) {\n return val;\n }\n val = callback(getTopRight(extent));\n if (val) {\n return val;\n }\n val = callback(getTopLeft(extent));\n if (val) {\n return val;\n }\n return false;\n}\n\n/**\n * Get the size of an extent.\n * @param {Extent} extent Extent.\n * @return {number} Area.\n * @api\n */\nexport function getArea(extent) {\n let area = 0;\n if (!isEmpty(extent)) {\n area = getWidth(extent) * getHeight(extent);\n }\n return area;\n}\n\n/**\n * Get the bottom left coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Bottom left coordinate.\n * @api\n */\nexport function getBottomLeft(extent) {\n return [extent[0], extent[1]];\n}\n\n/**\n * Get the bottom right coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Bottom right coordinate.\n * @api\n */\nexport function getBottomRight(extent) {\n return [extent[2], extent[1]];\n}\n\n/**\n * Get the center coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Center.\n * @api\n */\nexport function getCenter(extent) {\n return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];\n}\n\n/**\n * Get a corner coordinate of an extent.\n * @param {Extent} extent Extent.\n * @param {Corner} corner Corner.\n * @return {import(\"./coordinate.js\").Coordinate} Corner coordinate.\n */\nexport function getCorner(extent, corner) {\n let coordinate;\n if (corner === 'bottom-left') {\n coordinate = getBottomLeft(extent);\n } else if (corner === 'bottom-right') {\n coordinate = getBottomRight(extent);\n } else if (corner === 'top-left') {\n coordinate = getTopLeft(extent);\n } else if (corner === 'top-right') {\n coordinate = getTopRight(extent);\n } else {\n throw new Error('Invalid corner');\n }\n return coordinate;\n}\n\n/**\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @return {number} Enlarged area.\n */\nexport function getEnlargedArea(extent1, extent2) {\n const minX = Math.min(extent1[0], extent2[0]);\n const minY = Math.min(extent1[1], extent2[1]);\n const maxX = Math.max(extent1[2], extent2[2]);\n const maxY = Math.max(extent1[3], extent2[3]);\n return (maxX - minX) * (maxY - minY);\n}\n\n/**\n * @param {import(\"./coordinate.js\").Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {import(\"./size.js\").Size} size Size.\n * @param {Extent} [dest] Destination extent.\n * @return {Extent} Extent.\n */\nexport function getForViewAndSize(center, resolution, rotation, size, dest) {\n const [x0, y0, x1, y1, x2, y2, x3, y3] = getRotatedViewport(\n center,\n resolution,\n rotation,\n size\n );\n return createOrUpdate(\n Math.min(x0, x1, x2, x3),\n Math.min(y0, y1, y2, y3),\n Math.max(x0, x1, x2, x3),\n Math.max(y0, y1, y2, y3),\n dest\n );\n}\n\n/**\n * @param {import(\"./coordinate.js\").Coordinate} center Center.\n * @param {number} resolution Resolution.\n * @param {number} rotation Rotation.\n * @param {import(\"./size.js\").Size} size Size.\n * @return {Array} Linear ring representing the viewport.\n */\nexport function getRotatedViewport(center, resolution, rotation, size) {\n const dx = (resolution * size[0]) / 2;\n const dy = (resolution * size[1]) / 2;\n const cosRotation = Math.cos(rotation);\n const sinRotation = Math.sin(rotation);\n const xCos = dx * cosRotation;\n const xSin = dx * sinRotation;\n const yCos = dy * cosRotation;\n const ySin = dy * sinRotation;\n const x = center[0];\n const y = center[1];\n return [\n x - xCos + ySin,\n y - xSin - yCos,\n x - xCos - ySin,\n y - xSin + yCos,\n x + xCos - ySin,\n y + xSin + yCos,\n x + xCos + ySin,\n y + xSin - yCos,\n x - xCos + ySin,\n y - xSin - yCos,\n ];\n}\n\n/**\n * Get the height of an extent.\n * @param {Extent} extent Extent.\n * @return {number} Height.\n * @api\n */\nexport function getHeight(extent) {\n return extent[3] - extent[1];\n}\n\n/**\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @return {number} Intersection area.\n */\nexport function getIntersectionArea(extent1, extent2) {\n const intersection = getIntersection(extent1, extent2);\n return getArea(intersection);\n}\n\n/**\n * Get the intersection of two extents.\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent 2.\n * @param {Extent} [dest] Optional extent to populate with intersection.\n * @return {Extent} Intersecting extent.\n * @api\n */\nexport function getIntersection(extent1, extent2, dest) {\n const intersection = dest ? dest : createEmpty();\n if (intersects(extent1, extent2)) {\n if (extent1[0] > extent2[0]) {\n intersection[0] = extent1[0];\n } else {\n intersection[0] = extent2[0];\n }\n if (extent1[1] > extent2[1]) {\n intersection[1] = extent1[1];\n } else {\n intersection[1] = extent2[1];\n }\n if (extent1[2] < extent2[2]) {\n intersection[2] = extent1[2];\n } else {\n intersection[2] = extent2[2];\n }\n if (extent1[3] < extent2[3]) {\n intersection[3] = extent1[3];\n } else {\n intersection[3] = extent2[3];\n }\n } else {\n createOrUpdateEmpty(intersection);\n }\n return intersection;\n}\n\n/**\n * @param {Extent} extent Extent.\n * @return {number} Margin.\n */\nexport function getMargin(extent) {\n return getWidth(extent) + getHeight(extent);\n}\n\n/**\n * Get the size (width, height) of an extent.\n * @param {Extent} extent The extent.\n * @return {import(\"./size.js\").Size} The extent size.\n * @api\n */\nexport function getSize(extent) {\n return [extent[2] - extent[0], extent[3] - extent[1]];\n}\n\n/**\n * Get the top left coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Top left coordinate.\n * @api\n */\nexport function getTopLeft(extent) {\n return [extent[0], extent[3]];\n}\n\n/**\n * Get the top right coordinate of an extent.\n * @param {Extent} extent Extent.\n * @return {import(\"./coordinate.js\").Coordinate} Top right coordinate.\n * @api\n */\nexport function getTopRight(extent) {\n return [extent[2], extent[3]];\n}\n\n/**\n * Get the width of an extent.\n * @param {Extent} extent Extent.\n * @return {number} Width.\n * @api\n */\nexport function getWidth(extent) {\n return extent[2] - extent[0];\n}\n\n/**\n * Determine if one extent intersects another.\n * @param {Extent} extent1 Extent 1.\n * @param {Extent} extent2 Extent.\n * @return {boolean} The two extents intersect.\n * @api\n */\nexport function intersects(extent1, extent2) {\n return (\n extent1[0] <= extent2[2] &&\n extent1[2] >= extent2[0] &&\n extent1[1] <= extent2[3] &&\n extent1[3] >= extent2[1]\n );\n}\n\n/**\n * Determine if an extent is empty.\n * @param {Extent} extent Extent.\n * @return {boolean} Is empty.\n * @api\n */\nexport function isEmpty(extent) {\n return extent[2] < extent[0] || extent[3] < extent[1];\n}\n\n/**\n * @param {Extent} extent Extent.\n * @param {Extent} [dest] Extent.\n * @return {Extent} Extent.\n */\nexport function returnOrUpdate(extent, dest) {\n if (dest) {\n dest[0] = extent[0];\n dest[1] = extent[1];\n dest[2] = extent[2];\n dest[3] = extent[3];\n return dest;\n }\n return extent;\n}\n\n/**\n * @param {Extent} extent Extent.\n * @param {number} value Value.\n */\nexport function scaleFromCenter(extent, value) {\n const deltaX = ((extent[2] - extent[0]) / 2) * (value - 1);\n const deltaY = ((extent[3] - extent[1]) / 2) * (value - 1);\n extent[0] -= deltaX;\n extent[2] += deltaX;\n extent[1] -= deltaY;\n extent[3] += deltaY;\n}\n\n/**\n * Determine if the segment between two coordinates intersects (crosses,\n * touches, or is contained by) the provided extent.\n * @param {Extent} extent The extent.\n * @param {import(\"./coordinate.js\").Coordinate} start Segment start coordinate.\n * @param {import(\"./coordinate.js\").Coordinate} end Segment end coordinate.\n * @return {boolean} The segment intersects the extent.\n */\nexport function intersectsSegment(extent, start, end) {\n let intersects = false;\n const startRel = coordinateRelationship(extent, start);\n const endRel = coordinateRelationship(extent, end);\n if (\n startRel === Relationship.INTERSECTING ||\n endRel === Relationship.INTERSECTING\n ) {\n intersects = true;\n } else {\n const minX = extent[0];\n const minY = extent[1];\n const maxX = extent[2];\n const maxY = extent[3];\n const startX = start[0];\n const startY = start[1];\n const endX = end[0];\n const endY = end[1];\n const slope = (endY - startY) / (endX - startX);\n let x, y;\n if (!!(endRel & Relationship.ABOVE) && !(startRel & Relationship.ABOVE)) {\n // potentially intersects top\n x = endX - (endY - maxY) / slope;\n intersects = x >= minX && x <= maxX;\n }\n if (\n !intersects &&\n !!(endRel & Relationship.RIGHT) &&\n !(startRel & Relationship.RIGHT)\n ) {\n // potentially intersects right\n y = endY - (endX - maxX) * slope;\n intersects = y >= minY && y <= maxY;\n }\n if (\n !intersects &&\n !!(endRel & Relationship.BELOW) &&\n !(startRel & Relationship.BELOW)\n ) {\n // potentially intersects bottom\n x = endX - (endY - minY) / slope;\n intersects = x >= minX && x <= maxX;\n }\n if (\n !intersects &&\n !!(endRel & Relationship.LEFT) &&\n !(startRel & Relationship.LEFT)\n ) {\n // potentially intersects left\n y = endY - (endX - minX) * slope;\n intersects = y >= minY && y <= maxY;\n }\n }\n return intersects;\n}\n\n/**\n * Apply a transform function to the extent.\n * @param {Extent} extent Extent.\n * @param {import(\"./proj.js\").TransformFunction} transformFn Transform function.\n * Called with `[minX, minY, maxX, maxY]` extent coordinates.\n * @param {Extent} [dest] Destination extent.\n * @param {number} [stops] Number of stops per side used for the transform.\n * By default only the corners are used.\n * @return {Extent} Extent.\n * @api\n */\nexport function applyTransform(extent, transformFn, dest, stops) {\n if (isEmpty(extent)) {\n return createOrUpdateEmpty(dest);\n }\n let coordinates = [];\n if (stops > 1) {\n const width = extent[2] - extent[0];\n const height = extent[3] - extent[1];\n for (let i = 0; i < stops; ++i) {\n coordinates.push(\n extent[0] + (width * i) / stops,\n extent[1],\n extent[2],\n extent[1] + (height * i) / stops,\n extent[2] - (width * i) / stops,\n extent[3],\n extent[0],\n extent[3] - (height * i) / stops\n );\n }\n } else {\n coordinates = [\n extent[0],\n extent[1],\n extent[2],\n extent[1],\n extent[2],\n extent[3],\n extent[0],\n extent[3],\n ];\n }\n transformFn(coordinates, coordinates, 2);\n const xs = [];\n const ys = [];\n for (let i = 0, l = coordinates.length; i < l; i += 2) {\n xs.push(coordinates[i]);\n ys.push(coordinates[i + 1]);\n }\n return _boundingExtentXYs(xs, ys, dest);\n}\n\n/**\n * Modifies the provided extent in-place to be within the real world\n * extent.\n *\n * @param {Extent} extent Extent.\n * @param {import(\"./proj/Projection.js\").default} projection Projection\n * @return {Extent} The extent within the real world extent.\n */\nexport function wrapX(extent, projection) {\n const projectionExtent = projection.getExtent();\n const center = getCenter(extent);\n if (\n projection.canWrapX() &&\n (center[0] < projectionExtent[0] || center[0] >= projectionExtent[2])\n ) {\n const worldWidth = getWidth(projectionExtent);\n const worldsAway = Math.floor(\n (center[0] - projectionExtent[0]) / worldWidth\n );\n const offset = worldsAway * worldWidth;\n extent[0] -= offset;\n extent[2] -= offset;\n }\n return extent;\n}\n\n/**\n * Fits the extent to the real world\n *\n * If the extent does not cross the anti meridian, this will return the extent in an array\n * If the extent crosses the anti meridian, the extent will be sliced, so each part fits within the\n * real world\n *\n *\n * @param {Extent} extent Extent.\n * @param {import(\"./proj/Projection.js\").default} projection Projection\n * @return {Array} The extent within the real world extent.\n */\nexport function wrapAndSliceX(extent, projection) {\n if (projection.canWrapX()) {\n const projectionExtent = projection.getExtent();\n\n if (!isFinite(extent[0]) || !isFinite(extent[2])) {\n return [[projectionExtent[0], extent[1], projectionExtent[2], extent[3]]];\n }\n\n wrapX(extent, projection);\n const worldWidth = getWidth(projectionExtent);\n\n if (getWidth(extent) > worldWidth) {\n // the extent wraps around on itself\n return [[projectionExtent[0], extent[1], projectionExtent[2], extent[3]]];\n }\n if (extent[0] < projectionExtent[0]) {\n // the extent crosses the anti meridian, so it needs to be sliced\n return [\n [extent[0] + worldWidth, extent[1], projectionExtent[2], extent[3]],\n [projectionExtent[0], extent[1], extent[2], extent[3]],\n ];\n }\n if (extent[2] > projectionExtent[2]) {\n // the extent crosses the anti meridian, so it needs to be sliced\n return [\n [extent[0], extent[1], projectionExtent[2], extent[3]],\n [projectionExtent[0], extent[1], extent[2] - worldWidth, extent[3]],\n ];\n }\n }\n\n return [extent];\n}\n","/**\n * @module ol/proj/Units\n */\n\n/**\n * @typedef {'radians' | 'degrees' | 'ft' | 'm' | 'pixels' | 'tile-pixels' | 'us-ft'} Units\n * Projection units.\n */\n\n/**\n * See http://duff.ess.washington.edu/data/raster/drg/docs/geotiff.txt\n * @type {Object}\n */\nconst unitByCode = {\n '9001': 'm',\n '9002': 'ft',\n '9003': 'us-ft',\n '9101': 'radians',\n '9102': 'degrees',\n};\n\n/**\n * @param {number} code Unit code.\n * @return {Units} Units.\n */\nexport function fromCode(code) {\n return unitByCode[code];\n}\n\n/**\n * @typedef {Object} MetersPerUnitLookup\n * @property {number} radians Radians\n * @property {number} degrees Degrees\n * @property {number} ft Feet\n * @property {number} m Meters\n * @property {number} us-ft US feet\n */\n\n/**\n * Meters per unit lookup table.\n * @const\n * @type {MetersPerUnitLookup}\n * @api\n */\nexport const METERS_PER_UNIT = {\n // use the radius of the Normal sphere\n 'radians': 6370997 / (2 * Math.PI),\n 'degrees': (2 * Math.PI * 6370997) / 360,\n 'ft': 0.3048,\n 'm': 1,\n 'us-ft': 1200 / 3937,\n};\n","/**\n * @module ol/proj/Projection\n */\nimport {METERS_PER_UNIT} from './Units.js';\n\n/**\n * @typedef {Object} Options\n * @property {string} code The SRS identifier code, e.g. `EPSG:4326`.\n * @property {import(\"./Units.js\").Units} [units] Units. Required unless a\n * proj4 projection is defined for `code`.\n * @property {import(\"../extent.js\").Extent} [extent] The validity extent for the SRS.\n * @property {string} [axisOrientation='enu'] The axis orientation as specified in Proj4.\n * @property {boolean} [global=false] Whether the projection is valid for the whole globe.\n * @property {number} [metersPerUnit] The meters per unit for the SRS.\n * If not provided, the `units` are used to get the meters per unit from the {@link METERS_PER_UNIT}\n * lookup table.\n * @property {import(\"../extent.js\").Extent} [worldExtent] The world extent for the SRS.\n * @property {function(number, import(\"../coordinate.js\").Coordinate):number} [getPointResolution]\n * Function to determine resolution at a point. The function is called with a\n * `number` view resolution and a {@link module:ol/coordinate~Coordinate} as arguments, and returns\n * the `number` resolution in projection units at the passed coordinate. If this is `undefined`,\n * the default {@link module:ol/proj.getPointResolution} function will be used.\n */\n\n/**\n * @classdesc\n * Projection definition class. One of these is created for each projection\n * supported in the application and stored in the {@link module:ol/proj} namespace.\n * You can use these in applications, but this is not required, as API params\n * and options use {@link module:ol/proj~ProjectionLike} which means the simple string\n * code will suffice.\n *\n * You can use {@link module:ol/proj.get} to retrieve the object for a particular\n * projection.\n *\n * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together\n * with the following aliases:\n * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326,\n * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84,\n * http://www.opengis.net/gml/srs/epsg.xml#4326,\n * urn:x-ogc:def:crs:EPSG:4326\n * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913,\n * urn:ogc:def:crs:EPSG:6.18:3:3857,\n * http://www.opengis.net/gml/srs/epsg.xml#3857\n *\n * If you use [proj4js](https://github.com/proj4js/proj4js), aliases can\n * be added using `proj4.defs()`. After all required projection definitions are\n * added, call the {@link module:ol/proj/proj4.register} function.\n *\n * @api\n */\nclass Projection {\n /**\n * @param {Options} options Projection options.\n */\n constructor(options) {\n /**\n * @private\n * @type {string}\n */\n this.code_ = options.code;\n\n /**\n * Units of projected coordinates. When set to `TILE_PIXELS`, a\n * `this.extent_` and `this.worldExtent_` must be configured properly for each\n * tile.\n * @private\n * @type {import(\"./Units.js\").Units}\n */\n this.units_ = /** @type {import(\"./Units.js\").Units} */ (options.units);\n\n /**\n * Validity extent of the projection in projected coordinates. For projections\n * with `TILE_PIXELS` units, this is the extent of the tile in\n * tile pixel space.\n * @private\n * @type {import(\"../extent.js\").Extent}\n */\n this.extent_ = options.extent !== undefined ? options.extent : null;\n\n /**\n * Extent of the world in EPSG:4326. For projections with\n * `TILE_PIXELS` units, this is the extent of the tile in\n * projected coordinate space.\n * @private\n * @type {import(\"../extent.js\").Extent}\n */\n this.worldExtent_ =\n options.worldExtent !== undefined ? options.worldExtent : null;\n\n /**\n * @private\n * @type {string}\n */\n this.axisOrientation_ =\n options.axisOrientation !== undefined ? options.axisOrientation : 'enu';\n\n /**\n * @private\n * @type {boolean}\n */\n this.global_ = options.global !== undefined ? options.global : false;\n\n /**\n * @private\n * @type {boolean}\n */\n this.canWrapX_ = !!(this.global_ && this.extent_);\n\n /**\n * @private\n * @type {function(number, import(\"../coordinate.js\").Coordinate):number|undefined}\n */\n this.getPointResolutionFunc_ = options.getPointResolution;\n\n /**\n * @private\n * @type {import(\"../tilegrid/TileGrid.js\").default}\n */\n this.defaultTileGrid_ = null;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.metersPerUnit_ = options.metersPerUnit;\n }\n\n /**\n * @return {boolean} The projection is suitable for wrapping the x-axis\n */\n canWrapX() {\n return this.canWrapX_;\n }\n\n /**\n * Get the code for this projection, e.g. 'EPSG:4326'.\n * @return {string} Code.\n * @api\n */\n getCode() {\n return this.code_;\n }\n\n /**\n * Get the validity extent for this projection.\n * @return {import(\"../extent.js\").Extent} Extent.\n * @api\n */\n getExtent() {\n return this.extent_;\n }\n\n /**\n * Get the units of this projection.\n * @return {import(\"./Units.js\").Units} Units.\n * @api\n */\n getUnits() {\n return this.units_;\n }\n\n /**\n * Get the amount of meters per unit of this projection. If the projection is\n * not configured with `metersPerUnit` or a units identifier, the return is\n * `undefined`.\n * @return {number|undefined} Meters.\n * @api\n */\n getMetersPerUnit() {\n return this.metersPerUnit_ || METERS_PER_UNIT[this.units_];\n }\n\n /**\n * Get the world extent for this projection.\n * @return {import(\"../extent.js\").Extent} Extent.\n * @api\n */\n getWorldExtent() {\n return this.worldExtent_;\n }\n\n /**\n * Get the axis orientation of this projection.\n * Example values are:\n * enu - the default easting, northing, elevation.\n * neu - northing, easting, up - useful for \"lat/long\" geographic coordinates,\n * or south orientated transverse mercator.\n * wnu - westing, northing, up - some planetary coordinate systems have\n * \"west positive\" coordinate systems\n * @return {string} Axis orientation.\n * @api\n */\n getAxisOrientation() {\n return this.axisOrientation_;\n }\n\n /**\n * Is this projection a global projection which spans the whole world?\n * @return {boolean} Whether the projection is global.\n * @api\n */\n isGlobal() {\n return this.global_;\n }\n\n /**\n * Set if the projection is a global projection which spans the whole world\n * @param {boolean} global Whether the projection is global.\n * @api\n */\n setGlobal(global) {\n this.global_ = global;\n this.canWrapX_ = !!(global && this.extent_);\n }\n\n /**\n * @return {import(\"../tilegrid/TileGrid.js\").default} The default tile grid.\n */\n getDefaultTileGrid() {\n return this.defaultTileGrid_;\n }\n\n /**\n * @param {import(\"../tilegrid/TileGrid.js\").default} tileGrid The default tile grid.\n */\n setDefaultTileGrid(tileGrid) {\n this.defaultTileGrid_ = tileGrid;\n }\n\n /**\n * Set the validity extent for this projection.\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @api\n */\n setExtent(extent) {\n this.extent_ = extent;\n this.canWrapX_ = !!(this.global_ && extent);\n }\n\n /**\n * Set the world extent for this projection.\n * @param {import(\"../extent.js\").Extent} worldExtent World extent\n * [minlon, minlat, maxlon, maxlat].\n * @api\n */\n setWorldExtent(worldExtent) {\n this.worldExtent_ = worldExtent;\n }\n\n /**\n * Set the getPointResolution function (see {@link module:ol/proj.getPointResolution}\n * for this projection.\n * @param {function(number, import(\"../coordinate.js\").Coordinate):number} func Function\n * @api\n */\n setGetPointResolution(func) {\n this.getPointResolutionFunc_ = func;\n }\n\n /**\n * Get the custom point resolution function for this projection (if set).\n * @return {function(number, import(\"../coordinate.js\").Coordinate):number|undefined} The custom point\n * resolution function (if set).\n */\n getPointResolutionFunc() {\n return this.getPointResolutionFunc_;\n }\n}\n\nexport default Projection;\n","/**\n * @module ol/proj/epsg3857\n */\nimport Projection from './Projection.js';\n\n/**\n * Radius of WGS84 sphere\n *\n * @const\n * @type {number}\n */\nexport const RADIUS = 6378137;\n\n/**\n * @const\n * @type {number}\n */\nexport const HALF_SIZE = Math.PI * RADIUS;\n\n/**\n * @const\n * @type {import(\"../extent.js\").Extent}\n */\nexport const EXTENT = [-HALF_SIZE, -HALF_SIZE, HALF_SIZE, HALF_SIZE];\n\n/**\n * @const\n * @type {import(\"../extent.js\").Extent}\n */\nexport const WORLD_EXTENT = [-180, -85, 180, 85];\n\n/**\n * Maximum safe value in y direction\n * @const\n * @type {number}\n */\nexport const MAX_SAFE_Y = RADIUS * Math.log(Math.tan(Math.PI / 2));\n\n/**\n * @classdesc\n * Projection object for web/spherical Mercator (EPSG:3857).\n */\nclass EPSG3857Projection extends Projection {\n /**\n * @param {string} code Code.\n */\n constructor(code) {\n super({\n code: code,\n units: 'm',\n extent: EXTENT,\n global: true,\n worldExtent: WORLD_EXTENT,\n getPointResolution: function (resolution, point) {\n return resolution / Math.cosh(point[1] / RADIUS);\n },\n });\n }\n}\n\n/**\n * Projections equal to EPSG:3857.\n *\n * @const\n * @type {Array}\n */\nexport const PROJECTIONS = [\n new EPSG3857Projection('EPSG:3857'),\n new EPSG3857Projection('EPSG:102100'),\n new EPSG3857Projection('EPSG:102113'),\n new EPSG3857Projection('EPSG:900913'),\n new EPSG3857Projection('http://www.opengis.net/def/crs/EPSG/0/3857'),\n new EPSG3857Projection('http://www.opengis.net/gml/srs/epsg.xml#3857'),\n];\n\n/**\n * Transformation from EPSG:4326 to EPSG:3857.\n *\n * @param {Array} input Input array of coordinate values.\n * @param {Array} [output] Output array of coordinate values.\n * @param {number} [dimension] Dimension (default is `2`).\n * @return {Array} Output array of coordinate values.\n */\nexport function fromEPSG4326(input, output, dimension) {\n const length = input.length;\n dimension = dimension > 1 ? dimension : 2;\n if (output === undefined) {\n if (dimension > 2) {\n // preserve values beyond second dimension\n output = input.slice();\n } else {\n output = new Array(length);\n }\n }\n for (let i = 0; i < length; i += dimension) {\n output[i] = (HALF_SIZE * input[i]) / 180;\n let y = RADIUS * Math.log(Math.tan((Math.PI * (+input[i + 1] + 90)) / 360));\n if (y > MAX_SAFE_Y) {\n y = MAX_SAFE_Y;\n } else if (y < -MAX_SAFE_Y) {\n y = -MAX_SAFE_Y;\n }\n output[i + 1] = y;\n }\n return output;\n}\n\n/**\n * Transformation from EPSG:3857 to EPSG:4326.\n *\n * @param {Array} input Input array of coordinate values.\n * @param {Array} [output] Output array of coordinate values.\n * @param {number} [dimension] Dimension (default is `2`).\n * @return {Array} Output array of coordinate values.\n */\nexport function toEPSG4326(input, output, dimension) {\n const length = input.length;\n dimension = dimension > 1 ? dimension : 2;\n if (output === undefined) {\n if (dimension > 2) {\n // preserve values beyond second dimension\n output = input.slice();\n } else {\n output = new Array(length);\n }\n }\n for (let i = 0; i < length; i += dimension) {\n output[i] = (180 * input[i]) / HALF_SIZE;\n output[i + 1] =\n (360 * Math.atan(Math.exp(input[i + 1] / RADIUS))) / Math.PI - 90;\n }\n return output;\n}\n","/**\n * @module ol/proj/epsg4326\n */\nimport Projection from './Projection.js';\n\n/**\n * Semi-major radius of the WGS84 ellipsoid.\n *\n * @const\n * @type {number}\n */\nexport const RADIUS = 6378137;\n\n/**\n * Extent of the EPSG:4326 projection which is the whole world.\n *\n * @const\n * @type {import(\"../extent.js\").Extent}\n */\nexport const EXTENT = [-180, -90, 180, 90];\n\n/**\n * @const\n * @type {number}\n */\nexport const METERS_PER_UNIT = (Math.PI * RADIUS) / 180;\n\n/**\n * @classdesc\n * Projection object for WGS84 geographic coordinates (EPSG:4326).\n *\n * Note that OpenLayers does not strictly comply with the EPSG definition.\n * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x).\n * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates.\n */\nclass EPSG4326Projection extends Projection {\n /**\n * @param {string} code Code.\n * @param {string} [axisOrientation] Axis orientation.\n */\n constructor(code, axisOrientation) {\n super({\n code: code,\n units: 'degrees',\n extent: EXTENT,\n axisOrientation: axisOrientation,\n global: true,\n metersPerUnit: METERS_PER_UNIT,\n worldExtent: EXTENT,\n });\n }\n}\n\n/**\n * Projections equal to EPSG:4326.\n *\n * @const\n * @type {Array}\n */\nexport const PROJECTIONS = [\n new EPSG4326Projection('CRS:84'),\n new EPSG4326Projection('EPSG:4326', 'neu'),\n new EPSG4326Projection('urn:ogc:def:crs:OGC:1.3:CRS84'),\n new EPSG4326Projection('urn:ogc:def:crs:OGC:2:84'),\n new EPSG4326Projection('http://www.opengis.net/def/crs/OGC/1.3/CRS84'),\n new EPSG4326Projection('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),\n new EPSG4326Projection('http://www.opengis.net/def/crs/EPSG/0/4326', 'neu'),\n];\n","/**\n * @module ol/proj/projections\n */\n\n/**\n * @type {Object}\n */\nlet cache = {};\n\n/**\n * Clear the projections cache.\n */\nexport function clear() {\n cache = {};\n}\n\n/**\n * Get a cached projection by code.\n * @param {string} code The code for the projection.\n * @return {import(\"./Projection.js\").default} The projection (if cached).\n */\nexport function get(code) {\n return (\n cache[code] ||\n cache[code.replace(/urn:(x-)?ogc:def:crs:EPSG:(.*:)?(\\w+)$/, 'EPSG:$3')] ||\n null\n );\n}\n\n/**\n * Add a projection to the cache.\n * @param {string} code The projection code.\n * @param {import(\"./Projection.js\").default} projection The projection to cache.\n */\nexport function add(code, projection) {\n cache[code] = projection;\n}\n","/**\n * @module ol/proj/transforms\n */\nimport {isEmpty} from '../obj.js';\n\n/**\n * @private\n * @type {!Object>}\n */\nlet transforms = {};\n\n/**\n * Clear the transform cache.\n */\nexport function clear() {\n transforms = {};\n}\n\n/**\n * Registers a conversion function to convert coordinates from the source\n * projection to the destination projection.\n *\n * @param {import(\"./Projection.js\").default} source Source.\n * @param {import(\"./Projection.js\").default} destination Destination.\n * @param {import(\"../proj.js\").TransformFunction} transformFn Transform.\n */\nexport function add(source, destination, transformFn) {\n const sourceCode = source.getCode();\n const destinationCode = destination.getCode();\n if (!(sourceCode in transforms)) {\n transforms[sourceCode] = {};\n }\n transforms[sourceCode][destinationCode] = transformFn;\n}\n\n/**\n * Unregisters the conversion function to convert coordinates from the source\n * projection to the destination projection. This method is used to clean up\n * cached transforms during testing.\n *\n * @param {import(\"./Projection.js\").default} source Source projection.\n * @param {import(\"./Projection.js\").default} destination Destination projection.\n * @return {import(\"../proj.js\").TransformFunction} transformFn The unregistered transform.\n */\nexport function remove(source, destination) {\n const sourceCode = source.getCode();\n const destinationCode = destination.getCode();\n const transform = transforms[sourceCode][destinationCode];\n delete transforms[sourceCode][destinationCode];\n if (isEmpty(transforms[sourceCode])) {\n delete transforms[sourceCode];\n }\n return transform;\n}\n\n/**\n * Get a transform given a source code and a destination code.\n * @param {string} sourceCode The code for the source projection.\n * @param {string} destinationCode The code for the destination projection.\n * @return {import(\"../proj.js\").TransformFunction|undefined} The transform function (if found).\n */\nexport function get(sourceCode, destinationCode) {\n let transform;\n if (sourceCode in transforms && destinationCode in transforms[sourceCode]) {\n transform = transforms[sourceCode][destinationCode];\n }\n return transform;\n}\n","/**\n * @module ol/math\n */\n\n/**\n * Takes a number and clamps it to within the provided bounds.\n * @param {number} value The input number.\n * @param {number} min The minimum value to return.\n * @param {number} max The maximum value to return.\n * @return {number} The input number if it is within bounds, or the nearest\n * number within the bounds.\n */\nexport function clamp(value, min, max) {\n return Math.min(Math.max(value, min), max);\n}\n\n/**\n * Returns the square of the closest distance between the point (x, y) and the\n * line segment (x1, y1) to (x2, y2).\n * @param {number} x X.\n * @param {number} y Y.\n * @param {number} x1 X1.\n * @param {number} y1 Y1.\n * @param {number} x2 X2.\n * @param {number} y2 Y2.\n * @return {number} Squared distance.\n */\nexport function squaredSegmentDistance(x, y, x1, y1, x2, y2) {\n const dx = x2 - x1;\n const dy = y2 - y1;\n if (dx !== 0 || dy !== 0) {\n const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);\n if (t > 1) {\n x1 = x2;\n y1 = y2;\n } else if (t > 0) {\n x1 += dx * t;\n y1 += dy * t;\n }\n }\n return squaredDistance(x, y, x1, y1);\n}\n\n/**\n * Returns the square of the distance between the points (x1, y1) and (x2, y2).\n * @param {number} x1 X1.\n * @param {number} y1 Y1.\n * @param {number} x2 X2.\n * @param {number} y2 Y2.\n * @return {number} Squared distance.\n */\nexport function squaredDistance(x1, y1, x2, y2) {\n const dx = x2 - x1;\n const dy = y2 - y1;\n return dx * dx + dy * dy;\n}\n\n/**\n * Solves system of linear equations using Gaussian elimination method.\n *\n * @param {Array>} mat Augmented matrix (n x n + 1 column)\n * in row-major order.\n * @return {Array|null} The resulting vector.\n */\nexport function solveLinearSystem(mat) {\n const n = mat.length;\n\n for (let i = 0; i < n; i++) {\n // Find max in the i-th column (ignoring i - 1 first rows)\n let maxRow = i;\n let maxEl = Math.abs(mat[i][i]);\n for (let r = i + 1; r < n; r++) {\n const absValue = Math.abs(mat[r][i]);\n if (absValue > maxEl) {\n maxEl = absValue;\n maxRow = r;\n }\n }\n\n if (maxEl === 0) {\n return null; // matrix is singular\n }\n\n // Swap max row with i-th (current) row\n const tmp = mat[maxRow];\n mat[maxRow] = mat[i];\n mat[i] = tmp;\n\n // Subtract the i-th row to make all the remaining rows 0 in the i-th column\n for (let j = i + 1; j < n; j++) {\n const coef = -mat[j][i] / mat[i][i];\n for (let k = i; k < n + 1; k++) {\n if (i == k) {\n mat[j][k] = 0;\n } else {\n mat[j][k] += coef * mat[i][k];\n }\n }\n }\n }\n\n // Solve Ax=b for upper triangular matrix A (mat)\n const x = new Array(n);\n for (let l = n - 1; l >= 0; l--) {\n x[l] = mat[l][n] / mat[l][l];\n for (let m = l - 1; m >= 0; m--) {\n mat[m][n] -= mat[m][l] * x[l];\n }\n }\n return x;\n}\n\n/**\n * Converts radians to to degrees.\n *\n * @param {number} angleInRadians Angle in radians.\n * @return {number} Angle in degrees.\n */\nexport function toDegrees(angleInRadians) {\n return (angleInRadians * 180) / Math.PI;\n}\n\n/**\n * Converts degrees to radians.\n *\n * @param {number} angleInDegrees Angle in degrees.\n * @return {number} Angle in radians.\n */\nexport function toRadians(angleInDegrees) {\n return (angleInDegrees * Math.PI) / 180;\n}\n\n/**\n * Returns the modulo of a / b, depending on the sign of b.\n *\n * @param {number} a Dividend.\n * @param {number} b Divisor.\n * @return {number} Modulo.\n */\nexport function modulo(a, b) {\n const r = a % b;\n return r * b < 0 ? r + b : r;\n}\n\n/**\n * Calculates the linearly interpolated value of x between a and b.\n *\n * @param {number} a Number\n * @param {number} b Number\n * @param {number} x Value to be interpolated.\n * @return {number} Interpolated value.\n */\nexport function lerp(a, b, x) {\n return a + x * (b - a);\n}\n\n/**\n * Returns a number with a limited number of decimal digits.\n * @param {number} n The input number.\n * @param {number} decimals The maximum number of decimal digits.\n * @return {number} The input number with a limited number of decimal digits.\n */\nexport function toFixed(n, decimals) {\n const factor = Math.pow(10, decimals);\n return Math.round(n * factor) / factor;\n}\n\n/**\n * Rounds a number to the nearest integer value considering only the given number\n * of decimal digits (with rounding on the final digit).\n * @param {number} n The input number.\n * @param {number} decimals The maximum number of decimal digits.\n * @return {number} The nearest integer.\n */\nexport function round(n, decimals) {\n return Math.round(toFixed(n, decimals));\n}\n\n/**\n * Rounds a number to the next smaller integer considering only the given number\n * of decimal digits (with rounding on the final digit).\n * @param {number} n The input number.\n * @param {number} decimals The maximum number of decimal digits.\n * @return {number} The next smaller integer.\n */\nexport function floor(n, decimals) {\n return Math.floor(toFixed(n, decimals));\n}\n\n/**\n * Rounds a number to the next bigger integer considering only the given number\n * of decimal digits (with rounding on the final digit).\n * @param {number} n The input number.\n * @param {number} decimals The maximum number of decimal digits.\n * @return {number} The next bigger integer.\n */\nexport function ceil(n, decimals) {\n return Math.ceil(toFixed(n, decimals));\n}\n","/**\n * @module ol/coordinate\n */\nimport {getWidth} from './extent.js';\nimport {modulo, toFixed} from './math.js';\nimport {padNumber} from './string.js';\n\n/**\n * An array of numbers representing an `xy`, `xyz` or `xyzm` coordinate.\n * Example: `[16, 48]`.\n * @typedef {Array} Coordinate\n * @api\n */\n\n/**\n * A function that takes a {@link module:ol/coordinate~Coordinate} and\n * transforms it into a `{string}`.\n *\n * @typedef {function((Coordinate|undefined)): string} CoordinateFormat\n * @api\n */\n\n/**\n * Add `delta` to `coordinate`. `coordinate` is modified in place and returned\n * by the function.\n *\n * Example:\n *\n * import {add} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * add(coord, [-2, 4]);\n * // coord is now [5.85, 51.983333]\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {Coordinate} delta Delta.\n * @return {Coordinate} The input coordinate adjusted by\n * the given delta.\n * @api\n */\nexport function add(coordinate, delta) {\n coordinate[0] += +delta[0];\n coordinate[1] += +delta[1];\n return coordinate;\n}\n\n/**\n * Calculates the point closest to the passed coordinate on the passed circle.\n *\n * @param {Coordinate} coordinate The coordinate.\n * @param {import(\"./geom/Circle.js\").default} circle The circle.\n * @return {Coordinate} Closest point on the circumference.\n */\nexport function closestOnCircle(coordinate, circle) {\n const r = circle.getRadius();\n const center = circle.getCenter();\n const x0 = center[0];\n const y0 = center[1];\n const x1 = coordinate[0];\n const y1 = coordinate[1];\n\n let dx = x1 - x0;\n const dy = y1 - y0;\n if (dx === 0 && dy === 0) {\n dx = 1;\n }\n const d = Math.sqrt(dx * dx + dy * dy);\n\n const x = x0 + (r * dx) / d;\n const y = y0 + (r * dy) / d;\n\n return [x, y];\n}\n\n/**\n * Calculates the point closest to the passed coordinate on the passed segment.\n * This is the foot of the perpendicular of the coordinate to the segment when\n * the foot is on the segment, or the closest segment coordinate when the foot\n * is outside the segment.\n *\n * @param {Coordinate} coordinate The coordinate.\n * @param {Array} segment The two coordinates\n * of the segment.\n * @return {Coordinate} The foot of the perpendicular of\n * the coordinate to the segment.\n */\nexport function closestOnSegment(coordinate, segment) {\n const x0 = coordinate[0];\n const y0 = coordinate[1];\n const start = segment[0];\n const end = segment[1];\n const x1 = start[0];\n const y1 = start[1];\n const x2 = end[0];\n const y2 = end[1];\n const dx = x2 - x1;\n const dy = y2 - y1;\n const along =\n dx === 0 && dy === 0\n ? 0\n : (dx * (x0 - x1) + dy * (y0 - y1)) / (dx * dx + dy * dy || 0);\n let x, y;\n if (along <= 0) {\n x = x1;\n y = y1;\n } else if (along >= 1) {\n x = x2;\n y = y2;\n } else {\n x = x1 + along * dx;\n y = y1 + along * dy;\n }\n return [x, y];\n}\n\n/**\n * Returns a {@link module:ol/coordinate~CoordinateFormat} function that can be\n * used to format\n * a {Coordinate} to a string.\n *\n * Example without specifying the fractional digits:\n *\n * import {createStringXY} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const stringifyFunc = createStringXY();\n * const out = stringifyFunc(coord);\n * // out is now '8, 48'\n *\n * Example with explicitly specifying 2 fractional digits:\n *\n * import {createStringXY} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const stringifyFunc = createStringXY(2);\n * const out = stringifyFunc(coord);\n * // out is now '7.85, 47.98'\n *\n * @param {number} [fractionDigits] The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {CoordinateFormat} Coordinate format.\n * @api\n */\nexport function createStringXY(fractionDigits) {\n return (\n /**\n * @param {Coordinate} coordinate Coordinate.\n * @return {string} String XY.\n */\n function (coordinate) {\n return toStringXY(coordinate, fractionDigits);\n }\n );\n}\n\n/**\n * @param {string} hemispheres Hemispheres.\n * @param {number} degrees Degrees.\n * @param {number} [fractionDigits] The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} String.\n */\nexport function degreesToStringHDMS(hemispheres, degrees, fractionDigits) {\n const normalizedDegrees = modulo(degrees + 180, 360) - 180;\n const x = Math.abs(3600 * normalizedDegrees);\n const decimals = fractionDigits || 0;\n\n let deg = Math.floor(x / 3600);\n let min = Math.floor((x - deg * 3600) / 60);\n let sec = toFixed(x - deg * 3600 - min * 60, decimals);\n\n if (sec >= 60) {\n sec = 0;\n min += 1;\n }\n\n if (min >= 60) {\n min = 0;\n deg += 1;\n }\n\n let hdms = deg + '\\u00b0';\n if (min !== 0 || sec !== 0) {\n hdms += ' ' + padNumber(min, 2) + '\\u2032';\n }\n if (sec !== 0) {\n hdms += ' ' + padNumber(sec, 2, decimals) + '\\u2033';\n }\n if (normalizedDegrees !== 0) {\n hdms += ' ' + hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0);\n }\n\n return hdms;\n}\n\n/**\n * Transforms the given {@link module:ol/coordinate~Coordinate} to a string\n * using the given string template. The strings `{x}` and `{y}` in the template\n * will be replaced with the first and second coordinate values respectively.\n *\n * Example without specifying the fractional digits:\n *\n * import {format} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const template = 'Coordinate is ({x}|{y}).';\n * const out = format(coord, template);\n * // out is now 'Coordinate is (8|48).'\n *\n * Example explicitly specifying the fractional digits:\n *\n * import {format} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const template = 'Coordinate is ({x}|{y}).';\n * const out = format(coord, template, 2);\n * // out is now 'Coordinate is (7.85|47.98).'\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {string} template A template string with `{x}` and `{y}` placeholders\n * that will be replaced by first and second coordinate values.\n * @param {number} [fractionDigits] The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} Formatted coordinate.\n * @api\n */\nexport function format(coordinate, template, fractionDigits) {\n if (coordinate) {\n return template\n .replace('{x}', coordinate[0].toFixed(fractionDigits))\n .replace('{y}', coordinate[1].toFixed(fractionDigits));\n }\n return '';\n}\n\n/**\n * @param {Coordinate} coordinate1 First coordinate.\n * @param {Coordinate} coordinate2 Second coordinate.\n * @return {boolean} The two coordinates are equal.\n */\nexport function equals(coordinate1, coordinate2) {\n let equals = true;\n for (let i = coordinate1.length - 1; i >= 0; --i) {\n if (coordinate1[i] != coordinate2[i]) {\n equals = false;\n break;\n }\n }\n return equals;\n}\n\n/**\n * Rotate `coordinate` by `angle`. `coordinate` is modified in place and\n * returned by the function.\n *\n * Example:\n *\n * import {rotate} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const rotateRadians = Math.PI / 2; // 90 degrees\n * rotate(coord, rotateRadians);\n * // coord is now [-47.983333, 7.85]\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {number} angle Angle in radian.\n * @return {Coordinate} Coordinate.\n * @api\n */\nexport function rotate(coordinate, angle) {\n const cosAngle = Math.cos(angle);\n const sinAngle = Math.sin(angle);\n const x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;\n const y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;\n coordinate[0] = x;\n coordinate[1] = y;\n return coordinate;\n}\n\n/**\n * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned\n * by the function.\n *\n * Example:\n *\n * import {scale as scaleCoordinate} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const scale = 1.2;\n * scaleCoordinate(coord, scale);\n * // coord is now [9.42, 57.5799996]\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {number} scale Scale factor.\n * @return {Coordinate} Coordinate.\n */\nexport function scale(coordinate, scale) {\n coordinate[0] *= scale;\n coordinate[1] *= scale;\n return coordinate;\n}\n\n/**\n * @param {Coordinate} coord1 First coordinate.\n * @param {Coordinate} coord2 Second coordinate.\n * @return {number} Squared distance between coord1 and coord2.\n */\nexport function squaredDistance(coord1, coord2) {\n const dx = coord1[0] - coord2[0];\n const dy = coord1[1] - coord2[1];\n return dx * dx + dy * dy;\n}\n\n/**\n * @param {Coordinate} coord1 First coordinate.\n * @param {Coordinate} coord2 Second coordinate.\n * @return {number} Distance between coord1 and coord2.\n */\nexport function distance(coord1, coord2) {\n return Math.sqrt(squaredDistance(coord1, coord2));\n}\n\n/**\n * Calculate the squared distance from a coordinate to a line segment.\n *\n * @param {Coordinate} coordinate Coordinate of the point.\n * @param {Array} segment Line segment (2\n * coordinates).\n * @return {number} Squared distance from the point to the line segment.\n */\nexport function squaredDistanceToSegment(coordinate, segment) {\n return squaredDistance(coordinate, closestOnSegment(coordinate, segment));\n}\n\n/**\n * Format a geographic coordinate with the hemisphere, degrees, minutes, and\n * seconds.\n *\n * Example without specifying fractional digits:\n *\n * import {toStringHDMS} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const out = toStringHDMS(coord);\n * // out is now '47° 58′ 60″ N 7° 50′ 60″ E'\n *\n * Example explicitly specifying 1 fractional digit:\n *\n * import {toStringHDMS} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const out = toStringHDMS(coord, 1);\n * // out is now '47° 58′ 60.0″ N 7° 50′ 60.0″ E'\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {number} [fractionDigits] The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} Hemisphere, degrees, minutes and seconds.\n * @api\n */\nexport function toStringHDMS(coordinate, fractionDigits) {\n if (coordinate) {\n return (\n degreesToStringHDMS('NS', coordinate[1], fractionDigits) +\n ' ' +\n degreesToStringHDMS('EW', coordinate[0], fractionDigits)\n );\n }\n return '';\n}\n\n/**\n * Format a coordinate as a comma delimited string.\n *\n * Example without specifying fractional digits:\n *\n * import {toStringXY} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const out = toStringXY(coord);\n * // out is now '8, 48'\n *\n * Example explicitly specifying 1 fractional digit:\n *\n * import {toStringXY} from 'ol/coordinate.js';\n *\n * const coord = [7.85, 47.983333];\n * const out = toStringXY(coord, 1);\n * // out is now '7.8, 48.0'\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {number} [fractionDigits] The number of digits to include\n * after the decimal point. Default is `0`.\n * @return {string} XY.\n * @api\n */\nexport function toStringXY(coordinate, fractionDigits) {\n return format(coordinate, '{x}, {y}', fractionDigits);\n}\n\n/**\n * Modifies the provided coordinate in-place to be within the real world\n * extent. The lower projection extent boundary is inclusive, the upper one\n * exclusive.\n *\n * @param {Coordinate} coordinate Coordinate.\n * @param {import(\"./proj/Projection.js\").default} projection Projection.\n * @return {Coordinate} The coordinate within the real world extent.\n */\nexport function wrapX(coordinate, projection) {\n if (projection.canWrapX()) {\n const worldWidth = getWidth(projection.getExtent());\n const worldsAway = getWorldsAway(coordinate, projection, worldWidth);\n if (worldsAway) {\n coordinate[0] -= worldsAway * worldWidth;\n }\n }\n return coordinate;\n}\n/**\n * @param {Coordinate} coordinate Coordinate.\n * @param {import(\"./proj/Projection.js\").default} projection Projection.\n * @param {number} [sourceExtentWidth] Width of the source extent.\n * @return {number} Offset in world widths.\n */\nexport function getWorldsAway(coordinate, projection, sourceExtentWidth) {\n const projectionExtent = projection.getExtent();\n let worldsAway = 0;\n if (\n projection.canWrapX() &&\n (coordinate[0] < projectionExtent[0] || coordinate[0] > projectionExtent[2])\n ) {\n sourceExtentWidth = sourceExtentWidth || getWidth(projectionExtent);\n worldsAway = Math.floor(\n (coordinate[0] - projectionExtent[0]) / sourceExtentWidth\n );\n }\n return worldsAway;\n}\n","/**\n * @module ol/sphere\n */\nimport {toDegrees, toRadians} from './math.js';\n\n/**\n * Object literal with options for the {@link getLength} or {@link getArea}\n * functions.\n * @typedef {Object} SphereMetricOptions\n * @property {import(\"./proj.js\").ProjectionLike} [projection='EPSG:3857']\n * Projection of the geometry. By default, the geometry is assumed to be in\n * Web Mercator.\n * @property {number} [radius=6371008.8] Sphere radius. By default, the\n * [mean Earth radius](https://en.wikipedia.org/wiki/Earth_radius#Mean_radius)\n * for the WGS84 ellipsoid is used.\n */\n\n/**\n * The mean Earth radius (1/3 * (2a + b)) for the WGS84 ellipsoid.\n * https://en.wikipedia.org/wiki/Earth_radius#Mean_radius\n * @type {number}\n */\nexport const DEFAULT_RADIUS = 6371008.8;\n\n/**\n * Get the great circle distance (in meters) between two geographic coordinates.\n * @param {Array} c1 Starting coordinate.\n * @param {Array} c2 Ending coordinate.\n * @param {number} [radius] The sphere radius to use. Defaults to the Earth's\n * mean radius using the WGS84 ellipsoid.\n * @return {number} The great circle distance between the points (in meters).\n * @api\n */\nexport function getDistance(c1, c2, radius) {\n radius = radius || DEFAULT_RADIUS;\n const lat1 = toRadians(c1[1]);\n const lat2 = toRadians(c2[1]);\n const deltaLatBy2 = (lat2 - lat1) / 2;\n const deltaLonBy2 = toRadians(c2[0] - c1[0]) / 2;\n const a =\n Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) +\n Math.sin(deltaLonBy2) *\n Math.sin(deltaLonBy2) *\n Math.cos(lat1) *\n Math.cos(lat2);\n return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));\n}\n\n/**\n * Get the cumulative great circle length of linestring coordinates (geographic).\n * @param {Array} coordinates Linestring coordinates.\n * @param {number} radius The sphere radius to use.\n * @return {number} The length (in meters).\n */\nfunction getLengthInternal(coordinates, radius) {\n let length = 0;\n for (let i = 0, ii = coordinates.length; i < ii - 1; ++i) {\n length += getDistance(coordinates[i], coordinates[i + 1], radius);\n }\n return length;\n}\n\n/**\n * Get the spherical length of a geometry. This length is the sum of the\n * great circle distances between coordinates. For polygons, the length is\n * the sum of all rings. For points, the length is zero. For multi-part\n * geometries, the length is the sum of the length of each part.\n * @param {import(\"./geom/Geometry.js\").default} geometry A geometry.\n * @param {SphereMetricOptions} [options] Options for the\n * length calculation. By default, geometries are assumed to be in 'EPSG:3857'.\n * You can change this by providing a `projection` option.\n * @return {number} The spherical length (in meters).\n * @api\n */\nexport function getLength(geometry, options) {\n options = options || {};\n const radius = options.radius || DEFAULT_RADIUS;\n const projection = options.projection || 'EPSG:3857';\n const type = geometry.getType();\n if (type !== 'GeometryCollection') {\n geometry = geometry.clone().transform(projection, 'EPSG:4326');\n }\n let length = 0;\n let coordinates, coords, i, ii, j, jj;\n switch (type) {\n case 'Point':\n case 'MultiPoint': {\n break;\n }\n case 'LineString':\n case 'LinearRing': {\n coordinates = /** @type {import(\"./geom/SimpleGeometry.js\").default} */ (\n geometry\n ).getCoordinates();\n length = getLengthInternal(coordinates, radius);\n break;\n }\n case 'MultiLineString':\n case 'Polygon': {\n coordinates = /** @type {import(\"./geom/SimpleGeometry.js\").default} */ (\n geometry\n ).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n length += getLengthInternal(coordinates[i], radius);\n }\n break;\n }\n case 'MultiPolygon': {\n coordinates = /** @type {import(\"./geom/SimpleGeometry.js\").default} */ (\n geometry\n ).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n coords = coordinates[i];\n for (j = 0, jj = coords.length; j < jj; ++j) {\n length += getLengthInternal(coords[j], radius);\n }\n }\n break;\n }\n case 'GeometryCollection': {\n const geometries =\n /** @type {import(\"./geom/GeometryCollection.js\").default} */ (\n geometry\n ).getGeometries();\n for (i = 0, ii = geometries.length; i < ii; ++i) {\n length += getLength(geometries[i], options);\n }\n break;\n }\n default: {\n throw new Error('Unsupported geometry type: ' + type);\n }\n }\n return length;\n}\n\n/**\n * Returns the spherical area for a list of coordinates.\n *\n * [Reference](https://trs.jpl.nasa.gov/handle/2014/40409)\n * Robert. G. Chamberlain and William H. Duquette, \"Some Algorithms for\n * Polygons on a Sphere\", JPL Publication 07-03, Jet Propulsion\n * Laboratory, Pasadena, CA, June 2007\n *\n * @param {Array} coordinates List of coordinates of a linear\n * ring. If the ring is oriented clockwise, the area will be positive,\n * otherwise it will be negative.\n * @param {number} radius The sphere radius.\n * @return {number} Area (in square meters).\n */\nfunction getAreaInternal(coordinates, radius) {\n let area = 0;\n const len = coordinates.length;\n let x1 = coordinates[len - 1][0];\n let y1 = coordinates[len - 1][1];\n for (let i = 0; i < len; i++) {\n const x2 = coordinates[i][0];\n const y2 = coordinates[i][1];\n area +=\n toRadians(x2 - x1) *\n (2 + Math.sin(toRadians(y1)) + Math.sin(toRadians(y2)));\n x1 = x2;\n y1 = y2;\n }\n return (area * radius * radius) / 2.0;\n}\n\n/**\n * Get the spherical area of a geometry. This is the area (in meters) assuming\n * that polygon edges are segments of great circles on a sphere.\n * @param {import(\"./geom/Geometry.js\").default} geometry A geometry.\n * @param {SphereMetricOptions} [options] Options for the area\n * calculation. By default, geometries are assumed to be in 'EPSG:3857'.\n * You can change this by providing a `projection` option.\n * @return {number} The spherical area (in square meters).\n * @api\n */\nexport function getArea(geometry, options) {\n options = options || {};\n const radius = options.radius || DEFAULT_RADIUS;\n const projection = options.projection || 'EPSG:3857';\n const type = geometry.getType();\n if (type !== 'GeometryCollection') {\n geometry = geometry.clone().transform(projection, 'EPSG:4326');\n }\n let area = 0;\n let coordinates, coords, i, ii, j, jj;\n switch (type) {\n case 'Point':\n case 'MultiPoint':\n case 'LineString':\n case 'MultiLineString':\n case 'LinearRing': {\n break;\n }\n case 'Polygon': {\n coordinates = /** @type {import(\"./geom/Polygon.js\").default} */ (\n geometry\n ).getCoordinates();\n area = Math.abs(getAreaInternal(coordinates[0], radius));\n for (i = 1, ii = coordinates.length; i < ii; ++i) {\n area -= Math.abs(getAreaInternal(coordinates[i], radius));\n }\n break;\n }\n case 'MultiPolygon': {\n coordinates = /** @type {import(\"./geom/SimpleGeometry.js\").default} */ (\n geometry\n ).getCoordinates();\n for (i = 0, ii = coordinates.length; i < ii; ++i) {\n coords = coordinates[i];\n area += Math.abs(getAreaInternal(coords[0], radius));\n for (j = 1, jj = coords.length; j < jj; ++j) {\n area -= Math.abs(getAreaInternal(coords[j], radius));\n }\n }\n break;\n }\n case 'GeometryCollection': {\n const geometries =\n /** @type {import(\"./geom/GeometryCollection.js\").default} */ (\n geometry\n ).getGeometries();\n for (i = 0, ii = geometries.length; i < ii; ++i) {\n area += getArea(geometries[i], options);\n }\n break;\n }\n default: {\n throw new Error('Unsupported geometry type: ' + type);\n }\n }\n return area;\n}\n\n/**\n * Returns the coordinate at the given distance and bearing from `c1`.\n *\n * @param {import(\"./coordinate.js\").Coordinate} c1 The origin point (`[lon, lat]` in degrees).\n * @param {number} distance The great-circle distance between the origin\n * point and the target point.\n * @param {number} bearing The bearing (in radians).\n * @param {number} [radius] The sphere radius to use. Defaults to the Earth's\n * mean radius using the WGS84 ellipsoid.\n * @return {import(\"./coordinate.js\").Coordinate} The target point.\n */\nexport function offset(c1, distance, bearing, radius) {\n radius = radius || DEFAULT_RADIUS;\n const lat1 = toRadians(c1[1]);\n const lon1 = toRadians(c1[0]);\n const dByR = distance / radius;\n const lat = Math.asin(\n Math.sin(lat1) * Math.cos(dByR) +\n Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing)\n );\n const lon =\n lon1 +\n Math.atan2(\n Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1),\n Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat)\n );\n return [toDegrees(lon), toDegrees(lat)];\n}\n","/**\n * @module ol/console\n */\n\n/**\n * @typedef {'info'|'warn'|'error'|'none'} Level\n */\n\n/**\n * @type {Object}\n */\nconst levels = {\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n};\n\n/**\n * @type {number}\n */\nlet level = levels.info;\n\n/**\n * Set the logging level. By default, the level is set to 'info' and all\n * messages will be logged. Set to 'warn' to only display warnings and errors.\n * Set to 'error' to only display errors. Set to 'none' to silence all messages.\n *\n * @param {Level} l The new level.\n */\nexport function setLevel(l) {\n level = levels[l];\n}\n\n/**\n * @param {...any} args Arguments to log\n */\nexport function log(...args) {\n if (level > levels.info) {\n return;\n }\n console.log(...args); // eslint-disable-line no-console\n}\n\n/**\n * @param {...any} args Arguments to log\n */\nexport function warn(...args) {\n if (level > levels.warn) {\n return;\n }\n console.warn(...args); // eslint-disable-line no-console\n}\n\n/**\n * @param {...any} args Arguments to log\n */\nexport function error(...args) {\n if (level > levels.error) {\n return;\n }\n console.error(...args); // eslint-disable-line no-console\n}\n","/**\n * @module ol/proj\n */\n\n/**\n * The ol/proj module stores:\n * * a list of {@link module:ol/proj/Projection~Projection}\n * objects, one for each projection supported by the application\n * * a list of transform functions needed to convert coordinates in one projection\n * into another.\n *\n * The static functions are the methods used to maintain these.\n * Each transform function can handle not only simple coordinate pairs, but also\n * large arrays of coordinates such as vector geometries.\n *\n * When loaded, the library adds projection objects for EPSG:4326 (WGS84\n * geographic coordinates) and EPSG:3857 (Web or Spherical Mercator, as used\n * for example by Bing Maps or OpenStreetMap), together with the relevant\n * transform functions.\n *\n * Additional transforms may be added by using the http://proj4js.org/\n * library (version 2.2 or later). You can use the full build supplied by\n * Proj4js, or create a custom build to support those projections you need; see\n * the Proj4js website for how to do this. You also need the Proj4js definitions\n * for the required projections. These definitions can be obtained from\n * https://epsg.io/, and are a JS function, so can be loaded in a script\n * tag (as in the examples) or pasted into your application.\n *\n * After all required projection definitions are added to proj4's registry (by\n * using `proj4.defs()`), simply call `register(proj4)` from the `ol/proj/proj4`\n * package. Existing transforms are not changed by this function. See\n * examples/wms-image-custom-proj for an example of this.\n *\n * Additional projection definitions can be registered with `proj4.defs()` any\n * time. Just make sure to call `register(proj4)` again; for example, with user-supplied data where you don't\n * know in advance what projections are needed, you can initially load minimal\n * support and then load whichever are requested.\n *\n * Note that Proj4js does not support projection extents. If you want to add\n * one for creating default tile grids, you can add it after the Projection\n * object has been created with `setExtent`, for example,\n * `get('EPSG:1234').setExtent(extent)`.\n *\n * In addition to Proj4js support, any transform functions can be added with\n * {@link module:ol/proj.addCoordinateTransforms}. To use this, you must first create\n * a {@link module:ol/proj/Projection~Projection} object for the new projection and add it with\n * {@link module:ol/proj.addProjection}. You can then add the forward and inverse\n * functions with {@link module:ol/proj.addCoordinateTransforms}. See\n * examples/wms-custom-proj for an example of this.\n *\n * Note that if no transforms are needed and you only need to define the\n * projection, just add a {@link module:ol/proj/Projection~Projection} with\n * {@link module:ol/proj.addProjection}. See examples/wms-no-proj for an example of\n * this.\n */\nimport Projection from './proj/Projection.js';\nimport {\n PROJECTIONS as EPSG3857_PROJECTIONS,\n fromEPSG4326,\n toEPSG4326,\n} from './proj/epsg3857.js';\nimport {PROJECTIONS as EPSG4326_PROJECTIONS} from './proj/epsg4326.js';\nimport {METERS_PER_UNIT} from './proj/Units.js';\nimport {\n add as addProj,\n clear as clearProj,\n get as getProj,\n} from './proj/projections.js';\nimport {\n add as addTransformFunc,\n clear as clearTransformFuncs,\n get as getTransformFunc,\n} from './proj/transforms.js';\nimport {applyTransform, getWidth} from './extent.js';\nimport {clamp, modulo} from './math.js';\nimport {equals, getWorldsAway} from './coordinate.js';\nimport {getDistance} from './sphere.js';\nimport {warn} from './console.js';\n\n/**\n * A projection as {@link module:ol/proj/Projection~Projection}, SRS identifier\n * string or undefined.\n * @typedef {Projection|string|undefined} ProjectionLike\n * @api\n */\n\n/**\n * A transform function accepts an array of input coordinate values, an optional\n * output array, and an optional dimension (default should be 2). The function\n * transforms the input coordinate values, populates the output array, and\n * returns the output array.\n *\n * @typedef {function(Array, Array=, number=): Array} TransformFunction\n * @api\n */\n\nexport {METERS_PER_UNIT};\n\nexport {Projection};\n\nlet showCoordinateWarning = true;\n\n/**\n * @param {boolean} [disable = true] Disable console info about `useGeographic()`\n */\nexport function disableCoordinateWarning(disable) {\n const hide = disable === undefined ? true : disable;\n showCoordinateWarning = !hide;\n}\n\n/**\n * @param {Array} input Input coordinate array.\n * @param {Array} [output] Output array of coordinate values.\n * @return {Array} Output coordinate array (new array, same coordinate\n * values).\n */\nexport function cloneTransform(input, output) {\n if (output !== undefined) {\n for (let i = 0, ii = input.length; i < ii; ++i) {\n output[i] = input[i];\n }\n output = output;\n } else {\n output = input.slice();\n }\n return output;\n}\n\n/**\n * @param {Array} input Input coordinate array.\n * @param {Array} [output] Output array of coordinate values.\n * @return {Array} Input coordinate array (same array as input).\n */\nexport function identityTransform(input, output) {\n if (output !== undefined && input !== output) {\n for (let i = 0, ii = input.length; i < ii; ++i) {\n output[i] = input[i];\n }\n input = output;\n }\n return input;\n}\n\n/**\n * Add a Projection object to the list of supported projections that can be\n * looked up by their code.\n *\n * @param {Projection} projection Projection instance.\n * @api\n */\nexport function addProjection(projection) {\n addProj(projection.getCode(), projection);\n addTransformFunc(projection, projection, cloneTransform);\n}\n\n/**\n * @param {Array} projections Projections.\n */\nexport function addProjections(projections) {\n projections.forEach(addProjection);\n}\n\n/**\n * Fetches a Projection object for the code specified.\n *\n * @param {ProjectionLike} projectionLike Either a code string which is\n * a combination of authority and identifier such as \"EPSG:4326\", or an\n * existing projection object, or undefined.\n * @return {Projection|null} Projection object, or null if not in list.\n * @api\n */\nexport function get(projectionLike) {\n return typeof projectionLike === 'string'\n ? getProj(/** @type {string} */ (projectionLike))\n : /** @type {Projection} */ (projectionLike) || null;\n}\n\n/**\n * Get the resolution of the point in degrees or distance units.\n * For projections with degrees as the unit this will simply return the\n * provided resolution. For other projections the point resolution is\n * by default estimated by transforming the `point` pixel to EPSG:4326,\n * measuring its width and height on the normal sphere,\n * and taking the average of the width and height.\n * A custom function can be provided for a specific projection, either\n * by setting the `getPointResolution` option in the\n * {@link module:ol/proj/Projection~Projection} constructor or by using\n * {@link module:ol/proj/Projection~Projection#setGetPointResolution} to change an existing\n * projection object.\n * @param {ProjectionLike} projection The projection.\n * @param {number} resolution Nominal resolution in projection units.\n * @param {import(\"./coordinate.js\").Coordinate} point Point to find adjusted resolution at.\n * @param {import(\"./proj/Units.js\").Units} [units] Units to get the point resolution in.\n * Default is the projection's units.\n * @return {number} Point resolution.\n * @api\n */\nexport function getPointResolution(projection, resolution, point, units) {\n projection = get(projection);\n let pointResolution;\n const getter = projection.getPointResolutionFunc();\n if (getter) {\n pointResolution = getter(resolution, point);\n if (units && units !== projection.getUnits()) {\n const metersPerUnit = projection.getMetersPerUnit();\n if (metersPerUnit) {\n pointResolution =\n (pointResolution * metersPerUnit) / METERS_PER_UNIT[units];\n }\n }\n } else {\n const projUnits = projection.getUnits();\n if ((projUnits == 'degrees' && !units) || units == 'degrees') {\n pointResolution = resolution;\n } else {\n // Estimate point resolution by transforming the center pixel to EPSG:4326,\n // measuring its width and height on the normal sphere, and taking the\n // average of the width and height.\n const toEPSG4326 = getTransformFromProjections(\n projection,\n get('EPSG:4326')\n );\n if (toEPSG4326 === identityTransform && projUnits !== 'degrees') {\n // no transform is available\n pointResolution = resolution * projection.getMetersPerUnit();\n } else {\n let vertices = [\n point[0] - resolution / 2,\n point[1],\n point[0] + resolution / 2,\n point[1],\n point[0],\n point[1] - resolution / 2,\n point[0],\n point[1] + resolution / 2,\n ];\n vertices = toEPSG4326(vertices, vertices, 2);\n const width = getDistance(vertices.slice(0, 2), vertices.slice(2, 4));\n const height = getDistance(vertices.slice(4, 6), vertices.slice(6, 8));\n pointResolution = (width + height) / 2;\n }\n const metersPerUnit = units\n ? METERS_PER_UNIT[units]\n : projection.getMetersPerUnit();\n if (metersPerUnit !== undefined) {\n pointResolution /= metersPerUnit;\n }\n }\n }\n return pointResolution;\n}\n\n/**\n * Registers transformation functions that don't alter coordinates. Those allow\n * to transform between projections with equal meaning.\n *\n * @param {Array} projections Projections.\n * @api\n */\nexport function addEquivalentProjections(projections) {\n addProjections(projections);\n projections.forEach(function (source) {\n projections.forEach(function (destination) {\n if (source !== destination) {\n addTransformFunc(source, destination, cloneTransform);\n }\n });\n });\n}\n\n/**\n * Registers transformation functions to convert coordinates in any projection\n * in projection1 to any projection in projection2.\n *\n * @param {Array} projections1 Projections with equal\n * meaning.\n * @param {Array} projections2 Projections with equal\n * meaning.\n * @param {TransformFunction} forwardTransform Transformation from any\n * projection in projection1 to any projection in projection2.\n * @param {TransformFunction} inverseTransform Transform from any projection\n * in projection2 to any projection in projection1..\n */\nexport function addEquivalentTransforms(\n projections1,\n projections2,\n forwardTransform,\n inverseTransform\n) {\n projections1.forEach(function (projection1) {\n projections2.forEach(function (projection2) {\n addTransformFunc(projection1, projection2, forwardTransform);\n addTransformFunc(projection2, projection1, inverseTransform);\n });\n });\n}\n\n/**\n * Clear all cached projections and transforms.\n */\nexport function clearAllProjections() {\n clearProj();\n clearTransformFuncs();\n}\n\n/**\n * @param {Projection|string|undefined} projection Projection.\n * @param {string} defaultCode Default code.\n * @return {Projection} Projection.\n */\nexport function createProjection(projection, defaultCode) {\n if (!projection) {\n return get(defaultCode);\n }\n if (typeof projection === 'string') {\n return get(projection);\n }\n return /** @type {Projection} */ (projection);\n}\n\n/**\n * Creates a {@link module:ol/proj~TransformFunction} from a simple 2D coordinate transform\n * function.\n * @param {function(import(\"./coordinate.js\").Coordinate): import(\"./coordinate.js\").Coordinate} coordTransform Coordinate\n * transform.\n * @return {TransformFunction} Transform function.\n */\nexport function createTransformFromCoordinateTransform(coordTransform) {\n return (\n /**\n * @param {Array} input Input.\n * @param {Array} [output] Output.\n * @param {number} [dimension] Dimension.\n * @return {Array} Output.\n */\n function (input, output, dimension) {\n const length = input.length;\n dimension = dimension !== undefined ? dimension : 2;\n output = output !== undefined ? output : new Array(length);\n for (let i = 0; i < length; i += dimension) {\n const point = coordTransform(input.slice(i, i + dimension));\n const pointLength = point.length;\n for (let j = 0, jj = dimension; j < jj; ++j) {\n output[i + j] = j >= pointLength ? input[i + j] : point[j];\n }\n }\n return output;\n }\n );\n}\n\n/**\n * Registers coordinate transform functions to convert coordinates between the\n * source projection and the destination projection.\n * The forward and inverse functions convert coordinate pairs; this function\n * converts these into the functions used internally which also handle\n * extents and coordinate arrays.\n *\n * @param {ProjectionLike} source Source projection.\n * @param {ProjectionLike} destination Destination projection.\n * @param {function(import(\"./coordinate.js\").Coordinate): import(\"./coordinate.js\").Coordinate} forward The forward transform\n * function (that is, from the source projection to the destination\n * projection) that takes a {@link module:ol/coordinate~Coordinate} as argument and returns\n * the transformed {@link module:ol/coordinate~Coordinate}.\n * @param {function(import(\"./coordinate.js\").Coordinate): import(\"./coordinate.js\").Coordinate} inverse The inverse transform\n * function (that is, from the destination projection to the source\n * projection) that takes a {@link module:ol/coordinate~Coordinate} as argument and returns\n * the transformed {@link module:ol/coordinate~Coordinate}. If the transform function can only\n * transform less dimensions than the input coordinate, it is supposeed to return a coordinate\n * with only the length it can transform. The other dimensions will be taken unchanged from the\n * source.\n * @api\n */\nexport function addCoordinateTransforms(source, destination, forward, inverse) {\n const sourceProj = get(source);\n const destProj = get(destination);\n addTransformFunc(\n sourceProj,\n destProj,\n createTransformFromCoordinateTransform(forward)\n );\n addTransformFunc(\n destProj,\n sourceProj,\n createTransformFromCoordinateTransform(inverse)\n );\n}\n\n/**\n * Transforms a coordinate from longitude/latitude to a different projection.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate as longitude and latitude, i.e.\n * an array with longitude as 1st and latitude as 2nd element.\n * @param {ProjectionLike} [projection] Target projection. The\n * default is Web Mercator, i.e. 'EPSG:3857'.\n * @return {import(\"./coordinate.js\").Coordinate} Coordinate projected to the target projection.\n * @api\n */\nexport function fromLonLat(coordinate, projection) {\n disableCoordinateWarning();\n return transform(\n coordinate,\n 'EPSG:4326',\n projection !== undefined ? projection : 'EPSG:3857'\n );\n}\n\n/**\n * Transforms a coordinate to longitude/latitude.\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Projected coordinate.\n * @param {ProjectionLike} [projection] Projection of the coordinate.\n * The default is Web Mercator, i.e. 'EPSG:3857'.\n * @return {import(\"./coordinate.js\").Coordinate} Coordinate as longitude and latitude, i.e. an array\n * with longitude as 1st and latitude as 2nd element.\n * @api\n */\nexport function toLonLat(coordinate, projection) {\n const lonLat = transform(\n coordinate,\n projection !== undefined ? projection : 'EPSG:3857',\n 'EPSG:4326'\n );\n const lon = lonLat[0];\n if (lon < -180 || lon > 180) {\n lonLat[0] = modulo(lon + 180, 360) - 180;\n }\n return lonLat;\n}\n\n/**\n * Checks if two projections are the same, that is every coordinate in one\n * projection does represent the same geographic point as the same coordinate in\n * the other projection.\n *\n * @param {Projection} projection1 Projection 1.\n * @param {Projection} projection2 Projection 2.\n * @return {boolean} Equivalent.\n * @api\n */\nexport function equivalent(projection1, projection2) {\n if (projection1 === projection2) {\n return true;\n }\n const equalUnits = projection1.getUnits() === projection2.getUnits();\n if (projection1.getCode() === projection2.getCode()) {\n return equalUnits;\n }\n const transformFunc = getTransformFromProjections(projection1, projection2);\n return transformFunc === cloneTransform && equalUnits;\n}\n\n/**\n * Searches in the list of transform functions for the function for converting\n * coordinates from the source projection to the destination projection.\n *\n * @param {Projection} sourceProjection Source Projection object.\n * @param {Projection} destinationProjection Destination Projection\n * object.\n * @return {TransformFunction} Transform function.\n */\nexport function getTransformFromProjections(\n sourceProjection,\n destinationProjection\n) {\n const sourceCode = sourceProjection.getCode();\n const destinationCode = destinationProjection.getCode();\n let transformFunc = getTransformFunc(sourceCode, destinationCode);\n if (!transformFunc) {\n transformFunc = identityTransform;\n }\n return transformFunc;\n}\n\n/**\n * Given the projection-like objects, searches for a transformation\n * function to convert a coordinates array from the source projection to the\n * destination projection.\n *\n * @param {ProjectionLike} source Source.\n * @param {ProjectionLike} destination Destination.\n * @return {TransformFunction} Transform function.\n * @api\n */\nexport function getTransform(source, destination) {\n const sourceProjection = get(source);\n const destinationProjection = get(destination);\n return getTransformFromProjections(sourceProjection, destinationProjection);\n}\n\n/**\n * Transforms a coordinate from source projection to destination projection.\n * This returns a new coordinate (and does not modify the original).\n *\n * See {@link module:ol/proj.transformExtent} for extent transformation.\n * See the transform method of {@link module:ol/geom/Geometry~Geometry} and its\n * subclasses for geometry transforms.\n *\n * @param {import(\"./coordinate.js\").Coordinate} coordinate Coordinate.\n * @param {ProjectionLike} source Source projection-like.\n * @param {ProjectionLike} destination Destination projection-like.\n * @return {import(\"./coordinate.js\").Coordinate} Coordinate.\n * @api\n */\nexport function transform(coordinate, source, destination) {\n const transformFunc = getTransform(source, destination);\n return transformFunc(coordinate, undefined, coordinate.length);\n}\n\n/**\n * Transforms an extent from source projection to destination projection. This\n * returns a new extent (and does not modify the original).\n *\n * @param {import(\"./extent.js\").Extent} extent The extent to transform.\n * @param {ProjectionLike} source Source projection-like.\n * @param {ProjectionLike} destination Destination projection-like.\n * @param {number} [stops] Number of stops per side used for the transform.\n * By default only the corners are used.\n * @return {import(\"./extent.js\").Extent} The transformed extent.\n * @api\n */\nexport function transformExtent(extent, source, destination, stops) {\n const transformFunc = getTransform(source, destination);\n return applyTransform(extent, transformFunc, undefined, stops);\n}\n\n/**\n * Transforms the given point to the destination projection.\n *\n * @param {import(\"./coordinate.js\").Coordinate} point Point.\n * @param {Projection} sourceProjection Source projection.\n * @param {Projection} destinationProjection Destination projection.\n * @return {import(\"./coordinate.js\").Coordinate} Point.\n */\nexport function transformWithProjections(\n point,\n sourceProjection,\n destinationProjection\n) {\n const transformFunc = getTransformFromProjections(\n sourceProjection,\n destinationProjection\n );\n return transformFunc(point);\n}\n\n/**\n * @type {Projection|null}\n */\nlet userProjection = null;\n\n/**\n * Set the projection for coordinates supplied from and returned by API methods.\n * This includes all API methods except for those interacting with tile grids,\n * plus {@link import(\"./Map.js\").FrameState} and {@link import(\"./View.js\").State}.\n * @param {ProjectionLike} projection The user projection.\n * @api\n */\nexport function setUserProjection(projection) {\n userProjection = get(projection);\n}\n\n/**\n * Clear the user projection if set.\n * @api\n */\nexport function clearUserProjection() {\n userProjection = null;\n}\n\n/**\n * Get the projection for coordinates supplied from and returned by API methods.\n * @return {Projection|null} The user projection (or null if not set).\n * @api\n */\nexport function getUserProjection() {\n return userProjection;\n}\n\n/**\n * Use geographic coordinates (WGS-84 datum) in API methods.\n * This includes all API methods except for those interacting with tile grids,\n * plus {@link import(\"./Map.js\").FrameState} and {@link import(\"./View.js\").State}.\n * @api\n */\nexport function useGeographic() {\n setUserProjection('EPSG:4326');\n}\n\n/**\n * Return a coordinate transformed into the user projection. If no user projection\n * is set, the original coordinate is returned.\n * @param {Array} coordinate Input coordinate.\n * @param {ProjectionLike} sourceProjection The input coordinate projection.\n * @return {Array} The input coordinate in the user projection.\n */\nexport function toUserCoordinate(coordinate, sourceProjection) {\n if (!userProjection) {\n return coordinate;\n }\n return transform(coordinate, sourceProjection, userProjection);\n}\n\n/**\n * Return a coordinate transformed from the user projection. If no user projection\n * is set, the original coordinate is returned.\n * @param {Array} coordinate Input coordinate.\n * @param {ProjectionLike} destProjection The destination projection.\n * @return {Array} The input coordinate transformed.\n */\nexport function fromUserCoordinate(coordinate, destProjection) {\n if (!userProjection) {\n if (\n showCoordinateWarning &&\n !equals(coordinate, [0, 0]) &&\n coordinate[0] >= -180 &&\n coordinate[0] <= 180 &&\n coordinate[1] >= -90 &&\n coordinate[1] <= 90\n ) {\n showCoordinateWarning = false;\n warn(\n 'Call useGeographic() from ol/proj once to work with [longitude, latitude] coordinates.'\n );\n }\n return coordinate;\n }\n return transform(coordinate, userProjection, destProjection);\n}\n\n/**\n * Return an extent transformed into the user projection. If no user projection\n * is set, the original extent is returned.\n * @param {import(\"./extent.js\").Extent} extent Input extent.\n * @param {ProjectionLike} sourceProjection The input extent projection.\n * @return {import(\"./extent.js\").Extent} The input extent in the user projection.\n */\nexport function toUserExtent(extent, sourceProjection) {\n if (!userProjection) {\n return extent;\n }\n return transformExtent(extent, sourceProjection, userProjection);\n}\n\n/**\n * Return an extent transformed from the user projection. If no user projection\n * is set, the original extent is returned.\n * @param {import(\"./extent.js\").Extent} extent Input extent.\n * @param {ProjectionLike} destProjection The destination projection.\n * @return {import(\"./extent.js\").Extent} The input extent transformed.\n */\nexport function fromUserExtent(extent, destProjection) {\n if (!userProjection) {\n return extent;\n }\n return transformExtent(extent, userProjection, destProjection);\n}\n\n/**\n * Return the resolution in user projection units per pixel. If no user projection\n * is set, or source or user projection are missing units, the original resolution\n * is returned.\n * @param {number} resolution Resolution in input projection units per pixel.\n * @param {ProjectionLike} sourceProjection The input projection.\n * @return {number} Resolution in user projection units per pixel.\n */\nexport function toUserResolution(resolution, sourceProjection) {\n if (!userProjection) {\n return resolution;\n }\n const sourceMetersPerUnit = get(sourceProjection).getMetersPerUnit();\n const userMetersPerUnit = userProjection.getMetersPerUnit();\n return sourceMetersPerUnit && userMetersPerUnit\n ? (resolution * sourceMetersPerUnit) / userMetersPerUnit\n : resolution;\n}\n\n/**\n * Return the resolution in user projection units per pixel. If no user projection\n * is set, or source or user projection are missing units, the original resolution\n * is returned.\n * @param {number} resolution Resolution in user projection units per pixel.\n * @param {ProjectionLike} destProjection The destination projection.\n * @return {number} Resolution in destination projection units per pixel.\n */\nexport function fromUserResolution(resolution, destProjection) {\n if (!userProjection) {\n return resolution;\n }\n const destMetersPerUnit = get(destProjection).getMetersPerUnit();\n const userMetersPerUnit = userProjection.getMetersPerUnit();\n return destMetersPerUnit && userMetersPerUnit\n ? (resolution * userMetersPerUnit) / destMetersPerUnit\n : resolution;\n}\n\n/**\n * Creates a safe coordinate transform function from a coordinate transform function.\n * \"Safe\" means that it can handle wrapping of x-coordinates for global projections,\n * and that coordinates exceeding the source projection validity extent's range will be\n * clamped to the validity range.\n * @param {Projection} sourceProj Source projection.\n * @param {Projection} destProj Destination projection.\n * @param {function(import(\"./coordinate.js\").Coordinate): import(\"./coordinate.js\").Coordinate} transform Transform function (source to destination).\n * @return {function(import(\"./coordinate.js\").Coordinate): import(\"./coordinate.js\").Coordinate} Safe transform function (source to destination).\n */\nexport function createSafeCoordinateTransform(sourceProj, destProj, transform) {\n return function (coord) {\n let transformed, worldsAway;\n if (sourceProj.canWrapX()) {\n const sourceExtent = sourceProj.getExtent();\n const sourceExtentWidth = getWidth(sourceExtent);\n coord = coord.slice(0);\n worldsAway = getWorldsAway(coord, sourceProj, sourceExtentWidth);\n if (worldsAway) {\n // Move x to the real world\n coord[0] = coord[0] - worldsAway * sourceExtentWidth;\n }\n coord[0] = clamp(coord[0], sourceExtent[0], sourceExtent[2]);\n coord[1] = clamp(coord[1], sourceExtent[1], sourceExtent[3]);\n transformed = transform(coord);\n } else {\n transformed = transform(coord);\n }\n if (worldsAway && destProj.canWrapX()) {\n // Move transformed coordinate back to the offset world\n transformed[0] += worldsAway * getWidth(destProj.getExtent());\n }\n return transformed;\n };\n}\n\n/**\n * Add transforms to and from EPSG:4326 and EPSG:3857. This function is called\n * by when this module is executed and should only need to be called again after\n * `clearAllProjections()` is called (e.g. in tests).\n */\nexport function addCommon() {\n // Add transformations that don't alter coordinates to convert within set of\n // projections with equal meaning.\n addEquivalentProjections(EPSG3857_PROJECTIONS);\n addEquivalentProjections(EPSG4326_PROJECTIONS);\n // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like\n // coordinates and back.\n addEquivalentTransforms(\n EPSG4326_PROJECTIONS,\n EPSG3857_PROJECTIONS,\n fromEPSG4326,\n toEPSG4326\n );\n}\n\naddCommon();\n","/**\n * @module ol/geom/flat/transform\n */\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {import(\"../../transform.js\").Transform} transform Transform.\n * @param {Array} [dest] Destination.\n * @return {Array} Transformed coordinates.\n */\nexport function transform2D(\n flatCoordinates,\n offset,\n end,\n stride,\n transform,\n dest\n) {\n dest = dest ? dest : [];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n const x = flatCoordinates[j];\n const y = flatCoordinates[j + 1];\n dest[i++] = transform[0] * x + transform[2] * y + transform[4];\n dest[i++] = transform[1] * x + transform[3] * y + transform[5];\n }\n if (dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} angle Angle.\n * @param {Array} anchor Rotation anchor point.\n * @param {Array} [dest] Destination.\n * @return {Array} Transformed coordinates.\n */\nexport function rotate(\n flatCoordinates,\n offset,\n end,\n stride,\n angle,\n anchor,\n dest\n) {\n dest = dest ? dest : [];\n const cos = Math.cos(angle);\n const sin = Math.sin(angle);\n const anchorX = anchor[0];\n const anchorY = anchor[1];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n const deltaX = flatCoordinates[j] - anchorX;\n const deltaY = flatCoordinates[j + 1] - anchorY;\n dest[i++] = anchorX + deltaX * cos - deltaY * sin;\n dest[i++] = anchorY + deltaX * sin + deltaY * cos;\n for (let k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n/**\n * Scale the coordinates.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} sx Scale factor in the x-direction.\n * @param {number} sy Scale factor in the y-direction.\n * @param {Array} anchor Scale anchor point.\n * @param {Array} [dest] Destination.\n * @return {Array} Transformed coordinates.\n */\nexport function scale(\n flatCoordinates,\n offset,\n end,\n stride,\n sx,\n sy,\n anchor,\n dest\n) {\n dest = dest ? dest : [];\n const anchorX = anchor[0];\n const anchorY = anchor[1];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n const deltaX = flatCoordinates[j] - anchorX;\n const deltaY = flatCoordinates[j + 1] - anchorY;\n dest[i++] = anchorX + sx * deltaX;\n dest[i++] = anchorY + sy * deltaY;\n for (let k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n * @param {Array} [dest] Destination.\n * @return {Array} Transformed coordinates.\n */\nexport function translate(\n flatCoordinates,\n offset,\n end,\n stride,\n deltaX,\n deltaY,\n dest\n) {\n dest = dest ? dest : [];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n dest[i++] = flatCoordinates[j] + deltaX;\n dest[i++] = flatCoordinates[j + 1] + deltaY;\n for (let k = j + 2; k < j + stride; ++k) {\n dest[i++] = flatCoordinates[k];\n }\n }\n if (dest && dest.length != i) {\n dest.length = i;\n }\n return dest;\n}\n","/**\n * @module ol/geom/Geometry\n */\nimport BaseObject from '../Object.js';\nimport {abstract} from '../util.js';\nimport {\n compose as composeTransform,\n create as createTransform,\n} from '../transform.js';\nimport {\n createEmpty,\n createOrUpdateEmpty,\n getHeight,\n returnOrUpdate,\n} from '../extent.js';\nimport {get as getProjection, getTransform} from '../proj.js';\nimport {memoizeOne} from '../functions.js';\nimport {transform2D} from './flat/transform.js';\n\n/**\n * @typedef {'XY' | 'XYZ' | 'XYM' | 'XYZM'} GeometryLayout\n * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')\n * or measure ('M') coordinate is available.\n */\n\n/**\n * @typedef {'Point' | 'LineString' | 'LinearRing' | 'Polygon' | 'MultiPoint' | 'MultiLineString' | 'MultiPolygon' | 'GeometryCollection' | 'Circle'} Type\n * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,\n * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,\n * `'GeometryCollection'`, or `'Circle'`.\n */\n\n/**\n * @type {import(\"../transform.js\").Transform}\n */\nconst tmpTransform = createTransform();\n\n/**\n * @classdesc\n * Abstract base class; normally only used for creating subclasses and not\n * instantiated in apps.\n * Base class for vector geometries.\n *\n * To get notified of changes to the geometry, register a listener for the\n * generic `change` event on your geometry instance.\n *\n * @abstract\n * @api\n */\nclass Geometry extends BaseObject {\n constructor() {\n super();\n\n /**\n * @private\n * @type {import(\"../extent.js\").Extent}\n */\n this.extent_ = createEmpty();\n\n /**\n * @private\n * @type {number}\n */\n this.extentRevision_ = -1;\n\n /**\n * @protected\n * @type {number}\n */\n this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n\n /**\n * @protected\n * @type {number}\n */\n this.simplifiedGeometryRevision = 0;\n\n /**\n * Get a transformed and simplified version of the geometry.\n * @abstract\n * @param {number} revision The geometry revision.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {import(\"../proj.js\").TransformFunction} [transform] Optional transform function.\n * @return {Geometry} Simplified geometry.\n */\n this.simplifyTransformedInternal = memoizeOne(\n (revision, squaredTolerance, transform) => {\n if (!transform) {\n return this.getSimplifiedGeometry(squaredTolerance);\n }\n const clone = this.clone();\n clone.applyTransform(transform);\n return clone.getSimplifiedGeometry(squaredTolerance);\n }\n );\n }\n\n /**\n * Get a transformed and simplified version of the geometry.\n * @abstract\n * @param {number} squaredTolerance Squared tolerance.\n * @param {import(\"../proj.js\").TransformFunction} [transform] Optional transform function.\n * @return {Geometry} Simplified geometry.\n */\n simplifyTransformed(squaredTolerance, transform) {\n return this.simplifyTransformedInternal(\n this.getRevision(),\n squaredTolerance,\n transform\n );\n }\n\n /**\n * Make a complete copy of the geometry.\n * @abstract\n * @return {!Geometry} Clone.\n */\n clone() {\n return abstract();\n }\n\n /**\n * @abstract\n * @param {number} x X.\n * @param {number} y Y.\n * @param {import(\"../coordinate.js\").Coordinate} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @return {number} Minimum squared distance.\n */\n closestPointXY(x, y, closestPoint, minSquaredDistance) {\n return abstract();\n }\n\n /**\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\n containsXY(x, y) {\n const coord = this.getClosestPoint([x, y]);\n return coord[0] === x && coord[1] === y;\n }\n\n /**\n * Return the closest point of the geometry to the passed point as\n * {@link module:ol/coordinate~Coordinate coordinate}.\n * @param {import(\"../coordinate.js\").Coordinate} point Point.\n * @param {import(\"../coordinate.js\").Coordinate} [closestPoint] Closest point.\n * @return {import(\"../coordinate.js\").Coordinate} Closest point.\n * @api\n */\n getClosestPoint(point, closestPoint) {\n closestPoint = closestPoint ? closestPoint : [NaN, NaN];\n this.closestPointXY(point[0], point[1], closestPoint, Infinity);\n return closestPoint;\n }\n\n /**\n * Returns true if this geometry includes the specified coordinate. If the\n * coordinate is on the boundary of the geometry, returns false.\n * @param {import(\"../coordinate.js\").Coordinate} coordinate Coordinate.\n * @return {boolean} Contains coordinate.\n * @api\n */\n intersectsCoordinate(coordinate) {\n return this.containsXY(coordinate[0], coordinate[1]);\n }\n\n /**\n * @abstract\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @protected\n * @return {import(\"../extent.js\").Extent} extent Extent.\n */\n computeExtent(extent) {\n return abstract();\n }\n\n /**\n * Get the extent of the geometry.\n * @param {import(\"../extent.js\").Extent} [extent] Extent.\n * @return {import(\"../extent.js\").Extent} extent Extent.\n * @api\n */\n getExtent(extent) {\n if (this.extentRevision_ != this.getRevision()) {\n const extent = this.computeExtent(this.extent_);\n if (isNaN(extent[0]) || isNaN(extent[1])) {\n createOrUpdateEmpty(extent);\n }\n this.extentRevision_ = this.getRevision();\n }\n return returnOrUpdate(this.extent_, extent);\n }\n\n /**\n * Rotate the geometry around a given coordinate. This modifies the geometry\n * coordinates in place.\n * @abstract\n * @param {number} angle Rotation angle in radians.\n * @param {import(\"../coordinate.js\").Coordinate} anchor The rotation center.\n * @api\n */\n rotate(angle, anchor) {\n abstract();\n }\n\n /**\n * Scale the geometry (with an optional origin). This modifies the geometry\n * coordinates in place.\n * @abstract\n * @param {number} sx The scaling factor in the x-direction.\n * @param {number} [sy] The scaling factor in the y-direction (defaults to sx).\n * @param {import(\"../coordinate.js\").Coordinate} [anchor] The scale origin (defaults to the center\n * of the geometry extent).\n * @api\n */\n scale(sx, sy, anchor) {\n abstract();\n }\n\n /**\n * Create a simplified version of this geometry. For linestrings, this uses\n * the [Douglas Peucker](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm)\n * algorithm. For polygons, a quantization-based\n * simplification is used to preserve topology.\n * @param {number} tolerance The tolerance distance for simplification.\n * @return {Geometry} A new, simplified version of the original geometry.\n * @api\n */\n simplify(tolerance) {\n return this.getSimplifiedGeometry(tolerance * tolerance);\n }\n\n /**\n * Create a simplified version of this geometry using the Douglas Peucker\n * algorithm.\n * See https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm.\n * @abstract\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Geometry} Simplified geometry.\n */\n getSimplifiedGeometry(squaredTolerance) {\n return abstract();\n }\n\n /**\n * Get the type of this geometry.\n * @abstract\n * @return {Type} Geometry type.\n */\n getType() {\n return abstract();\n }\n\n /**\n * Apply a transform function to the coordinates of the geometry.\n * The geometry is modified in place.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n * @abstract\n * @param {import(\"../proj.js\").TransformFunction} transformFn Transform function.\n * Called with a flat array of geometry coordinates.\n */\n applyTransform(transformFn) {\n abstract();\n }\n\n /**\n * Test if the geometry and the passed extent intersect.\n * @abstract\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @return {boolean} `true` if the geometry and the extent intersect.\n */\n intersectsExtent(extent) {\n return abstract();\n }\n\n /**\n * Translate the geometry. This modifies the geometry coordinates in place. If\n * instead you want a new geometry, first `clone()` this geometry.\n * @abstract\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n * @api\n */\n translate(deltaX, deltaY) {\n abstract();\n }\n\n /**\n * Transform each coordinate of the geometry from one coordinate reference\n * system to another. The geometry is modified in place.\n * For example, a line will be transformed to a line and a circle to a circle.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n *\n * @param {import(\"../proj.js\").ProjectionLike} source The current projection. Can be a\n * string identifier or a {@link module:ol/proj/Projection~Projection} object.\n * @param {import(\"../proj.js\").ProjectionLike} destination The desired projection. Can be a\n * string identifier or a {@link module:ol/proj/Projection~Projection} object.\n * @return {Geometry} This geometry. Note that original geometry is\n * modified in place.\n * @api\n */\n transform(source, destination) {\n /** @type {import(\"../proj/Projection.js\").default} */\n const sourceProj = getProjection(source);\n const transformFn =\n sourceProj.getUnits() == 'tile-pixels'\n ? function (inCoordinates, outCoordinates, stride) {\n const pixelExtent = sourceProj.getExtent();\n const projectedExtent = sourceProj.getWorldExtent();\n const scale = getHeight(projectedExtent) / getHeight(pixelExtent);\n composeTransform(\n tmpTransform,\n projectedExtent[0],\n projectedExtent[3],\n scale,\n -scale,\n 0,\n 0,\n 0\n );\n transform2D(\n inCoordinates,\n 0,\n inCoordinates.length,\n stride,\n tmpTransform,\n outCoordinates\n );\n return getTransform(sourceProj, destination)(\n inCoordinates,\n outCoordinates,\n stride\n );\n }\n : getTransform(sourceProj, destination);\n this.applyTransform(transformFn);\n return this;\n }\n}\n\nexport default Geometry;\n","/**\n * @module ol/geom/SimpleGeometry\n */\nimport Geometry from './Geometry.js';\nimport {abstract} from '../util.js';\nimport {createOrUpdateFromFlatCoordinates, getCenter} from '../extent.js';\nimport {rotate, scale, transform2D, translate} from './flat/transform.js';\n\n/**\n * @classdesc\n * Abstract base class; only used for creating subclasses; do not instantiate\n * in apps, as cannot be rendered.\n *\n * @abstract\n * @api\n */\nclass SimpleGeometry extends Geometry {\n constructor() {\n super();\n\n /**\n * @protected\n * @type {import(\"./Geometry.js\").GeometryLayout}\n */\n this.layout = 'XY';\n\n /**\n * @protected\n * @type {number}\n */\n this.stride = 2;\n\n /**\n * @protected\n * @type {Array}\n */\n this.flatCoordinates;\n }\n\n /**\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @protected\n * @return {import(\"../extent.js\").Extent} extent Extent.\n */\n computeExtent(extent) {\n return createOrUpdateFromFlatCoordinates(\n this.flatCoordinates,\n 0,\n this.flatCoordinates.length,\n this.stride,\n extent\n );\n }\n\n /**\n * @abstract\n * @return {Array<*> | null} Coordinates.\n */\n getCoordinates() {\n return abstract();\n }\n\n /**\n * Return the first coordinate of the geometry.\n * @return {import(\"../coordinate.js\").Coordinate} First coordinate.\n * @api\n */\n getFirstCoordinate() {\n return this.flatCoordinates.slice(0, this.stride);\n }\n\n /**\n * @return {Array} Flat coordinates.\n */\n getFlatCoordinates() {\n return this.flatCoordinates;\n }\n\n /**\n * Return the last coordinate of the geometry.\n * @return {import(\"../coordinate.js\").Coordinate} Last point.\n * @api\n */\n getLastCoordinate() {\n return this.flatCoordinates.slice(\n this.flatCoordinates.length - this.stride\n );\n }\n\n /**\n * Return the {@link import(\"./Geometry.js\").GeometryLayout layout} of the geometry.\n * @return {import(\"./Geometry.js\").GeometryLayout} Layout.\n * @api\n */\n getLayout() {\n return this.layout;\n }\n\n /**\n * Create a simplified version of this geometry using the Douglas Peucker algorithm.\n * @param {number} squaredTolerance Squared tolerance.\n * @return {SimpleGeometry} Simplified geometry.\n */\n getSimplifiedGeometry(squaredTolerance) {\n if (this.simplifiedGeometryRevision !== this.getRevision()) {\n this.simplifiedGeometryMaxMinSquaredTolerance = 0;\n this.simplifiedGeometryRevision = this.getRevision();\n }\n // If squaredTolerance is negative or if we know that simplification will not\n // have any effect then just return this.\n if (\n squaredTolerance < 0 ||\n (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&\n squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)\n ) {\n return this;\n }\n\n const simplifiedGeometry =\n this.getSimplifiedGeometryInternal(squaredTolerance);\n const simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();\n if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {\n return simplifiedGeometry;\n }\n // Simplification did not actually remove any coordinates. We now know\n // that any calls to getSimplifiedGeometry with a squaredTolerance less\n // than or equal to the current squaredTolerance will also not have any\n // effect. This allows us to short circuit simplification (saving CPU\n // cycles) and prevents the cache of simplified geometries from filling\n // up with useless identical copies of this geometry (saving memory).\n this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;\n return this;\n }\n\n /**\n * @param {number} squaredTolerance Squared tolerance.\n * @return {SimpleGeometry} Simplified geometry.\n * @protected\n */\n getSimplifiedGeometryInternal(squaredTolerance) {\n return this;\n }\n\n /**\n * @return {number} Stride.\n */\n getStride() {\n return this.stride;\n }\n\n /**\n * @param {import(\"./Geometry.js\").GeometryLayout} layout Layout.\n * @param {Array} flatCoordinates Flat coordinates.\n */\n setFlatCoordinates(layout, flatCoordinates) {\n this.stride = getStrideForLayout(layout);\n this.layout = layout;\n this.flatCoordinates = flatCoordinates;\n }\n\n /**\n * @abstract\n * @param {!Array<*>} coordinates Coordinates.\n * @param {import(\"./Geometry.js\").GeometryLayout} [layout] Layout.\n */\n setCoordinates(coordinates, layout) {\n abstract();\n }\n\n /**\n * @param {import(\"./Geometry.js\").GeometryLayout|undefined} layout Layout.\n * @param {Array<*>} coordinates Coordinates.\n * @param {number} nesting Nesting.\n * @protected\n */\n setLayout(layout, coordinates, nesting) {\n let stride;\n if (layout) {\n stride = getStrideForLayout(layout);\n } else {\n for (let i = 0; i < nesting; ++i) {\n if (coordinates.length === 0) {\n this.layout = 'XY';\n this.stride = 2;\n return;\n }\n coordinates = /** @type {Array} */ (coordinates[0]);\n }\n stride = coordinates.length;\n layout = getLayoutForStride(stride);\n }\n this.layout = layout;\n this.stride = stride;\n }\n\n /**\n * Apply a transform function to the coordinates of the geometry.\n * The geometry is modified in place.\n * If you do not want the geometry modified in place, first `clone()` it and\n * then use this function on the clone.\n * @param {import(\"../proj.js\").TransformFunction} transformFn Transform function.\n * Called with a flat array of geometry coordinates.\n * @api\n */\n applyTransform(transformFn) {\n if (this.flatCoordinates) {\n transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);\n this.changed();\n }\n }\n\n /**\n * Rotate the geometry around a given coordinate. This modifies the geometry\n * coordinates in place.\n * @param {number} angle Rotation angle in counter-clockwise radians.\n * @param {import(\"../coordinate.js\").Coordinate} anchor The rotation center.\n * @api\n */\n rotate(angle, anchor) {\n const flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n const stride = this.getStride();\n rotate(\n flatCoordinates,\n 0,\n flatCoordinates.length,\n stride,\n angle,\n anchor,\n flatCoordinates\n );\n this.changed();\n }\n }\n\n /**\n * Scale the geometry (with an optional origin). This modifies the geometry\n * coordinates in place.\n * @param {number} sx The scaling factor in the x-direction.\n * @param {number} [sy] The scaling factor in the y-direction (defaults to sx).\n * @param {import(\"../coordinate.js\").Coordinate} [anchor] The scale origin (defaults to the center\n * of the geometry extent).\n * @api\n */\n scale(sx, sy, anchor) {\n if (sy === undefined) {\n sy = sx;\n }\n if (!anchor) {\n anchor = getCenter(this.getExtent());\n }\n const flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n const stride = this.getStride();\n scale(\n flatCoordinates,\n 0,\n flatCoordinates.length,\n stride,\n sx,\n sy,\n anchor,\n flatCoordinates\n );\n this.changed();\n }\n }\n\n /**\n * Translate the geometry. This modifies the geometry coordinates in place. If\n * instead you want a new geometry, first `clone()` this geometry.\n * @param {number} deltaX Delta X.\n * @param {number} deltaY Delta Y.\n * @api\n */\n translate(deltaX, deltaY) {\n const flatCoordinates = this.getFlatCoordinates();\n if (flatCoordinates) {\n const stride = this.getStride();\n translate(\n flatCoordinates,\n 0,\n flatCoordinates.length,\n stride,\n deltaX,\n deltaY,\n flatCoordinates\n );\n this.changed();\n }\n }\n}\n\n/**\n * @param {number} stride Stride.\n * @return {import(\"./Geometry.js\").GeometryLayout} layout Layout.\n */\nexport function getLayoutForStride(stride) {\n let layout;\n if (stride == 2) {\n layout = 'XY';\n } else if (stride == 3) {\n layout = 'XYZ';\n } else if (stride == 4) {\n layout = 'XYZM';\n }\n return /** @type {import(\"./Geometry.js\").GeometryLayout} */ (layout);\n}\n\n/**\n * @param {import(\"./Geometry.js\").GeometryLayout} layout Layout.\n * @return {number} Stride.\n */\nexport function getStrideForLayout(layout) {\n let stride;\n if (layout == 'XY') {\n stride = 2;\n } else if (layout == 'XYZ' || layout == 'XYM') {\n stride = 3;\n } else if (layout == 'XYZM') {\n stride = 4;\n }\n return /** @type {number} */ (stride);\n}\n\n/**\n * @param {SimpleGeometry} simpleGeometry Simple geometry.\n * @param {import(\"../transform.js\").Transform} transform Transform.\n * @param {Array} [dest] Destination.\n * @return {Array} Transformed flat coordinates.\n */\nexport function transformGeom2D(simpleGeometry, transform, dest) {\n const flatCoordinates = simpleGeometry.getFlatCoordinates();\n if (!flatCoordinates) {\n return null;\n }\n const stride = simpleGeometry.getStride();\n return transform2D(\n flatCoordinates,\n 0,\n flatCoordinates.length,\n stride,\n transform,\n dest\n );\n}\n\nexport default SimpleGeometry;\n","/**\n * @module ol/geom/flat/closest\n */\nimport {lerp, squaredDistance as squaredDx} from '../../math.js';\n\n/**\n * Returns the point on the 2D line segment flatCoordinates[offset1] to\n * flatCoordinates[offset2] that is closest to the point (x, y). Extra\n * dimensions are linearly interpolated.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset1 Offset 1.\n * @param {number} offset2 Offset 2.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array} closestPoint Closest point.\n */\nfunction assignClosest(\n flatCoordinates,\n offset1,\n offset2,\n stride,\n x,\n y,\n closestPoint\n) {\n const x1 = flatCoordinates[offset1];\n const y1 = flatCoordinates[offset1 + 1];\n const dx = flatCoordinates[offset2] - x1;\n const dy = flatCoordinates[offset2 + 1] - y1;\n let offset;\n if (dx === 0 && dy === 0) {\n offset = offset1;\n } else {\n const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);\n if (t > 1) {\n offset = offset2;\n } else if (t > 0) {\n for (let i = 0; i < stride; ++i) {\n closestPoint[i] = lerp(\n flatCoordinates[offset1 + i],\n flatCoordinates[offset2 + i],\n t\n );\n }\n closestPoint.length = stride;\n return;\n } else {\n offset = offset1;\n }\n }\n for (let i = 0; i < stride; ++i) {\n closestPoint[i] = flatCoordinates[offset + i];\n }\n closestPoint.length = stride;\n}\n\n/**\n * Return the squared of the largest distance between any pair of consecutive\n * coordinates.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function maxSquaredDelta(flatCoordinates, offset, end, stride, max) {\n let x1 = flatCoordinates[offset];\n let y1 = flatCoordinates[offset + 1];\n for (offset += stride; offset < end; offset += stride) {\n const x2 = flatCoordinates[offset];\n const y2 = flatCoordinates[offset + 1];\n const squaredDelta = squaredDx(x1, y1, x2, y2);\n if (squaredDelta > max) {\n max = squaredDelta;\n }\n x1 = x2;\n y1 = y2;\n }\n return max;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function arrayMaxSquaredDelta(\n flatCoordinates,\n offset,\n ends,\n stride,\n max\n) {\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n max = maxSquaredDelta(flatCoordinates, offset, end, stride, max);\n offset = end;\n }\n return max;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} max Max squared delta.\n * @return {number} Max squared delta.\n */\nexport function multiArrayMaxSquaredDelta(\n flatCoordinates,\n offset,\n endss,\n stride,\n max\n) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n max = arrayMaxSquaredDelta(flatCoordinates, offset, ends, stride, max);\n offset = ends[ends.length - 1];\n }\n return max;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array} [tmpPoint] Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestPoint(\n flatCoordinates,\n offset,\n end,\n stride,\n maxDelta,\n isRing,\n x,\n y,\n closestPoint,\n minSquaredDistance,\n tmpPoint\n) {\n if (offset == end) {\n return minSquaredDistance;\n }\n let i, squaredDistance;\n if (maxDelta === 0) {\n // All points are identical, so just test the first point.\n squaredDistance = squaredDx(\n x,\n y,\n flatCoordinates[offset],\n flatCoordinates[offset + 1]\n );\n if (squaredDistance < minSquaredDistance) {\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = flatCoordinates[offset + i];\n }\n closestPoint.length = stride;\n return squaredDistance;\n }\n return minSquaredDistance;\n }\n tmpPoint = tmpPoint ? tmpPoint : [NaN, NaN];\n let index = offset + stride;\n while (index < end) {\n assignClosest(\n flatCoordinates,\n index - stride,\n index,\n stride,\n x,\n y,\n tmpPoint\n );\n squaredDistance = squaredDx(x, y, tmpPoint[0], tmpPoint[1]);\n if (squaredDistance < minSquaredDistance) {\n minSquaredDistance = squaredDistance;\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = tmpPoint[i];\n }\n closestPoint.length = stride;\n index += stride;\n } else {\n // Skip ahead multiple points, because we know that all the skipped\n // points cannot be any closer than the closest point we have found so\n // far. We know this because we know how close the current point is, how\n // close the closest point we have found so far is, and the maximum\n // distance between consecutive points. For example, if we're currently\n // at distance 10, the best we've found so far is 3, and that the maximum\n // distance between consecutive points is 2, then we'll need to skip at\n // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of\n // finding a closer point. We use Math.max(..., 1) to ensure that we\n // always advance at least one point, to avoid an infinite loop.\n index +=\n stride *\n Math.max(\n ((Math.sqrt(squaredDistance) - Math.sqrt(minSquaredDistance)) /\n maxDelta) |\n 0,\n 1\n );\n }\n }\n if (isRing) {\n // Check the closing segment.\n assignClosest(\n flatCoordinates,\n end - stride,\n offset,\n stride,\n x,\n y,\n tmpPoint\n );\n squaredDistance = squaredDx(x, y, tmpPoint[0], tmpPoint[1]);\n if (squaredDistance < minSquaredDistance) {\n minSquaredDistance = squaredDistance;\n for (i = 0; i < stride; ++i) {\n closestPoint[i] = tmpPoint[i];\n }\n closestPoint.length = stride;\n }\n }\n return minSquaredDistance;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array} [tmpPoint] Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestArrayPoint(\n flatCoordinates,\n offset,\n ends,\n stride,\n maxDelta,\n isRing,\n x,\n y,\n closestPoint,\n minSquaredDistance,\n tmpPoint\n) {\n tmpPoint = tmpPoint ? tmpPoint : [NaN, NaN];\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n minSquaredDistance = assignClosestPoint(\n flatCoordinates,\n offset,\n end,\n stride,\n maxDelta,\n isRing,\n x,\n y,\n closestPoint,\n minSquaredDistance,\n tmpPoint\n );\n offset = end;\n }\n return minSquaredDistance;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} maxDelta Max delta.\n * @param {boolean} isRing Is ring.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {Array} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @param {Array} [tmpPoint] Temporary point object.\n * @return {number} Minimum squared distance.\n */\nexport function assignClosestMultiArrayPoint(\n flatCoordinates,\n offset,\n endss,\n stride,\n maxDelta,\n isRing,\n x,\n y,\n closestPoint,\n minSquaredDistance,\n tmpPoint\n) {\n tmpPoint = tmpPoint ? tmpPoint : [NaN, NaN];\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n minSquaredDistance = assignClosestArrayPoint(\n flatCoordinates,\n offset,\n ends,\n stride,\n maxDelta,\n isRing,\n x,\n y,\n closestPoint,\n minSquaredDistance,\n tmpPoint\n );\n offset = ends[ends.length - 1];\n }\n return minSquaredDistance;\n}\n","/**\n * @module ol/geom/flat/deflate\n */\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {import(\"../../coordinate.js\").Coordinate} coordinate Coordinate.\n * @param {number} stride Stride.\n * @return {number} offset Offset.\n */\nexport function deflateCoordinate(flatCoordinates, offset, coordinate, stride) {\n for (let i = 0, ii = coordinate.length; i < ii; ++i) {\n flatCoordinates[offset++] = coordinate[i];\n }\n return offset;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} coordinates Coordinates.\n * @param {number} stride Stride.\n * @return {number} offset Offset.\n */\nexport function deflateCoordinates(\n flatCoordinates,\n offset,\n coordinates,\n stride\n) {\n for (let i = 0, ii = coordinates.length; i < ii; ++i) {\n const coordinate = coordinates[i];\n for (let j = 0; j < stride; ++j) {\n flatCoordinates[offset++] = coordinate[j];\n }\n }\n return offset;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} coordinatess Coordinatess.\n * @param {number} stride Stride.\n * @param {Array} [ends] Ends.\n * @return {Array} Ends.\n */\nexport function deflateCoordinatesArray(\n flatCoordinates,\n offset,\n coordinatess,\n stride,\n ends\n) {\n ends = ends ? ends : [];\n let i = 0;\n for (let j = 0, jj = coordinatess.length; j < jj; ++j) {\n const end = deflateCoordinates(\n flatCoordinates,\n offset,\n coordinatess[j],\n stride\n );\n ends[i++] = end;\n offset = end;\n }\n ends.length = i;\n return ends;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>>} coordinatesss Coordinatesss.\n * @param {number} stride Stride.\n * @param {Array>} [endss] Endss.\n * @return {Array>} Endss.\n */\nexport function deflateMultiCoordinatesArray(\n flatCoordinates,\n offset,\n coordinatesss,\n stride,\n endss\n) {\n endss = endss ? endss : [];\n let i = 0;\n for (let j = 0, jj = coordinatesss.length; j < jj; ++j) {\n const ends = deflateCoordinatesArray(\n flatCoordinates,\n offset,\n coordinatesss[j],\n stride,\n endss[i]\n );\n if (ends.length === 0) {\n ends[0] = offset;\n }\n endss[i++] = ends;\n offset = ends[ends.length - 1];\n }\n endss.length = i;\n return endss;\n}\n","/**\n * @module ol/geom/flat/simplify\n */\n// Based on simplify-js https://github.com/mourner/simplify-js\n// Copyright (c) 2012, Vladimir Agafonkin\n// All rights reserved.\n//\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n//\n// 1. Redistributions of source code must retain the above copyright notice,\n// this list of conditions and the following disclaimer.\n//\n// 2. Redistributions in binary form must reproduce the above copyright\n// notice, this list of conditions and the following disclaimer in the\n// documentation and/or other materials provided with the distribution.\n//\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n// POSSIBILITY OF SUCH DAMAGE.\n\nimport {squaredDistance, squaredSegmentDistance} from '../../math.js';\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {boolean} highQuality Highest quality.\n * @param {Array} [simplifiedFlatCoordinates] Simplified flat\n * coordinates.\n * @return {Array} Simplified line string.\n */\nexport function simplifyLineString(\n flatCoordinates,\n offset,\n end,\n stride,\n squaredTolerance,\n highQuality,\n simplifiedFlatCoordinates\n) {\n simplifiedFlatCoordinates =\n simplifiedFlatCoordinates !== undefined ? simplifiedFlatCoordinates : [];\n if (!highQuality) {\n end = radialDistance(\n flatCoordinates,\n offset,\n end,\n stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n 0\n );\n flatCoordinates = simplifiedFlatCoordinates;\n offset = 0;\n stride = 2;\n }\n simplifiedFlatCoordinates.length = douglasPeucker(\n flatCoordinates,\n offset,\n end,\n stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n 0\n );\n return simplifiedFlatCoordinates;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function douglasPeucker(\n flatCoordinates,\n offset,\n end,\n stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset\n) {\n const n = (end - offset) / stride;\n if (n < 3) {\n for (; offset < end; offset += stride) {\n simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + 1];\n }\n return simplifiedOffset;\n }\n /** @type {Array} */\n const markers = new Array(n);\n markers[0] = 1;\n markers[n - 1] = 1;\n /** @type {Array} */\n const stack = [offset, end - stride];\n let index = 0;\n while (stack.length > 0) {\n const last = stack.pop();\n const first = stack.pop();\n let maxSquaredDistance = 0;\n const x1 = flatCoordinates[first];\n const y1 = flatCoordinates[first + 1];\n const x2 = flatCoordinates[last];\n const y2 = flatCoordinates[last + 1];\n for (let i = first + stride; i < last; i += stride) {\n const x = flatCoordinates[i];\n const y = flatCoordinates[i + 1];\n const squaredDistance = squaredSegmentDistance(x, y, x1, y1, x2, y2);\n if (squaredDistance > maxSquaredDistance) {\n index = i;\n maxSquaredDistance = squaredDistance;\n }\n }\n if (maxSquaredDistance > squaredTolerance) {\n markers[(index - offset) / stride] = 1;\n if (first + stride < index) {\n stack.push(first, index);\n }\n if (index + stride < last) {\n stack.push(index, last);\n }\n }\n }\n for (let i = 0; i < n; ++i) {\n if (markers[i]) {\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + i * stride];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + i * stride + 1];\n }\n }\n return simplifiedOffset;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array} simplifiedEnds Simplified ends.\n * @return {number} Simplified offset.\n */\nexport function douglasPeuckerArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset,\n simplifiedEnds\n) {\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n simplifiedOffset = douglasPeucker(\n flatCoordinates,\n offset,\n end,\n stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset\n );\n simplifiedEnds.push(simplifiedOffset);\n offset = end;\n }\n return simplifiedOffset;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array>} simplifiedEndss Simplified endss.\n * @return {number} Simplified offset.\n */\nexport function douglasPeuckerMultiArray(\n flatCoordinates,\n offset,\n endss,\n stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset,\n simplifiedEndss\n) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n /** @type {Array} */\n const simplifiedEnds = [];\n simplifiedOffset = douglasPeuckerArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset,\n simplifiedEnds\n );\n simplifiedEndss.push(simplifiedEnds);\n offset = ends[ends.length - 1];\n }\n return simplifiedOffset;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} squaredTolerance Squared tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function radialDistance(\n flatCoordinates,\n offset,\n end,\n stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset\n) {\n if (end <= offset + stride) {\n // zero or one point, no simplification possible, so copy and return\n for (; offset < end; offset += stride) {\n simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];\n simplifiedFlatCoordinates[simplifiedOffset++] =\n flatCoordinates[offset + 1];\n }\n return simplifiedOffset;\n }\n let x1 = flatCoordinates[offset];\n let y1 = flatCoordinates[offset + 1];\n // copy first point\n simplifiedFlatCoordinates[simplifiedOffset++] = x1;\n simplifiedFlatCoordinates[simplifiedOffset++] = y1;\n let x2 = x1;\n let y2 = y1;\n for (offset += stride; offset < end; offset += stride) {\n x2 = flatCoordinates[offset];\n y2 = flatCoordinates[offset + 1];\n if (squaredDistance(x1, y1, x2, y2) > squaredTolerance) {\n // copy point at offset\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n x1 = x2;\n y1 = y2;\n }\n }\n if (x2 != x1 || y2 != y1) {\n // copy last point\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n }\n return simplifiedOffset;\n}\n\n/**\n * @param {number} value Value.\n * @param {number} tolerance Tolerance.\n * @return {number} Rounded value.\n */\nexport function snap(value, tolerance) {\n return tolerance * Math.round(value / tolerance);\n}\n\n/**\n * Simplifies a line string using an algorithm designed by Tim Schaub.\n * Coordinates are snapped to the nearest value in a virtual grid and\n * consecutive duplicate coordinates are discarded. This effectively preserves\n * topology as the simplification of any subsection of a line string is\n * independent of the rest of the line string. This means that, for examples,\n * the common edge between two polygons will be simplified to the same line\n * string independently in both polygons. This implementation uses a single\n * pass over the coordinates and eliminates intermediate collinear points.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @return {number} Simplified offset.\n */\nexport function quantize(\n flatCoordinates,\n offset,\n end,\n stride,\n tolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset\n) {\n // do nothing if the line is empty\n if (offset == end) {\n return simplifiedOffset;\n }\n // snap the first coordinate (P1)\n let x1 = snap(flatCoordinates[offset], tolerance);\n let y1 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n // add the first coordinate to the output\n simplifiedFlatCoordinates[simplifiedOffset++] = x1;\n simplifiedFlatCoordinates[simplifiedOffset++] = y1;\n // find the next coordinate that does not snap to the same value as the first\n // coordinate (P2)\n let x2, y2;\n do {\n x2 = snap(flatCoordinates[offset], tolerance);\n y2 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n if (offset == end) {\n // all coordinates snap to the same value, the line collapses to a point\n // push the last snapped value anyway to ensure that the output contains\n // at least two points\n // FIXME should we really return at least two points anyway?\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n return simplifiedOffset;\n }\n } while (x2 == x1 && y2 == y1);\n while (offset < end) {\n // snap the next coordinate (P3)\n const x3 = snap(flatCoordinates[offset], tolerance);\n const y3 = snap(flatCoordinates[offset + 1], tolerance);\n offset += stride;\n // skip P3 if it is equal to P2\n if (x3 == x2 && y3 == y2) {\n continue;\n }\n // calculate the delta between P1 and P2\n const dx1 = x2 - x1;\n const dy1 = y2 - y1;\n // calculate the delta between P3 and P1\n const dx2 = x3 - x1;\n const dy2 = y3 - y1;\n // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from\n // P1 in the same direction then P2 is on the straight line between P1 and\n // P3\n if (\n dx1 * dy2 == dy1 * dx2 &&\n ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) &&\n ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))\n ) {\n // discard P2 and set P2 = P3\n x2 = x3;\n y2 = y3;\n continue;\n }\n // either P1, P2, and P3 are not colinear, or they are colinear but P3 is\n // between P3 and P1 or on the opposite half of the line to P2. add P2,\n // and continue with P1 = P2 and P2 = P3\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n x1 = x2;\n y1 = y2;\n x2 = x3;\n y2 = y3;\n }\n // add the last point (P2)\n simplifiedFlatCoordinates[simplifiedOffset++] = x2;\n simplifiedFlatCoordinates[simplifiedOffset++] = y2;\n return simplifiedOffset;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array} simplifiedEnds Simplified ends.\n * @return {number} Simplified offset.\n */\nexport function quantizeArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n tolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset,\n simplifiedEnds\n) {\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n simplifiedOffset = quantize(\n flatCoordinates,\n offset,\n end,\n stride,\n tolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset\n );\n simplifiedEnds.push(simplifiedOffset);\n offset = end;\n }\n return simplifiedOffset;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} tolerance Tolerance.\n * @param {Array} simplifiedFlatCoordinates Simplified flat\n * coordinates.\n * @param {number} simplifiedOffset Simplified offset.\n * @param {Array>} simplifiedEndss Simplified endss.\n * @return {number} Simplified offset.\n */\nexport function quantizeMultiArray(\n flatCoordinates,\n offset,\n endss,\n stride,\n tolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset,\n simplifiedEndss\n) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n /** @type {Array} */\n const simplifiedEnds = [];\n simplifiedOffset = quantizeArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n tolerance,\n simplifiedFlatCoordinates,\n simplifiedOffset,\n simplifiedEnds\n );\n simplifiedEndss.push(simplifiedEnds);\n offset = ends[ends.length - 1];\n }\n return simplifiedOffset;\n}\n","/**\n * @module ol/geom/flat/inflate\n */\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {Array} [coordinates] Coordinates.\n * @return {Array} Coordinates.\n */\nexport function inflateCoordinates(\n flatCoordinates,\n offset,\n end,\n stride,\n coordinates\n) {\n coordinates = coordinates !== undefined ? coordinates : [];\n let i = 0;\n for (let j = offset; j < end; j += stride) {\n coordinates[i++] = flatCoordinates.slice(j, j + stride);\n }\n coordinates.length = i;\n return coordinates;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {Array>} [coordinatess] Coordinatess.\n * @return {Array>} Coordinatess.\n */\nexport function inflateCoordinatesArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n coordinatess\n) {\n coordinatess = coordinatess !== undefined ? coordinatess : [];\n let i = 0;\n for (let j = 0, jj = ends.length; j < jj; ++j) {\n const end = ends[j];\n coordinatess[i++] = inflateCoordinates(\n flatCoordinates,\n offset,\n end,\n stride,\n coordinatess[i]\n );\n offset = end;\n }\n coordinatess.length = i;\n return coordinatess;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {Array>>} [coordinatesss]\n * Coordinatesss.\n * @return {Array>>} Coordinatesss.\n */\nexport function inflateMultiCoordinatesArray(\n flatCoordinates,\n offset,\n endss,\n stride,\n coordinatesss\n) {\n coordinatesss = coordinatesss !== undefined ? coordinatesss : [];\n let i = 0;\n for (let j = 0, jj = endss.length; j < jj; ++j) {\n const ends = endss[j];\n coordinatesss[i++] =\n ends.length === 1 && ends[0] === offset\n ? []\n : inflateCoordinatesArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n coordinatesss[i]\n );\n offset = ends[ends.length - 1];\n }\n coordinatesss.length = i;\n return coordinatesss;\n}\n","/**\n * @module ol/geom/flat/area\n */\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRing(flatCoordinates, offset, end, stride) {\n let twiceArea = 0;\n let x1 = flatCoordinates[end - stride];\n let y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n const x2 = flatCoordinates[offset];\n const y2 = flatCoordinates[offset + 1];\n twiceArea += y1 * x2 - x1 * y2;\n x1 = x2;\n y1 = y2;\n }\n return twiceArea / 2;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRings(flatCoordinates, offset, ends, stride) {\n let area = 0;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n area += linearRing(flatCoordinates, offset, end, stride);\n offset = end;\n }\n return area;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @return {number} Area.\n */\nexport function linearRingss(flatCoordinates, offset, endss, stride) {\n let area = 0;\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n area += linearRings(flatCoordinates, offset, ends, stride);\n offset = ends[ends.length - 1];\n }\n return area;\n}\n","/**\n * @module ol/geom/LinearRing\n */\nimport SimpleGeometry from './SimpleGeometry.js';\nimport {assignClosestPoint, maxSquaredDelta} from './flat/closest.js';\nimport {closestSquaredDistanceXY} from '../extent.js';\nimport {deflateCoordinates} from './flat/deflate.js';\nimport {douglasPeucker} from './flat/simplify.js';\nimport {inflateCoordinates} from './flat/inflate.js';\nimport {linearRing as linearRingArea} from './flat/area.js';\n\n/**\n * @classdesc\n * Linear ring geometry. Only used as part of polygon; cannot be rendered\n * on its own.\n *\n * @api\n */\nclass LinearRing extends SimpleGeometry {\n /**\n * @param {Array|Array} coordinates Coordinates.\n * For internal use, flat coordinates in combination with `layout` are also accepted.\n * @param {import(\"./Geometry.js\").GeometryLayout} [layout] Layout.\n */\n constructor(coordinates, layout) {\n super();\n\n /**\n * @private\n * @type {number}\n */\n this.maxDelta_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDeltaRevision_ = -1;\n\n if (layout !== undefined && !Array.isArray(coordinates[0])) {\n this.setFlatCoordinates(\n layout,\n /** @type {Array} */ (coordinates)\n );\n } else {\n this.setCoordinates(\n /** @type {Array} */ (\n coordinates\n ),\n layout\n );\n }\n }\n\n /**\n * Make a complete copy of the geometry.\n * @return {!LinearRing} Clone.\n * @api\n */\n clone() {\n return new LinearRing(this.flatCoordinates.slice(), this.layout);\n }\n\n /**\n * @param {number} x X.\n * @param {number} y Y.\n * @param {import(\"../coordinate.js\").Coordinate} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @return {number} Minimum squared distance.\n */\n closestPointXY(x, y, closestPoint, minSquaredDistance) {\n if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {\n return minSquaredDistance;\n }\n if (this.maxDeltaRevision_ != this.getRevision()) {\n this.maxDelta_ = Math.sqrt(\n maxSquaredDelta(\n this.flatCoordinates,\n 0,\n this.flatCoordinates.length,\n this.stride,\n 0\n )\n );\n this.maxDeltaRevision_ = this.getRevision();\n }\n return assignClosestPoint(\n this.flatCoordinates,\n 0,\n this.flatCoordinates.length,\n this.stride,\n this.maxDelta_,\n true,\n x,\n y,\n closestPoint,\n minSquaredDistance\n );\n }\n\n /**\n * Return the area of the linear ring on projected plane.\n * @return {number} Area (on projected plane).\n * @api\n */\n getArea() {\n return linearRingArea(\n this.flatCoordinates,\n 0,\n this.flatCoordinates.length,\n this.stride\n );\n }\n\n /**\n * Return the coordinates of the linear ring.\n * @return {Array} Coordinates.\n * @api\n */\n getCoordinates() {\n return inflateCoordinates(\n this.flatCoordinates,\n 0,\n this.flatCoordinates.length,\n this.stride\n );\n }\n\n /**\n * @param {number} squaredTolerance Squared tolerance.\n * @return {LinearRing} Simplified LinearRing.\n * @protected\n */\n getSimplifiedGeometryInternal(squaredTolerance) {\n /** @type {Array} */\n const simplifiedFlatCoordinates = [];\n simplifiedFlatCoordinates.length = douglasPeucker(\n this.flatCoordinates,\n 0,\n this.flatCoordinates.length,\n this.stride,\n squaredTolerance,\n simplifiedFlatCoordinates,\n 0\n );\n return new LinearRing(simplifiedFlatCoordinates, 'XY');\n }\n\n /**\n * Get the type of this geometry.\n * @return {import(\"./Geometry.js\").Type} Geometry type.\n * @api\n */\n getType() {\n return 'LinearRing';\n }\n\n /**\n * Test if the geometry and the passed extent intersect.\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @return {boolean} `true` if the geometry and the extent intersect.\n * @api\n */\n intersectsExtent(extent) {\n return false;\n }\n\n /**\n * Set the coordinates of the linear ring.\n * @param {!Array} coordinates Coordinates.\n * @param {import(\"./Geometry.js\").GeometryLayout} [layout] Layout.\n * @api\n */\n setCoordinates(coordinates, layout) {\n this.setLayout(layout, coordinates, 1);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n this.flatCoordinates.length = deflateCoordinates(\n this.flatCoordinates,\n 0,\n coordinates,\n this.stride\n );\n this.changed();\n }\n}\n\nexport default LinearRing;\n","/**\n * @module ol/geom/Point\n */\nimport SimpleGeometry from './SimpleGeometry.js';\nimport {containsXY, createOrUpdateFromCoordinate} from '../extent.js';\nimport {deflateCoordinate} from './flat/deflate.js';\nimport {squaredDistance as squaredDx} from '../math.js';\n\n/**\n * @classdesc\n * Point geometry.\n *\n * @api\n */\nclass Point extends SimpleGeometry {\n /**\n * @param {import(\"../coordinate.js\").Coordinate} coordinates Coordinates.\n * @param {import(\"./Geometry.js\").GeometryLayout} [layout] Layout.\n */\n constructor(coordinates, layout) {\n super();\n this.setCoordinates(coordinates, layout);\n }\n\n /**\n * Make a complete copy of the geometry.\n * @return {!Point} Clone.\n * @api\n */\n clone() {\n const point = new Point(this.flatCoordinates.slice(), this.layout);\n point.applyProperties(this);\n return point;\n }\n\n /**\n * @param {number} x X.\n * @param {number} y Y.\n * @param {import(\"../coordinate.js\").Coordinate} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @return {number} Minimum squared distance.\n */\n closestPointXY(x, y, closestPoint, minSquaredDistance) {\n const flatCoordinates = this.flatCoordinates;\n const squaredDistance = squaredDx(\n x,\n y,\n flatCoordinates[0],\n flatCoordinates[1]\n );\n if (squaredDistance < minSquaredDistance) {\n const stride = this.stride;\n for (let i = 0; i < stride; ++i) {\n closestPoint[i] = flatCoordinates[i];\n }\n closestPoint.length = stride;\n return squaredDistance;\n }\n return minSquaredDistance;\n }\n\n /**\n * Return the coordinate of the point.\n * @return {import(\"../coordinate.js\").Coordinate} Coordinates.\n * @api\n */\n getCoordinates() {\n return this.flatCoordinates.slice();\n }\n\n /**\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @protected\n * @return {import(\"../extent.js\").Extent} extent Extent.\n */\n computeExtent(extent) {\n return createOrUpdateFromCoordinate(this.flatCoordinates, extent);\n }\n\n /**\n * Get the type of this geometry.\n * @return {import(\"./Geometry.js\").Type} Geometry type.\n * @api\n */\n getType() {\n return 'Point';\n }\n\n /**\n * Test if the geometry and the passed extent intersect.\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @return {boolean} `true` if the geometry and the extent intersect.\n * @api\n */\n intersectsExtent(extent) {\n return containsXY(extent, this.flatCoordinates[0], this.flatCoordinates[1]);\n }\n\n /**\n * @param {!Array<*>} coordinates Coordinates.\n * @param {import(\"./Geometry.js\").GeometryLayout} [layout] Layout.\n * @api\n */\n setCoordinates(coordinates, layout) {\n this.setLayout(layout, coordinates, 0);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n this.flatCoordinates.length = deflateCoordinate(\n this.flatCoordinates,\n 0,\n coordinates,\n this.stride\n );\n this.changed();\n }\n}\n\nexport default Point;\n","/**\n * @module ol/geom/flat/contains\n */\nimport {forEachCorner} from '../../extent.js';\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} Contains extent.\n */\nexport function linearRingContainsExtent(\n flatCoordinates,\n offset,\n end,\n stride,\n extent\n) {\n const outside = forEachCorner(\n extent,\n /**\n * @param {import(\"../../coordinate.js\").Coordinate} coordinate Coordinate.\n * @return {boolean} Contains (x, y).\n */\n function (coordinate) {\n return !linearRingContainsXY(\n flatCoordinates,\n offset,\n end,\n stride,\n coordinate[0],\n coordinate[1]\n );\n }\n );\n return !outside;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingContainsXY(\n flatCoordinates,\n offset,\n end,\n stride,\n x,\n y\n) {\n // https://geomalgorithms.com/a03-_inclusion.html\n // Copyright 2000 softSurfer, 2012 Dan Sunday\n // This code may be freely used and modified for any purpose\n // providing that this copyright notice is included with it.\n // SoftSurfer makes no warranty for this code, and cannot be held\n // liable for any real or imagined damage resulting from its use.\n // Users of this code must verify correctness for their application.\n let wn = 0;\n let x1 = flatCoordinates[end - stride];\n let y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n const x2 = flatCoordinates[offset];\n const y2 = flatCoordinates[offset + 1];\n if (y1 <= y) {\n if (y2 > y && (x2 - x1) * (y - y1) - (x - x1) * (y2 - y1) > 0) {\n wn++;\n }\n } else if (y2 <= y && (x2 - x1) * (y - y1) - (x - x1) * (y2 - y1) < 0) {\n wn--;\n }\n x1 = x2;\n y1 = y2;\n }\n return wn !== 0;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingsContainsXY(\n flatCoordinates,\n offset,\n ends,\n stride,\n x,\n y\n) {\n if (ends.length === 0) {\n return false;\n }\n if (!linearRingContainsXY(flatCoordinates, offset, ends[0], stride, x, y)) {\n return false;\n }\n for (let i = 1, ii = ends.length; i < ii; ++i) {\n if (\n linearRingContainsXY(flatCoordinates, ends[i - 1], ends[i], stride, x, y)\n ) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\nexport function linearRingssContainsXY(\n flatCoordinates,\n offset,\n endss,\n stride,\n x,\n y\n) {\n if (endss.length === 0) {\n return false;\n }\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) {\n return true;\n }\n offset = ends[ends.length - 1];\n }\n return false;\n}\n","/**\n * @module ol/geom/flat/interiorpoint\n */\nimport {ascending} from '../../array.js';\nimport {linearRingsContainsXY} from './contains.js';\n\n/**\n * Calculates a point that is likely to lie in the interior of the linear rings.\n * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {Array} flatCenters Flat centers.\n * @param {number} flatCentersOffset Flat center offset.\n * @param {Array} [dest] Destination.\n * @return {Array} Destination point as XYM coordinate, where M is the\n * length of the horizontal intersection that the point belongs to.\n */\nexport function getInteriorPointOfArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n flatCenters,\n flatCentersOffset,\n dest\n) {\n let i, ii, x, x1, x2, y1, y2;\n const y = flatCenters[flatCentersOffset + 1];\n /** @type {Array} */\n const intersections = [];\n // Calculate intersections with the horizontal line\n for (let r = 0, rr = ends.length; r < rr; ++r) {\n const end = ends[r];\n x1 = flatCoordinates[end - stride];\n y1 = flatCoordinates[end - stride + 1];\n for (i = offset; i < end; i += stride) {\n x2 = flatCoordinates[i];\n y2 = flatCoordinates[i + 1];\n if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) {\n x = ((y - y1) / (y2 - y1)) * (x2 - x1) + x1;\n intersections.push(x);\n }\n x1 = x2;\n y1 = y2;\n }\n }\n // Find the longest segment of the horizontal line that has its center point\n // inside the linear ring.\n let pointX = NaN;\n let maxSegmentLength = -Infinity;\n intersections.sort(ascending);\n x1 = intersections[0];\n for (i = 1, ii = intersections.length; i < ii; ++i) {\n x2 = intersections[i];\n const segmentLength = Math.abs(x2 - x1);\n if (segmentLength > maxSegmentLength) {\n x = (x1 + x2) / 2;\n if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) {\n pointX = x;\n maxSegmentLength = segmentLength;\n }\n }\n x1 = x2;\n }\n if (isNaN(pointX)) {\n // There is no horizontal line that has its center point inside the linear\n // ring. Use the center of the the linear ring's extent.\n pointX = flatCenters[flatCentersOffset];\n }\n if (dest) {\n dest.push(pointX, y, maxSegmentLength);\n return dest;\n }\n return [pointX, y, maxSegmentLength];\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {Array} flatCenters Flat centers.\n * @return {Array} Interior points as XYM coordinates, where M is the\n * length of the horizontal intersection that the point belongs to.\n */\nexport function getInteriorPointsOfMultiArray(\n flatCoordinates,\n offset,\n endss,\n stride,\n flatCenters\n) {\n /** @type {Array} */\n let interiorPoints = [];\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n interiorPoints = getInteriorPointOfArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n flatCenters,\n 2 * i,\n interiorPoints\n );\n offset = ends[ends.length - 1];\n }\n return interiorPoints;\n}\n","/**\n * @module ol/geom/flat/segments\n */\n\n/**\n * This function calls `callback` for each segment of the flat coordinates\n * array. If the callback returns a truthy value the function returns that\n * value immediately. Otherwise the function returns `false`.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {function(import(\"../../coordinate.js\").Coordinate, import(\"../../coordinate.js\").Coordinate): T} callback Function\n * called for each segment.\n * @return {T|boolean} Value.\n * @template T\n */\nexport function forEach(flatCoordinates, offset, end, stride, callback) {\n let ret;\n offset += stride;\n for (; offset < end; offset += stride) {\n ret = callback(\n flatCoordinates.slice(offset - stride, offset),\n flatCoordinates.slice(offset, offset + stride)\n );\n if (ret) {\n return ret;\n }\n }\n return false;\n}\n","/**\n * @module ol/geom/flat/intersectsextent\n */\nimport {\n containsExtent,\n createEmpty,\n extendFlatCoordinates,\n intersects,\n intersectsSegment,\n} from '../../extent.js';\nimport {forEach as forEachSegment} from './segments.js';\nimport {linearRingContainsExtent, linearRingContainsXY} from './contains.js';\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLineString(\n flatCoordinates,\n offset,\n end,\n stride,\n extent\n) {\n const coordinatesExtent = extendFlatCoordinates(\n createEmpty(),\n flatCoordinates,\n offset,\n end,\n stride\n );\n if (!intersects(extent, coordinatesExtent)) {\n return false;\n }\n if (containsExtent(extent, coordinatesExtent)) {\n return true;\n }\n if (coordinatesExtent[0] >= extent[0] && coordinatesExtent[2] <= extent[2]) {\n return true;\n }\n if (coordinatesExtent[1] >= extent[1] && coordinatesExtent[3] <= extent[3]) {\n return true;\n }\n return forEachSegment(\n flatCoordinates,\n offset,\n end,\n stride,\n /**\n * @param {import(\"../../coordinate.js\").Coordinate} point1 Start point.\n * @param {import(\"../../coordinate.js\").Coordinate} point2 End point.\n * @return {boolean} `true` if the segment and the extent intersect,\n * `false` otherwise.\n */\n function (point1, point2) {\n return intersectsSegment(extent, point1, point2);\n }\n );\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLineStringArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n extent\n) {\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n if (\n intersectsLineString(flatCoordinates, offset, ends[i], stride, extent)\n ) {\n return true;\n }\n offset = ends[i];\n }\n return false;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRing(\n flatCoordinates,\n offset,\n end,\n stride,\n extent\n) {\n if (intersectsLineString(flatCoordinates, offset, end, stride, extent)) {\n return true;\n }\n if (\n linearRingContainsXY(\n flatCoordinates,\n offset,\n end,\n stride,\n extent[0],\n extent[1]\n )\n ) {\n return true;\n }\n if (\n linearRingContainsXY(\n flatCoordinates,\n offset,\n end,\n stride,\n extent[0],\n extent[3]\n )\n ) {\n return true;\n }\n if (\n linearRingContainsXY(\n flatCoordinates,\n offset,\n end,\n stride,\n extent[2],\n extent[1]\n )\n ) {\n return true;\n }\n if (\n linearRingContainsXY(\n flatCoordinates,\n offset,\n end,\n stride,\n extent[2],\n extent[3]\n )\n ) {\n return true;\n }\n return false;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRingArray(\n flatCoordinates,\n offset,\n ends,\n stride,\n extent\n) {\n if (!intersectsLinearRing(flatCoordinates, offset, ends[0], stride, extent)) {\n return false;\n }\n if (ends.length === 1) {\n return true;\n }\n for (let i = 1, ii = ends.length; i < ii; ++i) {\n if (\n linearRingContainsExtent(\n flatCoordinates,\n ends[i - 1],\n ends[i],\n stride,\n extent\n )\n ) {\n if (\n !intersectsLineString(\n flatCoordinates,\n ends[i - 1],\n ends[i],\n stride,\n extent\n )\n ) {\n return false;\n }\n }\n }\n return true;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Endss.\n * @param {number} stride Stride.\n * @param {import(\"../../extent.js\").Extent} extent Extent.\n * @return {boolean} True if the geometry and the extent intersect.\n */\nexport function intersectsLinearRingMultiArray(\n flatCoordinates,\n offset,\n endss,\n stride,\n extent\n) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n if (\n intersectsLinearRingArray(flatCoordinates, offset, ends, stride, extent)\n ) {\n return true;\n }\n offset = ends[ends.length - 1];\n }\n return false;\n}\n","/**\n * @module ol/geom/flat/reverse\n */\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n */\nexport function coordinates(flatCoordinates, offset, end, stride) {\n while (offset < end - stride) {\n for (let i = 0; i < stride; ++i) {\n const tmp = flatCoordinates[offset + i];\n flatCoordinates[offset + i] = flatCoordinates[end - stride + i];\n flatCoordinates[end - stride + i] = tmp;\n }\n offset += stride;\n end -= stride;\n }\n}\n","/**\n * @module ol/geom/flat/orient\n */\nimport {coordinates as reverseCoordinates} from './reverse.js';\n\n/**\n * Is the linear ring oriented clockwise in a coordinate system with a bottom-left\n * coordinate origin? For a coordinate system with a top-left coordinate origin,\n * the ring's orientation is clockwise when this function returns false.\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {boolean|undefined} Is clockwise.\n */\nexport function linearRingIsClockwise(flatCoordinates, offset, end, stride) {\n // https://stackoverflow.com/q/1165647/clockwise-method#1165943\n // https://github.com/OSGeo/gdal/blob/master/gdal/ogr/ogrlinearring.cpp\n let edge = 0;\n let x1 = flatCoordinates[end - stride];\n let y1 = flatCoordinates[end - stride + 1];\n for (; offset < end; offset += stride) {\n const x2 = flatCoordinates[offset];\n const y2 = flatCoordinates[offset + 1];\n edge += (x2 - x1) * (y2 + y1);\n x1 = x2;\n y1 = y2;\n }\n return edge === 0 ? undefined : edge > 0;\n}\n\n/**\n * Determines if linear rings are oriented. By default, left-hand orientation\n * is tested (first ring must be clockwise, remaining rings counter-clockwise).\n * To test for right-hand orientation, use the `right` argument.\n *\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean} [right] Test for right-hand orientation\n * (counter-clockwise exterior ring and clockwise interior rings).\n * @return {boolean} Rings are correctly oriented.\n */\nexport function linearRingsAreOriented(\n flatCoordinates,\n offset,\n ends,\n stride,\n right\n) {\n right = right !== undefined ? right : false;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n const isClockwise = linearRingIsClockwise(\n flatCoordinates,\n offset,\n end,\n stride\n );\n if (i === 0) {\n if ((right && isClockwise) || (!right && !isClockwise)) {\n return false;\n }\n } else {\n if ((right && !isClockwise) || (!right && isClockwise)) {\n return false;\n }\n }\n offset = end;\n }\n return true;\n}\n\n/**\n * Determines if linear rings are oriented. By default, left-hand orientation\n * is tested (first ring must be clockwise, remaining rings counter-clockwise).\n * To test for right-hand orientation, use the `right` argument.\n *\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Array of array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean} [right] Test for right-hand orientation\n * (counter-clockwise exterior ring and clockwise interior rings).\n * @return {boolean} Rings are correctly oriented.\n */\nexport function linearRingssAreOriented(\n flatCoordinates,\n offset,\n endss,\n stride,\n right\n) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n const ends = endss[i];\n if (!linearRingsAreOriented(flatCoordinates, offset, ends, stride, right)) {\n return false;\n }\n if (ends.length) {\n offset = ends[ends.length - 1];\n }\n }\n return true;\n}\n\n/**\n * Orient coordinates in a flat array of linear rings. By default, rings\n * are oriented following the left-hand rule (clockwise for exterior and\n * counter-clockwise for interior rings). To orient according to the\n * right-hand rule, use the `right` argument.\n *\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {boolean} [right] Follow the right-hand rule for orientation.\n * @return {number} End.\n */\nexport function orientLinearRings(\n flatCoordinates,\n offset,\n ends,\n stride,\n right\n) {\n right = right !== undefined ? right : false;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n const isClockwise = linearRingIsClockwise(\n flatCoordinates,\n offset,\n end,\n stride\n );\n const reverse =\n i === 0\n ? (right && isClockwise) || (!right && !isClockwise)\n : (right && !isClockwise) || (!right && isClockwise);\n if (reverse) {\n reverseCoordinates(flatCoordinates, offset, end, stride);\n }\n offset = end;\n }\n return offset;\n}\n\n/**\n * Orient coordinates in a flat array of linear rings. By default, rings\n * are oriented following the left-hand rule (clockwise for exterior and\n * counter-clockwise for interior rings). To orient according to the\n * right-hand rule, use the `right` argument.\n *\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array>} endss Array of array of end indexes.\n * @param {number} stride Stride.\n * @param {boolean} [right] Follow the right-hand rule for orientation.\n * @return {number} End.\n */\nexport function orientLinearRingsArray(\n flatCoordinates,\n offset,\n endss,\n stride,\n right\n) {\n for (let i = 0, ii = endss.length; i < ii; ++i) {\n offset = orientLinearRings(\n flatCoordinates,\n offset,\n endss[i],\n stride,\n right\n );\n }\n return offset;\n}\n\n/**\n * Return a two-dimensional endss\n * @param {Array} flatCoordinates Flat coordinates\n * @param {Array} ends Linear ring end indexes\n * @return {Array>} Two dimensional endss array that can\n * be used to construct a MultiPolygon\n */\nexport function inflateEnds(flatCoordinates, ends) {\n const endss = [];\n let offset = 0;\n let prevEndIndex = 0;\n let startOrientation;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n // classifies an array of rings into polygons with outer rings and holes\n const orientation = linearRingIsClockwise(flatCoordinates, offset, end, 2);\n if (startOrientation === undefined) {\n startOrientation = orientation;\n }\n if (orientation === startOrientation) {\n endss.push(ends.slice(prevEndIndex, i + 1));\n } else {\n if (endss.length === 0) {\n continue;\n }\n endss[endss.length - 1].push(ends[prevEndIndex]);\n }\n prevEndIndex = i + 1;\n offset = end;\n }\n return endss;\n}\n","/**\n * @module ol/geom/Polygon\n */\nimport LinearRing from './LinearRing.js';\nimport Point from './Point.js';\nimport SimpleGeometry from './SimpleGeometry.js';\nimport {arrayMaxSquaredDelta, assignClosestArrayPoint} from './flat/closest.js';\nimport {closestSquaredDistanceXY, getCenter, isEmpty} from '../extent.js';\nimport {deflateCoordinatesArray} from './flat/deflate.js';\nimport {extend} from '../array.js';\nimport {getInteriorPointOfArray} from './flat/interiorpoint.js';\nimport {inflateCoordinatesArray} from './flat/inflate.js';\nimport {intersectsLinearRingArray} from './flat/intersectsextent.js';\nimport {linearRingsAreOriented, orientLinearRings} from './flat/orient.js';\nimport {linearRings as linearRingsArea} from './flat/area.js';\nimport {linearRingsContainsXY} from './flat/contains.js';\nimport {modulo} from '../math.js';\nimport {quantizeArray} from './flat/simplify.js';\nimport {offset as sphereOffset} from '../sphere.js';\n\n/**\n * @classdesc\n * Polygon geometry.\n *\n * @api\n */\nclass Polygon extends SimpleGeometry {\n /**\n * @param {!Array>|!Array} coordinates\n * Array of linear rings that define the polygon. The first linear ring of the\n * array defines the outer-boundary or surface of the polygon. Each subsequent\n * linear ring defines a hole in the surface of the polygon. A linear ring is\n * an array of vertices' coordinates where the first coordinate and the last are\n * equivalent. (For internal use, flat coordinates in combination with\n * `layout` and `ends` are also accepted.)\n * @param {import(\"./Geometry.js\").GeometryLayout} [layout] Layout.\n * @param {Array} [ends] Ends (for internal use with flat coordinates).\n */\n constructor(coordinates, layout, ends) {\n super();\n\n /**\n * @type {Array}\n * @private\n */\n this.ends_ = [];\n\n /**\n * @private\n * @type {number}\n */\n this.flatInteriorPointRevision_ = -1;\n\n /**\n * @private\n * @type {import(\"../coordinate.js\").Coordinate|null}\n */\n this.flatInteriorPoint_ = null;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDelta_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.maxDeltaRevision_ = -1;\n\n /**\n * @private\n * @type {number}\n */\n this.orientedRevision_ = -1;\n\n /**\n * @private\n * @type {Array|null}\n */\n this.orientedFlatCoordinates_ = null;\n\n if (layout !== undefined && ends) {\n this.setFlatCoordinates(\n layout,\n /** @type {Array} */ (coordinates)\n );\n this.ends_ = ends;\n } else {\n this.setCoordinates(\n /** @type {Array>} */ (\n coordinates\n ),\n layout\n );\n }\n }\n\n /**\n * Append the passed linear ring to this polygon.\n * @param {LinearRing} linearRing Linear ring.\n * @api\n */\n appendLinearRing(linearRing) {\n if (!this.flatCoordinates) {\n this.flatCoordinates = linearRing.getFlatCoordinates().slice();\n } else {\n extend(this.flatCoordinates, linearRing.getFlatCoordinates());\n }\n this.ends_.push(this.flatCoordinates.length);\n this.changed();\n }\n\n /**\n * Make a complete copy of the geometry.\n * @return {!Polygon} Clone.\n * @api\n */\n clone() {\n const polygon = new Polygon(\n this.flatCoordinates.slice(),\n this.layout,\n this.ends_.slice()\n );\n polygon.applyProperties(this);\n return polygon;\n }\n\n /**\n * @param {number} x X.\n * @param {number} y Y.\n * @param {import(\"../coordinate.js\").Coordinate} closestPoint Closest point.\n * @param {number} minSquaredDistance Minimum squared distance.\n * @return {number} Minimum squared distance.\n */\n closestPointXY(x, y, closestPoint, minSquaredDistance) {\n if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {\n return minSquaredDistance;\n }\n if (this.maxDeltaRevision_ != this.getRevision()) {\n this.maxDelta_ = Math.sqrt(\n arrayMaxSquaredDelta(\n this.flatCoordinates,\n 0,\n this.ends_,\n this.stride,\n 0\n )\n );\n this.maxDeltaRevision_ = this.getRevision();\n }\n return assignClosestArrayPoint(\n this.flatCoordinates,\n 0,\n this.ends_,\n this.stride,\n this.maxDelta_,\n true,\n x,\n y,\n closestPoint,\n minSquaredDistance\n );\n }\n\n /**\n * @param {number} x X.\n * @param {number} y Y.\n * @return {boolean} Contains (x, y).\n */\n containsXY(x, y) {\n return linearRingsContainsXY(\n this.getOrientedFlatCoordinates(),\n 0,\n this.ends_,\n this.stride,\n x,\n y\n );\n }\n\n /**\n * Return the area of the polygon on projected plane.\n * @return {number} Area (on projected plane).\n * @api\n */\n getArea() {\n return linearRingsArea(\n this.getOrientedFlatCoordinates(),\n 0,\n this.ends_,\n this.stride\n );\n }\n\n /**\n * Get the coordinate array for this geometry. This array has the structure\n * of a GeoJSON coordinate array for polygons.\n *\n * @param {boolean} [right] Orient coordinates according to the right-hand\n * rule (counter-clockwise for exterior and clockwise for interior rings).\n * If `false`, coordinates will be oriented according to the left-hand rule\n * (clockwise for exterior and counter-clockwise for interior rings).\n * By default, coordinate orientation will depend on how the geometry was\n * constructed.\n * @return {Array>} Coordinates.\n * @api\n */\n getCoordinates(right) {\n let flatCoordinates;\n if (right !== undefined) {\n flatCoordinates = this.getOrientedFlatCoordinates().slice();\n orientLinearRings(flatCoordinates, 0, this.ends_, this.stride, right);\n } else {\n flatCoordinates = this.flatCoordinates;\n }\n\n return inflateCoordinatesArray(flatCoordinates, 0, this.ends_, this.stride);\n }\n\n /**\n * @return {Array} Ends.\n */\n getEnds() {\n return this.ends_;\n }\n\n /**\n * @return {Array} Interior point.\n */\n getFlatInteriorPoint() {\n if (this.flatInteriorPointRevision_ != this.getRevision()) {\n const flatCenter = getCenter(this.getExtent());\n this.flatInteriorPoint_ = getInteriorPointOfArray(\n this.getOrientedFlatCoordinates(),\n 0,\n this.ends_,\n this.stride,\n flatCenter,\n 0\n );\n this.flatInteriorPointRevision_ = this.getRevision();\n }\n return /** @type {import(\"../coordinate.js\").Coordinate} */ (\n this.flatInteriorPoint_\n );\n }\n\n /**\n * Return an interior point of the polygon.\n * @return {Point} Interior point as XYM coordinate, where M is the\n * length of the horizontal intersection that the point belongs to.\n * @api\n */\n getInteriorPoint() {\n return new Point(this.getFlatInteriorPoint(), 'XYM');\n }\n\n /**\n * Return the number of rings of the polygon, this includes the exterior\n * ring and any interior rings.\n *\n * @return {number} Number of rings.\n * @api\n */\n getLinearRingCount() {\n return this.ends_.length;\n }\n\n /**\n * Return the Nth linear ring of the polygon geometry. Return `null` if the\n * given index is out of range.\n * The exterior linear ring is available at index `0` and the interior rings\n * at index `1` and beyond.\n *\n * @param {number} index Index.\n * @return {LinearRing|null} Linear ring.\n * @api\n */\n getLinearRing(index) {\n if (index < 0 || this.ends_.length <= index) {\n return null;\n }\n return new LinearRing(\n this.flatCoordinates.slice(\n index === 0 ? 0 : this.ends_[index - 1],\n this.ends_[index]\n ),\n this.layout\n );\n }\n\n /**\n * Return the linear rings of the polygon.\n * @return {Array} Linear rings.\n * @api\n */\n getLinearRings() {\n const layout = this.layout;\n const flatCoordinates = this.flatCoordinates;\n const ends = this.ends_;\n const linearRings = [];\n let offset = 0;\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n const linearRing = new LinearRing(\n flatCoordinates.slice(offset, end),\n layout\n );\n linearRings.push(linearRing);\n offset = end;\n }\n return linearRings;\n }\n\n /**\n * @return {Array} Oriented flat coordinates.\n */\n getOrientedFlatCoordinates() {\n if (this.orientedRevision_ != this.getRevision()) {\n const flatCoordinates = this.flatCoordinates;\n if (linearRingsAreOriented(flatCoordinates, 0, this.ends_, this.stride)) {\n this.orientedFlatCoordinates_ = flatCoordinates;\n } else {\n this.orientedFlatCoordinates_ = flatCoordinates.slice();\n this.orientedFlatCoordinates_.length = orientLinearRings(\n this.orientedFlatCoordinates_,\n 0,\n this.ends_,\n this.stride\n );\n }\n this.orientedRevision_ = this.getRevision();\n }\n return /** @type {Array} */ (this.orientedFlatCoordinates_);\n }\n\n /**\n * @param {number} squaredTolerance Squared tolerance.\n * @return {Polygon} Simplified Polygon.\n * @protected\n */\n getSimplifiedGeometryInternal(squaredTolerance) {\n /** @type {Array} */\n const simplifiedFlatCoordinates = [];\n /** @type {Array} */\n const simplifiedEnds = [];\n simplifiedFlatCoordinates.length = quantizeArray(\n this.flatCoordinates,\n 0,\n this.ends_,\n this.stride,\n Math.sqrt(squaredTolerance),\n simplifiedFlatCoordinates,\n 0,\n simplifiedEnds\n );\n return new Polygon(simplifiedFlatCoordinates, 'XY', simplifiedEnds);\n }\n\n /**\n * Get the type of this geometry.\n * @return {import(\"./Geometry.js\").Type} Geometry type.\n * @api\n */\n getType() {\n return 'Polygon';\n }\n\n /**\n * Test if the geometry and the passed extent intersect.\n * @param {import(\"../extent.js\").Extent} extent Extent.\n * @return {boolean} `true` if the geometry and the extent intersect.\n * @api\n */\n intersectsExtent(extent) {\n return intersectsLinearRingArray(\n this.getOrientedFlatCoordinates(),\n 0,\n this.ends_,\n this.stride,\n extent\n );\n }\n\n /**\n * Set the coordinates of the polygon.\n * @param {!Array>} coordinates Coordinates.\n * @param {import(\"./Geometry.js\").GeometryLayout} [layout] Layout.\n * @api\n */\n setCoordinates(coordinates, layout) {\n this.setLayout(layout, coordinates, 2);\n if (!this.flatCoordinates) {\n this.flatCoordinates = [];\n }\n const ends = deflateCoordinatesArray(\n this.flatCoordinates,\n 0,\n coordinates,\n this.stride,\n this.ends_\n );\n this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];\n this.changed();\n }\n}\n\nexport default Polygon;\n\n/**\n * Create an approximation of a circle on the surface of a sphere.\n * @param {import(\"../coordinate.js\").Coordinate} center Center (`[lon, lat]` in degrees).\n * @param {number} radius The great-circle distance from the center to\n * the polygon vertices in meters.\n * @param {number} [n] Optional number of vertices for the resulting\n * polygon. Default is `32`.\n * @param {number} [sphereRadius] Optional radius for the sphere (defaults to\n * the Earth's mean radius using the WGS84 ellipsoid).\n * @return {Polygon} The \"circular\" polygon.\n * @api\n */\nexport function circular(center, radius, n, sphereRadius) {\n n = n ? n : 32;\n /** @type {Array} */\n const flatCoordinates = [];\n for (let i = 0; i < n; ++i) {\n extend(\n flatCoordinates,\n sphereOffset(center, radius, (2 * Math.PI * i) / n, sphereRadius)\n );\n }\n flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);\n return new Polygon(flatCoordinates, 'XY', [flatCoordinates.length]);\n}\n\n/**\n * Create a polygon from an extent. The layout used is `XY`.\n * @param {import(\"../extent.js\").Extent} extent The extent.\n * @return {Polygon} The polygon.\n * @api\n */\nexport function fromExtent(extent) {\n if (isEmpty(extent)) {\n throw new Error('Cannot create polygon from empty extent');\n }\n const minX = extent[0];\n const minY = extent[1];\n const maxX = extent[2];\n const maxY = extent[3];\n const flatCoordinates = [\n minX,\n minY,\n minX,\n maxY,\n maxX,\n maxY,\n maxX,\n minY,\n minX,\n minY,\n ];\n return new Polygon(flatCoordinates, 'XY', [flatCoordinates.length]);\n}\n\n/**\n * Create a regular polygon from a circle.\n * @param {import(\"./Circle.js\").default} circle Circle geometry.\n * @param {number} [sides] Number of sides of the polygon. Default is 32.\n * @param {number} [angle] Start angle for the first vertex of the polygon in\n * counter-clockwise radians. 0 means East. Default is 0.\n * @return {Polygon} Polygon geometry.\n * @api\n */\nexport function fromCircle(circle, sides, angle) {\n sides = sides ? sides : 32;\n const stride = circle.getStride();\n const layout = circle.getLayout();\n const center = circle.getCenter();\n const arrayLength = stride * (sides + 1);\n const flatCoordinates = new Array(arrayLength);\n for (let i = 0; i < arrayLength; i += stride) {\n flatCoordinates[i] = 0;\n flatCoordinates[i + 1] = 0;\n for (let j = 2; j < stride; j++) {\n flatCoordinates[i + j] = center[j];\n }\n }\n const ends = [flatCoordinates.length];\n const polygon = new Polygon(flatCoordinates, layout, ends);\n makeRegular(polygon, center, circle.getRadius(), angle);\n return polygon;\n}\n\n/**\n * Modify the coordinates of a polygon to make it a regular polygon.\n * @param {Polygon} polygon Polygon geometry.\n * @param {import(\"../coordinate.js\").Coordinate} center Center of the regular polygon.\n * @param {number} radius Radius of the regular polygon.\n * @param {number} [angle] Start angle for the first vertex of the polygon in\n * counter-clockwise radians. 0 means East. Default is 0.\n */\nexport function makeRegular(polygon, center, radius, angle) {\n const flatCoordinates = polygon.getFlatCoordinates();\n const stride = polygon.getStride();\n const sides = flatCoordinates.length / stride - 1;\n const startAngle = angle ? angle : 0;\n for (let i = 0; i <= sides; ++i) {\n const offset = i * stride;\n const angle = startAngle + (modulo(i, sides) * 2 * Math.PI) / sides;\n flatCoordinates[offset] = center[0] + radius * Math.cos(angle);\n flatCoordinates[offset + 1] = center[1] + radius * Math.sin(angle);\n }\n polygon.changed();\n}\n","/**\n * @module ol/render/EventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * Triggered before a layer is rendered.\n * @event module:ol/render/Event~RenderEvent#prerender\n * @api\n */\n PRERENDER: 'prerender',\n\n /**\n * Triggered after a layer is rendered.\n * @event module:ol/render/Event~RenderEvent#postrender\n * @api\n */\n POSTRENDER: 'postrender',\n\n /**\n * Triggered before layers are composed. When dispatched by the map, the event object will not have\n * a `context` set. When dispatched by a layer, the event object will have a `context` set. Only\n * WebGL layers currently dispatch this event.\n * @event module:ol/render/Event~RenderEvent#precompose\n * @api\n */\n PRECOMPOSE: 'precompose',\n\n /**\n * Triggered after layers are composed. When dispatched by the map, the event object will not have\n * a `context` set. When dispatched by a layer, the event object will have a `context` set. Only\n * WebGL layers currently dispatch this event.\n * @event module:ol/render/Event~RenderEvent#postcompose\n * @api\n */\n POSTCOMPOSE: 'postcompose',\n\n /**\n * Triggered when rendering is complete, i.e. all sources and tiles have\n * finished loading for the current viewport, and all tiles are faded in.\n * The event object will not have a `context` set.\n * @event module:ol/render/Event~RenderEvent#rendercomplete\n * @api\n */\n RENDERCOMPLETE: 'rendercomplete',\n};\n\n/**\n * @typedef {'postrender'|'precompose'|'postcompose'|'rendercomplete'} MapRenderEventTypes\n */\n\n/**\n * @typedef {'postrender'|'prerender'} LayerRenderEventTypes\n */\n","/**\n * @module ol/style/Fill\n */\n\n/**\n * @typedef {Object} Options\n * @property {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike|null} [color=null] A color, gradient or pattern.\n * See {@link module:ol/color~Color} and {@link module:ol/colorlike~ColorLike} for possible formats.\n * Default null; if null, the Canvas/renderer default black will be used.\n */\n\n/**\n * @classdesc\n * Set fill style for vector features.\n * @api\n */\nclass Fill {\n /**\n * @param {Options} [options] Options.\n */\n constructor(options) {\n options = options || {};\n\n /**\n * @private\n * @type {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike|null}\n */\n this.color_ = options.color !== undefined ? options.color : null;\n }\n\n /**\n * Clones the style. The color is not cloned if it is an {@link module:ol/colorlike~ColorLike}.\n * @return {Fill} The cloned style.\n * @api\n */\n clone() {\n const color = this.getColor();\n return new Fill({\n color: Array.isArray(color) ? color.slice() : color || undefined,\n });\n }\n\n /**\n * Get the fill color.\n * @return {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike|null} Color.\n * @api\n */\n getColor() {\n return this.color_;\n }\n\n /**\n * Set the color.\n *\n * @param {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike|null} color Color.\n * @api\n */\n setColor(color) {\n this.color_ = color;\n }\n}\n\nexport default Fill;\n","/**\n * @module ol/geom/flat/interpolate\n */\nimport {binarySearch} from '../../array.js';\nimport {lerp} from '../../math.js';\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} fraction Fraction.\n * @param {Array} [dest] Destination.\n * @param {number} [dimension] Destination dimension (default is `2`)\n * @return {Array} Destination.\n */\nexport function interpolatePoint(\n flatCoordinates,\n offset,\n end,\n stride,\n fraction,\n dest,\n dimension\n) {\n let o, t;\n const n = (end - offset) / stride;\n if (n === 1) {\n o = offset;\n } else if (n === 2) {\n o = offset;\n t = fraction;\n } else if (n !== 0) {\n let x1 = flatCoordinates[offset];\n let y1 = flatCoordinates[offset + 1];\n let length = 0;\n const cumulativeLengths = [0];\n for (let i = offset + stride; i < end; i += stride) {\n const x2 = flatCoordinates[i];\n const y2 = flatCoordinates[i + 1];\n length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n cumulativeLengths.push(length);\n x1 = x2;\n y1 = y2;\n }\n const target = fraction * length;\n const index = binarySearch(cumulativeLengths, target);\n if (index < 0) {\n t =\n (target - cumulativeLengths[-index - 2]) /\n (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]);\n o = offset + (-index - 2) * stride;\n } else {\n o = offset + index * stride;\n }\n }\n dimension = dimension > 1 ? dimension : 2;\n dest = dest ? dest : new Array(dimension);\n for (let i = 0; i < dimension; ++i) {\n dest[i] =\n o === undefined\n ? NaN\n : t === undefined\n ? flatCoordinates[o + i]\n : lerp(flatCoordinates[o + i], flatCoordinates[o + stride + i], t);\n }\n return dest;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @param {number} m M.\n * @param {boolean} extrapolate Extrapolate.\n * @return {import(\"../../coordinate.js\").Coordinate|null} Coordinate.\n */\nexport function lineStringCoordinateAtM(\n flatCoordinates,\n offset,\n end,\n stride,\n m,\n extrapolate\n) {\n if (end == offset) {\n return null;\n }\n let coordinate;\n if (m < flatCoordinates[offset + stride - 1]) {\n if (extrapolate) {\n coordinate = flatCoordinates.slice(offset, offset + stride);\n coordinate[stride - 1] = m;\n return coordinate;\n }\n return null;\n }\n if (flatCoordinates[end - 1] < m) {\n if (extrapolate) {\n coordinate = flatCoordinates.slice(end - stride, end);\n coordinate[stride - 1] = m;\n return coordinate;\n }\n return null;\n }\n // FIXME use O(1) search\n if (m == flatCoordinates[offset + stride - 1]) {\n return flatCoordinates.slice(offset, offset + stride);\n }\n let lo = offset / stride;\n let hi = end / stride;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if (m < flatCoordinates[(mid + 1) * stride - 1]) {\n hi = mid;\n } else {\n lo = mid + 1;\n }\n }\n const m0 = flatCoordinates[lo * stride - 1];\n if (m == m0) {\n return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride);\n }\n const m1 = flatCoordinates[(lo + 1) * stride - 1];\n const t = (m - m0) / (m1 - m0);\n coordinate = [];\n for (let i = 0; i < stride - 1; ++i) {\n coordinate.push(\n lerp(\n flatCoordinates[(lo - 1) * stride + i],\n flatCoordinates[lo * stride + i],\n t\n )\n );\n }\n coordinate.push(m);\n return coordinate;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {Array} ends Ends.\n * @param {number} stride Stride.\n * @param {number} m M.\n * @param {boolean} extrapolate Extrapolate.\n * @param {boolean} interpolate Interpolate.\n * @return {import(\"../../coordinate.js\").Coordinate|null} Coordinate.\n */\nexport function lineStringsCoordinateAtM(\n flatCoordinates,\n offset,\n ends,\n stride,\n m,\n extrapolate,\n interpolate\n) {\n if (interpolate) {\n return lineStringCoordinateAtM(\n flatCoordinates,\n offset,\n ends[ends.length - 1],\n stride,\n m,\n extrapolate\n );\n }\n let coordinate;\n if (m < flatCoordinates[stride - 1]) {\n if (extrapolate) {\n coordinate = flatCoordinates.slice(0, stride);\n coordinate[stride - 1] = m;\n return coordinate;\n }\n return null;\n }\n if (flatCoordinates[flatCoordinates.length - 1] < m) {\n if (extrapolate) {\n coordinate = flatCoordinates.slice(flatCoordinates.length - stride);\n coordinate[stride - 1] = m;\n return coordinate;\n }\n return null;\n }\n for (let i = 0, ii = ends.length; i < ii; ++i) {\n const end = ends[i];\n if (offset == end) {\n continue;\n }\n if (m < flatCoordinates[offset + stride - 1]) {\n return null;\n }\n if (m <= flatCoordinates[end - 1]) {\n return lineStringCoordinateAtM(\n flatCoordinates,\n offset,\n end,\n stride,\n m,\n false\n );\n }\n offset = end;\n }\n return null;\n}\n","/**\n * @module ol/geom/flat/length\n */\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Length.\n */\nexport function lineStringLength(flatCoordinates, offset, end, stride) {\n let x1 = flatCoordinates[offset];\n let y1 = flatCoordinates[offset + 1];\n let length = 0;\n for (let i = offset + stride; i < end; i += stride) {\n const x2 = flatCoordinates[i];\n const y2 = flatCoordinates[i + 1];\n length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n x1 = x2;\n y1 = y2;\n }\n return length;\n}\n\n/**\n * @param {Array} flatCoordinates Flat coordinates.\n * @param {number} offset Offset.\n * @param {number} end End.\n * @param {number} stride Stride.\n * @return {number} Perimeter.\n */\nexport function linearRingLength(flatCoordinates, offset, end, stride) {\n let perimeter = lineStringLength(flatCoordinates, offset, end, stride);\n const dx = flatCoordinates[end - stride] - flatCoordinates[offset];\n const dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1];\n perimeter += Math.sqrt(dx * dx + dy * dy);\n return perimeter;\n}\n","/**\n * @module ol/style/Stroke\n */\n\n/**\n * @typedef {Object} Options\n * @property {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} [color] A color, gradient or pattern.\n * See {@link module:ol/color~Color} and {@link module:ol/colorlike~ColorLike} for possible formats.\n * Default null; if null, the Canvas/renderer default black will be used.\n * @property {CanvasLineCap} [lineCap='round'] Line cap style: `butt`, `round`, or `square`.\n * @property {CanvasLineJoin} [lineJoin='round'] Line join style: `bevel`, `round`, or `miter`.\n * @property {Array} [lineDash] Line dash pattern. Default is `null` (no dash).\n * @property {number} [lineDashOffset=0] Line dash offset.\n * @property {number} [miterLimit=10] Miter limit.\n * @property {number} [width] Width.\n */\n\n/**\n * @classdesc\n * Set stroke style for vector features.\n * Note that the defaults given are the Canvas defaults, which will be used if\n * option is not defined. The `get` functions return whatever was entered in\n * the options; they will not return the default.\n * @api\n */\nclass Stroke {\n /**\n * @param {Options} [options] Options.\n */\n constructor(options) {\n options = options || {};\n\n /**\n * @private\n * @type {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike}\n */\n this.color_ = options.color !== undefined ? options.color : null;\n\n /**\n * @private\n * @type {CanvasLineCap|undefined}\n */\n this.lineCap_ = options.lineCap;\n\n /**\n * @private\n * @type {Array|null}\n */\n this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.lineDashOffset_ = options.lineDashOffset;\n\n /**\n * @private\n * @type {CanvasLineJoin|undefined}\n */\n this.lineJoin_ = options.lineJoin;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.miterLimit_ = options.miterLimit;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.width_ = options.width;\n }\n\n /**\n * Clones the style.\n * @return {Stroke} The cloned style.\n * @api\n */\n clone() {\n const color = this.getColor();\n return new Stroke({\n color: Array.isArray(color) ? color.slice() : color || undefined,\n lineCap: this.getLineCap(),\n lineDash: this.getLineDash() ? this.getLineDash().slice() : undefined,\n lineDashOffset: this.getLineDashOffset(),\n lineJoin: this.getLineJoin(),\n miterLimit: this.getMiterLimit(),\n width: this.getWidth(),\n });\n }\n\n /**\n * Get the stroke color.\n * @return {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} Color.\n * @api\n */\n getColor() {\n return this.color_;\n }\n\n /**\n * Get the line cap type for the stroke.\n * @return {CanvasLineCap|undefined} Line cap.\n * @api\n */\n getLineCap() {\n return this.lineCap_;\n }\n\n /**\n * Get the line dash style for the stroke.\n * @return {Array|null} Line dash.\n * @api\n */\n getLineDash() {\n return this.lineDash_;\n }\n\n /**\n * Get the line dash offset for the stroke.\n * @return {number|undefined} Line dash offset.\n * @api\n */\n getLineDashOffset() {\n return this.lineDashOffset_;\n }\n\n /**\n * Get the line join type for the stroke.\n * @return {CanvasLineJoin|undefined} Line join.\n * @api\n */\n getLineJoin() {\n return this.lineJoin_;\n }\n\n /**\n * Get the miter limit for the stroke.\n * @return {number|undefined} Miter limit.\n * @api\n */\n getMiterLimit() {\n return this.miterLimit_;\n }\n\n /**\n * Get the stroke width.\n * @return {number|undefined} Width.\n * @api\n */\n getWidth() {\n return this.width_;\n }\n\n /**\n * Set the color.\n *\n * @param {import(\"../color.js\").Color|import(\"../colorlike.js\").ColorLike} color Color.\n * @api\n */\n setColor(color) {\n this.color_ = color;\n }\n\n /**\n * Set the line cap.\n *\n * @param {CanvasLineCap|undefined} lineCap Line cap.\n * @api\n */\n setLineCap(lineCap) {\n this.lineCap_ = lineCap;\n }\n\n /**\n * Set the line dash.\n *\n * @param {Array|null} lineDash Line dash.\n * @api\n */\n setLineDash(lineDash) {\n this.lineDash_ = lineDash;\n }\n\n /**\n * Set the line dash offset.\n *\n * @param {number|undefined} lineDashOffset Line dash offset.\n * @api\n */\n setLineDashOffset(lineDashOffset) {\n this.lineDashOffset_ = lineDashOffset;\n }\n\n /**\n * Set the line join.\n *\n * @param {CanvasLineJoin|undefined} lineJoin Line join.\n * @api\n */\n setLineJoin(lineJoin) {\n this.lineJoin_ = lineJoin;\n }\n\n /**\n * Set the miter limit.\n *\n * @param {number|undefined} miterLimit Miter limit.\n * @api\n */\n setMiterLimit(miterLimit) {\n this.miterLimit_ = miterLimit;\n }\n\n /**\n * Set the width.\n *\n * @param {number|undefined} width Width.\n * @api\n */\n setWidth(width) {\n this.width_ = width;\n }\n}\n\nexport default Stroke;\n","/**\n * @module ol/ImageState\n */\n\n/**\n * @enum {number}\n */\nexport default {\n IDLE: 0,\n LOADING: 1,\n LOADED: 2,\n ERROR: 3,\n EMPTY: 4,\n};\n","/**\n * @module ol/size\n */\n\n/**\n * An array of numbers representing a size: `[width, height]`.\n * @typedef {Array} Size\n * @api\n */\n\n/**\n * Returns a buffered size.\n * @param {Size} size Size.\n * @param {number} num The amount by which to buffer.\n * @param {Size} [dest] Optional reusable size array.\n * @return {Size} The buffered size.\n */\nexport function buffer(size, num, dest) {\n if (dest === undefined) {\n dest = [0, 0];\n }\n dest[0] = size[0] + 2 * num;\n dest[1] = size[1] + 2 * num;\n return dest;\n}\n\n/**\n * Determines if a size has a positive area.\n * @param {Size} size The size to test.\n * @return {boolean} The size has a positive area.\n */\nexport function hasArea(size) {\n return size[0] > 0 && size[1] > 0;\n}\n\n/**\n * Returns a size scaled by a ratio. The result will be an array of integers.\n * @param {Size} size Size.\n * @param {number} ratio Ratio.\n * @param {Size} [dest] Optional reusable size array.\n * @return {Size} The scaled size.\n */\nexport function scale(size, ratio, dest) {\n if (dest === undefined) {\n dest = [0, 0];\n }\n dest[0] = (size[0] * ratio + 0.5) | 0;\n dest[1] = (size[1] * ratio + 0.5) | 0;\n return dest;\n}\n\n/**\n * Returns an `Size` array for the passed in number (meaning: square) or\n * `Size` array.\n * (meaning: non-square),\n * @param {number|Size} size Width and height.\n * @param {Size} [dest] Optional reusable size array.\n * @return {Size} Size.\n * @api\n */\nexport function toSize(size, dest) {\n if (Array.isArray(size)) {\n return size;\n }\n if (dest === undefined) {\n dest = [size, size];\n } else {\n dest[0] = size;\n dest[1] = size;\n }\n return dest;\n}\n","/**\n * @module ol/style/Image\n */\nimport {abstract} from '../util.js';\nimport {toSize} from '../size.js';\n\n/**\n * @typedef {Object} Options\n * @property {number} opacity Opacity.\n * @property {boolean} rotateWithView If the image should get rotated with the view.\n * @property {number} rotation Rotation.\n * @property {number|import(\"../size.js\").Size} scale Scale.\n * @property {Array} displacement Displacement.\n * @property {\"declutter\"|\"obstacle\"|\"none\"|undefined} declutterMode Declutter mode: `declutter`, `obstacle`, 'none */\n\n/**\n * @classdesc\n * A base class used for creating subclasses and not instantiated in\n * apps. Base class for {@link module:ol/style/Icon~Icon}, {@link module:ol/style/Circle~CircleStyle} and\n * {@link module:ol/style/RegularShape~RegularShape}.\n * @abstract\n * @api\n */\nclass ImageStyle {\n /**\n * @param {Options} options Options.\n */\n constructor(options) {\n /**\n * @private\n * @type {number}\n */\n this.opacity_ = options.opacity;\n\n /**\n * @private\n * @type {boolean}\n */\n this.rotateWithView_ = options.rotateWithView;\n\n /**\n * @private\n * @type {number}\n */\n this.rotation_ = options.rotation;\n\n /**\n * @private\n * @type {number|import(\"../size.js\").Size}\n */\n this.scale_ = options.scale;\n\n /**\n * @private\n * @type {import(\"../size.js\").Size}\n */\n this.scaleArray_ = toSize(options.scale);\n\n /**\n * @private\n * @type {Array}\n */\n this.displacement_ = options.displacement;\n\n /**\n * @private\n * @type {\"declutter\"|\"obstacle\"|\"none\"|undefined}\n */\n this.declutterMode_ = options.declutterMode;\n }\n\n /**\n * Clones the style.\n * @return {ImageStyle} The cloned style.\n * @api\n */\n clone() {\n const scale = this.getScale();\n return new ImageStyle({\n opacity: this.getOpacity(),\n scale: Array.isArray(scale) ? scale.slice() : scale,\n rotation: this.getRotation(),\n rotateWithView: this.getRotateWithView(),\n displacement: this.getDisplacement().slice(),\n declutterMode: this.getDeclutterMode(),\n });\n }\n\n /**\n * Get the symbolizer opacity.\n * @return {number} Opacity.\n * @api\n */\n getOpacity() {\n return this.opacity_;\n }\n\n /**\n * Determine whether the symbolizer rotates with the map.\n * @return {boolean} Rotate with map.\n * @api\n */\n getRotateWithView() {\n return this.rotateWithView_;\n }\n\n /**\n * Get the symoblizer rotation.\n * @return {number} Rotation.\n * @api\n */\n getRotation() {\n return this.rotation_;\n }\n\n /**\n * Get the symbolizer scale.\n * @return {number|import(\"../size.js\").Size} Scale.\n * @api\n */\n getScale() {\n return this.scale_;\n }\n\n /**\n * Get the symbolizer scale array.\n * @return {import(\"../size.js\").Size} Scale array.\n */\n getScaleArray() {\n return this.scaleArray_;\n }\n\n /**\n * Get the displacement of the shape\n * @return {Array} Shape's center displacement\n * @api\n */\n getDisplacement() {\n return this.displacement_;\n }\n\n /**\n * Get the declutter mode of the shape\n * @return {\"declutter\"|\"obstacle\"|\"none\"|undefined} Shape's declutter mode\n * @api\n */\n getDeclutterMode() {\n return this.declutterMode_;\n }\n\n /**\n * Get the anchor point in pixels. The anchor determines the center point for the\n * symbolizer.\n * @abstract\n * @return {Array} Anchor.\n */\n getAnchor() {\n return abstract();\n }\n\n /**\n * Get the image element for the symbolizer.\n * @abstract\n * @param {number} pixelRatio Pixel ratio.\n * @return {import('../DataTile.js').ImageLike} Image element.\n */\n getImage(pixelRatio) {\n return abstract();\n }\n\n /**\n * @abstract\n * @return {import('../DataTile.js').ImageLike} Image element.\n */\n getHitDetectionImage() {\n return abstract();\n }\n\n /**\n * Get the image pixel ratio.\n * @param {number} pixelRatio Pixel ratio.\n * @return {number} Pixel ratio.\n */\n getPixelRatio(pixelRatio) {\n return 1;\n }\n\n /**\n * @abstract\n * @return {import(\"../ImageState.js\").default} Image state.\n */\n getImageState() {\n return abstract();\n }\n\n /**\n * @abstract\n * @return {import(\"../size.js\").Size} Image size.\n */\n getImageSize() {\n return abstract();\n }\n\n /**\n * Get the origin of the symbolizer.\n * @abstract\n * @return {Array} Origin.\n */\n getOrigin() {\n return abstract();\n }\n\n /**\n * Get the size of the symbolizer (in pixels).\n * @abstract\n * @return {import(\"../size.js\").Size} Size.\n */\n getSize() {\n return abstract();\n }\n\n /**\n * Set the displacement.\n *\n * @param {Array} displacement Displacement.\n * @api\n */\n setDisplacement(displacement) {\n this.displacement_ = displacement;\n }\n\n /**\n * Set the opacity.\n *\n * @param {number} opacity Opacity.\n * @api\n */\n setOpacity(opacity) {\n this.opacity_ = opacity;\n }\n\n /**\n * Set whether to rotate the style with the view.\n *\n * @param {boolean} rotateWithView Rotate with map.\n * @api\n */\n setRotateWithView(rotateWithView) {\n this.rotateWithView_ = rotateWithView;\n }\n\n /**\n * Set the rotation.\n *\n * @param {number} rotation Rotation.\n * @api\n */\n setRotation(rotation) {\n this.rotation_ = rotation;\n }\n\n /**\n * Set the scale.\n *\n * @param {number|import(\"../size.js\").Size} scale Scale.\n * @api\n */\n setScale(scale) {\n this.scale_ = scale;\n this.scaleArray_ = toSize(scale);\n }\n\n /**\n * @abstract\n * @param {function(import(\"../events/Event.js\").default): void} listener Listener function.\n */\n listenImageChange(listener) {\n abstract();\n }\n\n /**\n * Load not yet loaded URI.\n * @abstract\n */\n load() {\n abstract();\n }\n\n /**\n * @abstract\n * @param {function(import(\"../events/Event.js\").default): void} listener Listener function.\n */\n unlistenImageChange(listener) {\n abstract();\n }\n}\n\nexport default ImageStyle;\n","/**\n * RGB space.\n *\n * @module color-space/rgb\n */\n\nexport default {\n\tname: 'rgb',\n\tmin: [0,0,0],\n\tmax: [255,255,255],\n\tchannel: ['red', 'green', 'blue'],\n\talias: ['RGB']\n};\n","/**\n * CIE XYZ\n *\n * @module color-space/xyz\n */\nimport rgb from './rgb.js';\n\nvar xyz = {\n\tname: 'xyz',\n\tmin: [0,0,0],\n\tchannel: ['X','Y','Z'],\n\talias: ['XYZ', 'ciexyz', 'cie1931']\n};\n\n\n/**\n * Whitepoint reference values with observer/illuminant\n *\n * http://en.wikipedia.org/wiki/Standard_illuminant\n */\nxyz.whitepoint = {\n\t//1931 2°\n\t2: {\n\t\t//incadescent\n\t\tA:[109.85, 100, 35.585],\n\t\t// B:[],\n\t\tC: [98.074, 100, 118.232],\n\t\tD50: [96.422, 100, 82.521],\n\t\tD55: [95.682, 100, 92.149],\n\t\t//daylight\n\t\tD65: [95.045592705167, 100, 108.9057750759878],\n\t\tD75: [94.972, 100, 122.638],\n\t\t//flourescent\n\t\t// F1: [],\n\t\tF2: [99.187, 100, 67.395],\n\t\t// F3: [],\n\t\t// F4: [],\n\t\t// F5: [],\n\t\t// F6:[],\n\t\tF7: [95.044, 100, 108.755],\n\t\t// F8: [],\n\t\t// F9: [],\n\t\t// F10: [],\n\t\tF11: [100.966, 100, 64.370],\n\t\t// F12: [],\n\t\tE: [100,100,100]\n\t},\n\n\t//1964 10°\n\t10: {\n\t\t//incadescent\n\t\tA:[111.144, 100, 35.200],\n\t\tC: [97.285, 100, 116.145],\n\t\tD50: [96.720, 100, 81.427],\n\t\tD55: [95.799, 100, 90.926],\n\t\t//daylight\n\t\tD65: [94.811, 100, 107.304],\n\t\tD75: [94.416, 100, 120.641],\n\t\t//flourescent\n\t\tF2: [103.280, 100, 69.026],\n\t\tF7: [95.792, 100, 107.687],\n\t\tF11: [103.866, 100, 65.627],\n\t\tE: [100,100,100]\n\t}\n};\n\n\n/**\n * Top values are the whitepoint’s top values, default are D65\n */\nxyz.max = xyz.whitepoint[2].D65;\n\n\n/**\n * Transform xyz to rgb\n *\n * @param {Array} xyz Array of xyz values\n *\n * @return {Array} RGB values\n */\nxyz.rgb = function (_xyz, white) {\n\t//FIXME: make sure we have to divide like this. Probably we have to replace matrix as well then\n\twhite = white || xyz.whitepoint[2].E;\n\n\tvar x = _xyz[0] / white[0],\n\t\ty = _xyz[1] / white[1],\n\t\tz = _xyz[2] / white[2],\n\t\tr, g, b;\n\n\t// assume sRGB\n\t// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html\n\tr = (x * 3.240969941904521) + (y * -1.537383177570093) + (z * -0.498610760293);\n\tg = (x * -0.96924363628087) + (y * 1.87596750150772) + (z * 0.041555057407175);\n\tb = (x * 0.055630079696993) + (y * -0.20397695888897) + (z * 1.056971514242878);\n\n\tr = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)\n\t\t: r = (r * 12.92);\n\n\tg = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)\n\t\t: g = (g * 12.92);\n\n\tb = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)\n\t\t: b = (b * 12.92);\n\n\tr = Math.min(Math.max(0, r), 1);\n\tg = Math.min(Math.max(0, g), 1);\n\tb = Math.min(Math.max(0, b), 1);\n\n\treturn [r * 255, g * 255, b * 255];\n}\n\n\n\n/**\n * RGB to XYZ\n *\n * @param {Array} rgb RGB channels\n *\n * @return {Array} XYZ channels\n */\nrgb.xyz = function(rgb, white) {\n\tvar r = rgb[0] / 255,\n\t\t\tg = rgb[1] / 255,\n\t\t\tb = rgb[2] / 255;\n\n\t// assume sRGB\n\tr = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);\n\tg = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);\n\tb = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);\n\n\tvar x = (r * 0.41239079926595) + (g * 0.35758433938387) + (b * 0.18048078840183);\n\tvar y = (r * 0.21263900587151) + (g * 0.71516867876775) + (b * 0.072192315360733);\n\tvar z = (r * 0.019330818715591) + (g * 0.11919477979462) + (b * 0.95053215224966);\n\n\twhite = white || xyz.whitepoint[2].E;\n\n\treturn [x * white[0], y * white[1], z * white[2]];\n};\n\n\n\nexport default xyz;\n","/**\n * CIE LUV (C'est la vie)\n *\n * @module color-space/luv\n */\n import xyz from './xyz.js';\n\nexport default {\n\tname: 'luv',\n\t//NOTE: luv has no rigidly defined limits\n\t//easyrgb fails to get proper coords\n\t//boronine states no rigid limits\n\t//colorMine refers this ones:\n\tmin: [0,-134,-140],\n\tmax: [100,224,122],\n\tchannel: ['lightness', 'u', 'v'],\n\talias: ['LUV', 'cieluv', 'cie1976'],\n\n\txyz: function(arg, i, o){\n\t\tvar _u, _v, l, u, v, x, y, z, xn, yn, zn, un, vn;\n\t\tl = arg[0], u = arg[1], v = arg[2];\n\n\t\tif (l === 0) return [0,0,0];\n\n\t\t//get constants\n\t\t//var e = 0.008856451679035631; //(6/29)^3\n\t\tvar k = 0.0011070564598794539; //(3/29)^3\n\n\t\t//get illuminant/observer\n\t\ti = i || 'D65';\n\t\to = o || 2;\n\n\t\txn = xyz.whitepoint[o][i][0];\n\t\tyn = xyz.whitepoint[o][i][1];\n\t\tzn = xyz.whitepoint[o][i][2];\n\n\t\tun = (4 * xn) / (xn + (15 * yn) + (3 * zn));\n\t\tvn = (9 * yn) / (xn + (15 * yn) + (3 * zn));\n\t\t// un = 0.19783000664283;\n\t\t// vn = 0.46831999493879;\n\n\n\t\t_u = u / (13 * l) + un || 0;\n\t\t_v = v / (13 * l) + vn || 0;\n\n\t\ty = l > 8 ? yn * Math.pow( (l + 16) / 116 , 3) : yn * l * k;\n\n\t\t//wikipedia method\n\t\tx = y * 9 * _u / (4 * _v) || 0;\n\t\tz = y * (12 - 3 * _u - 20 * _v) / (4 * _v) || 0;\n\n\t\t//boronine method\n\t\t//https://github.com/boronine/husl/blob/master/husl.coffee#L201\n\t\t// x = 0 - (9 * y * _u) / ((_u - 4) * _v - _u * _v);\n\t\t// z = (9 * y - (15 * _v * y) - (_v * x)) / (3 * _v);\n\n\t\treturn [x, y, z];\n\t}\n};\n\n// http://www.brucelindbloom.com/index.html?Equations.html\n// https://github.com/boronine/husl/blob/master/husl.coffee\n//i - illuminant\n//o - observer\nxyz.luv = function(arg, i, o) {\n\tvar _u, _v, l, u, v, x, y, z, xn, yn, zn, un, vn;\n\n\t//get constants\n\tvar e = 0.008856451679035631; //(6/29)^3\n\tvar k = 903.2962962962961; //(29/3)^3\n\n\t//get illuminant/observer coords\n\ti = i || 'D65';\n\to = o || 2;\n\n\txn = xyz.whitepoint[o][i][0];\n\tyn = xyz.whitepoint[o][i][1];\n\tzn = xyz.whitepoint[o][i][2];\n\n\tun = (4 * xn) / (xn + (15 * yn) + (3 * zn));\n\tvn = (9 * yn) / (xn + (15 * yn) + (3 * zn));\n\n\n\tx = arg[0], y = arg[1], z = arg[2];\n\n\n\t_u = (4 * x) / (x + (15 * y) + (3 * z)) || 0;\n\t_v = (9 * y) / (x + (15 * y) + (3 * z)) || 0;\n\n\tvar yr = y/yn;\n\n\tl = yr <= e ? k * yr : 116 * Math.pow(yr, 1/3) - 16;\n\n\tu = 13 * l * (_u - un);\n\tv = 13 * l * (_v - vn);\n\n\treturn [l, u, v];\n};\n","/**\n * Cylindrical CIE LUV\n *\n * @module color-space/lchuv\n */\nimport luv from './luv.js';\nimport xyz from './xyz.js';\n\n//cylindrical luv\nvar lchuv = {\n\tname: 'lchuv',\n\tchannel: ['lightness', 'chroma', 'hue'],\n\talias: ['LCHuv', 'cielchuv'],\n\tmin: [0,0,0],\n\tmax: [100,100,360],\n\n\tluv: function(luv){\n\t\tvar l = luv[0],\n\t\tc = luv[1],\n\t\th = luv[2],\n\t\tu, v, hr;\n\n\t\thr = h / 360 * 2 * Math.PI;\n\t\tu = c * Math.cos(hr);\n\t\tv = c * Math.sin(hr);\n\t\treturn [l, u, v];\n\t},\n\n\txyz: function(arg) {\n\t\treturn luv.xyz(lchuv.luv(arg));\n\t}\n};\n\nexport default lchuv;\n\nluv.lchuv = function(luv){\n\tvar l = luv[0], u = luv[1], v = luv[2];\n\n\tvar c = Math.sqrt(u*u + v*v);\n\tvar hr = Math.atan2(v,u);\n\tvar h = hr * 360 / 2 / Math.PI;\n\tif (h < 0) {\n\t\th += 360;\n\t}\n\n\treturn [l,c,h]\n};\n\nxyz.lchuv = function(arg){\n return luv.lchuv(xyz.luv(arg));\n};\n","'use strict'\r\n\r\nmodule.exports = {\r\n\t\"aliceblue\": [240, 248, 255],\r\n\t\"antiquewhite\": [250, 235, 215],\r\n\t\"aqua\": [0, 255, 255],\r\n\t\"aquamarine\": [127, 255, 212],\r\n\t\"azure\": [240, 255, 255],\r\n\t\"beige\": [245, 245, 220],\r\n\t\"bisque\": [255, 228, 196],\r\n\t\"black\": [0, 0, 0],\r\n\t\"blanchedalmond\": [255, 235, 205],\r\n\t\"blue\": [0, 0, 255],\r\n\t\"blueviolet\": [138, 43, 226],\r\n\t\"brown\": [165, 42, 42],\r\n\t\"burlywood\": [222, 184, 135],\r\n\t\"cadetblue\": [95, 158, 160],\r\n\t\"chartreuse\": [127, 255, 0],\r\n\t\"chocolate\": [210, 105, 30],\r\n\t\"coral\": [255, 127, 80],\r\n\t\"cornflowerblue\": [100, 149, 237],\r\n\t\"cornsilk\": [255, 248, 220],\r\n\t\"crimson\": [220, 20, 60],\r\n\t\"cyan\": [0, 255, 255],\r\n\t\"darkblue\": [0, 0, 139],\r\n\t\"darkcyan\": [0, 139, 139],\r\n\t\"darkgoldenrod\": [184, 134, 11],\r\n\t\"darkgray\": [169, 169, 169],\r\n\t\"darkgreen\": [0, 100, 0],\r\n\t\"darkgrey\": [169, 169, 169],\r\n\t\"darkkhaki\": [189, 183, 107],\r\n\t\"darkmagenta\": [139, 0, 139],\r\n\t\"darkolivegreen\": [85, 107, 47],\r\n\t\"darkorange\": [255, 140, 0],\r\n\t\"darkorchid\": [153, 50, 204],\r\n\t\"darkred\": [139, 0, 0],\r\n\t\"darksalmon\": [233, 150, 122],\r\n\t\"darkseagreen\": [143, 188, 143],\r\n\t\"darkslateblue\": [72, 61, 139],\r\n\t\"darkslategray\": [47, 79, 79],\r\n\t\"darkslategrey\": [47, 79, 79],\r\n\t\"darkturquoise\": [0, 206, 209],\r\n\t\"darkviolet\": [148, 0, 211],\r\n\t\"deeppink\": [255, 20, 147],\r\n\t\"deepskyblue\": [0, 191, 255],\r\n\t\"dimgray\": [105, 105, 105],\r\n\t\"dimgrey\": [105, 105, 105],\r\n\t\"dodgerblue\": [30, 144, 255],\r\n\t\"firebrick\": [178, 34, 34],\r\n\t\"floralwhite\": [255, 250, 240],\r\n\t\"forestgreen\": [34, 139, 34],\r\n\t\"fuchsia\": [255, 0, 255],\r\n\t\"gainsboro\": [220, 220, 220],\r\n\t\"ghostwhite\": [248, 248, 255],\r\n\t\"gold\": [255, 215, 0],\r\n\t\"goldenrod\": [218, 165, 32],\r\n\t\"gray\": [128, 128, 128],\r\n\t\"green\": [0, 128, 0],\r\n\t\"greenyellow\": [173, 255, 47],\r\n\t\"grey\": [128, 128, 128],\r\n\t\"honeydew\": [240, 255, 240],\r\n\t\"hotpink\": [255, 105, 180],\r\n\t\"indianred\": [205, 92, 92],\r\n\t\"indigo\": [75, 0, 130],\r\n\t\"ivory\": [255, 255, 240],\r\n\t\"khaki\": [240, 230, 140],\r\n\t\"lavender\": [230, 230, 250],\r\n\t\"lavenderblush\": [255, 240, 245],\r\n\t\"lawngreen\": [124, 252, 0],\r\n\t\"lemonchiffon\": [255, 250, 205],\r\n\t\"lightblue\": [173, 216, 230],\r\n\t\"lightcoral\": [240, 128, 128],\r\n\t\"lightcyan\": [224, 255, 255],\r\n\t\"lightgoldenrodyellow\": [250, 250, 210],\r\n\t\"lightgray\": [211, 211, 211],\r\n\t\"lightgreen\": [144, 238, 144],\r\n\t\"lightgrey\": [211, 211, 211],\r\n\t\"lightpink\": [255, 182, 193],\r\n\t\"lightsalmon\": [255, 160, 122],\r\n\t\"lightseagreen\": [32, 178, 170],\r\n\t\"lightskyblue\": [135, 206, 250],\r\n\t\"lightslategray\": [119, 136, 153],\r\n\t\"lightslategrey\": [119, 136, 153],\r\n\t\"lightsteelblue\": [176, 196, 222],\r\n\t\"lightyellow\": [255, 255, 224],\r\n\t\"lime\": [0, 255, 0],\r\n\t\"limegreen\": [50, 205, 50],\r\n\t\"linen\": [250, 240, 230],\r\n\t\"magenta\": [255, 0, 255],\r\n\t\"maroon\": [128, 0, 0],\r\n\t\"mediumaquamarine\": [102, 205, 170],\r\n\t\"mediumblue\": [0, 0, 205],\r\n\t\"mediumorchid\": [186, 85, 211],\r\n\t\"mediumpurple\": [147, 112, 219],\r\n\t\"mediumseagreen\": [60, 179, 113],\r\n\t\"mediumslateblue\": [123, 104, 238],\r\n\t\"mediumspringgreen\": [0, 250, 154],\r\n\t\"mediumturquoise\": [72, 209, 204],\r\n\t\"mediumvioletred\": [199, 21, 133],\r\n\t\"midnightblue\": [25, 25, 112],\r\n\t\"mintcream\": [245, 255, 250],\r\n\t\"mistyrose\": [255, 228, 225],\r\n\t\"moccasin\": [255, 228, 181],\r\n\t\"navajowhite\": [255, 222, 173],\r\n\t\"navy\": [0, 0, 128],\r\n\t\"oldlace\": [253, 245, 230],\r\n\t\"olive\": [128, 128, 0],\r\n\t\"olivedrab\": [107, 142, 35],\r\n\t\"orange\": [255, 165, 0],\r\n\t\"orangered\": [255, 69, 0],\r\n\t\"orchid\": [218, 112, 214],\r\n\t\"palegoldenrod\": [238, 232, 170],\r\n\t\"palegreen\": [152, 251, 152],\r\n\t\"paleturquoise\": [175, 238, 238],\r\n\t\"palevioletred\": [219, 112, 147],\r\n\t\"papayawhip\": [255, 239, 213],\r\n\t\"peachpuff\": [255, 218, 185],\r\n\t\"peru\": [205, 133, 63],\r\n\t\"pink\": [255, 192, 203],\r\n\t\"plum\": [221, 160, 221],\r\n\t\"powderblue\": [176, 224, 230],\r\n\t\"purple\": [128, 0, 128],\r\n\t\"rebeccapurple\": [102, 51, 153],\r\n\t\"red\": [255, 0, 0],\r\n\t\"rosybrown\": [188, 143, 143],\r\n\t\"royalblue\": [65, 105, 225],\r\n\t\"saddlebrown\": [139, 69, 19],\r\n\t\"salmon\": [250, 128, 114],\r\n\t\"sandybrown\": [244, 164, 96],\r\n\t\"seagreen\": [46, 139, 87],\r\n\t\"seashell\": [255, 245, 238],\r\n\t\"sienna\": [160, 82, 45],\r\n\t\"silver\": [192, 192, 192],\r\n\t\"skyblue\": [135, 206, 235],\r\n\t\"slateblue\": [106, 90, 205],\r\n\t\"slategray\": [112, 128, 144],\r\n\t\"slategrey\": [112, 128, 144],\r\n\t\"snow\": [255, 250, 250],\r\n\t\"springgreen\": [0, 255, 127],\r\n\t\"steelblue\": [70, 130, 180],\r\n\t\"tan\": [210, 180, 140],\r\n\t\"teal\": [0, 128, 128],\r\n\t\"thistle\": [216, 191, 216],\r\n\t\"tomato\": [255, 99, 71],\r\n\t\"turquoise\": [64, 224, 208],\r\n\t\"violet\": [238, 130, 238],\r\n\t\"wheat\": [245, 222, 179],\r\n\t\"white\": [255, 255, 255],\r\n\t\"whitesmoke\": [245, 245, 245],\r\n\t\"yellow\": [255, 255, 0],\r\n\t\"yellowgreen\": [154, 205, 50]\r\n};\r\n","/**\n * @module color-parse\n */\nimport names from 'color-name'\n\nexport default parse\n\n/**\n * Base hues\n * http://dev.w3.org/csswg/css-color/#typedef-named-hue\n */\n//FIXME: use external hue detector\nvar baseHues = {\n\tred: 0,\n\torange: 60,\n\tyellow: 120,\n\tgreen: 180,\n\tblue: 240,\n\tpurple: 300\n}\n\n/**\n * Parse color from the string passed\n *\n * @return {Object} A space indicator `space`, an array `values` and `alpha`\n */\nfunction parse(cstr) {\n\tvar m, parts = [], alpha = 1, space\n\n\t//numeric case\n\tif (typeof cstr === 'number') {\n\t\treturn { space: 'rgb', values: [cstr >>> 16, (cstr & 0x00ff00) >>> 8, cstr & 0x0000ff], alpha: 1 }\n\t}\n\tif (typeof cstr === 'number') return { space: 'rgb', values: [cstr >>> 16, (cstr & 0x00ff00) >>> 8, cstr & 0x0000ff], alpha: 1 }\n\n\tcstr = String(cstr).toLowerCase();\n\n\t//keyword\n\tif (names[cstr]) {\n\t\tparts = names[cstr].slice()\n\t\tspace = 'rgb'\n\t}\n\n\t//reserved words\n\telse if (cstr === 'transparent') {\n\t\talpha = 0\n\t\tspace = 'rgb'\n\t\tparts = [0, 0, 0]\n\t}\n\n\t//hex\n\telse if (cstr[0] === '#') {\n\t\tvar base = cstr.slice(1)\n\t\tvar size = base.length\n\t\tvar isShort = size <= 4\n\t\talpha = 1\n\n\t\tif (isShort) {\n\t\t\tparts = [\n\t\t\t\tparseInt(base[0] + base[0], 16),\n\t\t\t\tparseInt(base[1] + base[1], 16),\n\t\t\t\tparseInt(base[2] + base[2], 16)\n\t\t\t]\n\t\t\tif (size === 4) {\n\t\t\t\talpha = parseInt(base[3] + base[3], 16) / 255\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tparts = [\n\t\t\t\tparseInt(base[0] + base[1], 16),\n\t\t\t\tparseInt(base[2] + base[3], 16),\n\t\t\t\tparseInt(base[4] + base[5], 16)\n\t\t\t]\n\t\t\tif (size === 8) {\n\t\t\t\talpha = parseInt(base[6] + base[7], 16) / 255\n\t\t\t}\n\t\t}\n\n\t\tif (!parts[0]) parts[0] = 0\n\t\tif (!parts[1]) parts[1] = 0\n\t\tif (!parts[2]) parts[2] = 0\n\n\t\tspace = 'rgb'\n\t}\n\n\t// color space\n\telse if (m = /^((?:rgba?|hs[lvb]a?|hwba?|cmyk?|xy[zy]|gray|lab|lchu?v?|[ly]uv|lms|oklch|oklab|color))\\s*\\(([^\\)]*)\\)/.exec(cstr)) {\n\t\tvar name = m[1]\n\t\tspace = name.replace(/a$/, '')\n\t\tvar dims = space === 'cmyk' ? 4 : space === 'gray' ? 1 : 3\n\t\tparts = m[2].trim().split(/\\s*[,\\/]\\s*|\\s+/)\n\n\t\t// color(srgb-linear x x x) -> srgb-linear(x x x)\n\t\tif (space === 'color') space = parts.shift()\n\n\t\tparts = parts.map(function (x, i) {\n\t\t\t//\n\t\t\tif (x[x.length - 1] === '%') {\n\t\t\t\tx = parseFloat(x) / 100\n\t\t\t\t// alpha -> 0..1\n\t\t\t\tif (i === 3) return x\n\t\t\t\t// rgb -> 0..255\n\t\t\t\tif (space === 'rgb') return x * 255\n\t\t\t\t// hsl, hwb H -> 0..100\n\t\t\t\tif (space[0] === 'h') return x * 100\n\t\t\t\t// lch, lab L -> 0..100\n\t\t\t\tif (space[0] === 'l' && !i) return x * 100\n\t\t\t\t// lab A B -> -125..125\n\t\t\t\tif (space === 'lab') return x * 125\n\t\t\t\t// lch C -> 0..150, H -> 0..360\n\t\t\t\tif (space === 'lch') return i < 2 ? x * 150 : x * 360\n\t\t\t\t// oklch/oklab L -> 0..1\n\t\t\t\tif (space[0] === 'o' && !i) return x\n\t\t\t\t// oklab A B -> -0.4..0.4\n\t\t\t\tif (space === 'oklab') return x * 0.4\n\t\t\t\t// oklch C -> 0..0.4, H -> 0..360\n\t\t\t\tif (space === 'oklch') return i < 2 ? x * 0.4 : x * 360\n\t\t\t\t// color(xxx) -> 0..1\n\t\t\t\treturn x\n\t\t\t}\n\n\t\t\t//hue\n\t\t\tif (space[i] === 'h' || (i === 2 && space[space.length - 1] === 'h')) {\n\t\t\t\t//\n\t\t\t\tif (baseHues[x] !== undefined) return baseHues[x]\n\t\t\t\t//\n\t\t\t\tif (x.endsWith('deg')) return parseFloat(x)\n\t\t\t\t//\n\t\t\t\tif (x.endsWith('turn')) return parseFloat(x) * 360\n\t\t\t\tif (x.endsWith('grad')) return parseFloat(x) * 360 / 400\n\t\t\t\tif (x.endsWith('rad')) return parseFloat(x) * 180 / Math.PI\n\t\t\t}\n\t\t\tif (x === 'none') return 0\n\t\t\treturn parseFloat(x)\n\t\t});\n\n\t\talpha = parts.length > dims ? parts.pop() : 1\n\t}\n\n\t//named channels case\n\telse if (/[0-9](?:\\s|\\/|,)/.test(cstr)) {\n\t\tparts = cstr.match(/([0-9]+)/g).map(function (value) {\n\t\t\treturn parseFloat(value)\n\t\t})\n\n\t\tspace = cstr.match(/([a-z])/ig)?.join('')?.toLowerCase() || 'rgb'\n\t}\n\n\treturn {\n\t\tspace,\n\t\tvalues: parts,\n\t\talpha\n\t}\n}\n","/**\n * @module color-space/hsl\n */\nimport rgb from './rgb.js';\n\nexport default {\n\tname: 'hsl',\n\tmin: [0,0,0],\n\tmax: [360,100,100],\n\tchannel: ['hue', 'saturation', 'lightness'],\n\talias: ['HSL'],\n\n\trgb: function(hsl) {\n\t\tvar h = hsl[0]/360, s = hsl[1]/100, l = hsl[2]/100, t1, t2, t3, rgb, val, i=0;\n\n\t\tif (s === 0) return val = l * 255, [val, val, val];\n\n\t\tt2 = l < 0.5 ? l * (1 + s) : l + s - l * s;\n\t\tt1 = 2 * l - t2;\n\n\t\trgb = [0, 0, 0];\n\t\tfor (;i<3;) {\n\t\t\tt3 = h + 1 / 3 * - (i - 1);\n\t\t\tt3 < 0 ? t3++ : t3 > 1 && t3--;\n\t\t\tval = 6 * t3 < 1 ? t1 + (t2 - t1) * 6 * t3 :\n\t\t\t2 * t3 < 1 ? t2 :\n\t\t\t3 * t3 < 2 ? t1 + (t2 - t1) * (2 / 3 - t3) * 6 :\n\t\t\tt1;\n\t\t\trgb[i++] = val * 255;\n\t\t}\n\n\t\treturn rgb;\n\t}\n};\n\n\n//extend rgb\nrgb.hsl = function(rgb) {\n\tvar r = rgb[0]/255,\n\t\t\tg = rgb[1]/255,\n\t\t\tb = rgb[2]/255,\n\t\t\tmin = Math.min(r, g, b),\n\t\t\tmax = Math.max(r, g, b),\n\t\t\tdelta = max - min,\n\t\t\th, s, l;\n\n\tif (max === min) {\n\t\th = 0;\n\t}\n\telse if (r === max) {\n\t\th = (g - b) / delta;\n\t}\n\telse if (g === max) {\n\t\th = 2 + (b - r) / delta;\n\t}\n\telse if (b === max) {\n\t\th = 4 + (r - g)/ delta;\n\t}\n\n\th = Math.min(h * 60, 360);\n\n\tif (h < 0) {\n\t\th += 360;\n\t}\n\n\tl = (min + max) / 2;\n\n\tif (max === min) {\n\t\ts = 0;\n\t}\n\telse if (l <= 0.5) {\n\t\ts = delta / (max + min);\n\t}\n\telse {\n\t\ts = delta / (2 - max - min);\n\t}\n\n\treturn [h, s * 100, l * 100];\n};\n","/** @module color-rgba */\nimport parse from 'color-parse'\nimport rgb from 'color-space/rgb.js'\nimport hsl from 'color-space/hsl.js'\n\nexport default function rgba(color) {\n\t// template literals\n\tif (Array.isArray(color) && color.raw) color = String.raw(...arguments)\n\tif (color instanceof Number) color = +color\n\n\tvar values, i, l\n\n\t//attempt to parse non-array arguments\n\tvar parsed = parse(color)\n\n\tif (!parsed.space) return []\n\n\tconst min = parsed.space[0] === 'h' ? hsl.min : rgb.min\n\tconst max = parsed.space[0] === 'h' ? hsl.max : rgb.max\n\n\tvalues = Array(3)\n\tvalues[0] = Math.min(Math.max(parsed.values[0], min[0]), max[0])\n\tvalues[1] = Math.min(Math.max(parsed.values[1], min[1]), max[1])\n\tvalues[2] = Math.min(Math.max(parsed.values[2], min[2]), max[2])\n\n\tif (parsed.space[0] === 'h') {\n\t\tvalues = hsl.rgb(values)\n\t}\n\n\tvalues.push(Math.min(Math.max(parsed.alpha, 0), 1))\n\n\treturn values\n}\n","/**\n * @module ol/color\n */\nimport lchuv from 'color-space/lchuv.js';\nimport parseRgba from 'color-rgba';\nimport rgb from 'color-space/rgb.js';\nimport xyz from 'color-space/xyz.js';\nimport {clamp} from './math.js';\n\n/**\n * A color represented as a short array [red, green, blue, alpha].\n * red, green, and blue should be integers in the range 0..255 inclusive.\n * alpha should be a float in the range 0..1 inclusive. If no alpha value is\n * given then `1` will be used.\n * @typedef {Array} Color\n * @api\n */\n\n/**\n * Return the color as an rgba string.\n * @param {Color|string} color Color.\n * @return {string} Rgba string.\n * @api\n */\nexport function asString(color) {\n if (typeof color === 'string') {\n return color;\n }\n return toString(color);\n}\n\n/**\n * @type {number}\n */\nconst MAX_CACHE_SIZE = 1024;\n\n/**\n * We maintain a small cache of parsed strings. Whenever the cache grows too large,\n * we delete an arbitrary set of the entries.\n *\n * @type {Object}\n */\nconst cache = {};\n\n/**\n * @type {number}\n */\nlet cacheSize = 0;\n\n/**\n * @param {Color} color A color that may or may not have an alpha channel.\n * @return {Color} The input color with an alpha channel. If the input color has\n * an alpha channel, the input color will be returned unchanged. Otherwise, a new\n * array will be returned with the input color and an alpha channel of 1.\n */\nexport function withAlpha(color) {\n if (color.length === 4) {\n return color;\n }\n const output = color.slice();\n output[3] = 1;\n return output;\n}\n\n/**\n * @param {Color} color RGBA color.\n * @return {Color} LCHuv color with alpha.\n */\nexport function rgbaToLcha(color) {\n const output = xyz.lchuv(rgb.xyz(color));\n output[3] = color[3];\n return output;\n}\n\n/**\n * @param {Color} color LCHuv color with alpha.\n * @return {Color} RGBA color.\n */\nexport function lchaToRgba(color) {\n const output = xyz.rgb(lchuv.xyz(color));\n output[3] = color[3];\n return output;\n}\n\n/**\n * @param {string} s String.\n * @return {Color} Color.\n */\nexport function fromString(s) {\n if (cache.hasOwnProperty(s)) {\n return cache[s];\n }\n if (cacheSize >= MAX_CACHE_SIZE) {\n let i = 0;\n for (const key in cache) {\n if ((i++ & 3) === 0) {\n delete cache[key];\n --cacheSize;\n }\n }\n }\n\n const color = parseRgba(s);\n if (color.length !== 4) {\n throw new Error('Failed to parse \"' + s + '\" as color');\n }\n for (const c of color) {\n if (isNaN(c)) {\n throw new Error('Failed to parse \"' + s + '\" as color');\n }\n }\n normalize(color);\n cache[s] = color;\n ++cacheSize;\n return color;\n}\n\n/**\n * Return the color as an array. This function maintains a cache of calculated\n * arrays which means the result should not be modified.\n * @param {Color|string} color Color.\n * @return {Color} Color.\n * @api\n */\nexport function asArray(color) {\n if (Array.isArray(color)) {\n return color;\n }\n return fromString(color);\n}\n\n/**\n * Exported for the tests.\n * @param {Color} color Color.\n * @return {Color} Clamped color.\n */\nexport function normalize(color) {\n color[0] = clamp((color[0] + 0.5) | 0, 0, 255);\n color[1] = clamp((color[1] + 0.5) | 0, 0, 255);\n color[2] = clamp((color[2] + 0.5) | 0, 0, 255);\n color[3] = clamp(color[3], 0, 1);\n return color;\n}\n\n/**\n * @param {Color} color Color.\n * @return {string} String.\n */\nexport function toString(color) {\n let r = color[0];\n if (r != (r | 0)) {\n r = (r + 0.5) | 0;\n }\n let g = color[1];\n if (g != (g | 0)) {\n g = (g + 0.5) | 0;\n }\n let b = color[2];\n if (b != (b | 0)) {\n b = (b + 0.5) | 0;\n }\n const a = color[3] === undefined ? 1 : Math.round(color[3] * 100) / 100;\n return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';\n}\n\n/**\n * @param {string} s String.\n * @return {boolean} Whether the string is actually a valid color\n */\nexport function isStringColor(s) {\n try {\n fromString(s);\n return true;\n } catch (_) {\n return false;\n }\n}\n","/**\n * @module ol/colorlike\n */\nimport {toString} from './color.js';\n\n/**\n * A type accepted by CanvasRenderingContext2D.fillStyle\n * or CanvasRenderingContext2D.strokeStyle.\n * Represents a color, pattern, or gradient. The origin for patterns and\n * gradients as fill style is an increment of 512 css pixels from map coordinate\n * `[0, 0]`. For seamless repeat patterns, width and height of the pattern image\n * must be a factor of two (2, 4, 8, ..., 512).\n *\n * @typedef {string|CanvasPattern|CanvasGradient} ColorLike\n * @api\n */\n\n/**\n * @param {import(\"./color.js\").Color|ColorLike} color Color.\n * @return {ColorLike} The color as an {@link ol/colorlike~ColorLike}.\n * @api\n */\nexport function asColorLike(color) {\n if (Array.isArray(color)) {\n return toString(color);\n }\n return color;\n}\n","import {WORKER_OFFSCREEN_CANVAS} from './has.js';\n\n/**\n * @module ol/dom\n */\n\n//FIXME Move this function to the canvas module\n/**\n * Create an html canvas element and returns its 2d context.\n * @param {number} [width] Canvas width.\n * @param {number} [height] Canvas height.\n * @param {Array} [canvasPool] Canvas pool to take existing canvas from.\n * @param {CanvasRenderingContext2DSettings} [settings] CanvasRenderingContext2DSettings\n * @return {CanvasRenderingContext2D} The context.\n */\nexport function createCanvasContext2D(width, height, canvasPool, settings) {\n /** @type {HTMLCanvasElement|OffscreenCanvas} */\n let canvas;\n if (canvasPool && canvasPool.length) {\n canvas = /** @type {HTMLCanvasElement} */ (canvasPool.shift());\n } else if (WORKER_OFFSCREEN_CANVAS) {\n canvas = new OffscreenCanvas(width || 300, height || 300);\n } else {\n canvas = document.createElement('canvas');\n }\n if (width) {\n canvas.width = width;\n }\n if (height) {\n canvas.height = height;\n }\n //FIXME Allow OffscreenCanvasRenderingContext2D as return type\n return /** @type {CanvasRenderingContext2D} */ (\n canvas.getContext('2d', settings)\n );\n}\n\n/**\n * Releases canvas memory to avoid exceeding memory limits in Safari.\n * See https://pqina.nl/blog/total-canvas-memory-use-exceeds-the-maximum-limit/\n * @param {CanvasRenderingContext2D} context Context.\n */\nexport function releaseCanvas(context) {\n const canvas = context.canvas;\n canvas.width = 1;\n canvas.height = 1;\n context.clearRect(0, 0, 1, 1);\n}\n\n/**\n * Get the current computed width for the given element including margin,\n * padding and border.\n * Equivalent to jQuery's `$(el).outerWidth(true)`.\n * @param {!HTMLElement} element Element.\n * @return {number} The width.\n */\nexport function outerWidth(element) {\n let width = element.offsetWidth;\n const style = getComputedStyle(element);\n width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);\n\n return width;\n}\n\n/**\n * Get the current computed height for the given element including margin,\n * padding and border.\n * Equivalent to jQuery's `$(el).outerHeight(true)`.\n * @param {!HTMLElement} element Element.\n * @return {number} The height.\n */\nexport function outerHeight(element) {\n let height = element.offsetHeight;\n const style = getComputedStyle(element);\n height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);\n\n return height;\n}\n\n/**\n * @param {Node} newNode Node to replace old node\n * @param {Node} oldNode The node to be replaced\n */\nexport function replaceNode(newNode, oldNode) {\n const parent = oldNode.parentNode;\n if (parent) {\n parent.replaceChild(newNode, oldNode);\n }\n}\n\n/**\n * @param {Node} node The node to remove.\n * @return {Node|null} The node that was removed or null.\n */\nexport function removeNode(node) {\n return node && node.parentNode ? node.parentNode.removeChild(node) : null;\n}\n\n/**\n * @param {Node} node The node to remove the children from.\n */\nexport function removeChildren(node) {\n while (node.lastChild) {\n node.removeChild(node.lastChild);\n }\n}\n\n/**\n * Transform the children of a parent node so they match the\n * provided list of children. This function aims to efficiently\n * remove, add, and reorder child nodes while maintaining a simple\n * implementation (it is not guaranteed to minimize DOM operations).\n * @param {Node} node The parent node whose children need reworking.\n * @param {Array} children The desired children.\n */\nexport function replaceChildren(node, children) {\n const oldChildren = node.childNodes;\n\n for (let i = 0; true; ++i) {\n const oldChild = oldChildren[i];\n const newChild = children[i];\n\n // check if our work is done\n if (!oldChild && !newChild) {\n break;\n }\n\n // check if children match\n if (oldChild === newChild) {\n continue;\n }\n\n // check if a new child needs to be added\n if (!oldChild) {\n node.appendChild(newChild);\n continue;\n }\n\n // check if an old child needs to be removed\n if (!newChild) {\n node.removeChild(oldChild);\n --i;\n continue;\n }\n\n // reorder\n node.insertBefore(newChild, oldChild);\n }\n}\n","/**\n * @module ol/css\n */\n\n/**\n * @typedef {Object} FontParameters\n * @property {string} style Style.\n * @property {string} variant Variant.\n * @property {string} weight Weight.\n * @property {string} size Size.\n * @property {string} lineHeight LineHeight.\n * @property {string} family Family.\n * @property {Array} families Families.\n */\n\n/**\n * The CSS class for hidden feature.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_HIDDEN = 'ol-hidden';\n\n/**\n * The CSS class that we'll give the DOM elements to have them selectable.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_SELECTABLE = 'ol-selectable';\n\n/**\n * The CSS class that we'll give the DOM elements to have them unselectable.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_UNSELECTABLE = 'ol-unselectable';\n\n/**\n * The CSS class for unsupported feature.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_UNSUPPORTED = 'ol-unsupported';\n\n/**\n * The CSS class for controls.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_CONTROL = 'ol-control';\n\n/**\n * The CSS class that we'll give the DOM elements that are collapsed, i.e.\n * to those elements which usually can be expanded.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_COLLAPSED = 'ol-collapsed';\n\n/**\n * From https://stackoverflow.com/questions/10135697/regex-to-parse-any-css-font\n * @type {RegExp}\n */\nconst fontRegEx = new RegExp(\n [\n '^\\\\s*(?=(?:(?:[-a-z]+\\\\s*){0,2}(italic|oblique))?)',\n '(?=(?:(?:[-a-z]+\\\\s*){0,2}(small-caps))?)',\n '(?=(?:(?:[-a-z]+\\\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)',\n '(?:(?:normal|\\\\1|\\\\2|\\\\3)\\\\s*){0,3}((?:xx?-)?',\n '(?:small|large)|medium|smaller|larger|[\\\\.\\\\d]+(?:\\\\%|in|[cem]m|ex|p[ctx]))',\n '(?:\\\\s*\\\\/\\\\s*(normal|[\\\\.\\\\d]+(?:\\\\%|in|[cem]m|ex|p[ctx])?))',\n '?\\\\s*([-,\\\\\"\\\\\\'\\\\sa-z]+?)\\\\s*$',\n ].join(''),\n 'i'\n);\n/** @type {Array<'style'|'variant'|'weight'|'size'|'lineHeight'|'family'>} */\nconst fontRegExMatchIndex = [\n 'style',\n 'variant',\n 'weight',\n 'size',\n 'lineHeight',\n 'family',\n];\n\n/**\n * Get the list of font families from a font spec. Note that this doesn't work\n * for font families that have commas in them.\n * @param {string} fontSpec The CSS font property.\n * @return {FontParameters|null} The font parameters (or null if the input spec is invalid).\n */\nexport const getFontParameters = function (fontSpec) {\n const match = fontSpec.match(fontRegEx);\n if (!match) {\n return null;\n }\n const style = /** @type {FontParameters} */ ({\n lineHeight: 'normal',\n size: '1.2em',\n style: 'normal',\n weight: 'normal',\n variant: 'normal',\n });\n for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) {\n const value = match[i + 1];\n if (value !== undefined) {\n style[fontRegExMatchIndex[i]] = value;\n }\n }\n style.families = style.family.split(/,\\s?/);\n return style;\n};\n","/**\n * @module ol/render/canvas\n */\nimport BaseObject from '../Object.js';\nimport {WORKER_OFFSCREEN_CANVAS} from '../has.js';\nimport {clear} from '../obj.js';\nimport {createCanvasContext2D} from '../dom.js';\nimport {getFontParameters} from '../css.js';\n\n/**\n * @typedef {'Circle' | 'Image' | 'LineString' | 'Polygon' | 'Text' | 'Default'} BuilderType\n */\n\n/**\n * @typedef {Object} FillState\n * @property {import(\"../colorlike.js\").ColorLike} fillStyle FillStyle.\n */\n\n/**\n * @typedef Label\n * @property {number} width Width.\n * @property {number} height Height.\n * @property {Array} contextInstructions ContextInstructions.\n */\n\n/**\n * @typedef {Object} FillStrokeState\n * @property {import(\"../colorlike.js\").ColorLike} [currentFillStyle] Current FillStyle.\n * @property {import(\"../colorlike.js\").ColorLike} [currentStrokeStyle] Current StrokeStyle.\n * @property {CanvasLineCap} [currentLineCap] Current LineCap.\n * @property {Array} currentLineDash Current LineDash.\n * @property {number} [currentLineDashOffset] Current LineDashOffset.\n * @property {CanvasLineJoin} [currentLineJoin] Current LineJoin.\n * @property {number} [currentLineWidth] Current LineWidth.\n * @property {number} [currentMiterLimit] Current MiterLimit.\n * @property {number} [lastStroke] Last stroke.\n * @property {import(\"../colorlike.js\").ColorLike} [fillStyle] FillStyle.\n * @property {import(\"../colorlike.js\").ColorLike} [strokeStyle] StrokeStyle.\n * @property {CanvasLineCap} [lineCap] LineCap.\n * @property {Array} lineDash LineDash.\n * @property {number} [lineDashOffset] LineDashOffset.\n * @property {CanvasLineJoin} [lineJoin] LineJoin.\n * @property {number} [lineWidth] LineWidth.\n * @property {number} [miterLimit] MiterLimit.\n */\n\n/**\n * @typedef {Object} StrokeState\n * @property {CanvasLineCap} lineCap LineCap.\n * @property {Array} lineDash LineDash.\n * @property {number} lineDashOffset LineDashOffset.\n * @property {CanvasLineJoin} lineJoin LineJoin.\n * @property {number} lineWidth LineWidth.\n * @property {number} miterLimit MiterLimit.\n * @property {import(\"../colorlike.js\").ColorLike} strokeStyle StrokeStyle.\n */\n\n/**\n * @typedef {Object} TextState\n * @property {string} font Font.\n * @property {CanvasTextAlign} [textAlign] TextAlign.\n * @property {number} [repeat] Repeat.\n * @property {import(\"../style/Text.js\").TextJustify} [justify] Justify.\n * @property {CanvasTextBaseline} textBaseline TextBaseline.\n * @property {import(\"../style/Text.js\").TextPlacement} [placement] Placement.\n * @property {number} [maxAngle] MaxAngle.\n * @property {boolean} [overflow] Overflow.\n * @property {import(\"../style/Fill.js\").default} [backgroundFill] BackgroundFill.\n * @property {import(\"../style/Stroke.js\").default} [backgroundStroke] BackgroundStroke.\n * @property {import(\"../size.js\").Size} [scale] Scale.\n * @property {Array} [padding] Padding.\n */\n\n/**\n * @typedef {Object} SerializableInstructions\n * @property {Array<*>} instructions The rendering instructions.\n * @property {Array<*>} hitDetectionInstructions The rendering hit detection instructions.\n * @property {Array} coordinates The array of all coordinates.\n * @property {!Object} [textStates] The text states (decluttering).\n * @property {!Object} [fillStates] The fill states (decluttering).\n * @property {!Object} [strokeStates] The stroke states (decluttering).\n */\n\n/**\n * @typedef {Object} DeclutterImageWithText\n */\n\n/**\n * @const\n * @type {string}\n */\nexport const defaultFont = '10px sans-serif';\n\n/**\n * @const\n * @type {string}\n */\nexport const defaultFillStyle = '#000';\n\n/**\n * @const\n * @type {CanvasLineCap}\n */\nexport const defaultLineCap = 'round';\n\n/**\n * @const\n * @type {Array}\n */\nexport const defaultLineDash = [];\n\n/**\n * @const\n * @type {number}\n */\nexport const defaultLineDashOffset = 0;\n\n/**\n * @const\n * @type {CanvasLineJoin}\n */\nexport const defaultLineJoin = 'round';\n\n/**\n * @const\n * @type {number}\n */\nexport const defaultMiterLimit = 10;\n\n/**\n * @const\n * @type {import(\"../colorlike.js\").ColorLike}\n */\nexport const defaultStrokeStyle = '#000';\n\n/**\n * @const\n * @type {CanvasTextAlign}\n */\nexport const defaultTextAlign = 'center';\n\n/**\n * @const\n * @type {CanvasTextBaseline}\n */\nexport const defaultTextBaseline = 'middle';\n\n/**\n * @const\n * @type {Array}\n */\nexport const defaultPadding = [0, 0, 0, 0];\n\n/**\n * @const\n * @type {number}\n */\nexport const defaultLineWidth = 1;\n\n/**\n * @type {BaseObject}\n */\nexport const checkedFonts = new BaseObject();\n\n/**\n * @type {CanvasRenderingContext2D}\n */\nlet measureContext = null;\n\n/**\n * @type {string}\n */\nlet measureFont;\n\n/**\n * @type {!Object}\n */\nexport const textHeights = {};\n\n/**\n * Clears the label cache when a font becomes available.\n * @param {string} fontSpec CSS font spec.\n */\nexport const registerFont = (function () {\n const retries = 100;\n const size = '32px ';\n const referenceFonts = ['monospace', 'serif'];\n const len = referenceFonts.length;\n const text = 'wmytzilWMYTZIL@#/&?$%10\\uF013';\n let interval, referenceWidth;\n\n /**\n * @param {string} fontStyle Css font-style\n * @param {string} fontWeight Css font-weight\n * @param {*} fontFamily Css font-family\n * @return {boolean} Font with style and weight is available\n */\n function isAvailable(fontStyle, fontWeight, fontFamily) {\n let available = true;\n for (let i = 0; i < len; ++i) {\n const referenceFont = referenceFonts[i];\n referenceWidth = measureTextWidth(\n fontStyle + ' ' + fontWeight + ' ' + size + referenceFont,\n text\n );\n if (fontFamily != referenceFont) {\n const width = measureTextWidth(\n fontStyle +\n ' ' +\n fontWeight +\n ' ' +\n size +\n fontFamily +\n ',' +\n referenceFont,\n text\n );\n // If width and referenceWidth are the same, then the fallback was used\n // instead of the font we wanted, so the font is not available.\n available = available && width != referenceWidth;\n }\n }\n if (available) {\n return true;\n }\n return false;\n }\n\n function check() {\n let done = true;\n const fonts = checkedFonts.getKeys();\n for (let i = 0, ii = fonts.length; i < ii; ++i) {\n const font = fonts[i];\n if (checkedFonts.get(font) < retries) {\n if (isAvailable.apply(this, font.split('\\n'))) {\n clear(textHeights);\n // Make sure that loaded fonts are picked up by Safari\n measureContext = null;\n measureFont = undefined;\n checkedFonts.set(font, retries);\n } else {\n checkedFonts.set(font, checkedFonts.get(font) + 1, true);\n done = false;\n }\n }\n }\n if (done) {\n clearInterval(interval);\n interval = undefined;\n }\n }\n\n return function (fontSpec) {\n const font = getFontParameters(fontSpec);\n if (!font) {\n return;\n }\n const families = font.families;\n for (let i = 0, ii = families.length; i < ii; ++i) {\n const family = families[i];\n const key = font.style + '\\n' + font.weight + '\\n' + family;\n if (checkedFonts.get(key) === undefined) {\n checkedFonts.set(key, retries, true);\n if (!isAvailable(font.style, font.weight, family)) {\n checkedFonts.set(key, 0, true);\n if (interval === undefined) {\n interval = setInterval(check, 32);\n }\n }\n }\n }\n };\n})();\n\n/**\n * @param {string} font Font to use for measuring.\n * @return {import(\"../size.js\").Size} Measurement.\n */\nexport const measureTextHeight = (function () {\n /**\n * @type {HTMLDivElement}\n */\n let measureElement;\n return function (fontSpec) {\n let height = textHeights[fontSpec];\n if (height == undefined) {\n if (WORKER_OFFSCREEN_CANVAS) {\n const font = getFontParameters(fontSpec);\n const metrics = measureText(fontSpec, 'Žg');\n const lineHeight = isNaN(Number(font.lineHeight))\n ? 1.2\n : Number(font.lineHeight);\n height =\n lineHeight *\n (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent);\n } else {\n if (!measureElement) {\n measureElement = document.createElement('div');\n measureElement.innerHTML = 'M';\n measureElement.style.minHeight = '0';\n measureElement.style.maxHeight = 'none';\n measureElement.style.height = 'auto';\n measureElement.style.padding = '0';\n measureElement.style.border = 'none';\n measureElement.style.position = 'absolute';\n measureElement.style.display = 'block';\n measureElement.style.left = '-99999px';\n }\n measureElement.style.font = fontSpec;\n document.body.appendChild(measureElement);\n height = measureElement.offsetHeight;\n document.body.removeChild(measureElement);\n }\n textHeights[fontSpec] = height;\n }\n return height;\n };\n})();\n\n/**\n * @param {string} font Font.\n * @param {string} text Text.\n * @return {TextMetrics} Text metrics.\n */\nfunction measureText(font, text) {\n if (!measureContext) {\n measureContext = createCanvasContext2D(1, 1);\n }\n if (font != measureFont) {\n measureContext.font = font;\n measureFont = measureContext.font;\n }\n return measureContext.measureText(text);\n}\n\n/**\n * @param {string} font Font.\n * @param {string} text Text.\n * @return {number} Width.\n */\nexport function measureTextWidth(font, text) {\n return measureText(font, text).width;\n}\n\n/**\n * Measure text width using a cache.\n * @param {string} font The font.\n * @param {string} text The text to measure.\n * @param {Object} cache A lookup of cached widths by text.\n * @return {number} The text width.\n */\nexport function measureAndCacheTextWidth(font, text, cache) {\n if (text in cache) {\n return cache[text];\n }\n const width = text\n .split('\\n')\n .reduce((prev, curr) => Math.max(prev, measureTextWidth(font, curr)), 0);\n cache[text] = width;\n return width;\n}\n\n/**\n * @param {TextState} baseStyle Base style.\n * @param {Array} chunks Text chunks to measure.\n * @return {{width: number, height: number, widths: Array, heights: Array, lineWidths: Array}}} Text metrics.\n */\nexport function getTextDimensions(baseStyle, chunks) {\n const widths = [];\n const heights = [];\n const lineWidths = [];\n let width = 0;\n let lineWidth = 0;\n let height = 0;\n let lineHeight = 0;\n for (let i = 0, ii = chunks.length; i <= ii; i += 2) {\n const text = chunks[i];\n if (text === '\\n' || i === ii) {\n width = Math.max(width, lineWidth);\n lineWidths.push(lineWidth);\n lineWidth = 0;\n height += lineHeight;\n continue;\n }\n const font = chunks[i + 1] || baseStyle.font;\n const currentWidth = measureTextWidth(font, text);\n widths.push(currentWidth);\n lineWidth += currentWidth;\n const currentHeight = measureTextHeight(font);\n heights.push(currentHeight);\n lineHeight = Math.max(lineHeight, currentHeight);\n }\n return {width, height, widths, heights, lineWidths};\n}\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {number} rotation Rotation.\n * @param {number} offsetX X offset.\n * @param {number} offsetY Y offset.\n */\nexport function rotateAtOffset(context, rotation, offsetX, offsetY) {\n if (rotation !== 0) {\n context.translate(offsetX, offsetY);\n context.rotate(rotation);\n context.translate(-offsetX, -offsetY);\n }\n}\n\n/**\n * @param {CanvasRenderingContext2D} context Context.\n * @param {import(\"../transform.js\").Transform|null} transform Transform.\n * @param {number} opacity Opacity.\n * @param {Label|HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} labelOrImage Label.\n * @param {number} originX Origin X.\n * @param {number} originY Origin Y.\n * @param {number} w Width.\n * @param {number} h Height.\n * @param {number} x X.\n * @param {number} y Y.\n * @param {import(\"../size.js\").Size} scale Scale.\n */\nexport function drawImageOrLabel(\n context,\n transform,\n opacity,\n labelOrImage,\n originX,\n originY,\n w,\n h,\n x,\n y,\n scale\n) {\n context.save();\n\n if (opacity !== 1) {\n context.globalAlpha *= opacity;\n }\n if (transform) {\n context.transform.apply(context, transform);\n }\n\n if (/** @type {*} */ (labelOrImage).contextInstructions) {\n // label\n context.translate(x, y);\n context.scale(scale[0], scale[1]);\n executeLabelInstructions(/** @type {Label} */ (labelOrImage), context);\n } else if (scale[0] < 0 || scale[1] < 0) {\n // flipped image\n context.translate(x, y);\n context.scale(scale[0], scale[1]);\n context.drawImage(\n /** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ (\n labelOrImage\n ),\n originX,\n originY,\n w,\n h,\n 0,\n 0,\n w,\n h\n );\n } else {\n // if image not flipped translate and scale can be avoided\n context.drawImage(\n /** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ (\n labelOrImage\n ),\n originX,\n originY,\n w,\n h,\n x,\n y,\n w * scale[0],\n h * scale[1]\n );\n }\n\n context.restore();\n}\n\n/**\n * @param {Label} label Label.\n * @param {CanvasRenderingContext2D} context Context.\n */\nfunction executeLabelInstructions(label, context) {\n const contextInstructions = label.contextInstructions;\n for (let i = 0, ii = contextInstructions.length; i < ii; i += 2) {\n if (Array.isArray(contextInstructions[i + 1])) {\n context[contextInstructions[i]].apply(\n context,\n contextInstructions[i + 1]\n );\n } else {\n context[contextInstructions[i]] = contextInstructions[i + 1];\n }\n }\n}\n","/**\n * @module ol/style/RegularShape\n */\n\nimport ImageState from '../ImageState.js';\nimport ImageStyle from './Image.js';\nimport {asArray} from '../color.js';\nimport {asColorLike} from '../colorlike.js';\nimport {createCanvasContext2D} from '../dom.js';\nimport {\n defaultFillStyle,\n defaultLineCap,\n defaultLineJoin,\n defaultLineWidth,\n defaultMiterLimit,\n defaultStrokeStyle,\n} from '../render/canvas.js';\n\n/**\n * Specify radius for regular polygons, or radius1 and radius2 for stars.\n * @typedef {Object} Options\n * @property {import(\"./Fill.js\").default} [fill] Fill style.\n * @property {number} points Number of points for stars and regular polygons. In case of a polygon, the number of points\n * is the number of sides.\n * @property {number} [radius] Radius of a regular polygon.\n * @property {number} [radius1] First radius of a star. Ignored if radius is set.\n * @property {number} [radius2] Second radius of a star.\n * @property {number} [angle=0] Shape's angle in radians. A value of 0 will have one of the shape's points facing up.\n * @property {Array} [displacement=[0, 0]] Displacement of the shape in pixels.\n * Positive values will shift the shape right and up.\n * @property {import(\"./Stroke.js\").default} [stroke] Stroke style.\n * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).\n * @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view.\n * @property {number|import(\"../size.js\").Size} [scale=1] Scale. Unless two dimensional scaling is required a better\n * result may be obtained with appropriate settings for `radius`, `radius1` and `radius2`.\n * @property {\"declutter\"|\"obstacle\"|\"none\"|undefined} [declutterMode] Declutter mode.\n */\n\n/**\n * @typedef {Object} RenderOptions\n * @property {import(\"../colorlike.js\").ColorLike|undefined} strokeStyle StrokeStyle.\n * @property {number} strokeWidth StrokeWidth.\n * @property {number} size Size.\n * @property {CanvasLineCap} lineCap LineCap.\n * @property {Array|null} lineDash LineDash.\n * @property {number} lineDashOffset LineDashOffset.\n * @property {CanvasLineJoin} lineJoin LineJoin.\n * @property {number} miterLimit MiterLimit.\n */\n\n/**\n * @classdesc\n * Set regular shape style for vector features. The resulting shape will be\n * a regular polygon when `radius` is provided, or a star when `radius1` and\n * `radius2` are provided.\n * @api\n */\nclass RegularShape extends ImageStyle {\n /**\n * @param {Options} options Options.\n */\n constructor(options) {\n /**\n * @type {boolean}\n */\n const rotateWithView =\n options.rotateWithView !== undefined ? options.rotateWithView : false;\n\n super({\n opacity: 1,\n rotateWithView: rotateWithView,\n rotation: options.rotation !== undefined ? options.rotation : 0,\n scale: options.scale !== undefined ? options.scale : 1,\n displacement:\n options.displacement !== undefined ? options.displacement : [0, 0],\n declutterMode: options.declutterMode,\n });\n\n /**\n * @private\n * @type {Object}\n */\n this.canvases_;\n\n /**\n * @private\n * @type {HTMLCanvasElement|null}\n */\n this.hitDetectionCanvas_ = null;\n\n /**\n * @private\n * @type {import(\"./Fill.js\").default|null}\n */\n this.fill_ = options.fill !== undefined ? options.fill : null;\n\n /**\n * @private\n * @type {Array}\n */\n this.origin_ = [0, 0];\n\n /**\n * @private\n * @type {number}\n */\n this.points_ = options.points;\n\n /**\n * @protected\n * @type {number}\n */\n this.radius_ =\n options.radius !== undefined ? options.radius : options.radius1;\n\n /**\n * @private\n * @type {number|undefined}\n */\n this.radius2_ = options.radius2;\n\n /**\n * @private\n * @type {number}\n */\n this.angle_ = options.angle !== undefined ? options.angle : 0;\n\n /**\n * @private\n * @type {import(\"./Stroke.js\").default|null}\n */\n this.stroke_ = options.stroke !== undefined ? options.stroke : null;\n\n /**\n * @private\n * @type {import(\"../size.js\").Size}\n */\n this.size_;\n\n /**\n * @private\n * @type {RenderOptions}\n */\n this.renderOptions_;\n\n this.render();\n }\n\n /**\n * Clones the style.\n * @return {RegularShape} The cloned style.\n * @api\n */\n clone() {\n const scale = this.getScale();\n const style = new RegularShape({\n fill: this.getFill() ? this.getFill().clone() : undefined,\n points: this.getPoints(),\n radius: this.getRadius(),\n radius2: this.getRadius2(),\n angle: this.getAngle(),\n stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n rotation: this.getRotation(),\n rotateWithView: this.getRotateWithView(),\n scale: Array.isArray(scale) ? scale.slice() : scale,\n displacement: this.getDisplacement().slice(),\n declutterMode: this.getDeclutterMode(),\n });\n style.setOpacity(this.getOpacity());\n return style;\n }\n\n /**\n * Get the anchor point in pixels. The anchor determines the center point for the\n * symbolizer.\n * @return {Array} Anchor.\n * @api\n */\n getAnchor() {\n const size = this.size_;\n const displacement = this.getDisplacement();\n const scale = this.getScaleArray();\n // anchor is scaled by renderer but displacement should not be scaled\n // so divide by scale here\n return [\n size[0] / 2 - displacement[0] / scale[0],\n size[1] / 2 + displacement[1] / scale[1],\n ];\n }\n\n /**\n * Get the angle used in generating the shape.\n * @return {number} Shape's rotation in radians.\n * @api\n */\n getAngle() {\n return this.angle_;\n }\n\n /**\n * Get the fill style for the shape.\n * @return {import(\"./Fill.js\").default|null} Fill style.\n * @api\n */\n getFill() {\n return this.fill_;\n }\n\n /**\n * Set the fill style.\n * @param {import(\"./Fill.js\").default|null} fill Fill style.\n * @api\n */\n setFill(fill) {\n this.fill_ = fill;\n this.render();\n }\n\n /**\n * @return {HTMLCanvasElement} Image element.\n */\n getHitDetectionImage() {\n if (!this.hitDetectionCanvas_) {\n this.hitDetectionCanvas_ = this.createHitDetectionCanvas_(\n this.renderOptions_\n );\n }\n return this.hitDetectionCanvas_;\n }\n\n /**\n * Get the image icon.\n * @param {number} pixelRatio Pixel ratio.\n * @return {HTMLCanvasElement} Image or Canvas element.\n * @api\n */\n getImage(pixelRatio) {\n let image = this.canvases_[pixelRatio];\n if (!image) {\n const renderOptions = this.renderOptions_;\n const context = createCanvasContext2D(\n renderOptions.size * pixelRatio,\n renderOptions.size * pixelRatio\n );\n this.draw_(renderOptions, context, pixelRatio);\n\n image = context.canvas;\n this.canvases_[pixelRatio] = image;\n }\n return image;\n }\n\n /**\n * Get the image pixel ratio.\n * @param {number} pixelRatio Pixel ratio.\n * @return {number} Pixel ratio.\n */\n getPixelRatio(pixelRatio) {\n return pixelRatio;\n }\n\n /**\n * @return {import(\"../size.js\").Size} Image size.\n */\n getImageSize() {\n return this.size_;\n }\n\n /**\n * @return {import(\"../ImageState.js\").default} Image state.\n */\n getImageState() {\n return ImageState.LOADED;\n }\n\n /**\n * Get the origin of the symbolizer.\n * @return {Array} Origin.\n * @api\n */\n getOrigin() {\n return this.origin_;\n }\n\n /**\n * Get the number of points for generating the shape.\n * @return {number} Number of points for stars and regular polygons.\n * @api\n */\n getPoints() {\n return this.points_;\n }\n\n /**\n * Get the (primary) radius for the shape.\n * @return {number} Radius.\n * @api\n */\n getRadius() {\n return this.radius_;\n }\n\n /**\n * Get the secondary radius for the shape.\n * @return {number|undefined} Radius2.\n * @api\n */\n getRadius2() {\n return this.radius2_;\n }\n\n /**\n * Get the size of the symbolizer (in pixels).\n * @return {import(\"../size.js\").Size} Size.\n * @api\n */\n getSize() {\n return this.size_;\n }\n\n /**\n * Get the stroke style for the shape.\n * @return {import(\"./Stroke.js\").default|null} Stroke style.\n * @api\n */\n getStroke() {\n return this.stroke_;\n }\n\n /**\n * Set the stroke style.\n * @param {import(\"./Stroke.js\").default|null} stroke Stroke style.\n * @api\n */\n setStroke(stroke) {\n this.stroke_ = stroke;\n this.render();\n }\n\n /**\n * @param {function(import(\"../events/Event.js\").default): void} listener Listener function.\n */\n listenImageChange(listener) {}\n\n /**\n * Load not yet loaded URI.\n */\n load() {}\n\n /**\n * @param {function(import(\"../events/Event.js\").default): void} listener Listener function.\n */\n unlistenImageChange(listener) {}\n\n /**\n * Calculate additional canvas size needed for the miter.\n * @param {string} lineJoin Line join\n * @param {number} strokeWidth Stroke width\n * @param {number} miterLimit Miter limit\n * @return {number} Additional canvas size needed\n * @private\n */\n calculateLineJoinSize_(lineJoin, strokeWidth, miterLimit) {\n if (\n strokeWidth === 0 ||\n this.points_ === Infinity ||\n (lineJoin !== 'bevel' && lineJoin !== 'miter')\n ) {\n return strokeWidth;\n }\n // m | ^\n // i | |\\ .\n // t >| #\\\n // e | |\\ \\ .\n // r \\s\\\n // | \\t\\ . .\n // \\r\\ . .\n // | \\o\\ . . . . .\n // e \\k\\ . . . .\n // | \\e\\ . . . . .\n // d \\ \\ . . . .\n // | _ _a_ _\\# . . .\n // r1 / ` . .\n // | . .\n // b / . .\n // | . .\n // / r2 . .\n // | . .\n // / . .\n // |α . .\n // / . .\n // ° center\n let r1 = this.radius_;\n let r2 = this.radius2_ === undefined ? r1 : this.radius2_;\n if (r1 < r2) {\n const tmp = r1;\n r1 = r2;\n r2 = tmp;\n }\n const points =\n this.radius2_ === undefined ? this.points_ : this.points_ * 2;\n const alpha = (2 * Math.PI) / points;\n const a = r2 * Math.sin(alpha);\n const b = Math.sqrt(r2 * r2 - a * a);\n const d = r1 - b;\n const e = Math.sqrt(a * a + d * d);\n const miterRatio = e / a;\n if (lineJoin === 'miter' && miterRatio <= miterLimit) {\n return miterRatio * strokeWidth;\n }\n // Calculate the distance from center to the stroke corner where\n // it was cut short because of the miter limit.\n // l\n // ----+---- <= distance from center to here is maxr\n // /####|k ##\\\n // /#####^#####\\\n // /#### /+\\# s #\\\n // /### h/+++\\# t #\\\n // /### t/+++++\\# r #\\\n // /### a/+++++++\\# o #\\\n // /### p/++ fill +\\# k #\\\n ///#### /+++++^+++++\\# e #\\\n //#####/+++++/+\\+++++\\#####\\\n const k = strokeWidth / 2 / miterRatio;\n const l = (strokeWidth / 2) * (d / e);\n const maxr = Math.sqrt((r1 + k) * (r1 + k) + l * l);\n const bevelAdd = maxr - r1;\n if (this.radius2_ === undefined || lineJoin === 'bevel') {\n return bevelAdd * 2;\n }\n // If outer miter is over the miter limit the inner miter may reach through the\n // center and be longer than the bevel, same calculation as above but swap r1 / r2.\n const aa = r1 * Math.sin(alpha);\n const bb = Math.sqrt(r1 * r1 - aa * aa);\n const dd = r2 - bb;\n const ee = Math.sqrt(aa * aa + dd * dd);\n const innerMiterRatio = ee / aa;\n if (innerMiterRatio <= miterLimit) {\n const innerLength = (innerMiterRatio * strokeWidth) / 2 - r2 - r1;\n return 2 * Math.max(bevelAdd, innerLength);\n }\n return bevelAdd * 2;\n }\n\n /**\n * @return {RenderOptions} The render options\n * @protected\n */\n createRenderOptions() {\n let lineCap = defaultLineCap;\n let lineJoin = defaultLineJoin;\n let miterLimit = 0;\n let lineDash = null;\n let lineDashOffset = 0;\n let strokeStyle;\n let strokeWidth = 0;\n\n if (this.stroke_) {\n strokeStyle = asColorLike(this.stroke_.getColor() ?? defaultStrokeStyle);\n strokeWidth = this.stroke_.getWidth() ?? defaultLineWidth;\n lineDash = this.stroke_.getLineDash();\n lineDashOffset = this.stroke_.getLineDashOffset() ?? 0;\n lineJoin = this.stroke_.getLineJoin() ?? defaultLineJoin;\n lineCap = this.stroke_.getLineCap() ?? defaultLineCap;\n miterLimit = this.stroke_.getMiterLimit() ?? defaultMiterLimit;\n }\n\n const add = this.calculateLineJoinSize_(lineJoin, strokeWidth, miterLimit);\n const maxRadius = Math.max(this.radius_, this.radius2_ || 0);\n const size = Math.ceil(2 * maxRadius + add);\n\n return {\n strokeStyle: strokeStyle,\n strokeWidth: strokeWidth,\n size: size,\n lineCap: lineCap,\n lineDash: lineDash,\n lineDashOffset: lineDashOffset,\n lineJoin: lineJoin,\n miterLimit: miterLimit,\n };\n }\n\n /**\n * @protected\n */\n render() {\n this.renderOptions_ = this.createRenderOptions();\n const size = this.renderOptions_.size;\n this.canvases_ = {};\n this.hitDetectionCanvas_ = null;\n this.size_ = [size, size];\n }\n\n /**\n * @private\n * @param {RenderOptions} renderOptions Render options.\n * @param {CanvasRenderingContext2D} context The rendering context.\n * @param {number} pixelRatio The pixel ratio.\n */\n draw_(renderOptions, context, pixelRatio) {\n context.scale(pixelRatio, pixelRatio);\n // set origin to canvas center\n context.translate(renderOptions.size / 2, renderOptions.size / 2);\n\n this.createPath_(context);\n\n if (this.fill_) {\n let color = this.fill_.getColor();\n if (color === null) {\n color = defaultFillStyle;\n }\n context.fillStyle = asColorLike(color);\n context.fill();\n }\n if (renderOptions.strokeStyle) {\n context.strokeStyle = renderOptions.strokeStyle;\n context.lineWidth = renderOptions.strokeWidth;\n if (renderOptions.lineDash) {\n context.setLineDash(renderOptions.lineDash);\n context.lineDashOffset = renderOptions.lineDashOffset;\n }\n context.lineCap = renderOptions.lineCap;\n context.lineJoin = renderOptions.lineJoin;\n context.miterLimit = renderOptions.miterLimit;\n context.stroke();\n }\n }\n\n /**\n * @private\n * @param {RenderOptions} renderOptions Render options.\n * @return {HTMLCanvasElement} Canvas containing the icon\n */\n createHitDetectionCanvas_(renderOptions) {\n let context;\n if (this.fill_) {\n let color = this.fill_.getColor();\n\n // determine if fill is transparent (or pattern or gradient)\n let opacity = 0;\n if (typeof color === 'string') {\n color = asArray(color);\n }\n if (color === null) {\n opacity = 1;\n } else if (Array.isArray(color)) {\n opacity = color.length === 4 ? color[3] : 1;\n }\n if (opacity === 0) {\n // if a transparent fill style is set, create an extra hit-detection image\n // with a default fill style\n context = createCanvasContext2D(renderOptions.size, renderOptions.size);\n this.drawHitDetectionCanvas_(renderOptions, context);\n }\n }\n return context ? context.canvas : this.getImage(1);\n }\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} context The context to draw in.\n */\n createPath_(context) {\n let points = this.points_;\n const radius = this.radius_;\n if (points === Infinity) {\n context.arc(0, 0, radius, 0, 2 * Math.PI);\n } else {\n const radius2 = this.radius2_ === undefined ? radius : this.radius2_;\n if (this.radius2_ !== undefined) {\n points *= 2;\n }\n const startAngle = this.angle_ - Math.PI / 2;\n const step = (2 * Math.PI) / points;\n for (let i = 0; i < points; i++) {\n const angle0 = startAngle + i * step;\n const radiusC = i % 2 === 0 ? radius : radius2;\n context.lineTo(radiusC * Math.cos(angle0), radiusC * Math.sin(angle0));\n }\n context.closePath();\n }\n }\n\n /**\n * @private\n * @param {RenderOptions} renderOptions Render options.\n * @param {CanvasRenderingContext2D} context The context.\n */\n drawHitDetectionCanvas_(renderOptions, context) {\n // set origin to canvas center\n context.translate(renderOptions.size / 2, renderOptions.size / 2);\n\n this.createPath_(context);\n\n context.fillStyle = defaultFillStyle;\n context.fill();\n if (renderOptions.strokeStyle) {\n context.strokeStyle = renderOptions.strokeStyle;\n context.lineWidth = renderOptions.strokeWidth;\n if (renderOptions.lineDash) {\n context.setLineDash(renderOptions.lineDash);\n context.lineDashOffset = renderOptions.lineDashOffset;\n }\n context.lineJoin = renderOptions.lineJoin;\n context.miterLimit = renderOptions.miterLimit;\n context.stroke();\n }\n }\n}\n\nexport default RegularShape;\n","/**\n * @module ol/style/Circle\n */\n\nimport RegularShape from './RegularShape.js';\n\n/**\n * @typedef {Object} Options\n * @property {import(\"./Fill.js\").default} [fill] Fill style.\n * @property {number} radius Circle radius.\n * @property {import(\"./Stroke.js\").default} [stroke] Stroke style.\n * @property {Array} [displacement=[0,0]] displacement\n * @property {number|import(\"../size.js\").Size} [scale=1] Scale. A two dimensional scale will produce an ellipse.\n * Unless two dimensional scaling is required a better result may be obtained with an appropriate setting for `radius`.\n * @property {number} [rotation=0] Rotation in radians\n * (positive rotation clockwise, meaningful only when used in conjunction with a two dimensional scale).\n * @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view\n * (meaningful only when used in conjunction with a two dimensional scale).\n * @property {\"declutter\"|\"obstacle\"|\"none\"|undefined} [declutterMode] Declutter mode\n */\n\n/**\n * @classdesc\n * Set circle style for vector features.\n * @api\n */\nclass CircleStyle extends RegularShape {\n /**\n * @param {Options} [options] Options.\n */\n constructor(options) {\n options = options ? options : {radius: 5};\n\n super({\n points: Infinity,\n fill: options.fill,\n radius: options.radius,\n stroke: options.stroke,\n scale: options.scale !== undefined ? options.scale : 1,\n rotation: options.rotation !== undefined ? options.rotation : 0,\n rotateWithView:\n options.rotateWithView !== undefined ? options.rotateWithView : false,\n displacement:\n options.displacement !== undefined ? options.displacement : [0, 0],\n declutterMode: options.declutterMode,\n });\n }\n\n /**\n * Clones the style.\n * @return {CircleStyle} The cloned style.\n * @api\n */\n clone() {\n const scale = this.getScale();\n const style = new CircleStyle({\n fill: this.getFill() ? this.getFill().clone() : undefined,\n stroke: this.getStroke() ? this.getStroke().clone() : undefined,\n radius: this.getRadius(),\n scale: Array.isArray(scale) ? scale.slice() : scale,\n rotation: this.getRotation(),\n rotateWithView: this.getRotateWithView(),\n displacement: this.getDisplacement().slice(),\n declutterMode: this.getDeclutterMode(),\n });\n style.setOpacity(this.getOpacity());\n return style;\n }\n\n /**\n * Set the circle radius.\n *\n * @param {number} radius Circle radius.\n * @api\n */\n setRadius(radius) {\n this.radius_ = radius;\n this.render();\n }\n}\n\nexport default CircleStyle;\n","/**\n * @module ol/style/Style\n */\n\nimport CircleStyle from './Circle.js';\nimport Fill from './Fill.js';\nimport Stroke from './Stroke.js';\nimport {assert} from '../asserts.js';\n\n/**\n * A function that takes an {@link module:ol/Feature~Feature} and a `{number}`\n * representing the view's resolution. The function should return a\n * {@link module:ol/style/Style~Style} or an array of them. This way e.g. a\n * vector layer can be styled. If the function returns `undefined`, the\n * feature will not be rendered.\n *\n * @typedef {function(import(\"../Feature.js\").FeatureLike, number):(Style|Array