UNPKG

mapshaper

Version:

A tool for editing vector datasets for mapping and GIS.

1,863 lines (1,650 loc) 1.47 MB
(function () { var utils = /*#__PURE__*/Object.freeze({ __proto__: null, get addThousandsSep () { return addThousandsSep; }, get addslashes () { return addslashes; }, get arrayToIndex () { return arrayToIndex; }, get clamp () { return clamp; }, get cleanNumericString () { return cleanNumericString; }, get contains () { return contains; }, get copyElements () { return copyElements; }, get countValues () { return countValues; }, get createBuffer () { return createBuffer; }, get default () { return utils; }, get defaults () { return defaults; }, get difference () { return difference; }, get endsWith () { return endsWith; }, get every () { return every; }, get expandoBuffer () { return expandoBuffer; }, get extend () { return extend$1; }, get extendBuffer () { return extendBuffer; }, get find () { return find; }, get findMedian () { return findMedian; }, get findQuantile () { return findQuantile; }, get findRankByValue () { return findRankByValue; }, get findStringPrefix () { return findStringPrefix; }, get findValueByPct () { return findValueByPct; }, get findValueByRank () { return findValueByRank; }, get forEach () { return forEach; }, get forEachProperty () { return forEachProperty; }, get format () { return format; }, get formatDateISO () { return formatDateISO; }, get formatIntlNumber () { return formatIntlNumber; }, get formatNumber () { return formatNumber$1; }, get formatNumberForDisplay () { return formatNumberForDisplay; }, get formatVersionedName () { return formatVersionedName; }, get formatter () { return formatter; }, get genericSort () { return genericSort; }, get getArrayBounds () { return getArrayBounds; }, get getGenericComparator () { return getGenericComparator; }, get getKeyComparator () { return getKeyComparator; }, get getSortedIds () { return getSortedIds; }, get getUniqueName () { return getUniqueName; }, get groupBy () { return groupBy; }, get htmlEscape () { return htmlEscape; }, get indexOf () { return indexOf; }, get indexOn () { return indexOn; }, get inherit () { return inherit; }, get initializeArray () { return initializeArray; }, get intersection () { return intersection; }, get isArray () { return isArray; }, get isArrayLike () { return isArrayLike; }, get isBoolean () { return isBoolean; }, get isDate () { return isDate; }, get isEven () { return isEven; }, get isFiniteNumber () { return isFiniteNumber; }, get isFunction () { return isFunction; }, get isInteger () { return isInteger; }, get isNonNegNumber () { return isNonNegNumber; }, get isNumber () { return isNumber; }, get isObject () { return isObject; }, get isOdd () { return isOdd$1; }, get isPromise () { return isPromise; }, get isString () { return isString; }, get isValidNumber () { return isValidNumber; }, get lpad () { return lpad; }, get ltrim () { return ltrim; }, get mean () { return mean; }, get merge () { return merge; }, get mergeNames () { return mergeNames; }, get numToStr () { return numToStr; }, get parseIntlNumber () { return parseIntlNumber; }, get parseNumber () { return parseNumber; }, get parsePercent () { return parsePercent; }, get parseString () { return parseString; }, get pickOne () { return pickOne; }, get pluck () { return pluck; }, get pluralSuffix () { return pluralSuffix; }, get promisify () { return promisify; }, get quicksort () { return quicksort$1; }, get quicksortPartition () { return quicksortPartition; }, get range () { return range; }, get reduceAsync () { return reduceAsync; }, get regexEscape () { return regexEscape; }, get reorderArray () { return reorderArray; }, get repeat () { return repeat; }, get repeatString () { return repeatString; }, get replaceArray () { return replaceArray; }, get rpad () { return rpad; }, get rtrim () { return rtrim; }, get shuffle () { return shuffle; }, get some () { return some; }, get sortArrayIndex () { return sortArrayIndex; }, get sortOn () { return sortOn; }, get splitLines () { return splitLines; }, get sum () { return sum$1; }, get toArray () { return toArray; }, get toBuffer () { return toBuffer; }, get trim () { return trim; }, get trimQuotes () { return trimQuotes; }, get uniq () { return uniq; }, get uniqifyNames () { return uniqifyNames; }, get wildcardToRegExp () { return wildcardToRegExp; } }); // This module provides a way for multiple jobs to run together asynchronously // while keeping job-level context variables (like "defs") separate. var stash = {}; function stashVar(key, val) { if (key in stash) { error('Tried to replace a stashed variable:', key); } stash[key] = val; } function getStashedVar(key) { if (key in stash === false) { return undefined; // to support running commands in tests // error('Tried to read a nonexistent variable from the stash:', key); } return stash[key]; } function clearStash() { stash = {}; } var Stash = /*#__PURE__*/Object.freeze({ __proto__: null, clearStash: clearStash, getStashedVar: getStashedVar, stashVar: stashVar }); // Several dependencies are loaded via require() var f; if (typeof require == 'function') { // Node.js context: native require() function f = require; } else if (typeof window == 'object' && window.modules) { // running in web GUI f = function(name) { return window.modules[name]; }; } else { // stub to avoid runtime error in a handful of tests f = function() {}; } var require$1 = f; // Fall back to browserify's Buffer polyfill var B$3 = typeof Buffer != 'undefined' ? Buffer : require$1('buffer').Buffer; var uniqCount = 0; function getUniqueName(prefix) { return (prefix || "__id_") + (++uniqCount); } function isFunction(obj) { return typeof obj == 'function'; } function isPromise(arg) { return arg ? isFunction(arg.then) : false; } function isObject(obj) { return obj === Object(obj); // via underscore } function clamp(val, min, max) { return val < min ? min : (val > max ? max : val); } function isArray(obj) { return Array.isArray(obj); } // Is obj a valid number or NaN? (test if obj is type number) function isNumber(obj) { return obj != null && obj.constructor == Number; } function isValidNumber(val) { return isNumber(val) && !isNaN(val); } // Similar to isFinite() but does not coerce strings or other types function isFiniteNumber(val) { return isValidNumber(val) && val !== Infinity && val !== -Infinity; } // This uses type conversion // export function isFiniteNumber(val) { // return val > -Infinity && val < Infinity; // } function isNonNegNumber(val) { return isNumber(val) && val >= 0; } function isInteger(obj) { return isNumber(obj) && ((obj | 0) === obj); } function isEven(obj) { return (obj % 2) === 0; } function isOdd$1(obj) { return (obj % 2) === 1; } function isString(obj) { return obj != null && obj.toString === String.prototype.toString; // TODO: replace w/ something better. } function isDate(obj) { return !!obj && obj.getTime === Date.prototype.getTime; } function isBoolean(obj) { return obj === true || obj === false; } function formatDateISO(d) { if (!isDate(d)) return ''; return d.toISOString().replace(':00.000Z', 'Z'); } // Convert an array-like object to an Array, or make a copy if @obj is an Array function toArray(obj) { var arr; if (!isArrayLike(obj)) error("toArray() requires an array-like object"); try { arr = Array.prototype.slice.call(obj, 0); // breaks in ie8 } catch(e) { // support ie8 arr = []; for (var i=0, n=obj.length; i<n; i++) { arr[i] = obj[i]; } } return arr; } // Array like: has length property, is numerically indexed and mutable. // TODO: try to detect objects with length property but no indexed data elements function isArrayLike(obj) { if (!obj) return false; if (isArray(obj)) return true; if (isString(obj)) return false; if (obj.length === 0 || obj.length > 0) return true; return false; } // See https://raw.github.com/kvz/phpjs/master/functions/strings/addslashes.js function addslashes(str) { return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0'); } // Escape a literal string to use in a regexp. // Ref.: http://simonwillison.net/2006/Jan/20/escape/ function regexEscape(str) { return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); } // See https://github.com/janl/mustache.js/blob/master/mustache.js var entityMap = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;' }; function htmlEscape(s) { return String(s).replace(/[&<>"'/]/g, function(s) { return entityMap[s]; }); } function defaults(dest) { for (var i=1, n=arguments.length; i<n; i++) { var src = arguments[i] || {}; for (var key in src) { if (key in dest === false && src.hasOwnProperty(key)) { dest[key] = src[key]; } } } return dest; } function extend$1(o) { var dest = o || {}, n = arguments.length, key, i, src; for (i=1; i<n; i++) { src = arguments[i] || {}; for (key in src) { if (src.hasOwnProperty(key)) { dest[key] = src[key]; } } } return dest; } // Pseudoclassical inheritance // // Inherit from a Parent function: // inherit(Child, Parent); // Call parent's constructor (inside child constructor): // this.__super__([args...]); function inherit(targ, src) { var f = function() { if (this.__super__ == f) { // add __super__ of parent to front of lookup chain // so parent class constructor can call its parent using this.__super__ this.__super__ = src.prototype.__super__; // call parent constructor function. this.__super__ now points to parent-of-parent src.apply(this, arguments); // remove temp __super__, expose targ.prototype.__super__ again delete this.__super__; } }; f.prototype = src.prototype || src; // added || src to allow inheriting from objects as well as functions // Extend targ prototype instead of wiping it out -- // in case inherit() is called after targ.prototype = {stuff}; statement targ.prototype = extend$1(new f(), targ.prototype); // targ.prototype.constructor = targ; targ.prototype.__super__ = f; } function promisify(asyncFn) { return function() { var args = toArray(arguments); return new Promise((resolve, reject) => { var cb = function(err, data) { if (err) reject(err); else resolve(data); }; args.push(cb); asyncFn.apply(this, args); }); }; } // Call @iter on each member of an array (similar to Array#reduce(iter)) // iter: function(memo, item, callback) // Call @done when all members have been processed or if an error occurs // done: function(err, memo) // @memo: Initial value // function reduceAsync(arr, memo, iter, done) { var call = typeof setImmediate == 'undefined' ? setTimeout : setImmediate; var i=0; next(null, memo); function next(err, memo) { // Detach next operation from call stack to prevent overflow // Don't use setTimeout(, 0) if setImmediate is available // (setTimeout() can introduce a long delay if previous operation was slow, // as of Node 0.10.32 -- a bug?) if (err) { return done(err, null); } call(function() { if (i < arr.length === false) { done(null, memo); } else { iter(memo, arr[i++], next); } }, 0); } } // Append elements of @src array to @dest array function merge(dest, src) { if (!isArray(dest) || !isArray(src)) { error("Usage: merge(destArray, srcArray);"); } for (var i=0, n=src.length; i<n; i++) { dest.push(src[i]); } return dest; } // Returns elements in arr and not in other // (similar to underscore diff) function difference(arr, other) { var index = arrayToIndex(other); return arr.filter(function(el) { return !Object.prototype.hasOwnProperty.call(index, el); }); } // Return the intersection of two arrays function intersection(a, b) { return a.filter(function(el) { return b.includes(el); }); } function indexOf(arr, item) { var nan = item !== item; for (var i = 0, len = arr.length || 0; i < len; i++) { if (arr[i] === item) return i; if (nan && arr[i] !== arr[i]) return i; } return -1; } // Test a string or array-like object for existence of substring or element function contains(container, item) { if (isString(container)) { return container.indexOf(item) != -1; } else if (isArrayLike(container)) { return indexOf(container, item) != -1; } error("Expected Array or String argument"); } function some(arr, test) { return arr.reduce(function(val, item) { return val || test(item); // TODO: short-circuit? }, false); } function every(arr, test) { return arr.reduce(function(val, item) { return val && test(item); }, true); } function find(arr, test, ctx) { var matches = arr.filter(test, ctx); return matches.length === 0 ? null : matches[0]; } function range(len, start, inc) { var arr = [], v = start === void 0 ? 0 : start, i = inc === void 0 ? 1 : inc; while(len--) { arr.push(v); v += i; } return arr; } function repeat(times, func) { var values = [], val; for (var i=0; i<times; i++) { val = func(i); if (val !== void 0) { values[i] = val; } } return values.length > 0 ? values : void 0; } // Calc sum, skip falsy and NaN values // Assumes: no other non-numeric objects in array // function sum$1(arr, info) { if (!isArrayLike(arr)) error ("sum() expects an array, received:", arr); var tot = 0, nan = 0, val; for (var i=0, n=arr.length; i<n; i++) { val = arr[i]; if (val) { tot += val; } else if (isNaN(val)) { nan++; } } if (info) { info.nan = nan; } return tot; } // Calculate min and max values of an array, ignoring NaN values function getArrayBounds(arr) { var min = Infinity, max = -Infinity, nan = 0, val; for (var i=0, len=arr.length; i<len; i++) { val = arr[i]; if (val !== val) nan++; if (val < min) min = val; if (val > max) max = val; } return { min: min, max: max, nan: nan }; } // export function uniq(src) { // var index = {}; // return src.reduce(function(memo, el) { // if (el in index === false) { // index[el] = true; // memo.push(el); // } // return memo; // }, []); // } function uniq(src) { var index = new Set(); var arr = []; var item; for (var i=0, n=src.length; i<n; i++) { item = src[i]; if (!index.has(item)) { arr.push(item); index.add(item); } } return arr; } function pluck(arr, key) { return arr.map(function(obj) { return obj[key]; }); } function countValues(arr) { return arr.reduce(function(memo, val) { memo[val] = (val in memo) ? memo[val] + 1 : 1; return memo; }, {}); } function indexOn(arr, k) { return arr.reduce(function(index, o) { index[o[k]] = o; return index; }, {}); } function groupBy(arr, k) { return arr.reduce(function(index, o) { var keyval = o[k]; if (keyval in index) { index[keyval].push(o); } else { index[keyval] = [o]; } return index; }, {}); } function arrayToIndex(arr, val) { var init = arguments.length > 1; return arr.reduce(function(index, key) { index[key] = init ? val : true; return index; }, {}); } // Support for iterating over array-like objects, like typed arrays function forEach(arr, func, ctx) { if (!isArrayLike(arr)) { throw new Error("#forEach() takes an array-like argument. " + arr); } for (var i=0, n=arr.length; i < n; i++) { func.call(ctx, arr[i], i); } } function forEachProperty(o, func, ctx) { Object.keys(o).forEach(function(key) { func.call(ctx, o[key], key); }); } function initializeArray(arr, init) { for (var i=0, len=arr.length; i<len; i++) { arr[i] = init; } return arr; } function replaceArray(arr, arr2) { arr.splice(0, arr.length); for (var i=0, n=arr2.length; i<n; i++) { arr.push(arr2[i]); } } function repeatString(src, n) { var str = ""; for (var i=0; i<n; i++) str += src; return str; } function splitLines(str) { return str.split(/\r?\n/); } function pluralSuffix(count) { return count != 1 ? 's' : ''; } function endsWith(str, ending) { return str.indexOf(ending, str.length - ending.length) !== -1; } function lpad(str, size, pad) { pad = pad || ' '; str = String(str); return repeatString(pad, size - str.length) + str; } function rpad(str, size, pad) { pad = pad || ' '; str = String(str); return str + repeatString(pad, size - str.length); } function trim(str) { return ltrim(rtrim(str)); } var ltrimRxp = /^\s+/; function ltrim(str) { return str.replace(ltrimRxp, ''); } var rtrimRxp = /\s+$/; function rtrim(str) { return str.replace(rtrimRxp, ''); } function addThousandsSep(str) { var fmt = '', start = str[0] == '-' ? 1 : 0, dec = str.indexOf('.'), end = str.length, ins = (dec == -1 ? end : dec) - 3; while (ins > start) { fmt = ',' + str.substring(ins, end) + fmt; end = ins; ins -= 3; } return str.substring(0, end) + fmt; } function numToStr(num, decimals) { return decimals >= 0 ? num.toFixed(decimals) : String(num); } function formatNumber$1(val) { return val + ''; } function formatIntlNumber(val) { var str = formatNumber$1(val); return '"' + str.replace('.', ',') + '"'; // need to quote if comma-delimited } function formatNumberForDisplay(num, decimals, nullStr, showPos) { var fmt; if (isNaN(num)) { fmt = nullStr || '-'; } else { fmt = numToStr(num, decimals); fmt = addThousandsSep(fmt); if (showPos && parseFloat(fmt) > 0) { fmt = "+" + fmt; } } return fmt; } function shuffle(arr) { var tmp, i, j; for (i = arr.length - 1; i > 0; i--) { j = Math.floor(Math.random() * (i + 1)); tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } } function pickOne(arr) { return arr[Math.floor(Math.random() * arr.length)]; } // Sort an array of objects based on one or more properties. // Usage: sortOn(array, key1, asc?[, key2, asc? ...]) // function sortOn(arr) { var comparators = []; for (var i=1; i<arguments.length; i+=2) { comparators.push(getKeyComparator(arguments[i], arguments[i+1])); } arr.sort(function(a, b) { var cmp = 0, i = 0, n = comparators.length; while (i < n && cmp === 0) { cmp = comparators[i](a, b); i++; } return cmp; }); return arr; } // Sort array of values that can be compared with < > operators (strings, numbers) // null, undefined and NaN are sorted to the end of the array // default order is ascending // function genericSort(arr, ascending) { var compare = getGenericComparator(ascending); Array.prototype.sort.call(arr, compare); return arr; } function getSortedIds(arr, asc) { var ids = range(arr.length); sortArrayIndex(ids, arr, asc); return ids; } function sortArrayIndex(ids, arr, asc) { var compare = getGenericComparator(asc); ids.sort(function(i, j) { // added i, j comparison to guarantee that sort is stable var cmp = compare(arr[i], arr[j]); return cmp > 0 || cmp === 0 && i > j ? 1 : -1; }); } function reorderArray(arr, idxs) { var len = idxs.length; var arr2 = []; for (var i=0; i<len; i++) { var idx = idxs[i]; if (idx < 0 || idx >= len) error("Out-of-bounds array idx"); arr2[i] = arr[idx]; } replaceArray(arr, arr2); } function getKeyComparator(key, asc) { var compare = getGenericComparator(asc); return function(a, b) { return compare(a[key], b[key]); }; } function getGenericComparator(asc) { asc = asc !== false && asc != 'descending'; // ascending is the default return function(a, b) { var retn = 0; if (b == null) { retn = a == null ? 0 : -1; } else if (a == null) { retn = 1; } else if (a < b) { retn = asc ? -1 : 1; } else if (a > b) { retn = asc ? 1 : -1; } else if (a !== a) { retn = 1; } else if (b !== b) { retn = -1; } return retn; }; } // Generic in-place sort (null, NaN, undefined not handled) function quicksort$1(arr, asc) { quicksortPartition(arr, 0, arr.length-1); if (asc === false) Array.prototype.reverse.call(arr); // Works with typed arrays return arr; } // Moved out of quicksort() (saw >100% speedup in Chrome with deep recursion) function quicksortPartition (a, lo, hi) { var i = lo, j = hi, pivot, tmp; while (i < hi) { pivot = a[lo + hi >> 1]; // avoid n^2 performance on sorted arrays while (i <= j) { while (a[i] < pivot) i++; while (a[j] > pivot) j--; if (i <= j) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; i++; j--; } } if (lo < j) quicksortPartition(a, lo, j); lo = i; j = hi; } } function findRankByValue(arr, value) { if (isNaN(value)) return arr.length; var rank = 1; for (var i=0, n=arr.length; i<n; i++) { if (value > arr[i]) rank++; } return rank; } function findValueByPct(arr, pct) { var rank = Math.ceil((1-pct) * (arr.length)); return findValueByRank(arr, rank); } // See http://ndevilla.free.fr/median/median/src/wirth.c // Elements of @arr are reordered // function findValueByRank(arr, rank) { if (!arr.length || rank < 1 || rank > arr.length) error("[findValueByRank()] invalid input"); rank = clamp(rank | 0, 1, arr.length); var k = rank - 1, // conv. rank to array index n = arr.length, l = 0, m = n - 1, i, j, val, tmp; while (l < m) { val = arr[k]; i = l; j = m; do { while (arr[i] < val) {i++;} while (val < arr[j]) {j--;} if (i <= j) { tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; i++; j--; } } while (i <= j); if (j < k) l = i; if (k < i) m = j; } return arr[k]; } function findMedian(arr) { return findQuantile(arr, 0.5); } function findQuantile(arr, k) { var n = arr.length, i1 = Math.floor((n - 1) * k), i2 = Math.ceil((n - 1) * k); if (i1 < 0 || i2 >= n) return NaN; var v1 = findValueByRank(arr, i1 + 1); if (i1 == i2) return v1; var v2 = findValueByRank(arr, i2 + 1); // use linear interpolation var w1 = i2 / (n - 1) - k; var w2 = k - i1 / (n - 1); var v = (v1 * w1 + v2 * w2) * (n - 1); return v; } function mean(arr) { var count = 0, avg = NaN, val; for (var i=0, n=arr.length; i<n; i++) { val = arr[i]; if (isNaN(val)) continue; avg = ++count == 1 ? val : val / count + (count - 1) / count * avg; } return avg; } /* A simplified version of printf formatting Format codes: %[flags][width][.precision]type supported flags: + add '+' before positive numbers 0 left-pad with '0' ' Add thousands separator width: 1 to many precision: .(1 to many) type: s string di integers f decimal numbers xX hexidecimal (unsigned) % literal '%' Examples: code val formatted %+d 1 '+1' %4i 32 ' 32' %04i 32 '0032' %x 255 'ff' %.2f 0.125 '0.13' %'f 1000 '1,000' */ // Usage: format(formatString, [values]) // Tip: When reusing the same format many times, use formatter() for 5x - 10x better performance // function format(fmt) { var fn = formatter(fmt); var str = fn.apply(null, Array.prototype.slice.call(arguments, 1)); return str; } function formatValue(val, matches) { var flags = matches[1]; var padding = matches[2]; var decimals = matches[3] ? parseInt(matches[3].substr(1)) : void 0; var type = matches[4]; var isString = type == 's', isHex = type == 'x' || type == 'X', // isInt = type == 'd' || type == 'i', // isFloat = type == 'f', isNumber = !isString; var sign = "", padDigits = 0, isZero = false, isNeg = false; var str, padChar, padStr; if (isString) { str = String(val); } else if (isHex) { str = val.toString(16); if (type == 'X') str = str.toUpperCase(); } else if (isNumber) { // str = formatNumberForDisplay(val, isInt ? 0 : decimals); str = numToStr(val, decimals); if (str[0] == '-') { isNeg = true; str = str.substr(1); } isZero = parseFloat(str) == 0; if (flags.indexOf("'") != -1 || flags.indexOf(',') != -1) { str = addThousandsSep(str); } if (!isZero) { // BUG: sign is added when num rounds to 0 if (isNeg) { sign = "\u2212"; // U+2212 } else if (flags.indexOf('+') != -1) { sign = '+'; } } } if (padding) { var strLen = str.length + sign.length; var minWidth = parseInt(padding, 10); if (strLen < minWidth) { padDigits = minWidth - strLen; padChar = flags.indexOf('0') == -1 ? ' ' : '0'; padStr = repeatString(padChar, padDigits); } } if (padDigits == 0) { str = sign + str; } else if (padChar == '0') { str = sign + padStr + str; } else { str = padStr + sign + str; } return str; } // Get a function for interpolating formatted values into a string. function formatter(fmt) { var codeRxp = /%([',+0]*)([1-9]?)((?:\.[1-9])?)([sdifxX%])/g; var literals = [], formatCodes = [], startIdx = 0, prefix = "", matches = codeRxp.exec(fmt), literal; while (matches) { literal = fmt.substring(startIdx, codeRxp.lastIndex - matches[0].length); if (matches[0] == '%%') { prefix += literal + '%'; } else { literals.push(prefix + literal); prefix = ''; formatCodes.push(matches); } startIdx = codeRxp.lastIndex; matches = codeRxp.exec(fmt); } literals.push(prefix + fmt.substr(startIdx)); return function() { var str = literals[0], n = arguments.length; if (n != formatCodes.length) { error("[format()] Data does not match format string; format:", fmt, "data:", arguments); } for (var i=0; i<n; i++) { str += formatValue(arguments[i], formatCodes[i]) + literals[i+1]; } return str; }; } function wildcardToRegExp(name) { var rxp = name.split('*').map(function(str) { return regexEscape(str); }).join('.*'); return new RegExp('^' + rxp + '$'); } function createBuffer(arg, arg2) { if (isInteger(arg)) { return B$3.allocUnsafe ? B$3.allocUnsafe(arg) : new B$3(arg); } else { // check allocUnsafe to make sure Buffer.from() will accept strings (it didn't before Node v5.10) return B$3.from && B$3.allocUnsafe ? B$3.from(arg, arg2) : new B$3(arg, arg2); } } function toBuffer(src) { if (src instanceof B$3) return src; if (src instanceof ArrayBuffer) return B$3.from(src); if (src instanceof Uint8Array) { return B$3.from(src.buffer, src.byteOffset, src.byteLength); } error('Unexpected argument type'); } function expandoBuffer(constructor, rate) { var capacity = 0, k = rate >= 1 ? rate : 1.2, buf; return function(size) { if (size > capacity) { capacity = Math.ceil(size * k); buf = constructor ? new constructor(capacity) : createBuffer(capacity); } return buf; }; } function copyElements(src, i, dest, j, n, rev) { var same = src == dest || src.buffer && src.buffer == dest.buffer; var inc = 1, offs = 0, k; if (rev) { if (same) error('copy error'); inc = -1; offs = n - 1; } if (same && j > i) { for (k=n-1; k>=0; k--) { dest[j + k] = src[i + k]; } } else { for (k=0; k<n; k++, offs += inc) { dest[k + j] = src[i + offs]; } } } function extendBuffer(src, newLen, copyLen) { var len = Math.max(src.length, newLen); var n = copyLen || src.length; var dest = new src.constructor(len); copyElements(src, 0, dest, 0, n); return dest; } function mergeNames(name1, name2) { var merged; if (name1 && name2) { merged = findStringPrefix(name1, name2).replace(/[-_]$/, ''); } return merged || ''; } function findStringPrefix(a, b) { var i = 0; for (var n=a.length; i<n; i++) { if (a[i] !== b[i]) break; } return a.substr(0, i); } function parsePercent(o) { var str = String(o); var isPct = str.indexOf('%') > 0; var pct; if (isPct) { pct = Number(str.replace('%', '')) / 100; } else { pct = Number(str); } if (!(pct >= 0 && pct <= 1)) { stop(format("Invalid percentage: %s", str)); } return pct; } function formatVersionedName(name, i) { var suffix = String(i); if (/[0-9]$/.test(name)) { suffix = '-' + suffix; } return name + suffix; } function uniqifyNames(names, formatter) { var counts = countValues(names), format = formatter || formatVersionedName, names2 = []; names.forEach(function(name) { var i = 0, candidate = name, versionedName; while ( names2.indexOf(candidate) > -1 || // candidate name has already been used candidate == name && counts[candidate] > 1 || // duplicate unversioned names candidate != name && counts[candidate] > 0) { // versioned name is a preexisting name i++; versionedName = format(name, i); if (!versionedName || versionedName == candidate) { throw new Error("Naming error"); // catch buggy versioning function } candidate = versionedName; } names2.push(candidate); }); return names2; } // Assume: @raw is string, undefined or null function parseString(raw) { return raw ? raw : ""; } // Assume: @raw is string, undefined or null // Use null instead of NaN for unparsable values // (in part because if NaN is used, empty strings get converted to "NaN" // when re-exported). function parseNumber(raw) { return parseToNum(raw, cleanNumericString); } function parseIntlNumber(raw) { return parseToNum(raw, convertIntlNumString); } function parseToNum(raw, clean) { var str = String(raw).trim(); var parsed = str ? Number(clean(str)) : NaN; return isNaN(parsed) ? null : parsed; } // Remove comma separators from strings function cleanNumericString(str) { return (str.indexOf(',') > 0) ? str.replace(/,([0-9]{3})/g, '$1') : str; } function convertIntlNumString(str) { str = str.replace(/[ .]([0-9]{3})/g, '$1'); return str.replace(',', '.'); } function trimQuotes(str) { var len = str.length, first, last; if (len >= 2) { first = str.charAt(0); last = str.charAt(len-1); if (first == '"' && last == '"' && !str.includes('","') || first == "'" && last == "'" && !str.includes("','")) { str = str.substr(1, len-2); // remove string escapes str = str.replace(first == '"' ? /\\(?=")/g : /\\(?=')/g, ''); } } return str; } var LOGGING = false; var STDOUT = false; // use stdout for status messages var _error, _stop, _message, _warn; var _interrupt = function() { throw new NonFatalError(formatLogArgs(arguments)); }; setLoggingForCLI(); function getLoggingSetter() { var e = _error, s = _stop, m = _message, w = _warn; return function() { setLoggingFunctions(m, e, s, w); }; } function setLoggingForCLI() { function stop() { throw new UserError(formatLogArgs(arguments)); } function error() { var msg = utils.toArray(arguments).join(' '); throw new Error(msg); } function message() { logArgs(arguments); } // CLI warning is just a message (GUI behaves differently) var warn = message; setLoggingFunctions(message, error, stop, warn); } function enableLogging() { LOGGING = true; } function loggingEnabled() { return !!LOGGING; } // Handle an unexpected condition (internal error) function error() { _error.apply(null, utils.toArray(arguments)); } // Handle an error caused by invalid input or misuse of API function stop() { // _stop.apply(null, utils.toArray(arguments)); _stop.apply(null, messageArgs(arguments)); } function interrupt() { _interrupt.apply(null, utils.toArray(arguments)); } // Print a status message function message() { _message.apply(null, messageArgs(arguments)); } function warn() { _warn.apply(null, messageArgs(arguments)); } // A way for the GUI to replace the CLI logging functions function setLoggingFunctions(message, error, stop, warn) { _message = message; _error = error; _stop = stop; _warn = warn; } // get detailed error information from error stack (if available) // Example stack string (Node.js): /* /Users/someuser/somescript.js:226 opacity: Math.round(weight * 5 / 5 // 0.2 0.4 0.6 etc ^ SyntaxError: missing ) after argument list at internalCompileFunction (node:internal/vm:73:18) at wrapSafe (node:internal/modules/cjs/loader:1149:20) at Module._compile (node:internal/modules/cjs/loader:1190:27) ... */ function getErrorDetail(e) { var parts = (typeof e.stack == 'string') ? e.stack.split(/\n\s*\n/) : []; if (parts.length > 1 || true) { return '\nError details:\n' + parts[0]; } } // print a message to stdout function print() { STDOUT = true; // tell logArgs() to print to stdout, not stderr // calling message() adds the "[command name]" prefix _message(utils.toArray(arguments)); STDOUT = false; } function verbose() { // verbose can be set globally with the -verbose command or separately for each command if (getStashedVar('VERBOSE')) { message.apply(null, arguments); } } function debug() { if (getStashedVar('DEBUG')) { logArgs(arguments); } } function printError(err) { var msg; if (!LOGGING) return; if (utils.isString(err)) { err = new UserError(err); } if (err.name == 'NonFatalError') { console.error(messageArgs([err.message]).join(' ')); } else if (err.name == 'UserError') { msg = err.message; if (!/Error/.test(msg)) { msg = "Error: " + msg; } console.error(messageArgs([msg]).join(' ')); console.error("Run mapshaper -h to view help"); } else { // not a user error (i.e. a bug in mapshaper) console.error(err); // throw err; } } function UserError(msg) { var err = new Error(msg); err.name = 'UserError'; return err; } function NonFatalError(msg) { var err = new Error(msg); err.name = 'NonFatalError'; return err; } function formatColumns(arr, alignments) { var widths = arr.reduce(function(memo, line) { return line.map(function(str, i) { return memo ? Math.max(memo[i], str.length) : str.length; }); }, null); return arr.map(function(line) { line = line.map(function(str, i) { var rt = alignments && alignments[i] == 'right'; var pad = (rt ? str.padStart : str.padEnd).bind(str); return pad(widths[i], ' '); }); return ' ' + line.join(' '); }).join('\n'); } // Format an array of (preferably short) strings in columns for console logging. function formatStringsAsGrid(arr, width) { // TODO: variable column width var longest = arr.reduce(function(len, str) { return Math.max(len, str.length); }, 0), colWidth = longest + 2, perLine = Math.floor((width || 80) / colWidth) || 1; return arr.reduce(function(memo, name, i) { var col = i % perLine; if (i > 0 && col === 0) memo += '\n'; if (col < perLine - 1) { // right-pad all but rightmost column name = utils.rpad(name, colWidth - 2, ' '); } return memo + ' ' + name; }, ''); } // expose so GUI can use it function formatLogArgs(args) { return utils.toArray(args).join(' '); } function messageArgs(args) { var arr = utils.toArray(args); var cmd = getStashedVar('current_command'); if (cmd && cmd != 'help') { arr.unshift('[' + cmd + ']'); } return arr; } function logArgs(args) { if (!LOGGING || getStashedVar('QUIET') || !utils.isArrayLike(args)) return; var msg = formatLogArgs(args); if (STDOUT) console.log(msg); else console.error(msg); } function truncateString(str, maxLen) { maxLen = maxLen || 80; if (str.length > maxLen) { str = str.substring(0, maxLen - 3).trimEnd() + '...'; } return str; } var Logging = /*#__PURE__*/Object.freeze({ __proto__: null, NonFatalError: NonFatalError, UserError: UserError, debug: debug, enableLogging: enableLogging, error: error, formatColumns: formatColumns, formatLogArgs: formatLogArgs, formatStringsAsGrid: formatStringsAsGrid, getErrorDetail: getErrorDetail, getLoggingSetter: getLoggingSetter, interrupt: interrupt, logArgs: logArgs, loggingEnabled: loggingEnabled, message: message, print: print, printError: printError, setLoggingForCLI: setLoggingForCLI, setLoggingFunctions: setLoggingFunctions, stop: stop, truncateString: truncateString, verbose: verbose, warn: warn }); function Transform() { this.mx = this.my = 1; this.bx = this.by = 0; } Transform.prototype.isNull = function() { return !this.mx || !this.my || isNaN(this.bx) || isNaN(this.by); }; Transform.prototype.invert = function() { var inv = new Transform(); inv.mx = 1 / this.mx; inv.my = 1 / this.my; //inv.bx = -this.bx * inv.mx; //inv.by = -this.by * inv.my; inv.bx = -this.bx / this.mx; inv.by = -this.by / this.my; return inv; }; Transform.prototype.transform = function(x, y, xy) { xy = xy || []; xy[0] = x * this.mx + this.bx; xy[1] = y * this.my + this.by; return xy; }; Transform.prototype.toString = function() { return JSON.stringify(Object.assign({}, this)); }; function Bounds() { if (arguments.length > 0) { this.setBounds.apply(this, arguments); } } Bounds.from = function() { var b = new Bounds(); return b.setBounds.apply(b, arguments); }; Bounds.prototype.toString = function() { return JSON.stringify({ xmin: this.xmin, xmax: this.xmax, ymin: this.ymin, ymax: this.ymax }); }; Bounds.prototype.toArray = function() { return this.hasBounds() ? [this.xmin, this.ymin, this.xmax, this.ymax] : []; }; Bounds.prototype.hasBounds = function() { return this.xmin <= this.xmax && this.ymin <= this.ymax; }; Bounds.prototype.sameBounds = Bounds.prototype.equals = function(bb) { return bb && this.xmin === bb.xmin && this.xmax === bb.xmax && this.ymin === bb.ymin && this.ymax === bb.ymax; }; Bounds.prototype.width = function() { return (this.xmax - this.xmin) || 0; }; Bounds.prototype.height = function() { return (this.ymax - this.ymin) || 0; }; Bounds.prototype.area = function() { return this.width() * this.height() || 0; }; Bounds.prototype.empty = function() { this.xmin = this.ymin = this.xmax = this.ymax = void 0; return this; }; Bounds.prototype.setBounds = function(a, b, c, d) { if (arguments.length == 1) { // assume first arg is a Bounds or array if (utils.isArrayLike(a)) { b = a[1]; c = a[2]; d = a[3]; a = a[0]; } else { b = a.ymin; c = a.xmax; d = a.ymax; a = a.xmin; } } this.xmin = a; this.ymin = b; this.xmax = c; this.ymax = d; if (a > c || b > d) this.update(); return this; }; Bounds.prototype.centerX = function() { var x = (this.xmin + this.xmax) * 0.5; return x; }; Bounds.prototype.centerY = function() { var y = (this.ymax + this.ymin) * 0.5; return y; }; Bounds.prototype.containsPoint = function(x, y) { if (x >= this.xmin && x <= this.xmax && y <= this.ymax && y >= this.ymin) { return true; } return false; }; // intended to speed up slightly bubble symbol detection; could use intersects() instead // TODO: fix false positive where circle is just outside a corner of the box Bounds.prototype.containsBufferedPoint = Bounds.prototype.containsCircle = function(x, y, buf) { if ( x + buf > this.xmin && x - buf < this.xmax ) { if ( y - buf < this.ymax && y + buf > this.ymin ) { return true; } } return false; }; Bounds.prototype.intersects = function(bb) { if (bb.xmin <= this.xmax && bb.xmax >= this.xmin && bb.ymax >= this.ymin && bb.ymin <= this.ymax) { return true; } return false; }; Bounds.prototype.contains = function(bb) { if (bb.xmin >= this.xmin && bb.ymax <= this.ymax && bb.xmax <= this.xmax && bb.ymin >= this.ymin) { return true; } return false; }; Bounds.prototype.shift = function(x, y) { this.setBounds(this.xmin + x, this.ymin + y, this.xmax + x, this.ymax + y); }; Bounds.prototype.padBounds = function(a, b, c, d) { this.xmin -= a; this.ymin -= b; this.xmax += c; this.ymax += d; }; // Rescale the bounding box by a fraction. TODO: implement focus. // @param {number} pct Fraction of original extents // @param {number} pctY Optional amount to scale Y // Bounds.prototype.scale = function(pct, pctY) { /*, focusX, focusY*/ var halfWidth = (this.xmax - this.xmin) * 0.5; var halfHeight = (this.ymax - this.ymin) * 0.5; var kx = pct - 1; var ky = pctY === undefined ? kx : pctY - 1; this.xmin -= halfWidth * kx; this.ymin -= halfHeight * ky; this.xmax += halfWidth * kx; this.ymax += halfHeight * ky; return this; }; // Return a bounding box with the same extent as this one. Bounds.prototype.cloneBounds = // alias so child classes can override clone() Bounds.prototype.clone = function() { return new Bounds(this.xmin, this.ymin, this.xmax, this.ymax); }; Bounds.prototype.clearBounds = function() { this.setBounds(new Bounds()); }; Bounds.prototype.mergePoint = function(x, y) { if (this.xmin === void 0) { this.setBounds(x, y, x, y); } else { // this works even if x,y are NaN if (x < this.xmin) this.xmin = x; else if (x > this.xmax) this.xmax = x; if (y < this.ymin) this.ymin = y; else if (y > this.ymax) this.ymax = y; } }; // expands either x or y dimension to match @aspect (width/height ratio) // @focusX, @focusY (optional): expansion focus, as a fraction of width and height Bounds.prototype.fillOut = function(aspect, focusX, focusY) { if (arguments.length < 3) { focusX = 0.5; focusY = 0.5; } var w = this.width(), h = this.height(), currAspect = w / h, pad; if (isNaN(aspect) || aspect <= 0) ; else if (currAspect < aspect) { // fill out x dimension pad = h * aspect - w; this.xmin -= (1 - focusX) * pad; this.xmax += focusX * pad; } else { pad = w / aspect - h; this.ymin -= (1 - focusY) * pad; this.ymax += focusY * pad; } return this; }; Bounds.prototype.update = function() { var tmp; if (this.xmin > this.xmax) { tmp = this.xmin; this.xmin = this.xmax; this.xmax = tmp; } if (this.ymin > this.ymax) { tmp = this.ymin; this.ymin = this.ymax; this.ymax = tmp; } }; Bounds.prototype.transform = function(t) { this.xmin = this.xmin * t.mx + t.bx; this.xmax = this.xmax * t.mx + t.bx; this.ymin = this.ymin * t.my + t.by; this.ymax = this.ymax * t.my + t.by; this.update(); return this; }; // Returns a Transform object for mapping this onto Bounds @b2 // @flipY (optional) Flip y-axis coords, for converting to/from pixel coords // Bounds.prototype.getTransform = function(b2, flipY) { var t = new Transform(); t.mx = b2.width() / this.width() || 1; // TODO: better handling of 0 w,h t.bx = b2.xmin - t.mx * this.xmin; if (flipY) { t.my = -b2.height() / this.height() || 1; t.by = b2.ymax - t.my * this.ymin; } else { t.my = b2.height() / this.height() || 1; t.by = b2.ymin - t.my * this.ymin; } return t; }; Bounds.prototype.mergeCircle = function(x, y, r) { if (r < 0) r = -r; this.mergeBounds([x - r, y - r, x + r, y + r]); }; Bounds.prototype.mergeBounds = function(bb) { var a, b, c, d; if (bb instanceof Bounds) { a = bb.xmin; b = bb.ymin; c = bb.xmax; d = bb.ymax; } else if (arguments.length == 4) { a = arguments[0]; b = arguments[1]; c = arguments[2]; d = arguments[3]; } else if (bb.length == 4) { // assume array: [xmin, ymin, xmax, ymax] a = bb[0]; b = bb[1]; c = bb[2]; d = bb[3]; } else { error("Bounds#mergeBounds() invalid argument:", bb); } if (this.xmin === void 0) { this.setBounds(a, b, c, d); } else { if (a < this.xmin) this.xmin = a; if (b < this.ymin) this.ymin = b; if (c > this.xmax) this.xmax = c; if (d > this.ymax) this.ymax = d; } return this; }; function countPointsInLayer(lyr) { var count = 0; if (layerHasPoints(lyr)) { forEachPoint(lyr.shapes, function() {count++;}); } return count; } // export function getPointBounds(shapes) { // var bounds = new Bounds(); // forEachPoint(shapes, function(p) { // bounds.mergePoint(p[0], p[1]); // }); // return bounds; // } function getPointBounds$1(shapes) { new Bounds(); var shp, x, y, xmin = Infinity, ymin = Infinity, xmax = -Infinity, ymax = -Infinity; for (var i=0, n=shapes.length; i<n; i++) { shp = shapes[i]; for (var j=0, m=shp ? shp.length : 0; j<m; j++) { x = shp[j][0]; y = shp[j][1]; if (x > xmax) xmax = x; if (x < xmin) xmin = x; if (y > ymax) ymax = y; if (y < ymin) ymin = y; } } return shp ? new Bounds(xmin, ymin, xmax, ymax) : new Bounds(); } function getPointFeatureBounds(shape, bounds) { var n = shape ? shape.length : 0; var p; if (!bounds) bounds = new Bounds(); for (var i=0; i<n; i++) { p = shape[i]; bounds.mergePoint(p[0], p[1]); } return bounds; } // NOTE: layers can have multipoint features and null features function getPointsInLayer(lyr) { var coords = []; forEachPoint(lyr.shapes, function(p) { coords.push(p); }); return coords; } // Iterate over each [x,y] point in a layer // shapes: one layer's "shapes" array function forEachPoint(shapes, cb) { var i, n, j, m, shp; for (i=0, n=shapes.length; i<n; i++) { shp = shapes[i]; for (j=0, m=shp ? shp.length : 0; j<m; j++) { cb(shp[j], i); } } } var PointUtils = /*#__PURE__*/Object.freeze({ __proto__: null, countPointsInLayer: countPointsInLayer, forEachPoint: forEachPoint, getPointBounds: getPointBounds$1, getPointFeatureBounds: getPointFeatureBounds, getPointsInLayer: getPointsInLayer }); function absArcId(arcId) { return arcId >= 0 ? arcId : ~arcId; } function calcArcBounds(xx, yy, start, len) { var i = start | 0, n = isNaN(len) ? xx.length - i : len + i, x, y, xmin, ymin, xmax, ymax; if (n > 0) { xmin = xmax = xx[i]; ymin = ymax = yy[i]; } for (i++; i<n; i++) { x = xx[i]; y = yy[i]; if (x < xmin) xmin = x; if (x > xmax) xmax = x; if (y < ymin) ymin = y; if (y > ym